/// <summary> /// /// </summary> /// <param name="masterParent"></param> /// <param name="parent"></param> /// <param name="parentNode"></param> private static void ReadGroupTreeRecursively(LXFMLDoc.BrickGroup masterParent, LXFMLDoc.BrickGroup parent, XmlNode parentNode) { parent.brickRefs = ParseUtils.StringToIntArray(parentNode.Attributes["brickRefs"].Value); if (masterParent != parent) { var current = new List <int>(masterParent.brickRefs); current.AddRange(parent.brickRefs); masterParent.brickRefs = current.ToArray(); } var childNodes = parentNode.SelectNodes("Group"); if (childNodes.Count > 0) { var groupCount = 0; parent.children = new LXFMLDoc.BrickGroup[childNodes.Count]; foreach (XmlNode childNode in childNodes) { var group = new LXFMLDoc.BrickGroup(); parent.children[groupCount++] = group; group.parent = parent; ReadGroupTreeRecursively(masterParent, group, childNode); } } }
/// <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); }
private static void SetGroupBricksFromBrickRefs(List <LXFMLDoc.Brick> bricks, LXFMLDoc.BrickGroup group) { for (int i = 0; i < group.brickRefs.Length; ++i) { group.bricks.Add(bricks.Find((obj) => obj.refId == group.brickRefs[i])); } }
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(); }
//private static readonly string decorationMaterialsPath = "Assets/LEGOIntegrationHub/Internal/LXFML/Resources/Materials"; //public static Material decoCutoutMaterial = Resources.Load<Material>("LXFMLMaterials/transpcutoutMinifigure"); /// <summary> /// Translate the bricks in a given LXFML-group to interactable objects /// </summary> /// <param name="group">The LXFML-group</param> /// <param name="index">Index of the group</param> /// <param name="parent">The imported asset</param> /// <param name="absoluteFilePath">Path of the imported asset</param> /// <param name="relativeFilePath">Path of the imported asset</param> /// <param name="resultBricks">Dictionary containing the simple bricks</param> /// <param name="isSubGroup">Whether it is a subgroup or not</param> /// <param name="lightmapped">Whether it is lightmapped or not</param> /// <param name="missingGroups">List of groups containing missing elements</param> public static GameObject InstantiateModelGroup(LXFMLDoc.BrickGroup group, int index, GameObject parent, string absoluteFilePath, string relativeFilePath, ref Dictionary <int, Brick> resultBricks, bool isSubGroup, ModelGroupImportSettings importSettings) { ModelGroup groupComp; GameObject groupParent; if (isSubGroup) { groupParent = new GameObject("SubGroup " + index + " - " + group.name); } else { groupParent = new GameObject(group.name); } // FIXME Handle subgroups properly. //Recursively check subgroups if (group.children != null) { foreach (var subGroup in group.children) { foreach (var part in group.brickRefs) { //Apparently supergroups contain elements from subgroups. Duplicates are removed from supergroups. if (subGroup.brickRefs.Contains(part)) { group.brickRefs[Array.IndexOf(group.brickRefs, part)] = -1; } } InstantiateModelGroup(subGroup, Array.IndexOf(group.children, subGroup), groupParent, absoluteFilePath, relativeFilePath, ref resultBricks, true, importSettings); } } importSettings.lightmapped &= importSettings.isStatic; SetStaticAndGIParams(groupParent, importSettings.isStatic, importSettings.lightmapped); groupParent.transform.parent = parent.transform; groupParent.transform.SetSiblingIndex(index); if (!isSubGroup) { groupComp = groupParent.AddComponent <ModelGroup>(); groupComp.absoluteFilePath = absoluteFilePath; groupComp.relativeFilePath = relativeFilePath; groupComp.importSettings = importSettings; groupComp.groupName = group.name; groupComp.number = index; groupComp.parentName = parent.name; groupComp.optimizations = ModelGroup.Optimizations.Everything; // Add LEGOModelGroupAsset component. groupParent.AddComponent <LEGOModelGroupAsset>(); } var groupBricks = new HashSet <Brick>(); foreach (int id in group.brickRefs) { if (id == -1) { continue; } if (resultBricks.ContainsKey(id)) { groupBricks.Add(resultBricks[id]); resultBricks[id].transform.SetParent(groupParent.transform); } } return(groupParent); }
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(); }