예제 #1
0
 void UpdateGradient()
 {
     waterGradient = PWUtils.CreateGradient(GradientMode.Fixed,
                                            new KeyValuePair <float, Color>(waterLevel / (mapMax - mapMin), Color.blue),
                                            new KeyValuePair <float, Color>(1, Color.white));
     PWGUI.SetGradientForField(0, waterGradient);
 }
예제 #2
0
        private T               GetGUISettingData <T>(Func <T> newGUISettings) where T : PWGUISettings
        {
            if (settingsStorage == null)
            {
                settingsStorage = new List <PWGUISettings>();
            }

            if (currentSettingCount == settingsStorage.Count)
            {
                var s = newGUISettings();

                s.windowPosition = PWUtils.Round(editorWindowRect.size / 2);
                settingsStorage.Add(s);
            }
            if (settingsStorage[currentSettingCount].GetType() != typeof(T))
            {
                //try cast, if fails create a new object
                T ret = settingsStorage[currentSettingCount] as T;
                if (ret != null)
                {
                    return(ret);
                }
                Debug.Log("type mismatch and cast fail, creating a new insatnce !");
                settingsStorage[currentSettingCount] = newGUISettings();
            }
            return(settingsStorage[currentSettingCount++] as T);
        }
예제 #3
0
    void SelectAndDrag()
    {
        Profiler.BeginSample("[PW] Select and drag");

        //rendering the selection rect
        if (editorEvents.isSelecting)
        {
            Rect posiviteSelectionRect = PWUtils.CreateRect(e.mousePosition, editorEvents.selectionStartPoint);
            Rect decaledSelectionRect  = PWUtils.DecalRect(posiviteSelectionRect, -graph.panPosition);

            //draw selection rect
            if (e.type == EventType.Repaint)
            {
                selectionStyle.Draw(posiviteSelectionRect, false, false, false, false);
            }

            //iterate throw all nodes of the graph and check if the selection overlaps
            graph.nodes.ForEach(n => n.isSelected = decaledSelectionRect.Overlaps(n.rect));
            editorEvents.selectedNodeCount        = graph.nodes.Count(n => n.isSelected);
        }

        //multiple window drag:
        if (e.type == EventType.MouseDrag && editorEvents.isDraggingSelectedNodes)
        {
            graph.nodes.ForEach(n => {
                if (n.isSelected)
                {
                    n.rect.position += e.delta;
                }
            });
        }

        Profiler.EndSample();
    }
예제 #4
0
        public override void    OnNodeProcess()
        {
            if (inputTerrain != null)
            {
                PWUtils.ResizeSamplerIfNeeded(inputTerrain, ref outputTerrain);
            }

            if (!needUpdate)
            {
                return;
            }

            UpdateTerrain();
        }
        public override void OnNodeCreate()
        {
            externalName = "Temperature node";

            temperatureGradient = PWUtils.CreateGradient(
                new KeyValuePair <float, Color>(0f, Color.blue),
                new KeyValuePair <float, Color>(.25f, Color.cyan),
                new KeyValuePair <float, Color>(.5f, Color.yellow),
                new KeyValuePair <float, Color>(.75f, PWColorPalette.orange),
                new KeyValuePair <float, Color>(1f, Color.red)
                );

            UpdateTemperatureMap();
        }
    public override object  OnChunkCreate(ChunkData cd, Vector3 pos)
    {
        if (cd == null)
        {
            return(null);
        }

        if (rainbow == null)
        {
            rainbow = PWUtils.CreateRainbowGradient();
        }

        TopDown2DData chunk = (TopDown2DData)cd;

        //create the terrain texture:
        //TODO: bind the blendMap with biome maps to the terrain shader
        //TODO: bind all vertex datas from the mesh

        GameObject g = CreateChunkObject(pos * terrainScale);

        g.transform.rotation   = Quaternion.identity;
        g.transform.localScale = Vector3.one * chunkSize * terrainScale;

        MeshRenderer mr = g.AddComponent <MeshRenderer>();
        MeshFilter   mf = g.AddComponent <MeshFilter>();

        if (topDownTerrainMesh == null || topDownTerrainMeshSize != chunkSize)
        {
            GenerateTopDownTerrainMesh();
        }

        UpdateMeshDatas(chunk.biomeMap);

        mf.sharedMesh = topDownTerrainMesh;

        Shader topDown2DBasicTerrainShader = Shader.Find("ProceduralWorlds/Basic terrain");

        if (topDown2DBasicTerrainShader == null)
        {
            topDown2DBasicTerrainShader = Shader.Find("Standard");
        }
        Material mat = new Material(topDown2DBasicTerrainShader);

        mat.SetTexture("_AlbedoMaps", chunk.albedoMaps);
        mr.sharedMaterial = mat;
        //TODO: vertex painting
        return(g);
    }
