示例#1
0
        public static void FindModelFile()
        {
            var path = EditorUtility.OpenFilePanelWithFilters("Select model file", "Packages/com.unity.lego.modelimporter/Models", new string[] { "All model files", "ldr,io,lxfml,lxf", "LDraw files", "ldr", "Studio files", "io", "LXFML files", "lxfml", "LXF files", "lxf" });

            if (path.Length != 0)
            {
                lxfml = ReadFileLogic(path);
                if (lxfml != null)
                {
                    pivot    = Model.Pivot.BottomCenter;
                    filePath = path;

                    importSettings.Clear();
                    foreach (var group in lxfml.groups)
                    {
                        importSettings.Add(group.number, new ModelGroupImportSettings());
                    }

                    model = null;
                    group = null;

                    GetWindow <ImportModel>(true, "LEGO Model Importer");
                }
                else
                {
                    ShowReadError();
                }
            }
        }
示例#2
0
        public static void ReimportModelGroup(ModelGroup group)
        {
            lxfml = ReadFileLogic(group.relativeFilePath);
            if (lxfml == null)
            {
                lxfml = ReadFileLogic(group.absoluteFilePath);
            }
            if (lxfml != null)
            {
                filePath = null;

                importSettings.Clear();
                importSettings.Add(group.number, group.importSettings);

                // Check if group matches up with the file.
                // FIXME Next version could include option to match groups up manually.
                if (group.number >= lxfml.groups.Length || lxfml.groups[group.number].name != group.groupName)
                {
                    EditorUtility.DisplayDialog("Reimport failed", $"Model group {group.number} {group.groupName} does not match up with group in file", "Ok");
                    return;
                }

                model             = null;
                ImportModel.group = group;

                GetWindow <ImportModel>(true, "LEGO Model Importer");
            }
            else
            {
                ShowReadError();
            }
        }
示例#3
0
        private static LXFMLDoc.BrickGroup FindGroup(LXFMLDoc lxfml, LXFMLDoc.Brick brick)
        {
            foreach (var group in lxfml.groups)
            {
                if (group.brickRefs.Contains(brick.refId))
                {
                    return(group);
                }
            }

            return(null);
        }
示例#4
0
        private static void CreateDefaultGroup(LXFMLDoc lxfml)
        {
            lxfml.groups = new LXFMLDoc.BrickGroup[] { new LXFMLDoc.BrickGroup() };
            var group = lxfml.groups[0];

            group.name   = "Default";
            group.number = 0;

            group.brickRefs = new int[lxfml.bricks.Count];
            for (var i = 0; i < lxfml.bricks.Count; ++i)
            {
                group.brickRefs[i] = lxfml.bricks[i].refId;
                group.bricks.Add(lxfml.bricks[i]);
            }
        }
