public void DrawPopup () { //if (MapMagic.instance.guiGens == null) MapMagic.instance.guiGens = MapMagic.instance.gens; //GeneratorsAsset gens = MapMagic.instance.guiGens; //if (MapMagic.instance.guiGens != null) gens = MapMagic.instance.guiGens; Vector2 mousePos = gens.layout.ToInternal(Event.current.mousePosition); //finding something that was clicked Generator clickedGenerator = null; Group clickedGroup = null; Generator.Output clickedOutput = null; for (int i=0; i<gens.list.Length; i++) { Generator gen = gens.list[i]; if (gen.guiRect.Contains(mousePos)) { if (!(gen is Group)) clickedGenerator = gens.list[i]; else clickedGroup = gens.list[i] as Group; } foreach (Generator.Output output in gens.list[i].Outputs()) if (output.guiRect.Contains(mousePos)) clickedOutput = output; } if (clickedGenerator == null) clickedGenerator = clickedGroup; //create Dictionary<string, PopupMenu.MenuItem> itemsDict = new Dictionary<string, PopupMenu.MenuItem>(); foreach (System.Type type in typeof(Generator).Subtypes()) { if (System.Attribute.IsDefined(type, typeof(GeneratorMenuAttribute))) { GeneratorMenuAttribute attribute = System.Attribute.GetCustomAttribute(type, typeof(GeneratorMenuAttribute)) as GeneratorMenuAttribute; System.Type genType = type; if (attribute.disabled) continue; PopupMenu.MenuItem item = new PopupMenu.MenuItem(attribute.name, delegate () { CreateGenerator(genType, mousePos); }); item.priority = attribute.priority; if (attribute.menu.Length != 0) { if (!itemsDict.ContainsKey(attribute.menu)) itemsDict.Add(attribute.menu, new PopupMenu.MenuItem(attribute.menu, subs:new PopupMenu.MenuItem[0])); ArrayTools.Add(ref itemsDict[attribute.menu].subItems, createElement:() => item); } else itemsDict.Add(attribute.name, item); } } itemsDict["Map"].priority = 1; itemsDict["Objects"].priority = 2; itemsDict["Output"].priority = 3; itemsDict["Portal"].priority = 4; itemsDict["Group"].priority = 5; itemsDict["Biome"].priority = 6; itemsDict["Legacy"].priority = 7; PopupMenu.MenuItem[] createItems = new PopupMenu.MenuItem[itemsDict.Count]; itemsDict.Values.CopyTo(createItems, 0); //create group //PopupMenu.MenuItem createGroupItem = new PopupMenu.MenuItem("Group", delegate () { CreateGroup(mousePos); }); //Extensions.ArrayAdd(ref createItems, createItems.Length-1, createGroupItem); //additional name /*string additionalName = "All"; if (clickedGenerator != null) { additionalName = "Generator"; if (clickedGenerator is Group) additionalName = "Group"; }*/ //preview PopupMenu.MenuItem[] previewSubs = new PopupMenu.MenuItem[] { new PopupMenu.MenuItem("On Terrain", delegate() {PreviewOutput(clickedGenerator, clickedOutput, false);}, disabled:clickedOutput==null||clickedGenerator==null, priority:0), new PopupMenu.MenuItem("In Window", delegate() {PreviewOutput(clickedGenerator, clickedOutput, true);}, disabled:clickedOutput==null||clickedGenerator==null, priority:1), new PopupMenu.MenuItem("Clear", delegate() {PreviewOutput(null, null, false);}, priority:2 )//, disabled:MapMagic.instance.previewOutput==null) }; PopupMenu.MenuItem[] popupItems = new PopupMenu.MenuItem[] { new PopupMenu.MenuItem("Create", createItems, priority:0), new PopupMenu.MenuItem("Export", delegate () { ExportGenerator(clickedGenerator, mousePos); }, priority:10), new PopupMenu.MenuItem("Import", delegate () { ImportGenerator(mousePos); }, priority:20), new PopupMenu.MenuItem("Duplicate", delegate () { DuplicateGenerator(clickedGenerator); }, priority:30), new PopupMenu.MenuItem("Update", delegate () { UpdateGenerator(clickedGenerator); }, disabled:clickedGenerator==null || !CouldBeUpdated(clickedGenerator), priority:40), new PopupMenu.MenuItem("Remove", delegate () { if (clickedGenerator!=null) DeleteGenerator(clickedGenerator); }, disabled:clickedGenerator==null, priority:50), new PopupMenu.MenuItem("Reset", delegate () { if (clickedGenerator!=null) ResetGenerator(clickedGenerator); }, disabled:clickedGenerator==null, priority:60), new PopupMenu.MenuItem("Preview", previewSubs, priority:70) }; if (onDrawPopup != null) popupItems = onDrawPopup(popupItems, mousePos, gens, clickedGenerator, clickedGroup, clickedOutput); PopupMenu.DrawPopup(popupItems, Event.current.mousePosition, closeAllOther:true); }
void UpdateGenerator (Generator gen) { if (!updateWarningShowed) { if (EditorUtility.DisplayDialog("Warning", "Updating generator can break your graph. Make a backup before continue", "Go on, I've made a backup", "Cancel")) updateWarningShowed = true; else return; } Undo.RecordObject (gens, "MapMagic Update Generator"); gens.setDirty = !gens.setDirty; //Generator[] copyGens = gens.SmartDuplicateGenerators(gen); System.Type type = gen.GetType(); GeneratorMenuAttribute attribute = System.Attribute.GetCustomAttribute(type, typeof(GeneratorMenuAttribute)) as GeneratorMenuAttribute; //finding type to replace System.Type newType = null; if (attribute.updateType != null) newType = attribute.updateType; else { string name = attribute.name; name = name.Split(new string[] {" (Legacy"}, System.StringSplitOptions.None)[0]; //iterating types starting from current version for (int v=MapMagic.version; v>=0; v--) { //newType = System.Type.GetType("MapMagic." + name + "Generator" + v.ToString()); //does not work newType = System.Reflection.Assembly.Load("Assembly-CSharp").GetType("MapMagic." + name + "Generator" + v.ToString()); if (newType != null) break; } if (newType == null) for (int v=MapMagic.version; v>=0; v--) { newType = System.Reflection.Assembly.Load("Assembly-CSharp").GetType("MapMagic." + name + v.ToString()); //for generators that have no "Generator" in name if (newType != null) break; } } if (newType == null) { Debug.Log("Could not find a proper type to update"); return; } Generator newGen = System.Activator.CreateInstance(newType) as Generator; newGen.ReflectionCopyFrom(gen); //changing links for (int g=0; g<gens.list.Length; g++) foreach (Generator.Input input in gens.list[g].Inputs()) if (input != null && input.linkGen == gen) input.linkGen = newGen; //replacing in array int numInArray = ArrayTools.Find(gens.list, gen); gens.list[numInArray] = newGen; if (mapMagic != null) { mapMagic.ClearResults(gen); //copyGens mapMagic.Generate(); } EditorUtility.SetDirty(gens); }
private void OnGUI() { DrawWindow(); if (repaint) DrawWindow(); repaint = false; } //drawing window, or doing it twice if repaint is needed private void DrawWindow() { if (gens == null) return; //un-selecting field on drag #if !UNITY_EDITOR_LINUX if (Event.current.button != 0 && UnityEngine.GUI.GetNameOfFocusedControl() != "Temp") RemoveFocusOnControl(); #endif //startingscript.layout if (gens.layout==null) { gens.layout = new Layout(); gens.layout.scroll = gens.guiScroll; gens.layout.zoom = gens.guiZoom; gens.layout.maxZoom = 1f; } gens.layout.Zoom(); gens.layout.Scroll(); //scrolling and zooming if (gens.layout.zoom < 0.0001f) gens.layout.zoom = 1; gens.layout.field = this.position; //zoomning with keyboard if (Event.current.type == EventType.KeyDown) { if (Event.current.keyCode==KeyCode.Equals && Event.current.alt) { gens.layout.zoom += gens.layout.zoomStep; if (gens.layout.zoom>1) gens.layout.zoom=1; Event.current.Use(); } if (Event.current.keyCode==KeyCode.Minus && Event.current.alt) { gens.layout.zoom -= gens.layout.zoomStep; Event.current.Use(); } } //unity 5.4 beta if (Event.current.type == EventType.Layout) return; if (Event.current.type == EventType.MouseDrag) //skip all mouse drags (except when dragging text selection cursor in field) { if (!UnityEditor.EditorGUIUtility.editingTextField) return; if (UnityEngine.GUI.GetNameOfFocusedControl() == "Temp") return; } //using middle mouse click events if (Event.current.button == 2) Event.current.Use(); //undo Undo.undoRedoPerformed -= PerformUndo; Undo.undoRedoPerformed += PerformUndo; //setting title content titleContent = new GUIContent("Map Magic"); titleContent.image =gens.layout.GetIcon("MapMagic_WindowIcon"); //drawing background Vector2 windowZeroPos =gens.layout.ToInternal(Vector2.zero); windowZeroPos.x = ((int)(windowZeroPos.x/64f)) * 64; windowZeroPos.y = ((int)(windowZeroPos.y/64f)) * 64; Texture2D backTex = gens.layout.GetIcon("MapMagic_Background"); Rect backRect = new Rect(windowZeroPos - new Vector2(64,64), position.size + new Vector2(127,127)); UnityEditor.EditorGUI.DrawPreviewTexture(new Rect(0,0,position.width,position.height), backTex, null, ScaleMode.ScaleAndCrop); gens.layout.Icon(backTex, backRect, tile:true); //drawing test center //script.layout.Button("Zero", new Rect(-10,-10,20,20)); //calculating visible area Rect visibleArea = gens.layout.ToInternal( new Rect(0,0,position.size.x,position.size.y) ); if (forceAll) { visibleArea = new Rect(-200000,-200000,400000,400000); forceAll = false; } //visibleArea = new Rect(visibleArea.x+100, visibleArea.y+100, visibleArea.width-200, visibleArea.height-200); //layout.Label("Area", helpBox:true, rect:visibleArea); //checking if all generators are loaded, and none of them is null for (int i=gens.list.Length-1; i>=0; i--) { if (gens.list[i] == null) { ArrayTools.RemoveAt(ref gens.list, i); continue; } foreach (Generator.Input input in gens.list[i].Inputs()) { if (input == null) continue; if (input.linkGen == null) input.Link(null, null); } } #region Drawing groups for(int i=0; i<gens.list.Length; i++) { if (!(gens.list[i] is Group)) continue; Group group = gens.list[i] as Group; //checking if this is withinscript.layout field if (group.guiRect.x > visibleArea.x+visibleArea.width || group.guiRect.y > visibleArea.y+visibleArea.height || group.guiRect.x+group.guiRect.width < visibleArea.x || group.guiRect.y+group.guiRect.height < visibleArea.y) if (group.guiRect.width > 0.001f && gens.layout.dragState != Layout.DragState.Drag) continue; //if guiRect initialized and not dragging //settingscript.layout data group.layout.field = group.guiRect; group.layout.scroll = gens.layout.scroll; group.layout.zoom = gens.layout.zoom; group.OnGUI(gens); group.guiRect = group.layout.field; } #endregion #region Drawing connections (before generators to make them display under nodes) foreach(Generator gen in gens.list) { foreach (Generator.Input input in gen.Inputs()) { if (input==null || input.link == null) continue; //input could be null in layered generators if (gen is Portal) { Portal portal = (Portal)gen; if (!portal.drawInputConnection) continue; } gens.layout.Spline(input.link.guiConnectionPos, input.guiConnectionPos, color:GeneratorsAsset.CanConnect(input.link,input)? input.guiColor : Color.red); } } #endregion #region creating connections (after generators to make clicking in inout work) int dragIdCounter = gens.list.Length+1; foreach (Generator gen in gens.list) foreach (Generator.IGuiInout inout in gen.Inouts()) { if (inout == null) continue; if (gens.layout.DragDrop(inout.guiRect, dragIdCounter)) { //finding target Generator.IGuiInout target = null; foreach (Generator gen2 in gens.list) foreach (Generator.IGuiInout inout2 in gen2.Inouts()) if (inout2.guiRect.Contains(gens.layout.dragPos)) target = inout2; //converting inout to Input (or Output) and target to Output (or Input) Generator.Input input = inout as Generator.Input; if (input==null) input = target as Generator.Input; Generator.Output output = inout as Generator.Output; if (output==null) output = target as Generator.Output; //connection validity test bool canConnect = input!=null && output!=null && GeneratorsAsset.CanConnect(output,input); //infinite loop test if (canConnect) { Generator outputGen = output.GetGenerator(gens.list); Generator inputGen = input.GetGenerator(gens.list); if (inputGen == outputGen || gens.CheckDependence(inputGen,outputGen)) canConnect = false; } //drag //if (script.layout.dragState==Layout.DragState.Drag) //commented out because will not be displayed on repaint otherwise //{ if (input == null)gens.layout.Spline(output.guiConnectionPos,gens.layout.dragPos, color:Color.red); else if (output == null)gens.layout.Spline(gens.layout.dragPos, input.guiConnectionPos, color:Color.red); else gens.layout.Spline(output.guiConnectionPos, input.guiConnectionPos, color:canConnect? input.guiColor : Color.red); //} //release if (gens.layout.dragState==Layout.DragState.Released && input!=null) //on release. Do nothing if input not defined { Undo.RecordObject (gens, "MapMagic Connection"); gens.setDirty = !gens.setDirty; input.Unlink(); if (canConnect) input.Link(output, output.GetGenerator(gens.list)); if (mapMagic!=null) { mapMagic.ClearResults(gen); mapMagic.Generate(); } EditorUtility.SetDirty(gens); } } dragIdCounter++; } #endregion #region Drawing generators for(int i=0; i<gens.list.Length; i++) { Generator gen = gens.list[i]; if (gen is Group) continue; //skipping groups //checking if this generator is withinscript.layout field if (gen.guiRect.x > visibleArea.x+visibleArea.width || gen.guiRect.y > visibleArea.y+visibleArea.height || gen.guiRect.x+gen.guiRect.width < visibleArea.x || gen.guiRect.y+gen.guiRect.height < visibleArea.y) if (gen.guiRect.width > 0.001f && gens.layout.dragState != Layout.DragState.Drag) continue; //if guiRect initialized and not dragging if (gen.layout == null) gen.layout = new Layout(); gen.layout.field = gen.guiRect; gen.layout.field.width = 160; //MapMagic.instance.guiGeneratorWidth; //gen.layout.OnBeforeChange -= RecordGeneratorUndo; //gen.layout.OnBeforeChange += RecordGeneratorUndo; gen.layout.undoObject = gens; gen.layout.undoName = "MapMagic Generators Change"; gen.layout.dragChange = true; gen.layout.disabled = changeLock; //copyscript.layout params gen.layout.scroll = gens.layout.scroll; gen.layout.zoom = gens.layout.zoom; //drawing background gen.layout.Element("MapMagic_Window", gen.layout.field, new RectOffset(34,34,34,34), new RectOffset(33,33,33,33)); //resetting layout gen.layout.field.height = 0; gen.layout.field.width =160; gen.layout.cursor = new Rect(); gen.layout.change = false; gen.layout.margin = 1; gen.layout.rightMargin = 1; gen.layout.fieldSize = 0.4f; //drawing header gen.DrawHeader (mapMagic, gens); if (gen is OutputGenerator && gen.layout.change && gen.enabled == false) //if just disabled output gensBiomeHierarchy[0].OnDisableGenerator(gen); //drawing parameters #if WDEBUG gen.OnGUI(gens); #else try { gen.OnGUI(gens); } catch (UnityException e) { Debug.LogError("Error drawing generator " + GetType() + "\n" + e);} //should be system.exception but it causes ExitGUIException on opening curve/color/texture fields //it's so unity... //if something goes wrong but no error is displayed - you know where to find it #endif gen.layout.Par(3); //drawing debug generate time #if WDEBUG if (mapMagic!=null) { Rect timerRect = new Rect(gen.layout.field.x, gen.layout.field.y+gen.layout.field.height, 200, 20); string timeLabel = "g:" + gen.guiGenerateTime + "ms "; if (gen is OutputGenerator) { if (Generator.guiProcessTime.ContainsKey(gen.GetType())) timeLabel += " p:" + Generator.guiProcessTime[gen.GetType()] + "ms "; if (Generator.guiApplyTime.ContainsKey(gen.GetType())) timeLabel += " a:" + Generator.guiApplyTime[gen.GetType()] + "ms "; } gen.layout.Label(timeLabel, timerRect); } #endif //instant generate on params change if (gen.layout.change) { if (mapMagic!=null) { mapMagic.ClearResults(gen); mapMagic.Generate(); } repaint=true; Repaint(); EditorUtility.SetDirty(gens); } //drawing biome "edit" button. Rather hacky, but we have to call editor method when pressing "Edit" if (gen is Biome) { Biome biome = (Biome)gen; if (gen.layout.Button("Edit", disabled:biome.data==null)) { MapMagicWindow.Show(biome.data, mapMagic, forceOpen:true,asBiome: true); Repaint(); return; //cancel drawing this graph if biome was opened } gen.layout.Par(10); } //changing all of the output generators of the same type (in case this one was disabled to make refresh) if (gen.layout.change && !gen.enabled && gen is OutputGenerator) { foreach (GeneratorsAsset ga in gensBiomeHierarchy) foreach (OutputGenerator sameOut in ga.GeneratorsOfType<OutputGenerator>(onlyEnabled:true, checkBiomes:true)) if (sameOut.GetType() == gen.GetType()) { mapMagic.ClearResults(sameOut); mapMagic.Generate(); } } if (gen.guiRect.width<1 && gen.guiRect.height<1) { repaint=true; Repaint(); } //repainting if some of the generators rect is 0 gen.guiRect = gen.layout.field; } #endregion #region Toolbar if (toolbarLayout==null) toolbarLayout = new Layout(); toolbarLayout.margin = 0; toolbarLayout.rightMargin = 0; toolbarLayout.field.width = this.position.width; toolbarLayout.field.height = 18; toolbarLayout.cursor = new Rect(); //toolbarLayout.window = this; toolbarLayout.Par(18, padding:0); EditorGUI.LabelField(toolbarLayout.field, "", EditorStyles.toolbarButton); if (mapMagic!=null && mapMagic.ToString()!="null" && !ReferenceEquals(mapMagic.gameObject,null)) //check game object in case it was deleted //mapMagic.ToString()!="null" - the only efficient delete check. Nor Equals neither ReferenceEquals are reliable. I <3 Unity! { //drawing state icon toolbarLayout.Inset(25); if (ThreadWorker.IsWorking("MapMagic")) { toolbarLayout.Icon("MapMagic_Loading", new Rect(5,0,16,16), animationFrames:12); Repaint(); } else toolbarLayout.Icon("MapMagic_Success", new Rect(5,0,16,16)); //TODO: changed sign //mapmagic name Rect nameLabelRect = toolbarLayout.Inset(100); nameLabelRect.y+=1; //nameLabelRect.height-=4; EditorGUI.LabelField(nameLabelRect, mapMagic.gameObject.name, EditorStyles.miniLabel); //generate buttons if (GUI.Button(toolbarLayout.Inset(110,padding:0), "Generate Changed", EditorStyles.toolbarButton)) mapMagic.Generate(force:true); if (GUI.Button(toolbarLayout.Inset(110,padding:0), "Force Generate All", EditorStyles.toolbarButton)) { mapMagic.ClearResults(); if (MapMagic.instance != null) foreach (Chunk chunk in MapMagic.instance.chunks.All()) if (chunk.terrain != null) chunk.terrain.transform.RemoveChildren(); mapMagic.Generate(force:true); } //seed field toolbarLayout.Inset(10); Rect seedLabelRect = toolbarLayout.Inset(34); seedLabelRect.y+=1; seedLabelRect.height-=4; Rect seedFieldRect = toolbarLayout.Inset(64); seedFieldRect.y+=2; seedFieldRect.height-=4; } else { Rect nameLabelRect = toolbarLayout.Inset(300); nameLabelRect.y+=1; //nameLabelRect.height-=4; EditorGUI.LabelField(nameLabelRect, "External data '" + AssetDatabase.GetAssetPath(gens) + "'", EditorStyles.miniLabel); } //right part toolbarLayout.Inset(toolbarLayout.field.width - toolbarLayout.cursor.x - 150 - 22,padding:0); //drawing exit biome button Rect biomeRect = toolbarLayout.Inset(80, padding:0); if (gensBiomeHierarchy.Count>1) { if (toolbarLayout.Button("", biomeRect, icon:"MapMagic_ExitBiome", style:EditorStyles.toolbarButton)) { gensBiomeHierarchy.RemoveAt(gensBiomeHierarchy.Count-1); Repaint(); return; } toolbarLayout.Label("Exit Biome", new Rect(toolbarLayout.cursor.x-60, toolbarLayout.cursor.y+3, 60, toolbarLayout.cursor.height), fontSize:9); } //focus button // if (GUI.Button(script.toolbarLayout.Inset(100,padding:0), "Focus", EditorStyles.toolbarButton)) FocusOnGenerators(); if (toolbarLayout.Button("", toolbarLayout.Inset(23,padding:0), icon:"MapMagic_Focus", style:EditorStyles.toolbarButton)) FocusOnGenerators(); if (toolbarLayout.Button("", toolbarLayout.Inset(47,padding:0), icon:"MapMagic_Zoom", style:EditorStyles.toolbarButton)) gens.layout.zoom=1; toolbarLayout.Label((int)(gens.layout.zoom*100)+"%", new Rect(toolbarLayout.cursor.x-28, toolbarLayout.cursor.y+3, 28, toolbarLayout.cursor.height), fontSize:8); toolbarLayout.Inset(3, margin:0); toolbarLayout.Label("", toolbarLayout.Inset(22, margin:0), url:"https://gitlab.com/denispahunov/mapmagic/wikis/Editor%20Window", icon:"MapMagic_Help"); #endregion #region Draging //dragging generators for(int i=gens.list.Length-1; i>=0; i--) { Generator gen = gens.list[i]; if (gen is Group) continue; gen.layout.field = gen.guiRect; //dragging if (gens.layout.DragDrop(gen.layout.field, i)) { if (gens.layout.dragState == Layout.DragState.Pressed) { Undo.RecordObject (gens, "MapMagic Generators Drag"); gens.setDirty = !gens.setDirty; } if (gens.layout.dragState == Layout.DragState.Drag || gens.layout.dragState == Layout.DragState.Released) { //gen.Move(gens.layout.dragDelta,true); gen.layout.field.position += gens.layout.dragDelta; gen.guiRect = gens.layout.field; //moving inouts to remove lag foreach (Generator.IGuiInout inout in gen.Inouts()) inout.guiRect = new Rect(inout.guiRect.position+gens.layout.dragDelta, inout.guiRect.size); //moving group if (gen is Group) { Group group = gen as Group; for (int g=0; g<group.generators.Count; g++) //group.generators[g].Move(delta,false); { group.generators[g].layout.field.position += gens.layout.dragDelta; group.generators[g].guiRect = gens.layout.field; foreach (Generator.IGuiInout inout in group.generators[g].Inouts()) //moving inouts to remove lag inout.guiRect = new Rect(inout.guiRect.position+gens.layout.dragDelta, inout.guiRect.size); } } repaint=true; Repaint(); EditorUtility.SetDirty(gens); } } //saving all generator rects gen.guiRect = gen.layout.field; } //dragging groups for (int i=gens.list.Length-1; i>=0; i--) { //Generator gen = gens.list[i]; Group group = gens.list[i] as Group; if (group == null) continue; group.layout.field = group.guiRect; //resizing group.layout.field =gens.layout.ResizeRect(group.layout.field, i+20000); //dragging if (gens.layout.DragDrop(group.layout.field, i)) { if (gens.layout.dragState == Layout.DragState.Pressed) { Undo.RecordObject (gens, "MapMagic Group Drag"); gens.setDirty = !gens.setDirty; group.Populate(gens); } if (gens.layout.dragState == Layout.DragState.Drag || gens.layout.dragState == Layout.DragState.Released) { //group.Move(gens.layout.dragDelta,true); group.layout.field.position += gens.layout.dragDelta; group.guiRect = gens.layout.field; for (int g=0; g<group.generators.Count; g++) //group.generators[g].Move(delta,false); { group.generators[g].layout.field.position += gens.layout.dragDelta; group.generators[g].guiRect.position += gens.layout.dragDelta; // = gens.layout.field; // foreach (Generator.IGuiInout inout in group.generators[g].Inouts()) //moving inouts to remove lag // inout.guiRect = new Rect(inout.guiRect.position+gens.layout.dragDelta, inout.guiRect.size); } repaint=true; Repaint(); EditorUtility.SetDirty(gens); } if (gens.layout.dragState == Layout.DragState.Released && group != null) gens.SortGroups(); } //saving all group rects group.guiRect = group.layout.field; } #endregion //right-click menus if (Event.current.type == EventType.ContextClick || (Event.current.type == EventType.MouseDown && Event.current.control)) DrawPopup(); //debug center //EditorGUI.HelpBox(script.layout.ToLocal(new Rect(-25,-10,50,20)), "Zero", MessageType.None); //assigning portal popup action Portal.OnChooseEnter -= DrawPortalSelector; Portal.OnChooseEnter += DrawPortalSelector; //saving scroll and zoom gens.guiScroll = gens.layout.scroll; gens.guiZoom = gens.layout.zoom; DrawDemoLock(); }
static public void ErosionIteration(Matrix heights, Matrix erosion, Matrix sedimentSum, CoordRect area = new CoordRect(), float erosionDurability = 0.9f, float erosionAmount = 1f, float sedimentAmount = 0.5f, int erosionFluidityIterations = 3, float ruffle = 0.1f, Matrix torrents = null, Matrix sediments = null, int[] stepsArray = null, int[] heightsInt = null, int[] order = null) { if (area.isZero) { area = heights.rect; } int count = heights.count; int seed = 12345; #region Creating order array int steps = 1000000; //creating int-type copy of heights if (heightsInt == null) { heightsInt = new int[count]; } for (int i = 0; i < heights.count; i++) { heightsInt[i] = (int)(Mathf.Clamp01(heights.array[i]) * steps); } //order array if (order == null) { order = new int[count]; } order = ArrayTools.Order(heightsInt, order: order, max: heights.count, stepsArray: stepsArray); //setting out-of-area order num to negative for (int j = 0; j < heights.count; j++) { int pos = order[j]; Coord coord = heights.rect.CoordByNum(pos); if (!area.CheckInRangeAndBounds(coord)) { order[j] = -1; } } #endregion #region Creating torrents if (torrents == null) { torrents = new Matrix(heights.rect); } torrents.ChangeRect(heights.rect); torrents.Fill(1f); //casting initial rain for (int j = count - 1; j >= 0; j--) { //finding column ordered by height int pos = order[j]; if (pos < 0) { continue; } /* * MooreCross height = new MooreCross(heights, pos); //moore * MooreCross torrent = new MooreCross(torrents, pos); //moore * if (torrent.c > 2000000000) torrent.c = 2000000000; * * //creating torrents * MooreCross delta = new MooreCross(height); //moore * delta.SubtractInverse(height.c); * delta.ClampPositive(); * * delta.Percent(); //every side now determines a percent - how many water should go to it * delta.Multiply(torrent.c); * torrent.Add(delta); */ //getting height values float[] m = heights.array; int i = pos; int sizeX = heights.rect.size.x; float h = m[i]; float hx = m[i - 1]; float hX = m[i + 1]; float hz = m[i - sizeX]; float hZ = m[i + sizeX]; float hxz = m[i - 1 - sizeX]; float hXz = m[i + 1 - sizeX]; float hxZ = m[i - 1 + sizeX]; float hXZ = m[i + 1 + sizeX]; //creating delta float d = h - h; float dx = h - hx; float dX = h - hX; float dz = h - hz; float dZ = h - hZ; float dxz = h - hxz; float dXz = h - hXz; float dxZ = h - hxZ; float dXZ = h - hXZ; //ignoring negative delta values d = d > 0? d : 0; dx = dx > 0? dx : 0; dX = dX > 0? dX : 0; dz = dz > 0? dz : 0; dZ = dZ > 0? dZ : 0; dxz = dxz > 0? dxz : 0; dXz = dXz > 0? dXz : 0; dxZ = dxZ > 0? dxZ : 0; dXZ = dXZ > 0? dXZ : 0; //finding percents float p = 0, px = 0, pX = 0, pz = 0, pZ = 0, pxz = 0, pXz = 0, pxZ = 0, pXZ = 0; float s = d + dx + dX + dz + dZ + dxz + dXz + dxZ + dXZ; if (s > 0.00001f) { p = d / s; px = dx / s; pX = dX / s; pz = dz / s; pZ = dZ / s; pxz = dxz / s; pXz = dXz / s; pxZ = dxZ / s; pXZ = dXZ / s; } //getting central torrent (and clamping it) float t = torrents.array[i]; if (t > 2000000000) { t = 2000000000; } //spreading central torrent according percents delta. And adding to torrents array m = torrents.array; m[i] += t * p; m[i - 1] += t * px; m[i + 1] += t * pX; m[i - sizeX] += t * pz; m[i + sizeX] += t * pZ; m[i - 1 - sizeX] += t * pxz; m[i + 1 - sizeX] += t * pXz; m[i - 1 + sizeX] += t * pxZ; m[i + 1 + sizeX] += t * pXZ; } #endregion #region Erosion if (sediments == null) { sediments = new Matrix(heights.rect); } else { sediments.ChangeRect(heights.rect); } sediments.Clear(); for (int j = count - 1; j >= 0; j--) { //finding column ordered by height int pos = order[j]; if (pos < 0) { continue; } /* * Cross height = new Cross(heights, pos); * Cross torrent = new Cross(torrents, pos); * Cross sediment = new Cross(sediments, pos); * * //erosion * float erodeLine = (height.c + height.min)/2f; //halfway between current and maximum height * * if (height.c > erodeLine) //raising soil if column is higher than eroded column * { * float raised = height.c - erodeLine; * raised = Mathf.Min(raised, raised*(torrent.c-1) * (1-erosionDurability)); //could not raise more soil than height-minHeight. //torrents always have 1 or more * raised *= erosionAmount; * * heights.array[pos] -= raised; //raising soil * height.c -= raised; * sediments.array[pos] += raised * sedimentAmount; //and saving raised to sediment * sediment.c += raised * sedimentAmount; * * if (paintErosion != null) paintErosion.array[pos] += raised * mapsFactor; //and writing to ref * } */ //getting height values float[] m = heights.array; int i = pos; int sizeX = heights.rect.size.x; float h = m[i]; float hx = m[i - 1]; float hX = m[i + 1]; float hz = m[i - sizeX]; float hZ = m[i + sizeX]; //height minimum float h_min = h; if (hx < h_min) { h_min = hx; } if (hX < h_min) { h_min = hX; } if (hz < h_min) { h_min = hz; } if (hZ < h_min) { h_min = hZ; } //erosion line float erodeLine = (h + h_min) / 2f; //halfway between current and maximum height if (h < erodeLine) { continue; } //raising soil float raised = h - erodeLine; float maxRaised = raised * (torrents.array[pos] - 1) * (1 - erosionDurability); if (raised > maxRaised) { raised = maxRaised; } raised *= erosionAmount; //saving arrays heights.array[pos] -= raised; sediments.array[pos] += raised * sedimentAmount; if (erosion != null) { erosion.array[pos] += raised; //and writing to ref } } #endregion #region Settling sediment for (int l = 0; l < erosionFluidityIterations; l++) { for (int j = count - 1; j >= 0; j--) { //finding column ordered by height int pos = order[j]; if (pos < 0) { continue; } /* * Cross height = new Cross(heights, pos); * Cross sediment = new Cross(sediments, pos); * float sedimentSum = sediment.c+sediment.px+sediment.nx+sediment.pz+sediment.nz; * if (sedimentSum < 0.00001f) continue; * * //finding columns that sediment will spread to * Cross spread = new Cross(1,1,1,1,1); //actually it'a s bool-cross * * //from top to bottom * foreach (int i in height.Sorted()) * { * //float curMaxLevel = (height*spread).max; * float curMaxLevel = 0; * if (spread.c > 0.1f && height.c > curMaxLevel) curMaxLevel = height.c; * if (spread.px > 0.1f && height.px > curMaxLevel) curMaxLevel = height.px; * if (spread.nx > 0.1f && height.nx > curMaxLevel) curMaxLevel = height.nx; * if (spread.pz > 0.1f && height.pz > curMaxLevel) curMaxLevel = height.pz; * if (spread.nz > 0.1f && height.nz > curMaxLevel) curMaxLevel = height.nz; * * //sum of lack of heights to current max level less then total sediment * float lackSum = 0; //... + Mathf.Max(curMaxLevel-height.px, 0) + ... * if (curMaxLevel-height.c > 0) lackSum += curMaxLevel-height.c; * if (curMaxLevel-height.px > 0) lackSum += curMaxLevel-height.px; * if (curMaxLevel-height.pz > 0) lackSum += curMaxLevel-height.pz; * if (curMaxLevel-height.nx > 0) lackSum += curMaxLevel-height.nx; * if (curMaxLevel-height.nz > 0) lackSum += curMaxLevel-height.nz; * * if (lackSum < sedimentSum) break; * spread[i] = 0; //I find your lack of sediment disturbing! * * //if ((lackSum < sedimentSum)) spread = new Cross(1,1,1,1,1); * //else spread = new Cross(0,0,0,0,0); * * } * * //find sediment-filled level * float columnsRemain = spread.c+spread.px+spread.nx+spread.pz+spread.nz; //aka spread.sum; * float filledLevel = 0; * if (columnsRemain > 0.00001f) filledLevel = // ((height*spread).sum + sediment.sum)/columnsRemain * ((height.c*spread.c)+(height.px*spread.px)+(height.nx*spread.nx)+(height.pz*spread.pz)+(height.nz*spread.nz) + sedimentSum)/columnsRemain; * * //transfering sediment * sediment = new Cross( * filledLevel-height.c>0 ? (filledLevel-height.c)*spread.c : 0, * filledLevel-height.px>0 ? (filledLevel-height.px)*spread.px : 0, * filledLevel-height.nx>0 ? (filledLevel-height.nx)*spread.nx : 0, * filledLevel-height.pz>0 ? (filledLevel-height.pz)*spread.pz : 0, * filledLevel-height.nz>0 ? (filledLevel-height.nz)*spread.nz : 0); * * sediment.ToMatrix(sediments, pos); */ //getting height values float[] m = heights.array; int sizeX = heights.rect.size.x; float h = m[pos]; float hx = m[pos - 1]; float hX = m[pos + 1]; float hz = m[pos - sizeX]; float hZ = m[pos + sizeX]; //getting sediment values m = sediments.array; float s = m[pos]; float sx = m[pos - 1]; float sX = m[pos + 1]; float sz = m[pos - sizeX]; float sZ = m[pos + sizeX]; //sediment sum float sum = s + sx + sX + sz + sZ; if (sum < 0.00001f) { continue; } //pouring sum to all cells float sedimentFifth = sum / 5; s = sedimentFifth; sx = sedimentFifth; sX = sedimentFifth; sz = sedimentFifth; sZ = sedimentFifth; //levelling //for (int i=0; i<2; i++) //{ //x line float avg = (h + s + sx + hx) / 2; if (h + s > hx + sx) { float transfer = s + h - avg; if (transfer > s) { transfer = s; } s -= transfer; sx += transfer; } else { float transfer = sx + hx - avg; if (transfer > sx) { transfer = sx; } sx -= transfer; s += transfer; } avg = (hx + sx + sX + hX) / 2; if (hx + sx > hX + sX) { float transfer = sx + hx - avg; if (transfer > sx) { transfer = sx; } sx -= transfer; sX += transfer; } else { float transfer = sX + hX - avg; if (transfer > sX) { transfer = sX; } sX -= transfer; sx += transfer; } avg = (h + s + sX + hX) / 2; if (h + s > hX + sX) { float transfer = s + h - avg; if (transfer > s) { transfer = s; } s -= transfer; sX += transfer; } else { float transfer = sX + hX - avg; if (transfer > sX) { transfer = sX; } sX -= transfer; s += transfer; } //z line avg = (h + s + sz + hz) / 2; if (h + s > hz + sz) { float transfer = s + h - avg; if (transfer > s) { transfer = s; } s -= transfer; sz += transfer; } else { float transfer = sz + hz - avg; if (transfer > sz) { transfer = sz; } sz -= transfer; s += transfer; } avg = (hZ + sZ + sz + hz) / 2; if (hZ + sZ > hz + sz) { float transfer = sZ + hZ - avg; if (transfer > sZ) { transfer = sZ; } sZ -= transfer; sz += transfer; } else { float transfer = sz + hz - avg; if (transfer > sz) { transfer = sz; } sz -= transfer; sZ += transfer; } avg = (h + s + sz + hz) / 2; if (h + s > hz + sz) { float transfer = s + h - avg; if (transfer > s) { transfer = s; } s -= transfer; sz += transfer; } else { float transfer = sz + hz - avg; if (transfer > sz) { transfer = sz; } sz -= transfer; s += transfer; } //side pairs avg = (hx + sx + sz + hz) / 2; if (hx + sx > hz + sz) { float transfer = sx + hx - avg; if (transfer > sx) { transfer = sx; } sx -= transfer; sz += transfer; } else { float transfer = sz + hz - avg; if (transfer > sz) { transfer = sz; } sz -= transfer; sx += transfer; } avg = (hX + sX + sZ + hZ) / 2; if (hX + sX > hZ + sZ) { float transfer = sX + hX - avg; if (transfer > sX) { transfer = sX; } sX -= transfer; sZ += transfer; } else { float transfer = sZ + hZ - avg; if (transfer > sZ) { transfer = sZ; } sZ -= transfer; sX += transfer; } avg = (hx + sx + sZ + hZ) / 2; if (hx + sx > hZ + sZ) { float transfer = sx + hx - avg; if (transfer > sx) { transfer = sx; } sx -= transfer; sZ += transfer; } else { float transfer = sZ + hZ - avg; if (transfer > sZ) { transfer = sZ; } sZ -= transfer; sx += transfer; } avg = (hX + sX + sz + hz) / 2; if (hX + sX > hz + sz) { float transfer = sX + hX - avg; if (transfer > sX) { transfer = sX; } sX -= transfer; sz += transfer; } else { float transfer = sz + hz - avg; if (transfer > sz) { transfer = sz; } sz -= transfer; sX += transfer; } //} //additionally levelling /*int sNum = 0; //number of cells with sediment * float total = 0; //total height + sediment level * if (s>0.001f) { sNum++; total+=h+s; } * if (sx>0.001f) { sNum++; total+=hx+sx; } if (sX>0.001f) { sNum++; total+=hX+sX; } * if (sz>0.001f) { sNum++; total+=hz+sz; } if (sZ>0.001f) { sNum++; total+=hZ+sZ; } * * float totalAvg = total / sNum; * if (s>0.001f) s=totalAvg-h; * if (sx>0.001f) sx=totalAvg-hx; if (sX>0.001f) sX=totalAvg-hX; * if (sz>0.001f) sz=totalAvg-hz; if (sZ>0.001f) sZ=totalAvg-hZ;*/ //to matrix m = sediments.array; m[pos] = s; m[pos - 1] = sx; m[pos + 1] = sX; m[pos - sizeX] = sz; m[pos + sizeX] = sZ; if (sedimentSum != null) { m = sedimentSum.array; m[pos] += s; m[pos - 1] += sx; m[pos + 1] += sX; m[pos - sizeX] += sz; m[pos + sizeX] += sZ; } } } #endregion #region Writing sediments back to height, adding smooth and ruffle for (int j = count - 1; j >= 0; j--) { //writing heights heights.array[j] += sediments.array[j]; seed = 214013 * seed + 2531011; float random = ((seed >> 16) & 0x7FFF) / 32768f; int pos = order[j]; if (pos < 0) { continue; } float[] m = heights.array; int sizeX = heights.rect.size.x; float h = m[pos]; float hx = m[pos - 1]; float hX = m[pos + 1]; float hz = m[pos - sizeX]; float hZ = m[pos + sizeX]; //smoothing sediments a bit float s = sediments.array[pos]; if (s > 0.0001f) { float smooth = s / 2f; if (smooth > 0.75f) { smooth = 0.75f; } heights.array[pos] = h * (1 - smooth) + (hx + hX + hz + hZ) / 4f * smooth; } else { float maxHeight = hx; if (hX > maxHeight) { maxHeight = hX; } if (hz > maxHeight) { maxHeight = hz; } if (hZ > maxHeight) { maxHeight = hZ; } float minHeight = hx; if (hX < minHeight) { minHeight = hX; } if (hz < minHeight) { minHeight = hz; } if (hZ < minHeight) { minHeight = hZ; } float randomHeight = random * (maxHeight - minHeight) + minHeight; heights.array[pos] = heights.array[pos] * (1 - ruffle) + randomHeight * ruffle; } //Cross height = new Cross(heights, pos); //float maxAround = Mathf.Max(heights.array[pos-1], heights.array[pos+1], heights.array[pos-heights.rect.size.x], heights.array[pos+heights.rect.size.x]); //heights.array[pos] = Mathf.Min(heights.array[pos], maxAround); //heights.array[pos] = Mathf.Min(height.c, height.maxAround); //heights.array[pos] = Mathf.Min(height.c, height.avgAround)*0.5f + height.c*0.5f; //float maxHeight = height.maxAround; //float minHeight = height.minAround; //float randomHeight = random*(maxHeight-minHeight) + minHeight; //heights.array[pos] = heights.array[pos]*(1-ruffle) + randomHeight*ruffle; } #endregion } //erosion iteration
public void DeleteGenerator(Generator gen) { //removing generator from 'ready' and 'results' arrays ChangeGenerator(gen); //manually resetting all dependent generators ready stae for (int g = 0; g < list.Length; g++) { if (list[g].IsDependentFrom(gen)) { ChangeGenerator(list[g]); } } //clearing if it is output gen //if (gen is IOutput) // foreach (MapMagic.Chunk chunk in MapMagic.instance.terrains.Objects()) // (gen as IOutput).Clear(chunk); //removing group members if it is group #if UNITY_EDITOR if (gen is Group && UnityEditor.EditorUtility.DisplayDialog("Remove Containing Generators", "Do you want to remove a contaning generators as well?", "Remove Generators", "Remove Group Only")) { Group group = gen as Group; group.Populate(); for (int g = group.generators.Count - 1; g >= 0; g--) { MapMagic.instance.gens.DeleteGenerator(group.generators[g]); } } #endif //unlinking and removing it's reference in inputs and outputs //for (int g=0; g<list.Length; g++) // foreach (Generator.Input input in list[g].Inputs()) // if (input.linkGen == gen) input.Unlink(); UnlinkGenerator(gen); //removing from output generators list //if (gen is IOutput) // Extensions.ArrayRemove(ref outputs, gen); //removing from array ArrayTools.Remove(ref list, gen); //if it is preview - applying splats if (gen is PreviewOutput) { SplatOutput splatOut = GetGenerator <SplatOutput>(); if (splatOut != null) { ChangeGenerator(splatOut); } else { foreach (MapMagic.Chunk chunk in MapMagic.instance.terrains.Objects()) { chunk.ClearSplats(); } } } }
private void OnGUI() { DrawWindow(); if (repaint) DrawWindow(); repaint = false; } //drawing window, or doing it twice if repaint is needed private void DrawWindow() { if (MapMagic.instance == null) MapMagic.instance = FindObjectOfType<MapMagic>(); MapMagic script = MapMagic.instance; if (script==null) return; if (MapMagic.instance.guiGens == null) MapMagic.instance.guiGens = MapMagic.instance.gens; GeneratorsAsset gens = MapMagic.instance.guiGens; //if (script.guiGens != null) gens = script.guiGens; //if (script.gens==null) script.gens = ScriptableObject.CreateInstance<GeneratorsAsset>(); //un-selecting field on drag if (Event.current.button != 0) UnityEditor.EditorGUI.FocusTextInControl(""); //startingscript.layout if (script.layout==null) { script.layout = new Layout(); script.layout.scroll = script.guiScroll; script.layout.zoom = script.guiZoom; script.layout.maxZoom = 1f; } script.layout.Zoom(); script.layout.Scroll(); //scrolling and zooming script.layout.field = this.position; //unity 5.4 beta if (Event.current.type == EventType.MouseDrag || Event.current.type == EventType.layout) return; if (script.guiDebug) Profiler.BeginSample("Redraw Window"); //using middle mouse click events if (Event.current.button == 2) Event.current.Use(); //undo Undo.undoRedoPerformed -= PerformUndo; Undo.undoRedoPerformed += PerformUndo; //setting title content titleContent = new GUIContent("Map Magic"); titleContent.image =script.layout.GetIcon("MapMagic_WindowIcon"); //drawing background Vector2 windowZeroPos =script.layout.ToInternal(Vector2.zero); windowZeroPos.x = ((int)(windowZeroPos.x/64f)) * 64; windowZeroPos.y = ((int)(windowZeroPos.y/64f)) * 64; script.layout.Icon( "MapMagic_Background", new Rect(windowZeroPos - new Vector2(64,64), position.size + new Vector2(128,128)), tile:true); //drawing test center //script.layout.Button("Zero", new Rect(-10,-10,20,20)); //calculating visible area Rect visibleArea = script.layout.ToInternal( new Rect(0,0,position.size.x,position.size.y) ); if (forceAll) { visibleArea = new Rect(-200000,-200000,400000,400000); forceAll = false; } //visibleArea = new Rect(visibleArea.x+100, visibleArea.y+100, visibleArea.width-200, visibleArea.height-200); //layout.Label("Area", helpBox:true, rect:visibleArea); //checking if all generators are loaded, and none of them is null for (int i=gens.list.Length-1; i>=0; i--) { if (gens.list[i] == null) { ArrayTools.RemoveAt(ref gens.list, i); continue; } foreach (Generator.Input input in gens.list[i].Inputs()) { if (input == null) continue; if (input.linkGen == null) input.Link(null, null); } } #region Drawing groups if (script.guiDebug) Profiler.BeginSample("Drawing Groups"); for(int i=0; i<gens.list.Length; i++) { if (!(gens.list[i] is Group)) continue; Group group = gens.list[i] as Group; //checking if this is withinscript.layout field if (group.guiRect.x > visibleArea.x+visibleArea.width || group.guiRect.y > visibleArea.y+visibleArea.height || group.guiRect.x+group.guiRect.width < visibleArea.x || group.guiRect.y+group.guiRect.height < visibleArea.y) if (group.guiRect.width > 0.001f &&script.layout.dragState != Layout.DragState.Drag) continue; //if guiRect initialized and not dragging //settingscript.layout data group.layout.field = group.guiRect; group.layout.scroll =script.layout.scroll; group.layout.zoom =script.layout.zoom; group.OnGUI(); group.guiRect = group.layout.field; } if (script.guiDebug) Profiler.EndSample(); #endregion #region Drawing connections (before generators to make them display under nodes) if (script.guiDebug) Profiler.BeginSample("Drawing Connections"); foreach(Generator gen in gens.list) { foreach (Generator.Input input in gen.Inputs()) { if (input==null || input.link == null) continue; //input could be null in layered generators if (gen is Portal) { Portal portal = (Portal)gen; if (!portal.drawInputConnection) continue; } script.layout.Spline(input.link.guiConnectionPos, input.guiConnectionPos, color:Generator.CanConnect(input.link,input)? input.guiColor : Color.red); } } if (script.guiDebug) Profiler.EndSample(); #endregion #region creating connections (after generators to make clicking in inout work) if (script.guiDebug) Profiler.BeginSample("Creating Connections"); int dragIdCounter = gens.list.Length+1; foreach (Generator gen in gens.list) foreach (Generator.IGuiInout inout in gen.Inouts()) { if (inout == null) continue; if (script.layout.DragDrop(inout.guiRect, dragIdCounter)) { //finding target Generator.IGuiInout target = null; foreach (Generator gen2 in gens.list) foreach (Generator.IGuiInout inout2 in gen2.Inouts()) if (inout2.guiRect.Contains(script.layout.dragPos)) target = inout2; //converting inout to Input (or Output) and target to Output (or Input) Generator.Input input = inout as Generator.Input; if (input==null) input = target as Generator.Input; Generator.Output output = inout as Generator.Output; if (output==null) output = target as Generator.Output; //connection validity test bool canConnect = input!=null && output!=null && Generator.CanConnect(output,input); //infinite loop test if (canConnect) { Generator outputGen = output.GetGenerator(gens.list); Generator inputGen = input.GetGenerator(gens.list); if (inputGen == outputGen || outputGen.IsDependentFrom(inputGen)) canConnect = false; } //drag //if (script.layout.dragState==Layout.DragState.Drag) //commented out because will not be displayed on repaint otherwise //{ if (input == null)script.layout.Spline(output.guiConnectionPos,script.layout.dragPos, color:Color.red); else if (output == null)script.layout.Spline(script.layout.dragPos, input.guiConnectionPos, color:Color.red); else script.layout.Spline(output.guiConnectionPos, input.guiConnectionPos, color:canConnect? input.guiColor : Color.red); //} //release if (script.layout.dragState==Layout.DragState.Released && input!=null) //on release. Do nothing if input not defined { Undo.RecordObject (gens, "MapMagic Connection"); gens.setDirty = !gens.setDirty; input.Unlink(); if (canConnect) input.Link(output, output.GetGenerator(gens.list)); gens.ChangeGenerator(gen); EditorUtility.SetDirty(gens); } } dragIdCounter++; } if (script.guiDebug) Profiler.EndSample(); #endregion #region Drawing generators if (script.guiDebug) Profiler.BeginSample("Drawing Generators"); for(int i=0; i<gens.list.Length; i++) { Generator gen = gens.list[i]; if (gen is Group) continue; //skipping groups //checking if this generator is withinscript.layout field if (gen.guiRect.x > visibleArea.x+visibleArea.width || gen.guiRect.y > visibleArea.y+visibleArea.height || gen.guiRect.x+gen.guiRect.width < visibleArea.x || gen.guiRect.y+gen.guiRect.height < visibleArea.y) if (gen.guiRect.width > 0.001f &&script.layout.dragState != Layout.DragState.Drag) continue; //if guiRect initialized and not dragging if (gen.layout == null) gen.layout = new Layout(); gen.layout.field = gen.guiRect; gen.layout.field.width = MapMagic.instance.guiGeneratorWidth; //gen.layout.OnBeforeChange -= RecordGeneratorUndo; //gen.layout.OnBeforeChange += RecordGeneratorUndo; gen.layout.undoObject = gens; gen.layout.undoName = "MapMagic Generators Change"; gen.layout.dragChange = true; gen.layout.disabled = locked; //copyscript.layout params gen.layout.scroll =script.layout.scroll; gen.layout.zoom =script.layout.zoom; //drawing if (script.guiDebug) Profiler.BeginSample("Generator GUI"); gen.OnGUIBase(); if (script.guiDebug) Profiler.EndSample(); //instant generate on params change if (gen.layout.change) { gens.ChangeGenerator(gen); repaint=true; Repaint(); EditorUtility.SetDirty(gens); } if (gen.guiRect.width<1 && gen.guiRect.height<1) { repaint=true; Repaint(); } //repainting if some of the generators rect is 0 gen.guiRect = gen.layout.field; } if (script.guiDebug) Profiler.EndSample(); #endregion #region Toolbar if (script.guiDebug) Profiler.BeginSample("Toolbar"); if (script.toolbarLayout==null) script.toolbarLayout = new Layout(); script.toolbarLayout.margin = 0; script.toolbarLayout.rightMargin = 0; script.toolbarLayout.field.width = this.position.width; script.toolbarLayout.field.height = 18; script.toolbarLayout.cursor = new Rect(); //script.toolbarLayout.window = this; script.toolbarLayout.Par(18, padding:0); EditorGUI.LabelField(script.toolbarLayout.field, "", EditorStyles.toolbarButton); //drawing state icon script.toolbarLayout.Inset(25); if (!MapMagic.instance.terrains.complete) { script.toolbarLayout.Icon("MapMagic_Loading", new Rect(5,0,16,16), animationFrames:12); Repaint(); } else script.toolbarLayout.Icon("MapMagic_Success", new Rect(5,0,16,16)); //TODO: changed sign //generate buttons if (GUI.Button(script.toolbarLayout.Inset(120,padding:0), "Generate Changed", EditorStyles.toolbarButton) && MapMagic.instance.enabled) MapMagic.instance.Generate(); if (GUI.Button(script.toolbarLayout.Inset(120,padding:0), "Force Generate All", EditorStyles.toolbarButton) && MapMagic.instance.enabled) MapMagic.instance.ForceGenerate(); //seed field script.toolbarLayout.Inset(10); Rect seedLabelRect = script.toolbarLayout.Inset(34); seedLabelRect.y+=1; seedLabelRect.height-=4; Rect seedFieldRect = script.toolbarLayout.Inset(64); seedFieldRect.y+=2; seedFieldRect.height-=4; EditorGUI.LabelField(seedLabelRect, "Seed:", EditorStyles.miniLabel); int newSeed = EditorGUI.IntField(seedFieldRect, MapMagic.instance.seed, EditorStyles.toolbarTextField); if (newSeed != MapMagic.instance.seed) { MapMagic.instance.seed = newSeed; if (MapMagic.instance.instantGenerate) MapMagic.instance.ForceGenerate(); } //right part script.toolbarLayout.Inset(script.toolbarLayout.field.width - script.toolbarLayout.cursor.x - 150,padding:0); //drawing exit biome button Rect biomeRect = script.toolbarLayout.Inset(80, padding:0); if (MapMagic.instance.guiGens != null && MapMagic.instance.guiGens != MapMagic.instance.gens) { if (script.toolbarLayout.Button("", biomeRect, icon:"MapMagic_ExitBiome", style:EditorStyles.toolbarButton)) MapMagic.instance.guiGens = null; script.toolbarLayout.Label("Exit Biome", new Rect(script.toolbarLayout.cursor.x-60, script.toolbarLayout.cursor.y+3, 60, script.toolbarLayout.cursor.height), fontSize:9); } //focus button // if (GUI.Button(script.toolbarLayout.Inset(100,padding:0), "Focus", EditorStyles.toolbarButton)) FocusOnGenerators(); if (script.toolbarLayout.Button("", script.toolbarLayout.Inset(23,padding:0), icon:"MapMagic_Focus", style:EditorStyles.toolbarButton)) FocusOnGenerators(); if (script.toolbarLayout.Button("", script.toolbarLayout.Inset(60,padding:0), icon:"MapMagic_Zoom", style:EditorStyles.toolbarButton))script.layout.zoom=1; script.toolbarLayout.Label((int)(script.layout.zoom*100)+"%", new Rect(script.toolbarLayout.cursor.x-42, script.toolbarLayout.cursor.y+3, 42, script.toolbarLayout.cursor.height), fontSize:8); if (script.guiDebug) Profiler.EndSample(); #endregion #region Draging if (script.guiDebug) Profiler.BeginSample("Dragging"); //dragging generators for(int i=gens.list.Length-1; i>=0; i--) { Generator gen = gens.list[i]; if (gen is Group) continue; gen.layout.field = gen.guiRect; //dragging if (script.layout.DragDrop(gen.layout.field, i)) { if (script.layout.dragState == Layout.DragState.Pressed) { Undo.RecordObject (gens, "MapMagic Generators Drag"); gens.setDirty = !gens.setDirty; } if (script.layout.dragState == Layout.DragState.Drag ||script.layout.dragState == Layout.DragState.Released) { //moving inout rects to remove lag //foreach (Generator.IGuiInout inout in gen.Inouts()) // inout.guiRect = new Rect(inout.guiRect.position+layout.dragDelta, inout.guiRect.size); gen.Move(script.layout.dragDelta,true); repaint=true; Repaint(); EditorUtility.SetDirty(gens); } } //saving all generator rects gen.guiRect = gen.layout.field; } //dragging groups for (int i=gens.list.Length-1; i>=0; i--) { //Generator gen = gens.list[i]; Group group = gens.list[i] as Group; if (group == null) continue; group.layout.field = group.guiRect; //resizing group.layout.field =script.layout.ResizeRect(group.layout.field, i+20000); //dragging if (script.layout.DragDrop(group.layout.field, i)) { if (script.layout.dragState == Layout.DragState.Pressed) { Undo.RecordObject (gens, "MapMagic Group Drag"); gens.setDirty = !gens.setDirty; group.Populate(gens); } if (script.layout.dragState == Layout.DragState.Drag ||script.layout.dragState == Layout.DragState.Released) { group.Move(script.layout.dragDelta,true); repaint=true; Repaint(); EditorUtility.SetDirty(gens); } if (script.layout.dragState == Layout.DragState.Released && group != null) gens.SortGroups(); } //saving all group rects group.guiRect = group.layout.field; } if (script.guiDebug) Profiler.EndSample(); #endregion //right-click menus if (Event.current.type == EventType.MouseDown && Event.current.button == 1) DrawPopup(); //debug center //EditorGUI.HelpBox(script.layout.ToLocal(new Rect(-25,-10,50,20)), "Zero", MessageType.None); //assigning portal popup action Portal.OnChooseEnter -= DrawPortalSelector; Portal.OnChooseEnter += DrawPortalSelector; //saving scroll and zoom script.guiScroll =script.layout.scroll; script.guiZoom =script.layout.zoom; //producing synthetic lag to test performance //for (int i=0; i<10; i++) Debug.LogWarning("Lag"); //drawing lock warning if (locked) { script.toolbarLayout.Label("", rect: new Rect(4,20,300,155), helpbox:true); script.toolbarLayout.Label("You are using the demo version of Map Magic. " + "It should be used for evaluation purposes only and has a save limitation: although the node graph could be saved, " + "it could not be edited after the load. " + "You can get a fully functional version at the Asset Store or reset your graph to proceed editing:", rect: new Rect(4,20,300,155), helpbox:true); if (script.toolbarLayout.Button("Get MapMagic at the Asset Store", rect: new Rect(20,120, 260, 22))) Application.OpenURL("https://www.assetstore.unity3d.com/en/#!/content/56762"); if (script.toolbarLayout.Button("Reset node graph", rect: new Rect(20,145, 260, 18))) { MapMagic.instance.gens = ScriptableObject.CreateInstance<GeneratorsAsset>(); gens = MapMagic.instance.gens; MapMagic.instance.guiGens = gens; gens.OnBeforeSerialize(); } } if (script.guiDebug) Profiler.EndSample(); }
public void DeleteGenerator(Generator gen) { //removing generator from 'ready' and 'results' arrays ChangeGenerator(gen); //manually resetting all dependent generators ready stae for (int g = 0; g < list.Length; g++) { if (list[g].IsDependentFrom(gen)) { ChangeGenerator(list[g]); } } //clearing if it is output gen //if (gen is IOutput) // foreach (Chunk chunk in MapMagic.instance.terrains.Objects()) // (gen as IOutput).Clear(chunk); //removing group members if it is group #if UNITY_EDITOR if (gen is Group) { int dialogResult = UnityEditor.EditorUtility.DisplayDialogComplex("Remove Containing Generators", "Do you want to remove a contaning generators as well?", "Remove Generators", "Remove Group Only", "Cancel"); if (dialogResult == 2) { return; //cancel } if (dialogResult == 0) //generators { Group group = gen as Group; group.Populate(this); for (int g = group.generators.Count - 1; g >= 0; g--) { DeleteGenerator(group.generators[g]); } } } #endif //unlinking and removing it's reference in inputs and outputs //for (int g=0; g<list.Length; g++) // foreach (Generator.Input input in list[g].Inputs()) // if (input.linkGen == gen) input.Unlink(); UnlinkGenerator(gen); //removing from output generators list //if (gen is IOutput) // Extensions.ArrayRemove(ref outputs, gen); //removing from array ArrayTools.Remove(ref list, gen); //removing from preview if (MapMagic.instance.previewGenerator == gen) { MapMagic.instance.previewGenerator = null; MapMagic.instance.previewOutput = null; } //force regenerate if it was an output if (gen is Generator.IOutput) { MapMagic.instance.ForceGenerate(); } }
public void DrawPopup () { Vector2 mousePos = layout.ToInternal(Event.current.mousePosition); //finding something that was clicked Generator clickedGenerator = null; for (int i=0; i<MapMagic.instance.gens.list.Length; i++) { Generator gen = MapMagic.instance.gens.list[i]; if (gen.guiRect.Contains(mousePos) && !(gen is Group)) clickedGenerator = MapMagic.instance.gens.list[i]; } Group clickedGroup = null; for (int i=0; i<MapMagic.instance.gens.list.Length; i++) { Generator gen = MapMagic.instance.gens.list[i]; if (gen.guiRect.Contains(mousePos) && gen is Group) clickedGroup = MapMagic.instance.gens.list[i] as Group; } if (clickedGenerator == null) clickedGenerator = clickedGroup; Generator.Output clickedOutput = null; for (int i=0; i<MapMagic.instance.gens.list.Length; i++) foreach (Generator.Output output in MapMagic.instance.gens.list[i].Outputs()) if (output.guiRect.Contains(mousePos)) clickedOutput = output; //create Dictionary<string, PopupMenu.MenuItem> itemsDict = new Dictionary<string, PopupMenu.MenuItem>(); List<System.Type> allGeneratorTypes = typeof(Generator).GetAllChildTypes(); for (int i=0; i<allGeneratorTypes.Count; i++) { if (System.Attribute.IsDefined(allGeneratorTypes[i], typeof(GeneratorMenuAttribute))) { GeneratorMenuAttribute attribute = System.Attribute.GetCustomAttribute(allGeneratorTypes[i], typeof(GeneratorMenuAttribute)) as GeneratorMenuAttribute; System.Type genType = allGeneratorTypes[i]; if (attribute.disabled) continue; PopupMenu.MenuItem item = new PopupMenu.MenuItem(attribute.name, delegate () { CreateGenerator(genType, mousePos); }); item.priority = attribute.priority; if (attribute.menu.Length != 0) { if (!itemsDict.ContainsKey(attribute.menu)) itemsDict.Add(attribute.menu, new PopupMenu.MenuItem(attribute.menu, subs:new PopupMenu.MenuItem[0])); ArrayTools.Add(ref itemsDict[attribute.menu].subItems, item); } else itemsDict.Add(attribute.name, item); } } PopupMenu.MenuItem[] createItems = new PopupMenu.MenuItem[itemsDict.Count]; itemsDict.Values.CopyTo(createItems, 0); //create group //PopupMenu.MenuItem createGroupItem = new PopupMenu.MenuItem("Group", delegate () { CreateGroup(mousePos); }); //Extensions.ArrayAdd(ref createItems, createItems.Length-1, createGroupItem); //additional name string additionalName = "All"; if (clickedGenerator != null) { additionalName = "Generator"; if (clickedGenerator is Group) additionalName = "Group"; } //preview PopupMenu.MenuItem[] previewSubs = new PopupMenu.MenuItem[] { new PopupMenu.MenuItem("On Terrain", delegate() {PreviewOutput(clickedGenerator, clickedOutput, false);}, disabled:clickedOutput==null||clickedGenerator==null), new PopupMenu.MenuItem("In Window", delegate() {PreviewOutput(clickedGenerator, clickedOutput, true);}, disabled:clickedOutput==null||clickedGenerator==null), new PopupMenu.MenuItem("Clear", delegate() {PreviewOutput(null, null, false);}, disabled:MapMagic.instance.gens.GetGenerator<PreviewOutput>()==null) }; PopupMenu.MenuItem[] popupItems = new PopupMenu.MenuItem[] { new PopupMenu.MenuItem("Create", createItems), new PopupMenu.MenuItem("Save " + additionalName, delegate () { SaveGenerator(clickedGenerator, mousePos); }), new PopupMenu.MenuItem("Load", delegate () { LoadGenerator(mousePos); }), new PopupMenu.MenuItem("Duplicate", delegate () { DuplicateGenerator(clickedGenerator); }), new PopupMenu.MenuItem("Remove", delegate () { if (clickedGenerator!=null) DeleteGenerator(clickedGenerator); }, disabled:(clickedGenerator==null)), new PopupMenu.MenuItem("Reset", delegate () { if (clickedGenerator!=null) ResetGenerator(clickedGenerator); }, disabled:clickedGenerator==null), new PopupMenu.MenuItem("Preview", previewSubs) }; PopupMenu.DrawPopup(popupItems, Event.current.mousePosition, closeAllOther:true); }