예제 #7
0
        public override void OnNodeEnable()
        {
            UpdateTemperatureMap();

            temperatureGradient = PWUtils.CreateGradient(
                new KeyValuePair <float, Color>(0f, Color.blue),
                new KeyValuePair <float, Color>(.25f, Color.cyan),
                new KeyValuePair <float, Color>(.5f, Color.yellow),
                new KeyValuePair <float, Color>(.75f, PWColor.orange),
                new KeyValuePair <float, Color>(1f, Color.red)
                );

            delayedChanges.BindCallback(delayedTemperatureKey, (unused) => {
                NotifyReload();
            });
        }
예제 #8
0
        public bool             Overlaps(BiomeSwitchCellParams cellParams)
        {
            int length = cellParams.switchParams.Length;

            for (int i = 0; i < length; i++)
            {
                var c  = cellParams.switchParams[i];
                var sp = switchParams.switchParams[i];
                if (c.enabled && sp.enabled &&
                    !PWUtils.Overlap(sp.min, sp.max, c.min, c.max))
                {
                    return(false);
                }
            }
            return(true);
        }
예제 #9
0
        public float    GapWidth(BiomeSwitchCell c2)
        {
            float gap = 0;

            int length = c2.switchParams.switchParams.Length;

            for (int i = 0; i < length; i++)
            {
                if (switchParams.switchParams[i].enabled)
                {
                    var s1 = switchParams.switchParams[i];
                    var s2 = c2.switchParams.switchParams[i];
                    gap += PWUtils.GapWidth(s1.min, s1.max, s2.min, s2.max);
                }
            }

            return(gap);
        }
예제 #10
0
        public float                            GapWidth(BiomeSurfaceSwitch b2)
        {
            float gap = 0;

            if (heightEnabled)
            {
                gap += PWUtils.GapWidth(minHeight, maxHeight, b2.minHeight, b2.maxHeight);
            }
            if (slopeEnabled)
            {
                gap += PWUtils.GapWidth(minSlope, maxSlope, b2.minSlope, b2.maxSlope);
            }
            if (paramEnabled)
            {
                gap += PWUtils.GapWidth(minParam, maxParam, b2.minParam, b2.maxParam);
            }

            return(gap);
        }
예제 #11
0
    void RenderDecaledNode(int id, PWNode node)
    {
        //node grid snapping when pressing cmd/crtl
        if (node.isDragged && e.command)
        {
            Vector2 pos = node.rect.position;
            //aproximative grid cell size
            float snapPixels = 25.6f;

            pos.x = Mathf.RoundToInt(Mathf.RoundToInt(pos.x / snapPixels) * snapPixels);
            pos.y = Mathf.RoundToInt(Mathf.RoundToInt(pos.y / snapPixels) * snapPixels);
            node.rect.position = pos;
        }

        //move the node if panPosition changed:
        node.rect = PWUtils.DecalRect(node.rect, graph.panPosition);
        Rect decaledRect = GUILayout.Window(id, node.rect, node.OnWindowGUI, node.name, (node.isSelected) ? nodeSelectedStyle : nodeStyle, GUILayout.Height(node.viewHeight));

        node.visualRect = decaledRect;
        node.rect       = PWUtils.DecalRect(decaledRect, -graph.panPosition);

        //draw node header:
        //Draw the node header using the color scheme:
        if (e.type == EventType.Repaint)
        {
            float h = nodeStyle.border.top;
            float w = decaledRect.width - nodeStyle.border.right - nodeStyle.border.left;
            GUI.color = PWColorTheme.GetNodeColor(node.colorSchemeName);
            // GUI.DrawTexture(new Rect(0, 0, w, h), nodeHeaderStyle.normal.background);
            nodeHeaderStyle.Draw(new Rect(decaledRect.x, decaledRect.y, w, h), false, false, false, false);
            GUI.color = Color.white;
        }

        if (node.debug)
        {
            Rect debugRect = decaledRect;
            debugRect.y -= 20;
            EditorGUI.LabelField(debugRect, "id: " + node.id);
            debugRect.y -= 20;
            EditorGUI.LabelField(debugRect, "comp order: " + node.computeOrder + " | can work: " + node.canWork);
        }
    }