示例#5
0
        private static bool FixLooseBricks(LXFMLDoc lxfml)
        {
            var looseBricks = new List <LXFMLDoc.Brick>();

            foreach (var brick in lxfml.bricks)
            {
                if (!FindBrickInGroups(brick, lxfml.groups))
                {
                    looseBricks.Add(brick);
                }
            }

            if (looseBricks.Count > 0)
            {
                var newGroups = new List <LXFMLDoc.BrickGroup>(lxfml.groups);
                newGroups.Insert(0, new LXFMLDoc.BrickGroup());
                lxfml.groups = newGroups.ToArray();

                var group = newGroups[0];
                group.name   = "Main model";
                group.number = 0;

                for (var i = 1; i < newGroups.Count; ++i)
                {
                    newGroups[i].number = i;
                }

                group.brickRefs = new int[looseBricks.Count];
                for (var i = 0; i < looseBricks.Count; ++i)
                {
                    group.brickRefs[i] = looseBricks[i].refId;
                    group.bricks.Add(looseBricks[i]);
                }

                return(true);
            }

            return(false);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="lxfmlDoc"></param>
        /// <param name="lxfml"></param>
        /// <returns></returns>
        public static bool ReadLxfml(XmlDocument lxfmlDoc, ref LXFMLDoc lxfml)
        {
            var success = false;

            if (lxfmlDoc != null)
            {
                try
                {
                    success = true;

                    var lxfmlNode  = lxfmlDoc.SelectSingleNode("LXFML");
                    var cameraNode = lxfmlNode.SelectSingleNode("Cameras/Camera");

                    if (cameraNode != null)
                    {
                        var lxfmlCamera = new LXFMLDoc.LxfmlCamera();
                        lxfmlCamera.fov            = float.Parse(cameraNode.Attributes["fieldOfView"].Value, CultureInfo.InvariantCulture);
                        lxfmlCamera.distance       = float.Parse(cameraNode.Attributes["distance"].Value, CultureInfo.InvariantCulture);
                        lxfmlCamera.transformation = ParseUtils.StringToFloatArray(cameraNode.Attributes["transformation"].Value);
                        var transformation = new Matrix4x4();
                        var mArr           = ParseUtils.StringToFloatArray(cameraNode.Attributes["transformation"].Value);

                        for (var i = 0; i < 4; ++i)
                        {
                            transformation.SetRow(i, new Vector4(mArr[i * 3], mArr[i * 3 + 1], mArr[i * 3 + 2], 0));
                        }

                        lxfmlCamera.position = GetPosition(transformation);
                        lxfmlCamera.rotation = GetRotation(transformation);
                        lxfml.camera         = lxfmlCamera;
                    }

                    var lxfmlNameAttrib = lxfmlNode.Attributes["name"];
                    if (lxfmlNameAttrib != null)
                    {
                        lxfml.name = lxfmlNameAttrib.Value;
                    }

                    var bricksNode = lxfmlNode.SelectSingleNode("Bricks");
                    var brickNodes = bricksNode.SelectNodes("Brick");

                    foreach (XmlNode brickNode in brickNodes)
                    {
                        var brick = PopulateBrick(brickNode);
                        lxfml.bricks.Add(brick);
                    }

                    var groupsNode = lxfmlNode.SelectSingleNode("GroupSystems");

                    if (groupsNode != null)
                    {
                        var brickGroupSystemNode = groupsNode.SelectSingleNode("BrickGroupSystem"); // TODO: Handle PartGroupSystem.
                        if (brickGroupSystemNode != null)
                        {
                            var rootGroupNodes = brickGroupSystemNode.SelectNodes("Group");

                            if (rootGroupNodes.Count > 0)
                            {
                                lxfml.groups = new LXFMLDoc.BrickGroup[rootGroupNodes.Count];
                                var groupCount = 0;

                                foreach (XmlNode rootGroupNode in rootGroupNodes)
                                {
                                    var group         = new LXFMLDoc.BrickGroup();
                                    var nameAttribute = rootGroupNode.Attributes["name"];
                                    if (nameAttribute != null)
                                    {
                                        group.name = nameAttribute.Value;
                                    }
                                    group.number = groupCount;

                                    lxfml.groups[groupCount++] = group;

                                    //Sub groups!
                                    if (rootGroupNode.SelectNodes("Group").Count > 0)
                                    {
                                        ReadGroupTreeRecursively(group, group, rootGroupNode);
                                    }
                                    else
                                    {
                                        var brickRefsAttribute = rootGroupNode.Attributes["brickRefs"];

                                        if (brickRefsAttribute != null)
                                        {
                                            group.brickRefs = ParseUtils.StringToIntArray(brickRefsAttribute.Value);
                                            SetGroupBricksFromBrickRefs(lxfml.bricks, group);
                                        }
                                        else
                                        {
                                            group.brickRefs = new int[0];
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    Debug.LogWarning(e + "\t" + e.StackTrace);
                    success = false;
                }
            }

            return(success);
        }
示例#7
0
        public static void ReimportModelGroup(LXFMLDoc lxfml, ModelGroup group, ModelGroupImportSettings importSettings, bool detectConnectivity = false)
        {
            // Assign the new group import settings to the group.
            group.importSettings = importSettings;

            // We assume that the group can be found, so reimport it.
            if (group.processed)
            {
                // Remove all processed meshes.
                var renderers = group.GetComponentsInChildren <MeshRenderer>();
                foreach (var renderer in renderers)
                {
                    // FIXME Destroy the mesh? Prevents undo..
                    var filter = renderer.GetComponent <MeshFilter>();
                    //Undo.DestroyObjectImmediate(filter.sharedMesh);

                    if (renderer.GetComponent <ModelGroup>() == null)
                    {
                        // Destroy submesh game objects entirely.
                        Undo.DestroyObjectImmediate(renderer.gameObject);
                    }
                    else
                    {
                        // Destroy mesh related components on group game object.
                        Object.DestroyImmediate(filter);
                        Object.DestroyImmediate(renderer);
                    }
                }
            }

            // FIXME Check if bricks are referenced.
            // FIXME Check if bricks have custom components attached.

            // Remove group bricks.
            var existingBricks = group.GetComponentsInChildren <Brick>();

            foreach (var brick in existingBricks)
            {
                Undo.DestroyObjectImmediate(brick.gameObject);
            }

            var groupLightMapped = group.importSettings.isStatic && group.importSettings.lightmapped;

            SetStaticAndGIParams(group.gameObject, group.importSettings.isStatic, groupLightMapped);

            // Move group to origo to ensure that bricks are instantiated in the correct positions.
            var originalGroupLocalPosition = group.transform.localPosition;
            var originalGroupLocalRotation = group.transform.localRotation;
            var originalGroupLocalScale    = group.transform.localScale;
            var originalGroupParent        = group.transform.parent;
            var originalGroupSiblingIndex  = group.transform.GetSiblingIndex();

            group.transform.SetParent(null);
            group.transform.localPosition = Vector3.zero;
            group.transform.localRotation = Quaternion.identity;
            group.transform.localScale    = Vector3.one;

            // Create dictionary with just this group.
            var modelGroupImportSettingsDictionary = new DictionaryIntToModelGroupImportSettings();

            modelGroupImportSettingsDictionary.Add(group.number, group.importSettings);

            // Instantiate group bricks.
            var resultBricks = new Dictionary <int, Brick>(lxfml.bricks.Count);

            InstantiateModelBricks(lxfml, modelGroupImportSettingsDictionary, ref resultBricks, group.number);

            // Assign bricks to group.
            foreach (var brick in resultBricks.Values)
            {
                brick.transform.SetParent(group.transform);
            }
            ModelGroupUtility.RecomputePivot(group, false, ModelGroupUtility.UndoBehavior.withoutUndo);

            // Move group back to original location.
            group.transform.SetParent(originalGroupParent);
            group.transform.SetSiblingIndex(originalGroupSiblingIndex);
            group.transform.localPosition = originalGroupLocalPosition;
            group.transform.localRotation = originalGroupLocalRotation;
            group.transform.localScale    = originalGroupLocalScale;

            /*if (group.processed)
             * {
             *  // Process the group again.
             *  // FIXME Is this even a good idea?
             *  if (group.type == GroupType.Environment || group.type == GroupType.Static)
             *  {
             *      Vector2Int vertCount = Vector2Int.zero;
             *      Vector2Int triCount = Vector2Int.zero;
             *      Vector2Int meshCount = Vector2Int.zero;
             *      Vector2Int colliderCount = Vector2Int.zero;
             *      ModelProcessor.ProcessModelGroup(group, ref vertCount, ref triCount, ref meshCount, ref colliderCount);
             *
             *      Debug.Log($"Process result (before/after):\nVerts {vertCount.x}/{vertCount.y}, tris {triCount.x}/{triCount.y}, meshes {meshCount.x}/{meshCount.y}, colliders {colliderCount.x}/{colliderCount.y}");
             *  }
             * }*/

            if (detectConnectivity && group.importSettings.connectivity)
            {
                var sceneBricks = new HashSet <Brick>(StageUtility.GetCurrentStageHandle().FindComponentsOfType <Brick>());
                DetectConnectivity(new HashSet <Brick>(resultBricks.Values), sceneBricks);
            }

            EditorUtility.ClearProgressBar();
        }
示例#8
0
        public static void ReimportModel(LXFMLDoc lxfml, Model model, DictionaryIntToModelGroupImportSettings importSettings)
        {
            var brickBuilding = SceneBrickBuilder.GetToggleBrickBuildingStatus();

            if (brickBuilding)
            {
                SceneBrickBuilder.ToggleBrickBuilding();
            }

            // FIXME Next version could include option to match groups up manually.

            var groups = model.GetComponentsInChildren <ModelGroup>();

            for (var i = groups.Length - 1; i >= 0; i--)
            {
                var group = groups[i];
                if (group.autoGenerated)
                {
                    Undo.DestroyObjectImmediate(group.gameObject);
                }
                else if (group.number >= lxfml.groups.Length)
                {
                    Debug.LogWarning("Group " + group.number + " " + group.groupName + " does not match up with files. Wiping.");
                    Undo.DestroyObjectImmediate(group.gameObject);
                }
            }

            groups = model.GetComponentsInChildren <ModelGroup>();

            var removedGroups = new List <LXFMLDoc.BrickGroup>();

            for (var i = 0; i < lxfml.groups.Length; i++)
            {
                LXFMLDoc.BrickGroup group = lxfml.groups[i];
                bool exists = false;
                for (var j = 0; j < groups.Length; j++)
                {
                    if (groups[j].number == group.number)
                    {
                        exists = true;
                        break;
                    }
                }

                if (!exists)
                {
                    removedGroups.Add(group);
                }
            }

            // Assign the new model import settings to the model.
            model.importSettings = new DictionaryIntToModelGroupImportSettings(importSettings);
            var bricksWithConnectivity = new HashSet <Brick>();

            if (removedGroups.Count > 0)
            {
                var resultBricks = new Dictionary <int, Brick>(lxfml.bricks.Count);
                foreach (var group in removedGroups)
                {
                    var number = group.number;
                    InstantiateModelBricks(lxfml, model.importSettings, ref resultBricks, number);
                    var groupGO = InstantiateModelGroup(group, number, model.gameObject, model.absoluteFilePath, model.relativeFilePath, ref resultBricks, false, importSettings[number]);
                    groupGO.transform.position = model.transform.position;
                    Undo.RegisterCreatedObjectUndo(groupGO, "Re-creating model group");
                    if (importSettings[number].connectivity)
                    {
                        bricksWithConnectivity.UnionWith(groupGO.GetComponentsInChildren <Brick>());
                    }
                }
            }

            foreach (var group in groups)
            {
                group.absoluteFilePath = model.absoluteFilePath;
                group.relativeFilePath = model.relativeFilePath;
                ReimportModelGroup(lxfml, group, importSettings[group.number]);
                if (group.importSettings.connectivity)
                {
                    bricksWithConnectivity.UnionWith(group.GetComponentsInChildren <Brick>());
                }
            }

            if (bricksWithConnectivity.Count > 0)
            {
                var sceneBricks = new HashSet <Brick>(StageUtility.GetCurrentStageHandle().FindComponentsOfType <Brick>());
                DetectConnectivity(bricksWithConnectivity, sceneBricks);
            }

            if (brickBuilding)
            {
                SceneBrickBuilder.ToggleBrickBuilding();
            }

            if (SceneBrickBuilder.GetAutoUpdateHierarchy())
            {
                groups = model.GetComponentsInChildren <ModelGroup>();
                var bricks = new HashSet <Brick>();
                foreach (var group in groups)
                {
                    if (group.importSettings.connectivity)
                    {
                        var groupBricks = group.GetComponentsInChildren <Brick>();
                        foreach (var brick in groupBricks)
                        {
                            bricks.Add(brick);
                        }
                    }
                }

                // On reimport, the model will be positioned weirdly compared to the rest of the scene, so we just ignore all other bricks
                ModelGroupUtility.RecomputeModelGroups(bricks);
            }

            EditorUtility.ClearProgressBar();
        }
示例#9
0
        /// <summary>
        /// Instantiate all bricks and groups in an LXFML document
        /// </summary>
        /// <param name="lxfml">The LXFML document</param>
        /// <param name="nameOfObject">Path of the LXFML document</param>
        public static GameObject InstantiateModel(LXFMLDoc lxfml, string filePath, Model.Pivot pivot, DictionaryIntToModelGroupImportSettings importSettings)
        {
            //Create "root" LXFML gameobject
            GameObject parent = new GameObject(Path.GetFileNameWithoutExtension(filePath));

            Undo.RegisterCreatedObjectUndo(parent, "Model");
            parent.transform.position = Vector3.zero;

            var model = parent.AddComponent <Model>();

            model.absoluteFilePath = filePath;
            model.relativeFilePath = PathUtils.GetRelativePath(Directory.GetCurrentDirectory(), filePath);
            model.pivot            = pivot;
            model.importSettings   = new DictionaryIntToModelGroupImportSettings(importSettings);

            EditorUtility.DisplayProgressBar("Importing", "Creating bricks.", 0.0f);

            var resultBricks = new Dictionary <int, Brick>(lxfml.bricks.Count);

            InstantiateModelBricks(lxfml, importSettings, ref resultBricks);

            EditorUtility.DisplayProgressBar("Importing", "Creating groups.", 0.8f);

            if (resultBricks.Count > 0)
            {
                var bricksWithConnectivity = new HashSet <Brick>();
                var groups = lxfml.groups;

                for (int i = 0; i < groups.Length; i++)
                {
                    var        number      = groups[i].number;
                    GameObject groupParent = InstantiateModelGroup(groups[i], i, parent, filePath, model.relativeFilePath, ref resultBricks, false, importSettings[number]);
                    if (importSettings[number].connectivity)
                    {
                        bricksWithConnectivity.UnionWith(groupParent.GetComponentsInChildren <Brick>());
                    }
                }

                if (bricksWithConnectivity.Count > 0)
                {
                    var sceneBricks = new HashSet <Brick>(StageUtility.GetCurrentStageHandle().FindComponentsOfType <Brick>());
                    DetectConnectivity(bricksWithConnectivity, sceneBricks);
                }


                if (SceneBrickBuilder.GetAutoUpdateHierarchy())
                {
                    var bricks = new HashSet <Brick>();
                    foreach (var pair in resultBricks)
                    {
                        foreach (var part in pair.Value.parts)
                        {
                            if (part.connectivity)
                            {
                                bricks.Add(pair.Value);
                                break;
                            }
                        }
                    }

                    // On import, the model will be positioned weirdly compared to the rest of the scene, so we just ignore all other bricks
                    ModelGroupUtility.RecomputeModelGroups(bricks, false, ModelGroupUtility.UndoBehavior.withoutUndo);
                }
            }

            // Change the pivot.
            if (pivot != Model.Pivot.Original)
            {
                EditorUtility.DisplayProgressBar("Importing", "Computing bounds.", 0.9f);

                var bounds   = ComputeBounds(parent.transform);
                var newPivot = bounds.center;
                switch (pivot)
                {
                case Model.Pivot.BottomCenter:
                {
                    newPivot += -parent.transform.up * bounds.extents.y;
                    break;
                }
                }

                foreach (Transform child in parent.transform)
                {
                    child.position -= newPivot;
                }
                parent.transform.position += newPivot;
            }

            // Add LEGOModelAsset component.
            parent.AddComponent <LEGOModelAsset>();

            EditorUtility.ClearProgressBar();

            return(parent);
        }
示例#10
0
        /// <summary>
        /// Instantiate game objects for each brick in an LXFML-file
        /// </summary>
        /// <param name="lxfml">The LXFML-file</param>
        /// <param name="colliders">Add colliders to part</param>
        /// <param name="connectivity">Add connectivity to part</param>
        /// <param name="isStatic">Make the part static</param>
        /// <param name="lightmapped">Instantiate meshes with or without lightmap UVs</param>
        /// <param name="randomizeRotation">Slightly rotate rotation of part</param>
        /// <param name="preferLegacy">Choose legacy meshes if available</param>
        /// <param name="lod">Instantiate meshes of a certain LOD</param>
        /// <param name="resultBricks">Dictionary that contains brick component, using refID as key</param>
        /// <param name="groupNumber">If non-negative, only instantiate bricks from the specified group number</param>
        public static void InstantiateModelBricks(LXFMLDoc lxfml, DictionaryIntToModelGroupImportSettings importSettings, ref Dictionary <int, Brick> resultBricks, int groupNumber = -1)
        {
            for (var i = 0; i < lxfml.bricks.Count; ++i)
            {
                if (i % 200 == 0)
                {
                    EditorUtility.DisplayProgressBar("Importing", "Creating bricks.", ((float)i / lxfml.bricks.Count) * 0.7f);
                }

                var brick = lxfml.bricks[i];

                var group = FindGroup(lxfml, brick);

                // Discard bricks from other groups if group number is specified.
                if (groupNumber >= 0 && group != null && group.number != groupNumber)
                {
                    continue;
                }

                // Determine whether or not to be static and to generate light map UVs.
                var brickStatic      = (group != null ? importSettings[group.number].isStatic : false);
                var brickLightmapped = brickStatic && (group != null ? importSettings[group.number].lightmapped : false);
                var brickLod         = (group != null ? importSettings[group.number].lod : 0);

                var brickGO   = new GameObject(brick.designId, typeof(Brick));
                var brickComp = brickGO.GetComponent <Brick>();
                Undo.RegisterCreatedObjectUndo(brickGO, "Brick");

                foreach (var part in brick.parts)
                {
                    GameObject partToInstantiate = null;

                    var partExistenceResult = PartUtility.UnpackPart(part.partDesignId, brickLightmapped, group != null ? importSettings[group.number].preferLegacy : false, brickLod);

                    if (partExistenceResult.existence != PartUtility.PartExistence.None)
                    {
                        // FIXME Make a note of changed design ids.
                        partToInstantiate = PartUtility.LoadPart(partExistenceResult.designID, brickLightmapped, partExistenceResult.existence == PartUtility.PartExistence.Legacy, brickLod);
                    }

                    if (partToInstantiate == null)
                    {
                        Debug.LogError("Missing part FBX -> " + partExistenceResult.designID);
                        continue;
                    }
                    var partGO = Object.Instantiate(partToInstantiate);
                    partGO.name = partToInstantiate.name;

                    // Assign legacy, material IDs and set up references.
                    var partComp = partGO.AddComponent <Part>();
                    partComp.designID = Convert.ToInt32(part.partDesignId);
                    partComp.legacy   = partExistenceResult.existence == PartUtility.PartExistence.Legacy;
                    foreach (var material in part.materials)
                    {
                        partComp.materialIDs.Add(material.colorId);
                    }
                    partComp.brick = brickComp;
                    brickComp.parts.Add(partComp);


                    if (partExistenceResult.existence == PartUtility.PartExistence.New)
                    {
                        // FIXME Handle normal mapped model.
                        InstantiateKnobsAndTubes(partComp, brickLightmapped, brickLod);
                    }

                    // Create collider and connectivity information.
                    var brickColliders    = (group != null ? importSettings[group.number].colliders : false);
                    var brickConnectivity = brickColliders && (group != null ? importSettings[group.number].connectivity : false);

                    if (brickColliders)
                    {
                        GameObject collidersToInstantiate = null;

                        var collidersAvailable = PartUtility.UnpackCollidersForPart(partExistenceResult.designID);
                        if (collidersAvailable)
                        {
                            collidersToInstantiate = PartUtility.LoadCollidersPrefab(partExistenceResult.designID);
                        }

                        if (collidersToInstantiate == null && partExistenceResult.existence != PartUtility.PartExistence.Legacy)
                        {
                            Debug.LogError("Missing part collider information -> " + partExistenceResult.designID);
                        }

                        if (collidersToInstantiate)
                        {
                            var collidersGO = Object.Instantiate(collidersToInstantiate);
                            collidersGO.name = "Colliders";
                            collidersGO.transform.SetParent(partGO.transform, false);
                            var colliderComps = collidersGO.GetComponentsInChildren <Collider>();
                            partComp.colliders.AddRange(colliderComps);
                        }
                    }

                    if (brickConnectivity)
                    {
                        GameObject connectivityToInstantiate = null;

                        var connectivityAvailable = PartUtility.UnpackConnectivityForPart(partExistenceResult.designID);
                        if (connectivityAvailable)
                        {
                            connectivityToInstantiate = PartUtility.LoadConnectivityPrefab(partExistenceResult.designID);
                        }

                        if (connectivityToInstantiate == null && partExistenceResult.existence != PartUtility.PartExistence.Legacy)
                        {
                            Debug.LogError("Missing part connectivity information -> " + partExistenceResult.designID);
                        }

                        if (connectivityToInstantiate)
                        {
                            var connectivityGO = Object.Instantiate(connectivityToInstantiate);
                            connectivityGO.name = "Connectivity";
                            connectivityGO.transform.SetParent(partGO.transform, false);
                            var connectivityComp = connectivityGO.GetComponent <Connectivity>();
                            partComp.connectivity = connectivityComp;
                            brickComp.totalBounds.Encapsulate(connectivityComp.extents);
                            connectivityComp.part = partComp;

                            foreach (var field in connectivityComp.connectionFields)
                            {
                                foreach (var connection in field.connections)
                                {
                                    MatchConnectionWithKnob(connection, partComp.knobs);
                                    MatchConnectionWithTubes(connection, partComp.tubes);
                                }
                            }
                        }
                    }

                    SetMaterials(partComp, part.materials, partExistenceResult.existence == PartUtility.PartExistence.Legacy);
                    SetDecorations(partComp, part.decorations, partExistenceResult.existence == PartUtility.PartExistence.Legacy);

                    SetStaticAndGIParams(partGO, brickStatic, brickLightmapped, true);

                    // Set Position & Rotation
                    SetPositionRotation(partGO, part);

                    if (group != null ? importSettings[group.number].randomizeRotation : false)
                    {
                        RandomizeRotation(partComp, brickConnectivity);
                    }

                    // If first part, place brick at same position.
                    if (brickGO.transform.childCount == 0)
                    {
                        brickGO.transform.position   = partGO.transform.position;
                        brickGO.transform.rotation   = partGO.transform.rotation;
                        brickGO.transform.localScale = Vector3.one;
                    }
                    partGO.transform.SetParent(brickGO.transform, true);

                    if (!brickConnectivity)
                    {
                        var worldBounds = ComputeBounds(partGO.transform);
                        worldBounds.SetMinMax(brickComp.transform.InverseTransformPoint(worldBounds.min), brickComp.transform.InverseTransformPoint(worldBounds.max));
                        brickComp.totalBounds.Encapsulate(worldBounds);
                    }
                }

                // If all parts were missing, discard brick.
                if (brickGO.transform.childCount == 0)
                {
                    Undo.DestroyObjectImmediate(brickGO);
                    continue;
                }

                SetStaticAndGIParams(brickGO, brickStatic, brickLightmapped);

                // Assign uuid
                brickComp.designID = Convert.ToInt32(brick.designId);
                brickComp.uuid     = brick.uuid;

                // Add LEGOAsset component.
                brickGO.AddComponent <LEGOAsset>();

                resultBricks[brick.refId] = brickComp;
            }
        }
示例#11
0
        public static void ReimportModel(Model model, string newReimportPath = null)
        {
            var absoluteFilePath = model.absoluteFilePath;
            var relativeFilePath = model.relativeFilePath;

            // Update the file path
            if (newReimportPath != null)
            {
                absoluteFilePath = newReimportPath;
                relativeFilePath = PathUtils.GetRelativePath(Directory.GetCurrentDirectory(), newReimportPath);
            }

            lxfml = ReadFileLogic(relativeFilePath);
            if (lxfml == null)
            {
                lxfml = ReadFileLogic(absoluteFilePath);
            }
            if (lxfml != null)
            {
                pivot = model.pivot;

                // Store the new reimport path so it can be applied to the model if reimport is successful.
                filePath = newReimportPath;

                importSettings.Clear();

                // Make sure we are compatible with models from before ModelGroupImportSettings by adding default import settings.
                if (model.importSettings.Keys.Count == 0)
                {
                    foreach (var group in lxfml.groups)
                    {
                        importSettings.Add(group.number, new ModelGroupImportSettings());
                    }
                }
                else
                {
                    foreach (var entry in model.importSettings)
                    {
                        importSettings.Add(entry.Key, entry.Value);
                    }
                }

                foreach (var group in lxfml.groups)
                {
                    if (!importSettings.ContainsKey(group.number))
                    {
                        importSettings.Add(group.number, new ModelGroupImportSettings());
                    }
                }

                // Check if groups match up with the file.
                // FIXME Next version could include option to match groups up manually.
                // FIXME Check on group name? We do not have direct access to the groups from the model.
                var groupsMatch = true;
                foreach (var entry in importSettings)
                {
                    if (entry.Key >= lxfml.groups.Length)
                    {
                        Debug.LogWarning("Group " + entry.Key + " does not match up with file.");
                        groupsMatch = false;
                    }
                }

                if (!groupsMatch)
                {
                    EditorUtility.DisplayDialog("Reimport failed", "Model groups do not match up with groups in file. Check log for details", "Ok");
                    return;
                }

                ImportModel.model = model;
                group             = null;

                GetWindow <ImportModel>(true, "LEGO Model Importer");
            }
            else
            {
                ShowReadError();
            }
        }
示例#12
0
        private static LXFMLDoc ReadFileLogic(string path)
        {
            var extension = Path.GetExtension(path).ToLowerInvariant();

            // Reset tracked errors.
            trackedErrors = new Dictionary <string, List <string> >();

            XmlDocument doc = null;

            switch (extension)
            {
            case ".lxfml":
            {
                doc = new XmlDocument();
                doc.LoadXml(File.ReadAllText(path));
                break;
            }

            case ".lxf":
            {
                // Open LXF file.
                using (var lxfArchive = ZipFile.OpenRead(path))
                {
                    var entry = lxfArchive.GetEntry("IMAGE100.LXFML");
                    if (entry != null)
                    {
                        doc = new XmlDocument();
                        var lxfmlStream = entry.Open();
                        doc.Load(lxfmlStream);
                        lxfmlStream.Dispose();
                    }
                }
                break;
            }

            case ".ldr":
            {
                var ldrStream = new FileStream(path, FileMode.Open);
                doc = LDrawConverter.ConvertLDrawToLXFML(ldrStream, path);
                ldrStream.Dispose();
                trackedErrors = LDrawConverter.GetErrors();
                break;
            }

            case ".io":
            {
                // Cannot open IO file.

                break;
            }
            }

            if (doc != null)
            {
                var lxfml = new LXFMLDoc();

                if (LXFMLReader.ReadLxfml(doc, ref lxfml))
                {
                    if (lxfml.groups == null)
                    {
                        Debug.Log("No groups in " + path + " Creating default group.");
                        CreateDefaultGroup(lxfml);
                    }
                    else if (FixLooseBricks(lxfml))
                    {
                        Debug.Log("Found bricks with no group. Adding them to main model.");
                    }

                    return(lxfml);
                }
            }

            return(null);
        }
示例#13
0
        public static void ReimportModelGroup(LXFMLDoc lxfml, ModelGroup group, ModelGroupImportSettings importSettings, bool detectConnectivity = false)
        {
            // Assign the new group import settings to the group.
            group.importSettings = importSettings;

            // We assume that the group can be found, so reimport it.
            if (group.processed)
            {
                // Remove all processed meshes.
                var renderers = group.GetComponentsInChildren <MeshRenderer>();
                foreach (var renderer in renderers)
                {
                    // FIXME Destroy the mesh? Prevents undo..
                    var filter = renderer.GetComponent <MeshFilter>();
                    //Undo.DestroyObjectImmediate(filter.sharedMesh);

                    if (renderer.GetComponent <ModelGroup>() == null)
                    {
                        // Destroy submesh game objects entirely.
                        Undo.DestroyObjectImmediate(renderer.gameObject);
                    }
                    else
                    {
                        // Destroy mesh related components on group game object.
                        Object.DestroyImmediate(filter);
                        Object.DestroyImmediate(renderer);
                    }
                }
            }

            // FIXME Check if bricks are referenced.
            // FIXME Check if bricks have custom components attached.

            // Remove group bricks.
            var existingBricks = group.GetComponentsInChildren <Brick>();

            foreach (var brick in existingBricks)
            {
                Undo.DestroyObjectImmediate(brick.gameObject);
            }

            var groupLightMapped = group.importSettings.isStatic && group.importSettings.lightmapped;

            SetStaticAndGIParams(group.gameObject, group.importSettings.isStatic, groupLightMapped);

            // Move group to origo to ensure that bricks are instantiated in the correct positions.
            var originalGroupParent       = group.transform.parent;
            var originalGroupSiblingIndex = group.transform.GetSiblingIndex();

            group.transform.parent        = null;
            group.transform.localPosition = Vector3.zero;
            group.transform.localRotation = Quaternion.identity;
            group.transform.localScale    = Vector3.one;

            // Create dictionary with just this group.
            var modelGroupImportSettingsDictionary = new DictionaryIntToModelGroupImportSettings();

            modelGroupImportSettingsDictionary.Add(group.number, group.importSettings);

            // Instantiate group bricks.
            var resultBricks = new Dictionary <int, Brick>(lxfml.bricks.Count);

            InstantiateModelBricks(lxfml, modelGroupImportSettingsDictionary, ref resultBricks, group.number);

            // Assign bricks to group.
            foreach (var brick in resultBricks.Values)
            {
                brick.transform.SetParent(group.transform);
            }

            // Set parent of group back to original.
            group.transform.parent = originalGroupParent;
            group.transform.SetSiblingIndex(originalGroupSiblingIndex);

            if (detectConnectivity && group.importSettings.connectivity)
            {
                var sceneBricks = new HashSet <Brick>(StageUtility.GetCurrentStageHandle().FindComponentsOfType <Brick>());
                DetectConnectivity(new HashSet <Brick>(resultBricks.Values), sceneBricks);
            }

            EditorUtility.ClearProgressBar();
        }
示例#14
0
        public static void ReimportModel(LXFMLDoc lxfml, Model model, Model.Pivot previousPivot, DictionaryIntToModelGroupImportSettings importSettings)
        {
            var brickBuilding = SceneBrickBuilder.GetToggleBrickBuildingStatus();

            if (brickBuilding)
            {
                SceneBrickBuilder.ToggleBrickBuilding();
            }

            // FIXME Next version could include option to match groups up manually.

            var oldPosition = model.transform.position;
            var oldRotation = model.transform.rotation;

            model.transform.position = Vector3.zero;
            model.transform.rotation = Quaternion.identity;

            var groups = model.GetComponentsInChildren <ModelGroup>();

            for (var i = groups.Length - 1; i >= 0; i--)
            {
                var group = groups[i];
                if (group.autoGenerated)
                {
                    Undo.DestroyObjectImmediate(group.gameObject);
                }
                else if (group.number >= lxfml.groups.Length)
                {
                    Debug.LogWarning("Group " + group.number + " " + group.groupName + " does not match up with files. Wiping.");
                    Undo.DestroyObjectImmediate(group.gameObject);
                }
            }

            groups = model.GetComponentsInChildren <ModelGroup>();

            var removedGroups = new List <LXFMLDoc.BrickGroup>();

            for (var i = 0; i < lxfml.groups.Length; i++)
            {
                LXFMLDoc.BrickGroup group = lxfml.groups[i];
                bool exists = false;
                for (var j = 0; j < groups.Length; j++)
                {
                    if (groups[j].number == group.number)
                    {
                        exists = true;
                        break;
                    }
                }

                if (!exists)
                {
                    removedGroups.Add(group);
                }
            }

            // Assign the new model import settings to the model.
            model.importSettings = new DictionaryIntToModelGroupImportSettings(importSettings);
            var bricksWithConnectivity = new HashSet <Brick>();

            if (removedGroups.Count > 0)
            {
                var resultBricks = new Dictionary <int, Brick>(lxfml.bricks.Count);
                foreach (var group in removedGroups)
                {
                    var number = group.number;
                    InstantiateModelBricks(lxfml, model.importSettings, ref resultBricks, number);
                    var groupGO = InstantiateModelGroup(group, number, model.gameObject, model.absoluteFilePath, model.relativeFilePath, ref resultBricks, false, importSettings[number]);
                    groupGO.transform.position = model.transform.position;
                    Undo.RegisterCreatedObjectUndo(groupGO, "Re-creating model group");
                    if (importSettings[number].connectivity)
                    {
                        bricksWithConnectivity.UnionWith(groupGO.GetComponentsInChildren <Brick>());
                    }
                }
            }

            foreach (var group in groups)
            {
                group.absoluteFilePath = model.absoluteFilePath;
                group.relativeFilePath = model.relativeFilePath;
                ReimportModelGroup(lxfml, group, importSettings[group.number]);
                if (group.importSettings.connectivity)
                {
                    bricksWithConnectivity.UnionWith(group.GetComponentsInChildren <Brick>());
                }
            }

            if (bricksWithConnectivity.Count > 0)
            {
                var sceneBricks = new HashSet <Brick>(StageUtility.GetCurrentStageHandle().FindComponentsOfType <Brick>());
                DetectConnectivity(bricksWithConnectivity, sceneBricks);
            }

            if (SceneBrickBuilder.GetAutoUpdateHierarchy())
            {
                groups = model.GetComponentsInChildren <ModelGroup>();
                var bricks = new HashSet <Brick>();
                foreach (var group in groups)
                {
                    if (group.importSettings.connectivity)
                    {
                        var groupBricks = group.GetComponentsInChildren <Brick>();
                        foreach (var brick in groupBricks)
                        {
                            bricks.Add(brick);
                        }
                    }
                }
                ModelGroupUtility.RecomputeHierarchy(bricks, false, ModelGroupUtility.UndoBehavior.withUndo);

                var oldToNew = model.transform.position;
                model.transform.rotation = oldRotation;
                model.transform.position = oldPosition;
                oldToNew = model.transform.TransformVector(oldToNew);

                if ((previousPivot == Model.Pivot.Center || previousPivot == Model.Pivot.BottomCenter) && model.pivot == Model.Pivot.Original)
                {
                    ModelGroupUtility.RecomputePivot(model.transform, previousPivot, true, ModelGroupUtility.UndoBehavior.withoutUndo);
                    var oldPivotPos = model.transform.position;
                    model.transform.position = oldPosition;
                    var diff = model.transform.position - oldPivotPos;
                    model.transform.position += diff;
                    foreach (var brick in model.GetComponentsInChildren <Brick>())
                    {
                        brick.transform.position -= diff;
                    }
                    model.transform.rotation = oldRotation;
                }

                if (model.pivot != Model.Pivot.Original && previousPivot == Model.Pivot.Original)
                {
                    model.transform.position += oldToNew;
                    model.transform.rotation  = oldRotation;
                }

                if (model.pivot != Model.Pivot.Original && previousPivot != Model.Pivot.Original)
                {
                    if (model.pivot != previousPivot)
                    {
                        ModelGroupUtility.RecomputePivot(model.transform, previousPivot, true, ModelGroupUtility.UndoBehavior.withoutUndo);
                        model.transform.position = oldPosition;
                        ModelGroupUtility.RecomputePivot(model, false, ModelGroupUtility.UndoBehavior.withoutUndo);
                        model.transform.rotation = oldRotation;
                    }
                }
            }

            if (brickBuilding)
            {
                SceneBrickBuilder.ToggleBrickBuilding();
            }

            EditorUtility.ClearProgressBar();
        }