예제 #12
0
    void RenderNode(int id, PWNode node)
    {
        RenderDecaledNode(id, node);

        //check if the mouse is over this node
        if (node.rect.Contains(e.mousePosition - graph.panPosition))
        {
            graph.editorEvents.mouseOverNode        = node;
            graph.editorEvents.isMouseOverNodeFrame = true;
        }

        //display the process time of the window (if > .1ms)
        if (node.processTime > .1f)
        {
            GUIStyle gs     = new GUIStyle();
            Rect     msRect = PWUtils.DecalRect(node.rect, graph.panPosition);
            msRect.position    += new Vector2(msRect.size.x / 2 - 10, msRect.size.y + 5);
            gs.normal.textColor = greenRedGradient.Evaluate(node.processTime / 20);             //20ms ok, after is red
            GUI.Label(msRect, node.processTime.ToString("F1") + " ms", gs);
        }
    }
예제 #13
0
        public override void OnNodeProcess()
        {
            if (mergedBiomeTerrain == null)
            {
                mergedBiomeTerrain = new FinalTerrain();
            }

            if (inputBlendedTerrain.biomeData == null)
            {
                Debug.LogError("[PWBiomeMerger] Can't find BiomeData, did you forgot to specify the BiomeGraph in a Biome node");
                return;
            }

            var inputTerrain = inputBlendedTerrain.biomeData.GetSampler(BiomeSamplerName.terrainHeight);

            finalTerrain = inputTerrain.Clone(finalTerrain);

            if (finalTerrain.type == SamplerType.Sampler2D)
            {
                BiomeMap2D biomeMap = inputBlendedTerrain.biomeData.biomeMap;

                (finalTerrain as Sampler2D).Foreach((x, y, val) => {
                    float ret = 0;

                    var biomeInfo = biomeMap.GetBiomeBlendInfo(x, y);
                    foreach (var biome in inputBlendedTerrain.biomes)
                    {
                        var terrain = biome.modifiedTerrain as Sampler2D;

                        if (terrain == null)
                        {
                            PWUtils.LogErrorMax("[PWNodeMerger] can't access to the terrain of the biome " + biome.id + "(" + biome.name + ")", 100);
                            continue;
                        }

                        //TODO: test this blending !
                        for (int i = 0; i < biomeInfo.length; i++)
                        {
                            if (biomeInfo.biomeIds[i] == biome.id)
                            {
                                ret += terrain[x, y] * biomeInfo.biomeBlends[i] / biomeInfo.totalBlend;
                            }
                        }
                    }

                    return(ret);
                });
            }
            else if (finalTerrain.type == SamplerType.Sampler3D)
            {
                Debug.Log("TODO: 3D Terrains");
            }

            mergedBiomeTerrain.biomeData        = inputBlendedTerrain.biomeData;
            mergedBiomeTerrain.mergedTerrain    = finalTerrain;
            mergedBiomeTerrain.materializerType = mainGraphRef.materializerType;

            mergedBiomeTerrain.biomeSurfacesList.Clear();
            foreach (var biome in inputBlendedTerrain.biomes)
            {
                if (mergedBiomeTerrain.biomeSurfacesList.ContainsKey(biome.id))
                {
                    Debug.LogError("[PWBiomeMerger] Duplicate biome in the biome graph: " + biome.name + ", id: " + biome.id);
                }
                mergedBiomeTerrain.biomeSurfacesList[biome.id] = biome.biomeSurfaceGraph;
            }

            update = true;
        }
예제 #14
0
        public void Sampler2DPreview(GUIContent prefix, Sampler2D samp, bool update, bool settings = true, FilterMode fm = FilterMode.Bilinear)
        {
            int previewSize = (int)currentWindowRect.width - 20 - 20;             //padding + texture margin
            var e           = Event.current;

            if (samp == null)
            {
                return;
            }

            if (prefix != null && !String.IsNullOrEmpty(prefix.text))
            {
                EditorGUILayout.LabelField(prefix);
            }

            var fieldSettings = GetGUISettingData(() => {
                var state        = new PWGUISettings();
                state.filterMode = fm;
                state.debug      = false;
                state.gradient   = new SerializableGradient(
                    PWUtils.CreateGradient(
                        new KeyValuePair <float, Color>(0, Color.black),
                        new KeyValuePair <float, Color>(1, Color.white)
                        )
                    );
                return(state);
            });

            //recreated texture if it has been destoryed:
            if (fieldSettings.texture == null)
            {
                fieldSettings.texture            = new Texture2D(previewSize, previewSize, TextureFormat.RGBA32, false);
                fieldSettings.texture.filterMode = fieldSettings.filterMode;
            }

            //same for the gradient:
            if (fieldSettings.gradient == null || fieldSettings.gradient.alphaKeys == null)
            {
                fieldSettings.gradient = fieldSettings.serializableGradient;
            }

            Texture2D tex      = fieldSettings.texture;
            Gradient  gradient = fieldSettings.gradient;

            if (samp.size != tex.width)
            {
                tex.Resize(samp.size, samp.size, TextureFormat.RGBA32, false);
            }

            Rect previewRect = EditorGUILayout.GetControlRect(GUILayout.ExpandWidth(true), GUILayout.Height(0));

            if (previewRect.width > 2)
            {
                fieldSettings.savedRect = previewRect;
            }

            TexturePreview(tex, false, false, false);

            //draw the settings window
            if (settings && fieldSettings.active)
            {
                PWPopup.AddToRender(fieldSettings, "Sampler 2D settings", () => {
                    EditorGUILayout.BeginVertical();
                    {
                        EditorGUI.BeginChangeCheck();
                        fieldSettings.filterMode = (FilterMode)EditorGUILayout.EnumPopup(fieldSettings.filterMode);
                        if (EditorGUI.EndChangeCheck())
                        {
                            tex.filterMode = fieldSettings.filterMode;
                        }
                        gradient = (Gradient)gradientField.Invoke(null, new object[] { "", gradient, null });
                        if (!gradient.Compare(fieldSettings.serializableGradient))
                        {
                            fieldSettings.update = true;
                        }
                        fieldSettings.serializableGradient = (SerializableGradient)gradient;
                    }
                    EditorGUILayout.EndVertical();

                    if (e.type == EventType.KeyDown && fieldSettings.active)
                    {
                        if (e.keyCode == KeyCode.Return || e.keyCode == KeyCode.KeypadEnter || e.keyCode == KeyCode.Escape)
                        {
                            fieldSettings.InActive();
                            e.Use();
                        }
                    }

                    EditorGUIUtility.labelWidth = 100;
                    fieldSettings.debug         = EditorGUILayout.Toggle("debug", fieldSettings.debug);

                    if (GUILayout.Button("force update"))
                    {
                        fieldSettings.update = true;
                    }
                });
            }

            if (settings)
            {
                //draw the setting icon and manage his events
                int  icSettingsSize    = 16;
                int  icSettingsPadding = 4;
                Rect icSettingsRect    = new Rect(previewRect.x + previewRect.width - icSettingsSize - icSettingsPadding, previewRect.y + icSettingsPadding, icSettingsSize, icSettingsSize);

                GUI.DrawTexture(icSettingsRect, ic_settings);
                if (e.type == EventType.MouseDown && e.button == 0)
                {
                    if (icSettingsRect.Contains(e.mousePosition))
                    {
                        fieldSettings.Invert(null);
                        e.Use();
                    }
                    else if (fieldSettings.active)
                    {
                        fieldSettings.InActive();
                        e.Use();
                    }
                }
            }

            if (!settings && fieldSettings.texture.filterMode != fm)
            {
                fieldSettings.texture.filterMode = fm;
            }

            //update the texture with the gradient
            if (update || fieldSettings.update)
            {
                samp.Foreach((x, y, val) => {
                    tex.SetPixel(x, y, gradient.Evaluate(Mathf.Clamp01(val)));
                }, true);
                tex.Apply();
                fieldSettings.update = false;
            }

            if (fieldSettings.debug)
            {
                Vector2 pixelPos = e.mousePosition - fieldSettings.savedRect.position;

                pixelPos *= samp.size / fieldSettings.savedRect.width;

                EditorGUILayout.LabelField("Sampler2D min: " + samp.min + ", max: " + samp.max);

                if (pixelPos.x >= 0 && pixelPos.y >= 0 && pixelPos.x < samp.size && pixelPos.y < samp.size)
                {
                    if (e.isMouse)
                    {
                        e.Use();
                    }
                    EditorGUILayout.LabelField("(" + (int)pixelPos.x + ", " + (int)pixelPos.y + "): " + samp[(int)pixelPos.x, (int)pixelPos.y]);
                }
                else
                {
                    EditorGUILayout.LabelField("(NA, NA): NA");
                }
            }
        }
예제 #15
0
        public override void OnNodeProcess()
        {
            ints   = values.GetValues <int>();
            floats = values.GetValues <float>();
            vec2s  = values.GetValues <Vector2>();
            vec3s  = values.GetValues <Vector3>();
            vec4s  = values.GetValues <Vector4>();

            //check nominal type:

            fOutput  = 0;
            v2Output = Vector2.zero;
            v3Output = Vector3.zero;
            v4Output = Vector4.zero;

            if (vec4s.Count != 0)
            {
                foreach (var vec4 in vec4s)
                {
                    v4Output += vec4;
                }
                foreach (var vec3 in vec3s)
                {
                    v4Output += (Vector4)vec3;
                }
                foreach (var vec2 in vec2s)
                {
                    v4Output += (Vector4)vec2;
                }
                foreach (var flt in floats)
                {
                    v4Output += new Vector4(flt, flt, flt, flt);
                }
                foreach (var integer in ints)
                {
                    v4Output += new Vector4(integer, integer, integer, integer);
                }
                if (intify)
                {
                    v4Output = PWUtils.Round(v4Output);
                }
            }
            else if (vec3s.Count != 0)
            {
                foreach (var vec3 in vec3s)
                {
                    v3Output += (Vector3)vec3;
                }
                foreach (var vec2 in vec2s)
                {
                    v3Output += (Vector3)vec2;
                }
                foreach (var flt in floats)
                {
                    v3Output += new Vector3(flt, flt, flt);
                }
                foreach (var integer in ints)
                {
                    v3Output += new Vector3(integer, integer, integer);
                }
                if (intify)
                {
                    v3Output = PWUtils.Round(v3Output);
                }
            }
            else if (vec2s.Count != 0)
            {
                foreach (var vec2 in vec2s)
                {
                    v2Output += (Vector2)vec2;
                }
                foreach (var flt in floats)
                {
                    v2Output += new Vector2(flt, flt);
                }
                foreach (var integer in ints)
                {
                    v2Output += new Vector2(integer, integer);
                }
                if (intify)
                {
                    v2Output = PWUtils.Round(v2Output);
                }
            }
            else             //int and floats
            {
                foreach (var flt in floats)
                {
                    fOutput += flt;
                }
                foreach (var integer in ints)
                {
                    fOutput += integer;
                }
                if (intify)
                {
                    fOutput = Mathf.Round(fOutput);
                }
            }
        }
예제 #16
0
        public bool                                     Overlaps(BiomeSurfaceSwitch b2)
        {
            bool slopeOverlaps  = (!slopeEnabled || !b2.slopeEnabled) || (slopeEnabled && b2.slopeEnabled && PWUtils.Overlap(minSlope, maxSlope, b2.minSlope, b2.maxSlope));
            bool heightOverlaps = (!heightEnabled || !b2.heightEnabled) || (heightEnabled && b2.heightEnabled && PWUtils.Overlap(minHeight, maxHeight, b2.minHeight, b2.maxHeight));
            bool paramOverlaps  = (!paramEnabled || !b2.paramEnabled) || (paramEnabled && b2.paramEnabled && PWUtils.Overlap(minParam, maxParam, b2.minParam, b2.maxParam));

            return(slopeOverlaps && heightOverlaps && paramOverlaps);
        }
        public void FillBiomeMap(int biomeBlendCount, BiomeData biomeData)
        {
            bool is3DBiomes  = false;
            bool is3DTerrain = biomeData.terrain3D != null;

            Biome[] nearestBiomes = new Biome[biomeBlendCount];

            //TODO: biome blend count > 1 management

            //TODO: biomeData.datas3D null check
            if (biomeData.air3D != null || biomeData.wind3D != null || biomeData.wetness3D != null || biomeData.temperature3D != null)
            {
                is3DBiomes = true;
            }

            if (biomeData.terrainRef == null)
            {
                return;
            }

            int   terrainSize = (is3DTerrain) ? biomeData.terrain3D.size : biomeData.terrain.size;
            float terrainStep = (is3DTerrain) ? biomeData.terrain3D.step : biomeData.terrain.step;

            if (is3DBiomes)
            {
                biomeData.biomeIds3D = new BiomeMap3D(terrainSize, terrainStep);
            }
            else
            {
                biomeData.biomeIds = new BiomeMap2D(terrainSize, terrainStep);
            }

            if (is3DBiomes)
            {
                //TODO
            }
            else
            {
                for (int x = 0; x < terrainSize; x++)
                {
                    for (int y = 0; y < terrainSize; y++)
                    {
                        bool  water = (biomeData.isWaterless) ? false : biomeData.waterHeight[x, y] > 0;
                        float temp  = (biomeData.temperature != null) ? biomeData.temperature[x, y] : 0;
                        float wet   = (biomeData.wetness != null) ? biomeData.wetness[x, y] : 0;
                        // Debug.Log("map [" + x + "/" + y + "] = " + biomeData.terrain[x, y]);
                        //TODO: 3D terrain management
                        float           height  = (is3DTerrain) ? 0 : biomeData.terrain[x, y];
                        BiomeSwitchNode current = root;
                        while (true)
                        {
nextChild:
                            if (current.biome != null)
                            {
                                break;
                            }
                            int childCount = current.GetChildCount();
                            for (int i = 0; i < childCount; i++)
                            {
                                var child = current.GetChildAt(i);
                                switch (child.biomeSwitchMode)
                                {
                                case BiomeSwitchMode.Water:
                                    if (child.value == water)
                                    {
                                        current = child; goto nextChild;
                                    }
                                    break;

                                case BiomeSwitchMode.Height:
                                    if (height > child.min && height <= child.max)
                                    {
                                        current = child; goto nextChild;
                                    }
                                    break;

                                case BiomeSwitchMode.Temperature:
                                    if (temp > child.min && temp <= child.max)
                                    {
                                        current = child; goto nextChild;
                                    }
                                    break;

                                case BiomeSwitchMode.Wetness:
                                    if (wet > child.min && wet <= child.max)
                                    {
                                        current = child; goto nextChild;
                                    }
                                    break;
                                }
                            }
                            //if flow reach this part, values are missing in the biome graph so biome can't be chosen.
                            break;
                        }
                        //TODO: blending with second biome
                        if (current.biome != null)
                        {
                            biomeData.biomeIds.SetFirstBiomeId(x, y, current.biome.id);
                        }
                        else
                        {
                            //FIXME!!!!
                            biomeData.biomeIds.SetFirstBiomeId(x, y, -1);
                            // PWUtils.LogWarningMax("Can't choose biome with water:" + water + ", temp: " + temp + ", wet: " + wet + ", height: " + height, 200);
                            PWUtils.LogWarningMax("Can't choose biome with water:" + water + ", temp: " + temp + ", wet: " + wet + ", height: " + height, 300);
                            continue;
                        }
                    }
                }
            }
        }
예제 #18
0
        public void Render(PWGraph graph, Vector2 screenSize)
        {
            var  e      = Event.current;
            Rect screen = new Rect(-graph.panPosition, screenSize);

            //check if ordering group is not visible
            if (!orderGroupRect.Overlaps(screen))
            {
                return;
            }

            //Start GUI frame
            PWGUI.StartFrame(screen);

            if (orderingGroupStyle == null)
            {
                LoadStyles();
            }

            Rect orderGroupWorldRect = PWUtils.DecalRect(orderGroupRect, graph.panPosition);

            callbackId = 0;

            int controlSize = 8;
            int cornerSize  = 14;

            CreateAnchorRectCallabck(             //left resize anchor
                new Rect(orderGroupWorldRect.x, orderGroupWorldRect.y + cornerSize, controlSize, orderGroupWorldRect.height - cornerSize * 2),
                MouseCursor.ResizeHorizontal,
                () => orderGroupRect.xMin += e.delta.x
                );
            CreateAnchorRectCallabck(             //right resize anchor
                new Rect(orderGroupWorldRect.x + orderGroupWorldRect.width - controlSize, orderGroupWorldRect.y + cornerSize, controlSize, orderGroupWorldRect.height - cornerSize * 2),
                MouseCursor.ResizeHorizontal,
                () => orderGroupRect.xMax += e.delta.x
                );
            CreateAnchorRectCallabck(             //top resize anchor
                new Rect(orderGroupWorldRect.x + cornerSize, orderGroupWorldRect.y, orderGroupWorldRect.width - cornerSize * 2, controlSize),
                MouseCursor.ResizeVertical,
                () => orderGroupRect.yMin += e.delta.y
                );
            CreateAnchorRectCallabck(             //down resize anchor
                new Rect(orderGroupWorldRect.x + cornerSize, orderGroupWorldRect.y + orderGroupWorldRect.height - controlSize, orderGroupWorldRect.width - cornerSize * 2, controlSize),
                MouseCursor.ResizeVertical,
                () => orderGroupRect.yMax += e.delta.y
                );

            CreateAnchorRectCallabck(             //top left anchor
                new Rect(orderGroupWorldRect.x, orderGroupWorldRect.y, cornerSize, cornerSize),
                MouseCursor.ResizeUpLeft,
                () => { orderGroupRect.yMin += e.delta.y; orderGroupRect.xMin += e.delta.x; }
                );
            CreateAnchorRectCallabck(             //top right anchor
                new Rect(orderGroupWorldRect.x + orderGroupWorldRect.width - cornerSize, orderGroupWorldRect.y, cornerSize, cornerSize),
                MouseCursor.ResizeUpRight,
                () => { orderGroupRect.yMin += e.delta.y; orderGroupRect.xMax += e.delta.x; }
                );
            CreateAnchorRectCallabck(             //down left anchor
                new Rect(orderGroupWorldRect.x, orderGroupWorldRect.y + orderGroupWorldRect.height - cornerSize, cornerSize, cornerSize),
                MouseCursor.ResizeUpRight,
                () => { orderGroupRect.yMax += e.delta.y; orderGroupRect.xMin += e.delta.x; }
                );
            CreateAnchorRectCallabck(             //down right anchor
                new Rect(orderGroupWorldRect.x + orderGroupWorldRect.width - cornerSize, orderGroupWorldRect.y + orderGroupWorldRect.height - cornerSize, cornerSize, cornerSize),
                MouseCursor.ResizeUpLeft,
                () => { orderGroupRect.yMax += e.delta.y; orderGroupRect.xMax += e.delta.x; }
                );

            if (e.rawType == EventType.MouseUp)
            {
                resizing = false;
            }

            //draw renamable name field
            orderingGroupNameStyle.normal.textColor = color;
            PWGUI.TextField(orderGroupWorldRect.position + new Vector2(10, -22), ref name, true, orderingGroupNameStyle);

            //draw move pad
            Rect movePadRect = new Rect(orderGroupWorldRect.position + new Vector2(10, 10), new Vector2(50, 30));

            GUI.DrawTextureWithTexCoords(movePadRect, movepadTexture, new Rect(0, 0, 5, 4));
            EditorGUIUtility.AddCursorRect(movePadRect, MouseCursor.MoveArrow);
            if (e.type == EventType.MouseDown && e.button == 0)
            {
                if (movePadRect.Contains(e.mousePosition))
                {
                    innerNodes = graph.nodes.Where(n => n.rect.Overlaps(orderGroupRect)).ToList();
                    moving     = true;
                    e.Use();
                }
            }
            if (e.rawType == EventType.MouseUp)
            {
                moving = false;
            }

            if (moving && e.type == EventType.MouseDrag)
            {
                orderGroupRect.position += e.delta;
                innerNodes.ForEach(n => n.rect.position += e.delta);
            }

            //draw ordering group
            GUI.color = color;
            GUI.Label(orderGroupWorldRect, (string)null, orderingGroupStyle);
            GUI.color = Color.white;

            //draw color picker
            Rect colorPickerRect = new Rect(orderGroupWorldRect.x + orderGroupWorldRect.width - 30, orderGroupWorldRect.y + 10, 20, 20);

            PWGUI.ColorPicker(colorPickerRect, ref color, false);

            if (orderGroupWorldRect.Contains(e.mousePosition))
            {
                graph.editorEvents.mouseOverOrderingGroup        = this;
                graph.editorEvents.isMouseOverOrderingGroupFrame = true;
            }
        }