void Update()
        {
            if (!m_isInitialized)
            {
                Init();
                return;
            }

            #region Draw Collisions
            // Generate texture again in case window has been resized
            Vector2 screenSize = new Vector2(Screen.width, Screen.height);
            if (m_prevScreenSize != screenSize)
            {
                _GenerateCollisionTexture();
            }
            m_prevScreenSize = screenSize;

            m_spriteCollLayer.SetActive(m_showCollisions);
            if (m_showCollisions && (int)(Time.timeSinceLevelLoad * 4) % 2 == 0)
            {
                SpriteRenderer sprRender = m_spriteCollLayer.GetComponent <SpriteRenderer>();
                Vector3        vPos      = m_camera2D.transform.position;
                vPos.x -= (vPos.x % (m_autoTileMap.Tileset.TileWorldWidth / 4));
                vPos.y -= (vPos.y % (m_autoTileMap.Tileset.TileWorldHeight / 4));
                vPos.z += 1f;

                // Collision texture position snap to a quarter of tile part
                sprRender.transform.position = vPos;

                // Collision texture pixel scaled to a quarter of tile part
                sprRender.transform.localScale = new Vector3((m_autoTileMap.Tileset.TilePartWidth / 2), (m_autoTileMap.Tileset.TilePartHeight / 2), 1f);

                vPos = m_camera2D.Camera.WorldToScreenPoint(sprRender.transform.position);                   // vPos = center of collision texture in screen coords
                Vector3 vTopLeftOff = new Vector3(sprRender.sprite.texture.width * (m_autoTileMap.Tileset.TilePartWidth / 2) / 2, -sprRender.sprite.texture.height * (m_autoTileMap.Tileset.TilePartHeight / 2) / 2) * m_camera2D.Zoom;
                vPos -= vTopLeftOff;
                vPos  = m_camera2D.Camera.ScreenToWorldPoint(vPos); // vPos is now the top left corner of the collison texture in world coordinates

                Color32[] colors  = sprRender.sprite.texture.GetPixels32();
                float     factorX = m_autoTileMap.Tileset.TileWorldWidth / 4; //smallest collision part has a size of a quarter of tile part
                float     factorY = m_autoTileMap.Tileset.TileWorldHeight / 4;
                for (int y = 0; y < sprRender.sprite.texture.height; ++y)
                {
                    for (int x = 0; x < sprRender.sprite.texture.width; ++x)
                    {
                        Vector3 vCheckPos = vPos;
                        vCheckPos.x += (x + 0.5f) * factorX;
                        vCheckPos.y -= (y + 0.5f) * factorY;
                        AutoTileMap.eTileCollisionType collType = m_autoTileMap.GetAutotileCollisionAtPosition(vCheckPos);
                        //Color32 color = (x+y)%2 == 0? new Color32(0, 0, 64, 128) : new Color32(64, 0, 0, 128) ;
                        Color32 color = new Color32(0, 0, 0, 0);
                        colors[(sprRender.sprite.texture.height - 1 - y) * sprRender.sprite.texture.width + x] = (collType != AutoTileMap.eTileCollisionType.PASSABLE)? new Color32(255, 0, 0, 128) : color;
                    }
                }
                sprRender.sprite.texture.SetPixels32(colors);
                sprRender.sprite.texture.Apply();
            }
            #endregion

            if (Input.GetKeyDown(KeyCode.Delete))  //TODO: only delete the tiles in ground layer, fix this
            {
                // select delete tile
                m_selectedTileIdx = -1;

                // Remove Brush
                m_autoTileMap.BrushGizmo.Clear();
                m_tilesetSelStart = m_tilesetSelEnd = -1;
            }

            #region Undo / Redo
            if (m_isCtrlKeyHold)
            {
                if (Input.GetKeyDown(KeyCode.Z))
                {
                    m_autoTileMap.BrushGizmo.UndoAction();
                }
                else if (Input.GetKeyDown(KeyCode.Y))
                {
                    m_autoTileMap.BrushGizmo.RedoAction();
                }

                //+++ Key Repetition Implementation
                if (Input.GetKey(KeyCode.Z))
                {
                    m_keyPressTimer += Time.deltaTime;
                    if (m_keyPressTimer >= k_timeBeforeKeyRepeat)
                    {
                        m_keyPressTimer -= k_timeBetweenKeyRepeat;
                        m_autoTileMap.BrushGizmo.UndoAction();
                    }
                }
                else if (Input.GetKey(KeyCode.Y))
                {
                    m_keyPressTimer += Time.deltaTime;
                    if (m_keyPressTimer >= k_timeBeforeKeyRepeat)
                    {
                        m_keyPressTimer -= k_timeBetweenKeyRepeat;
                        m_autoTileMap.BrushGizmo.RedoAction();
                    }
                }
                else
                {
                    m_keyPressTimer = 0f;
                }
                //---
            }
            #endregion

            if (Input.GetKeyDown(KeyCode.M))
            {
                m_showMinimap = !m_showMinimap;
            }
            if (Input.GetKeyDown(KeyCode.C))
            {
                m_showCollisions = !m_showCollisions;
            }

            bool isMouseLeft      = Input.GetMouseButton(0);
            bool isMouseRight     = Input.GetMouseButton(1);
            bool isMouseMiddle    = Input.GetMouseButton(2);
            bool isMouseLeftDown  = Input.GetMouseButtonDown(0);
            bool isMouseRightDown = Input.GetMouseButtonDown(1);

            m_drawSelectionRect = false;

            Vector3 vGuiMouse      = new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y);
            Vector3 vGuiMouseDelta = vGuiMouse - m_mousePrevPos;
            m_mousePrevPos = vGuiMouse;

            //+++ Set window with focus
            if (!isMouseLeft)
            {
                if (m_rEditorRect.Contains(vGuiMouse))
                {
                    m_focusWindow = eEditorWindow.TOOLS;
                }
                else if (m_rMinimapRect.Contains(vGuiMouse) && m_showMinimap)
                {
                    m_focusWindow = eEditorWindow.MINIMAP;
                }
                // Added an extra padding to avoid drawing tiles when resizing window
                else if (new Rect(m_rEditorRect.x + m_rEditorRect.width + 10f, 10f, Screen.width - 20f - (m_rEditorRect.x + m_rEditorRect.width), Screen.height - 20f).Contains(vGuiMouse))
                {
                    m_focusWindow = eEditorWindow.MAPVIEW;
                }
                else
                {
                    m_focusWindow = eEditorWindow.NONE;
                }
            }
            //---

            // drag and move over the map
            if (isMouseMiddle)
            {
                if (m_camera2DFollowBehaviour)
                {
                    m_camera2DFollowBehaviour.Target = null;
                }
                Vector3 vTemp = vGuiMouseDelta; vTemp.y = -vTemp.y;
                m_camera2D.transform.position -= (vTemp / 100) / m_camera2D.Zoom;
            }

            //
            // Inputs inside Editor Rect
            //
            if (m_rEditorRect.Contains(vGuiMouse))
            {
                if (m_rTilesetRect.Contains(vGuiMouse))
                {
                    vGuiMouse += new Vector3(m_scrollPos.x, m_scrollPos.y);
                    Vector3 vOff        = new Vector2(vGuiMouse.x, vGuiMouse.y) - m_rTilesetRect.position;
                    int     tileX       = (int)(vOff.x / k_visualTileWidth);
                    int     tileY       = (int)(vOff.y / k_visualTileHeight);
                    int     autotileIdx = tileY * m_autoTileMap.Tileset.AutoTilesPerRow + tileX + (m_subTilesetIdx * 256);

                    if (isMouseLeftDown || isMouseRightDown && m_isCtrlKeyHold)
                    {
                        if (m_isCtrlKeyHold)
                        {
                            // cycle pressed tile collision type
                            int collType = (int)m_autoTileMap.Tileset.AutotileCollType[autotileIdx];
                            collType += isMouseLeftDown? 1 : (int)AutoTileMap.eTileCollisionType._SIZE - 1;
                            collType %= (int)AutoTileMap.eTileCollisionType._SIZE;
                            m_autoTileMap.Tileset.AutotileCollType[autotileIdx] = (AutoTileMap.eTileCollisionType)(collType);
                        }
                        else
                        {
                            // select pressed tile
                            m_selectedTileIdx = autotileIdx;

                            // Remove Brush
                            m_autoTileMap.BrushGizmo.Clear();
                            m_tilesetSelStart = m_tilesetSelEnd = -1;
                        }
                    }
                    else if (isMouseRightDown)
                    {
                        m_tilesetSelStart = m_tilesetSelEnd = autotileIdx;
                    }
                    else if (isMouseRight)
                    {
                        m_tilesetSelEnd = autotileIdx;
                    }
                    else if (m_tilesetSelStart >= 0 && m_tilesetSelEnd >= 0)
                    {
                        m_autoTileMap.BrushGizmo.RefreshBrushGizmoFromTileset(m_tilesetSelStart, m_tilesetSelEnd);
                        m_tilesetSelStart = m_tilesetSelEnd = -1;
                    }
                }
            }
            //
            // Inputs inside Minimap Rect
            //
            else if (m_showMinimap && m_rMinimapRect.Contains(vGuiMouse) && m_focusWindow == eEditorWindow.MINIMAP)
            {
                if (isMouseLeft)
                {
                    float   minimapScale = m_rMinimapRect.width / m_autoTileMap.MinimapTexture.width;
                    Vector3 vPos         = vGuiMouse - new Vector3(m_rMinimapRect.position.x, m_rMinimapRect.position.y);
                    vPos.y  = -vPos.y;
                    vPos.x *= m_autoTileMap.Tileset.TileWidth / (AutoTileset.PixelToUnits * minimapScale);
                    vPos.y *= m_autoTileMap.Tileset.TileHeight / (AutoTileset.PixelToUnits * minimapScale);
                    vPos.z  = m_camera2D.transform.position.z;
                    m_camera2D.transform.position = vPos;
                    if (m_camera2DFollowBehaviour)
                    {
                        m_camera2DFollowBehaviour.Target = null;
                    }
                }
            }
            //
            // Insputs inside map view
            //
            else if (m_focusWindow == eEditorWindow.MAPVIEW)
            {
                Vector3 vWorldMousePos = m_autoTileMap.ViewCamera.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y));
                m_autoTileMap.BrushGizmo.UpdateBrushGizmo(vWorldMousePos);

                if (isMouseRight || isMouseLeft)
                {
                    m_drawSelectionRect = isMouseRight;

                    //+++ Move camera automatically when near bounds
                    if (isMouseLeft)
                    {
                        float fAutoDragDistX = m_rMapViewRect.width / 15;
                        float fAutoDragDistY = m_rMapViewRect.height / 15;
                        float fHDist         = m_rMapViewRect.center.x - vGuiMouse.x;
                        float fVDist         = m_rMapViewRect.center.y - vGuiMouse.y;
                        float fHSpeed        = Mathf.Lerp(0f, -Mathf.Sign(fHDist), Mathf.Abs(fHDist) < (m_rMapViewRect.width / 2 - fAutoDragDistX)? 0 : 1f - (m_rMapViewRect.width / 2 - Mathf.Abs(fHDist)) / fAutoDragDistX);
                        float fVSpeed        = Mathf.Lerp(0f, Mathf.Sign(fVDist), Mathf.Abs(fVDist) < (m_rMapViewRect.height / 2 - fAutoDragDistY)? 0 : 1f - (m_rMapViewRect.height / 2 - Mathf.Abs(fVDist)) / fAutoDragDistY);
                        if (fVSpeed != 0f || fHSpeed != 0f)
                        {
                            if (m_camera2DFollowBehaviour)
                            {
                                m_camera2DFollowBehaviour.Target = null;
                            }
                            m_camera2D.transform.position += (new Vector3(fHSpeed, fVSpeed, 0f) / 30) / m_camera2D.Zoom;
                        }
                    }
                    //---

                    Ray   ray      = Camera.main.ScreenPointToRay(Input.mousePosition);
                    Plane hPlane   = new Plane(Vector3.forward, Vector3.zero);
                    float distance = 0;
                    if (hPlane.Raycast(ray, out distance))
                    {
                        // get the hit point:
                        Vector3 vPos   = ray.GetPoint(distance);
                        int     tile_x = (int)(vPos.x / m_autoTileMap.Tileset.TileWorldWidth);
                        int     tile_y = (int)(-vPos.y / m_autoTileMap.Tileset.TileWorldHeight);

                        // for optimization, is true when mouse is over a diffent tile during the first update
                        bool isMouseTileChanged = (tile_x != m_prevMouseTileX) || (tile_y != m_prevMouseTileY);

                        //if ( m_autoTileMap.IsValidAutoTilePos(tile_x, tile_y)) // commented to allow drawing outside map, useful when brush has a lot of copied tiles
                        {
                            int gndTileType        = m_autoTileMap.GetAutoTile(tile_x, tile_y, m_autoTileMap.BrushGizmo.SelectedLayer).Id;
                            int gndOverlayTileType = m_autoTileMap.GetAutoTile(tile_x, tile_y, m_autoTileMap.BrushGizmo.SelectedLayer + 1).Id;

                            // mouse right for tile selection
                            if (isMouseRightDown || isMouseRight && isMouseTileChanged)
                            {
                                if (isMouseRightDown)
                                {
                                    m_startDragTileX = tile_x;
                                    m_startDragTileY = tile_y;

                                    // copy tile
                                    if (m_isCtrlKeyHold)
                                    {
                                        m_selectedTileIdx = -2;                                         //NOTE: -2 means, ignore this tile when painting
                                    }
                                    else
                                    {
                                        m_selectedTileIdx = gndTileType >= 0? gndTileType : gndOverlayTileType;
                                    }
                                }
                                m_dragTileX = tile_x;
                                m_dragTileY = tile_y;

                                // Remove Brush
                                m_autoTileMap.BrushGizmo.Clear();
                                m_tilesetSelStart = m_tilesetSelEnd = -1;
                            }
                            // isMouseLeft
                            else if (isMouseLeftDown || isMouseTileChanged)                              // avoid Push the same action twice during mouse drag
                            {
                                AutoTileBrush.TileAction action = new AutoTileBrush.TileAction();
                                if (m_autoTileMap.BrushGizmo.BrushAction != null)
                                {
                                    //+++ case of multiple tiles painting
                                    action.CopyRelative(m_autoTileMap, m_autoTileMap.BrushGizmo.BrushAction, tile_x, tile_y);
                                    if (m_isCtrlKeyHold && (m_autoTileMap.BrushGizmo.SelectedLayer + 1) < m_autoTileMap.GetLayerCount())
                                    {
                                        // old functionality: ground tiles become ground overlay, ground overlay are removed, overlay tiles remains
                                        // Tiles in SelectedLayer are moved to next layer
                                        action.BecomeOverlay(m_autoTileMap.BrushGizmo.SelectedLayer);
                                    }
                                }
                                else
                                {
                                    //+++ case of single tile painting
                                    // If smart brush is enabled, the tiles with collision type Overlay will be placed directly in the first overlay layer found over current SelectedLayer
                                    int overlayLayer = m_autoTileMap.FindFirstLayerIdx(AutoTileMap.eLayerType.Overlay, m_autoTileMap.BrushGizmo.SelectedLayer);
                                    if (m_autoTileMap.BrushGizmo.SmartBrushEnabled && overlayLayer >= 0 && m_selectedTileIdx >= 0 && m_autoTileMap.Tileset.AutotileCollType[m_selectedTileIdx] == AutoTileMap.eTileCollisionType.OVERLAY)
                                    {
                                        action.Push(m_autoTileMap, tile_x, tile_y, m_selectedTileIdx, overlayLayer);
                                    }
                                    else
                                    {
                                        if (m_isCtrlKeyHold || m_autoTileMap.IsAutoTileHasAlpha(m_selectedTileIdx) && m_autoTileMap.BrushGizmo.SmartBrushEnabled)
                                        {
                                            // Put tiles with alpha in the layer over Selected Layer
                                            action.Push(m_autoTileMap, tile_x, tile_y, m_selectedTileIdx, m_autoTileMap.BrushGizmo.SelectedLayer + 1);
                                        }
                                        else if (m_selectedTileIdx >= 0)
                                        {
                                            // Paint the selected tile
                                            action.Push(m_autoTileMap, tile_x, tile_y, m_selectedTileIdx, m_autoTileMap.BrushGizmo.SelectedLayer);
                                        }
                                        else //if (m_selectedTileIdx < 0)
                                        {
                                            // Delete all tiles of all layers
                                            for (int i = 0; i < m_autoTileMap.GetLayerCount(); ++i)
                                            {
                                                if (
                                                    m_autoTileMap.MapLayers[i].LayerType == AutoTileMap.eLayerType.Ground ||
                                                    m_autoTileMap.MapLayers[i].LayerType == AutoTileMap.eLayerType.Overlay ||
                                                    m_autoTileMap.MapLayers[i].LayerType == AutoTileMap.eLayerType.FogOfWar
                                                    )
                                                {
                                                    action.Push(m_autoTileMap, tile_x, tile_y, -1, i);
                                                }
                                            }
                                        }
                                    }
                                }

                                m_autoTileMap.BrushGizmo.PerformAction(action);
                            }
                        }

                        m_prevMouseTileX = tile_x;
                        m_prevMouseTileY = tile_y;
                    }
                }
                else
                {
                    // Copy selected tiles
                    if (m_dragTileX != -1 && m_dragTileY != -1)
                    {
                        m_autoTileMap.BrushGizmo.BrushAction = new AutoTileBrush.TileAction();
                        int startTileX = Mathf.Min(m_startDragTileX, m_dragTileX);
                        int startTileY = Mathf.Min(m_startDragTileY, m_dragTileY);
                        int endTileX   = Mathf.Max(m_startDragTileX, m_dragTileX);
                        int endTileY   = Mathf.Max(m_startDragTileY, m_dragTileY);

                        for (int tile_x = startTileX; tile_x <= endTileX; ++tile_x)
                        {
                            for (int tile_y = startTileY; tile_y <= endTileY; ++tile_y)
                            {
                                // Tile position is relative to last released position ( m_dragTile )
                                if (m_isCtrlKeyHold)
                                {
                                    // Copy overlay only
                                    for (int i = m_autoTileMap.BrushGizmo.SelectedLayer + 1; i < m_autoTileMap.GetLayerCount(); ++i)
                                    {
                                        int tileType = m_autoTileMap.GetAutoTile(tile_x, tile_y, i).Id;
                                        if (
                                            (m_autoTileMap.MapLayers[i].LayerType != AutoTileMap.eLayerType.Ground) ||
                                            (tileType >= 0) // this allow paste overlay tiles without removing ground or ground overlay
                                            )
                                        {
                                            m_autoTileMap.BrushGizmo.BrushAction.Push(m_autoTileMap, tile_x - m_dragTileX, tile_y - m_dragTileY, tileType, i);
                                        }
                                    }
                                }
                                else
                                {
                                    for (int i = 0; i < m_autoTileMap.GetLayerCount(); ++i)
                                    {
                                        int tileType = m_autoTileMap.GetAutoTile(tile_x, tile_y, i).Id;
                                        m_autoTileMap.BrushGizmo.BrushAction.Push(m_autoTileMap, tile_x - m_dragTileX, tile_y - m_dragTileY, tileType, i);
                                    }
                                }
                            }
                        }

                        m_autoTileMap.BrushGizmo.RefreshBrushGizmo(startTileX, startTileY, endTileX, endTileY, m_dragTileX, m_dragTileY, m_isCtrlKeyHold);

                        m_dragTileX = m_dragTileY = -1;
                    }

                    if (Input.GetAxis("Mouse ScrollWheel") < 0)                     // back
                    {
                        if (m_camera2D.Zoom > 1f)
                        {
                            m_camera2D.Zoom = Mathf.Max(m_camera2D.Zoom - 1, 1);
                        }
                        else
                        {
                            m_camera2D.Zoom = Mathf.Max(m_camera2D.Zoom / 2f, 0.05f);
                        }
                    }
                    else if (Input.GetAxis("Mouse ScrollWheel") > 0)                     // forward
                    {
                        if (m_camera2D.Zoom >= 1f)
                        {
                            m_camera2D.Zoom = Mathf.Min(m_camera2D.Zoom + 1, 10);
                        }
                        else
                        {
                            m_camera2D.Zoom *= 2f;
                        }
                    }
                }
            }
        }
Example #2
0
        public void OnSceneGUI()
        {
            #region Undo / Redo
            if (Event.current.isKey && Event.current.shift && Event.current.type == EventType.KeyUp)
            {
                if (Event.current.keyCode == KeyCode.Z)
                {
                    m_autoTileMap.BrushGizmo.UndoAction();
                }
                if (Event.current.keyCode == KeyCode.Y)
                {
                    m_autoTileMap.BrushGizmo.RedoAction();
                }
            }
            #endregion

            Rect rSceneView = new Rect(0, 0, Screen.width, Screen.height);
            if (rSceneView.Contains(Event.current.mousePosition))
            {
                UpdateMouseInputs();

                Ray   ray      = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
                Plane hPlane   = new Plane(Vector3.forward, Vector3.zero);
                float distance = 0;
                if (hPlane.Raycast(ray, out distance))
                {
                    // get the hit point:
                    Vector3 vPos = ray.GetPoint(distance);
                    m_autoTileMap.BrushGizmo.UpdateBrushGizmo(vPos);

                    if (m_isMouseRight || m_isMouseLeft)
                    {
                        int tile_x = (int)(vPos.x / m_autoTileMap.Tileset.TileWorldWidth);
                        int tile_y = (int)(-vPos.y / m_autoTileMap.Tileset.TileWorldHeight);

                        // for optimization, is true when mouse is over a diffent tile during the first update
                        bool isMouseTileChanged = (tile_x != m_prevMouseTileX) || (tile_y != m_prevMouseTileY);

                        //if ( m_autoTileMap.IsValidAutoTilePos(tile_x, tile_y)) // commented to allow drawing outside map, useful when brush has a lot of copied tiles
                        {
                            int gndTileType        = m_autoTileMap.GetAutoTile(tile_x, tile_y, m_autoTileMap.BrushGizmo.SelectedLayer).Id;
                            int gndOverlayTileType = m_autoTileMap.GetAutoTile(tile_x, tile_y, m_autoTileMap.BrushGizmo.SelectedLayer + 1).Id;

                            // mouse right for tile selection
                            if (m_isMouseRightDown || m_isMouseRight && isMouseTileChanged)
                            {
                                if (m_isMouseRightDown)
                                {
                                    m_startDragTileX = tile_x;
                                    m_startDragTileY = tile_y;

                                    // Remove Brush
                                    m_autoTileMap.BrushGizmo.Clear();
                                    m_tilesetSelStart = m_tilesetSelEnd = -1;

                                    // copy tile
                                    if (Event.current.shift)
                                    {
                                        m_selectedTileId = -2;                                         //NOTE: -2 means, ignore this tile when painting
                                    }
                                    else
                                    {
                                        m_selectedTileId = gndTileType >= 0? gndTileType : gndOverlayTileType;
                                    }
                                }
                                m_dragTileX = tile_x;
                                m_dragTileY = tile_y;
                            }
                            // isMouseLeft
                            else if (m_isMouseLeftDown || isMouseTileChanged)                              // avoid Push the same action twice during mouse drag
                            {
                                AutoTileBrush.TileAction action = new AutoTileBrush.TileAction();
                                if (m_autoTileMap.BrushGizmo.BrushAction != null)
                                {
                                    //+++ case of multiple tiles painting
                                    action.CopyRelative(m_autoTileMap, m_autoTileMap.BrushGizmo.BrushAction, tile_x, tile_y);
                                    if (Event.current.shift && (m_autoTileMap.BrushGizmo.SelectedLayer + 1) < m_autoTileMap.GetLayerCount())
                                    {
                                        // old functionality: ground tiles become ground overlay, ground overlay are removed, overlay tiles remains
                                        // Tiles in SelectedLayer are moved to next layer
                                        action.BecomeOverlay(m_autoTileMap.BrushGizmo.SelectedLayer);
                                    }
                                }
                                else
                                {
                                    //+++ case of single tile painting
                                    // If smart brush is enabled, the tiles with collision type Overlay will be placed directly in the first overlay layer found over current SelectedLayer
                                    int overlayLayer = m_autoTileMap.FindFirstLayerIdx(eLayerType.Overlay, m_autoTileMap.BrushGizmo.SelectedLayer);
                                    if (m_autoTileMap.BrushGizmo.SmartBrushEnabled && overlayLayer >= 0 && m_selectedTileId >= 0 && m_autoTileMap.Tileset.AutotileCollType[m_selectedTileId] == eTileCollisionType.OVERLAY)
                                    {
                                        action.Push(m_autoTileMap, tile_x, tile_y, m_selectedTileId, overlayLayer);
                                    }
                                    else
                                    {
                                        if (Event.current.shift || m_autoTileMap.IsAutoTileHasAlpha(m_selectedTileId) && m_autoTileMap.BrushGizmo.SmartBrushEnabled)
                                        {
                                            // Put tiles with alpha in the layer over Selected Layer
                                            action.Push(m_autoTileMap, tile_x, tile_y, m_selectedTileId, m_autoTileMap.BrushGizmo.SelectedLayer + 1);
                                        }
                                        else
                                        {
                                            action.Push(m_autoTileMap, tile_x, tile_y, m_selectedTileId, m_autoTileMap.BrushGizmo.SelectedLayer);
                                        }
                                    }
                                }

                                m_autoTileMap.BrushGizmo.PerformAction(action);
                                EditorUtility.SetDirty(m_autoTileMap);
                            }
                        }

                        m_prevMouseTileX = tile_x;
                        m_prevMouseTileY = tile_y;
                    }
                    else
                    {
                        // Copy selected tiles
                        if (m_dragTileX != -1 && m_dragTileY != -1)
                        {
                            m_autoTileMap.BrushGizmo.BrushAction = new AutoTileBrush.TileAction();
                            int startTileX = Mathf.Min(m_startDragTileX, m_dragTileX);
                            int startTileY = Mathf.Min(m_startDragTileY, m_dragTileY);
                            int endTileX   = Mathf.Max(m_startDragTileX, m_dragTileX);
                            int endTileY   = Mathf.Max(m_startDragTileY, m_dragTileY);

                            for (int tile_x = startTileX; tile_x <= endTileX; ++tile_x)
                            {
                                for (int tile_y = startTileY; tile_y <= endTileY; ++tile_y)
                                {
                                    // Tile position is relative to last released position ( m_dragTile )
                                    if (Event.current.shift)
                                    {
                                        // Copy overlay only
                                        for (int i = m_autoTileMap.BrushGizmo.SelectedLayer + 1; i < m_autoTileMap.GetLayerCount(); ++i)
                                        {
                                            int tileType = m_autoTileMap.GetAutoTile(tile_x, tile_y, i).Id;
                                            if (
                                                (m_autoTileMap.MapLayers[i].LayerType != eLayerType.Ground) ||
                                                (tileType >= 0) // this allow paste overlay tiles without removing ground or ground overlay
                                                )
                                            {
                                                m_autoTileMap.BrushGizmo.BrushAction.Push(m_autoTileMap, tile_x - m_dragTileX, tile_y - m_dragTileY, tileType, i);
                                            }
                                        }
                                    }
                                    else
                                    {
                                        for (int i = 0; i < m_autoTileMap.GetLayerCount(); ++i)
                                        {
                                            int tileType = m_autoTileMap.GetAutoTile(tile_x, tile_y, i).Id;
                                            m_autoTileMap.BrushGizmo.BrushAction.Push(m_autoTileMap, tile_x - m_dragTileX, tile_y - m_dragTileY, tileType, i);
                                        }
                                    }
                                }
                            }

                            m_autoTileMap.BrushGizmo.RefreshBrushGizmo(startTileX, startTileY, endTileX, endTileY, m_dragTileX, m_dragTileY, Event.current.shift);

                            m_dragTileX = m_dragTileY = -1;
                        }
                    }
                }

                // Draw selection rect
                if (m_isMouseRight)
                {
                    float rX         = m_autoTileMap.transform.position.x + Mathf.Min(m_startDragTileX, m_dragTileX) * m_autoTileMap.Tileset.TileWorldWidth;
                    float rY         = m_autoTileMap.transform.position.y + Mathf.Min(m_startDragTileY, m_dragTileY) * m_autoTileMap.Tileset.TileWorldHeight;
                    float rWidth     = (Mathf.Abs(m_dragTileX - m_startDragTileX) + 1) * m_autoTileMap.Tileset.TileWorldWidth;
                    float rHeight    = (Mathf.Abs(m_dragTileY - m_startDragTileY) + 1) * m_autoTileMap.Tileset.TileWorldHeight;
                    Rect  rSelection = new Rect(rX, -rY, rWidth, -rHeight);
                    UtilsGuiDrawing.DrawRectWithOutline(rSelection, new Color(0f, 1f, 0f, 0.2f), new Color(0f, 1f, 0f, 1f));
                }
            }
        }
		public void OnSceneGUI()
		{

			#region Undo / Redo
			if( Event.current.isKey && Event.current.shift && Event.current.type == EventType.KeyUp )
			{
				if( Event.current.keyCode == KeyCode.Z )
				{
					m_autoTileMap.BrushGizmo.UndoAction();
				}
				if( Event.current.keyCode == KeyCode.Y )
				{
					m_autoTileMap.BrushGizmo.RedoAction();
				}
			}
			#endregion

			Rect rSceneView = new Rect( 0, 0, Screen.width, Screen.height );
			if( rSceneView.Contains( Event.current.mousePosition ) )
			{
				UpdateMouseInputs();

				Ray ray = HandleUtility.GUIPointToWorldRay( Event.current.mousePosition );
				Plane hPlane = new Plane(Vector3.forward, Vector3.zero);		
				float distance = 0; 
				if ( hPlane.Raycast(ray, out distance) )
				{
					// get the hit point:
					Vector3 vPos = ray.GetPoint(distance);
					m_autoTileMap.BrushGizmo.UpdateBrushGizmo( vPos );

					if( m_isMouseRight || m_isMouseLeft )
					{
						int tile_x = (int)(vPos.x / m_autoTileMap.Tileset.TileWorldWidth);
                        int tile_y = (int)(-vPos.y / m_autoTileMap.Tileset.TileWorldHeight);

						// for optimization, is true when mouse is over a diffent tile during the first update
						bool isMouseTileChanged = (tile_x != m_prevMouseTileX) || (tile_y != m_prevMouseTileY);
						
						//if ( m_autoTileMap.IsValidAutoTilePos(tile_x, tile_y)) // commented to allow drawing outside map, useful when brush has a lot of copied tiles
						{
							int gndTileType = m_autoTileMap.GetAutoTile( tile_x, tile_y, (int)AutoTileMap.eTileLayer.GROUND ).Idx;
							int gndOverlayTileType = m_autoTileMap.GetAutoTile( tile_x, tile_y, (int)AutoTileMap.eTileLayer.GROUND_OVERLAY ).Idx;
							
							// mouse right for tile selection
							if( m_isMouseRightDown || m_isMouseRight && isMouseTileChanged )
							{
								if( m_isMouseRightDown )
								{
									m_startDragTileX = tile_x;
									m_startDragTileY = tile_y;
								
									// Remove Brush
									m_autoTileMap.BrushGizmo.Clear();
									m_tilesetSelStart = m_tilesetSelEnd = -1;

									// copy tile
									if( Event.current.shift )
									{
										m_selectedTileIdx = -2; //NOTE: -2 means, ignore this tile when painting
									}
									else
									{
										m_selectedTileIdx = gndTileType >= 0? gndTileType : gndOverlayTileType;
									}
								}
								m_dragTileX = tile_x;
								m_dragTileY = tile_y;
								

							}
							// isMouseLeft
							else if( m_isMouseLeftDown || isMouseTileChanged ) // avoid Push the same action twice during mouse drag
							{
								AutoTileBrush.TileAction action = new AutoTileBrush.TileAction();
								if( m_autoTileMap.BrushGizmo.BrushAction != null )
								{
									//+++ case of multiple tiles painting
									action.CopyRelative( m_autoTileMap, m_autoTileMap.BrushGizmo.BrushAction, tile_x, tile_y );
									if(Event.current.shift)
									{
										// ground tiles become ground overlay, ground overlay are removed, overlay tiles remains
										action.BecomeOverlay();
									}
								}
								else 
								{
									//+++ case of single tile painting
									
									if( Event.current.shift || m_autoTileMap.IsAutoTileHasAlpha( m_selectedTileIdx ) )
									{
										// Put tiles with alpha in the overlay layer
										action.Push( m_autoTileMap, tile_x, tile_y, m_selectedTileIdx, (int)AutoTileMap.eTileLayer.GROUND_OVERLAY );
									}
									else
									{
										action.Push( m_autoTileMap, tile_x, tile_y, m_selectedTileIdx, (int)AutoTileMap.eTileLayer.GROUND );
									}
								}
								
								m_autoTileMap.BrushGizmo.PerformAction( action );
								EditorUtility.SetDirty( m_autoTileMap );
							}
						}
						
						m_prevMouseTileX = tile_x;
						m_prevMouseTileY = tile_y;
					}
					else
					{
						// Copy selected tiles
						if( m_dragTileX != -1 && m_dragTileY != -1 )
						{
							m_autoTileMap.BrushGizmo.BrushAction = new AutoTileBrush.TileAction();
							int startTileX = Mathf.Min( m_startDragTileX, m_dragTileX );
							int startTileY = Mathf.Min( m_startDragTileY, m_dragTileY );
							int endTileX = Mathf.Max( m_startDragTileX, m_dragTileX );
							int endTileY = Mathf.Max( m_startDragTileY, m_dragTileY );
							
							for( int tile_x = startTileX; tile_x <= endTileX; ++tile_x  )
							{
								for( int tile_y = startTileY; tile_y <= endTileY; ++tile_y  )
								{
									int gndTileType = m_autoTileMap.GetAutoTile( tile_x, tile_y, (int)AutoTileMap.eTileLayer.GROUND ).Idx;
									int gndOverlayTileType = m_autoTileMap.GetAutoTile( tile_x, tile_y, (int)AutoTileMap.eTileLayer.GROUND_OVERLAY ).Idx;
									int overlayTileType = m_autoTileMap.GetAutoTile( tile_x, tile_y, (int)AutoTileMap.eTileLayer.OVERLAY ).Idx;
									
									// Tile position is relative to last released position ( m_dragTile )
									if( Event.current.shift )
									{
										// Copy overlay only
										if( gndOverlayTileType >= 0 ) // this allow paste overlay tiles without removing ground or ground overlay
											m_autoTileMap.BrushGizmo.BrushAction.Push( m_autoTileMap, tile_x - m_dragTileX, tile_y - m_dragTileY, gndOverlayTileType, (int)AutoTileMap.eTileLayer.GROUND_OVERLAY);
										m_autoTileMap.BrushGizmo.BrushAction.Push( m_autoTileMap, tile_x - m_dragTileX, tile_y - m_dragTileY, overlayTileType, (int)AutoTileMap.eTileLayer.OVERLAY);
									}
									else
									{
										m_autoTileMap.BrushGizmo.BrushAction.Push( m_autoTileMap, tile_x - m_dragTileX, tile_y - m_dragTileY, gndTileType, (int)AutoTileMap.eTileLayer.GROUND);
										m_autoTileMap.BrushGizmo.BrushAction.Push( m_autoTileMap, tile_x - m_dragTileX, tile_y - m_dragTileY, gndOverlayTileType, (int)AutoTileMap.eTileLayer.GROUND_OVERLAY);
										m_autoTileMap.BrushGizmo.BrushAction.Push( m_autoTileMap, tile_x - m_dragTileX, tile_y - m_dragTileY, overlayTileType, (int)AutoTileMap.eTileLayer.OVERLAY);
									}
								}
							}
							
							m_autoTileMap.BrushGizmo.RefreshBrushGizmo( startTileX, startTileY, endTileX, endTileY, m_dragTileX, m_dragTileY, Event.current.shift );
							
							m_dragTileX = m_dragTileY = -1;
						}
					}
				}

				// Draw selection rect
				if( m_isMouseRight )
				{
                    float rX = m_autoTileMap.transform.position.x + Mathf.Min(m_startDragTileX, m_dragTileX) * m_autoTileMap.Tileset.TileWorldWidth;
                    float rY = m_autoTileMap.transform.position.y + Mathf.Min(m_startDragTileY, m_dragTileY) * m_autoTileMap.Tileset.TileWorldHeight;
                    float rWidth = (Mathf.Abs(m_dragTileX - m_startDragTileX) + 1) * m_autoTileMap.Tileset.TileWorldWidth;
                    float rHeight = (Mathf.Abs(m_dragTileY - m_startDragTileY) + 1) * m_autoTileMap.Tileset.TileWorldHeight;
					Rect rSelection = new Rect( rX, -rY, rWidth, -rHeight );
					UtilsGuiDrawing.DrawRectWithOutline( rSelection, new Color(0f, 1f, 0f, 0.2f), new Color(0f, 1f, 0f, 1f));
				}
			}
		}
		void Update () 
		{

			if( !m_isInitialized )
			{
				Init();
				return;
			}

			#region Draw Collisions
			// Generate texture again in case window has been resized
			Vector2 screenSize = new Vector2(Screen.width, Screen.height);
			if( m_prevScreenSize != screenSize )
			{
				_GenerateCollisionTexture();
			}
			m_prevScreenSize = screenSize;

			m_spriteCollLayer.SetActive( m_showCollisions );
			if( m_showCollisions && (int)(Time.timeSinceLevelLoad*4)%2 == 0 )
			{
				SpriteRenderer sprRender = m_spriteCollLayer.GetComponent<SpriteRenderer>();
				Vector3 vPos = m_camera2D.transform.position;
                vPos.x -= (vPos.x % ( m_autoTileMap.Tileset.TileWorldWidth / 4));
                vPos.y -= (vPos.y % ( m_autoTileMap.Tileset.TileWorldHeight / 4));
				vPos.z += 1f;

				// Collision texture position snap to a quarter of tile part
				sprRender.transform.position = vPos;

				// Collision texture pixel scaled to a quarter of tile part
                sprRender.transform.localScale = new Vector3((m_autoTileMap.Tileset.TilePartWidth / 2), (m_autoTileMap.Tileset.TilePartHeight / 2), 1f);

				vPos = m_camera2D.Camera.WorldToScreenPoint( sprRender.transform.position ); // vPos = center of collision texture in screen coords
                Vector3 vTopLeftOff = new Vector3(sprRender.sprite.texture.width * (m_autoTileMap.Tileset.TilePartWidth / 2) / 2, -sprRender.sprite.texture.height * (m_autoTileMap.Tileset.TilePartHeight / 2) / 2) * m_camera2D.Zoom;
				vPos -= vTopLeftOff;
                vPos = m_camera2D.Camera.ScreenToWorldPoint(vPos); // vPos is now the top left corner of the collison texture in world coordinates

				Color32[] colors = sprRender.sprite.texture.GetPixels32();
                float factorX = m_autoTileMap.Tileset.TileWorldWidth / 4; //smallest collision part has a size of a quarter of tile part
                float factorY = m_autoTileMap.Tileset.TileWorldHeight / 4;
				for( int y = 0; y < sprRender.sprite.texture.height; ++y )
				{
					for( int x = 0; x < sprRender.sprite.texture.width; ++x )
					{
						Vector3 vCheckPos = vPos;
						vCheckPos.x += (x+0.5f)*factorX;
						vCheckPos.y -= (y+0.5f)*factorY;
						AutoTileMap.eTileCollisionType collType = m_autoTileMap.GetAutotileCollisionAtPosition( vCheckPos );
						//Color32 color = (x+y)%2 == 0? new Color32(0, 0, 64, 128) : new Color32(64, 0, 0, 128) ;
						Color32 color = new Color32(0, 0, 0, 0);
						colors[ (sprRender.sprite.texture.height-1-y) * sprRender.sprite.texture.width + x ] = (collType != AutoTileMap.eTileCollisionType.PASSABLE)? new Color32(255, 0, 0, 128) : color;
					}
				}
				sprRender.sprite.texture.SetPixels32( colors );
				sprRender.sprite.texture.Apply();
			}
			#endregion

			#region Undo / Redo
			if( m_isCtrlKeyHold )
			{
				if( Input.GetKeyDown(KeyCode.Z ) )
				{
					m_autoTileMap.BrushGizmo.UndoAction();
				}
				else if( Input.GetKeyDown(KeyCode.Y ) )
				{
					m_autoTileMap.BrushGizmo.RedoAction();
				}

				//+++ Key Repetition Implementation
				if( Input.GetKey(KeyCode.Z ) )
				{
					m_keyPressTimer += Time.deltaTime;
					if( m_keyPressTimer >= k_timeBeforeKeyRepeat )
					{
						m_keyPressTimer -= k_timeBetweenKeyRepeat;
						m_autoTileMap.BrushGizmo.UndoAction();
					}
				}
				else if( Input.GetKey(KeyCode.Y ) )
				{
					m_keyPressTimer += Time.deltaTime;
					if( m_keyPressTimer >= k_timeBeforeKeyRepeat )
					{
						m_keyPressTimer -= k_timeBetweenKeyRepeat;
						m_autoTileMap.BrushGizmo.RedoAction();
					}
				}
				else
				{
					m_keyPressTimer = 0f;
				}
				//---
			}
			#endregion

			if( Input.GetKeyDown(KeyCode.M) ) m_showMinimap = !m_showMinimap;
			if( Input.GetKeyDown(KeyCode.C) ) m_showCollisions = !m_showCollisions;

			bool isMouseLeft = Input.GetMouseButton(0);
			bool isMouseRight = Input.GetMouseButton(1);
			bool isMouseMiddle = Input.GetMouseButton(2);
			bool isMouseLeftDown = Input.GetMouseButtonDown(0);
			bool isMouseRightDown = Input.GetMouseButtonDown(1);
			
			m_drawSelectionRect = false;

			Vector3 vGuiMouse = new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y);
			Vector3 vGuiMouseDelta = vGuiMouse - m_mousePrevPos;
			m_mousePrevPos = vGuiMouse;

			//+++ Set window with focus
			if( !isMouseLeft )
			{
				if( m_rEditorRect.Contains( vGuiMouse ) )
				{
					m_focusWindow = eEditorWindow.TOOLS;
				}
				else if( m_rMinimapRect.Contains( vGuiMouse ) && m_showMinimap )
				{
					m_focusWindow = eEditorWindow.MINIMAP;
				}
				// Added an extra padding to avoid drawing tiles when resizing window
				else if( new Rect(m_rEditorRect.x + m_rEditorRect.width + 10f, 10f, Screen.width-20f-(m_rEditorRect.x + m_rEditorRect.width), Screen.height-20f).Contains( vGuiMouse ) )
				{
					m_focusWindow = eEditorWindow.MAPVIEW;
				}
				else
				{
					m_focusWindow = eEditorWindow.NONE;
				}
			}
			//---

			// drag and move over the map
			if( isMouseMiddle )
			{
				if( m_camera2DFollowBehaviour )
				{
					m_camera2DFollowBehaviour.Target = null;
				}
				Vector3 vTemp = vGuiMouseDelta; vTemp.y = -vTemp.y;
				m_camera2D.transform.position -= (vTemp/100)/m_camera2D.Zoom;
			}

			//
			// Inputs inside Editor Rect
			//
			if( m_rEditorRect.Contains( vGuiMouse ) )
			{
				if( m_rTilesetRect.Contains( vGuiMouse ) )
				{
					vGuiMouse += new Vector3(m_scrollPos.x, m_scrollPos.y);
					Vector3 vOff = new Vector2(vGuiMouse.x, vGuiMouse.y) - m_rTilesetRect.position;
                    int tileX = (int)(vOff.x / k_visualTileWidth);
                    int tileY = (int)(vOff.y / k_visualTileHeight);
					int autotileIdx = tileY * m_autoTileMap.Tileset.AutoTilesPerRow + tileX + (m_subTilesetIdx * 256);

					if( isMouseLeftDown || isMouseRightDown && m_isCtrlKeyHold )
					{
						if( m_isCtrlKeyHold )
						{
							// cycle pressed tile collision type
							int collType = (int)m_autoTileMap.Tileset.AutotileCollType[ autotileIdx ];
							collType += isMouseLeftDown? 1 : (int)AutoTileMap.eTileCollisionType._SIZE - 1;
							collType%=(int)AutoTileMap.eTileCollisionType._SIZE;
							m_autoTileMap.Tileset.AutotileCollType[ autotileIdx ] = (AutoTileMap.eTileCollisionType)(collType);
						}
						else
						{
							// select pressed tile
							m_selectedTileIdx = autotileIdx;

							// Remove Brush
							m_autoTileMap.BrushGizmo.Clear();
							m_tilesetSelStart = m_tilesetSelEnd = -1;
						}
					}
					else if( isMouseRightDown )
					{
						m_tilesetSelStart = m_tilesetSelEnd = autotileIdx;
					}
					else if( isMouseRight )
					{
						m_tilesetSelEnd = autotileIdx;
					}
					else if( m_tilesetSelStart >= 0 && m_tilesetSelEnd >= 0 )
					{
						m_autoTileMap.BrushGizmo.RefreshBrushGizmoFromTileset( m_tilesetSelStart, m_tilesetSelEnd );
						m_tilesetSelStart = m_tilesetSelEnd = -1;
					}
				}
			}
			//
			// Inputs inside Minimap Rect
			//
			else if( m_showMinimap && m_rMinimapRect.Contains( vGuiMouse ) && m_focusWindow == eEditorWindow.MINIMAP )
			{
				if( isMouseLeft )
				{
                    float minimapScale = m_rMinimapRect.width / m_autoTileMap.MinimapTexture.width;
					Vector3 vPos = vGuiMouse - new Vector3( m_rMinimapRect.position.x, m_rMinimapRect.position.y);
					vPos.y = -vPos.y;
                    vPos.x *= m_autoTileMap.Tileset.TileWidth / (AutoTileset.PixelToUnits * minimapScale);
                    vPos.y *= m_autoTileMap.Tileset.TileHeight / (AutoTileset.PixelToUnits * minimapScale);
					vPos.z = m_camera2D.transform.position.z;
					m_camera2D.transform.position = vPos;
					if( m_camera2DFollowBehaviour )
					{
						m_camera2DFollowBehaviour.Target = null;
					}
				}
			}
			//
			// Insputs inside map view
			//
			else if( m_focusWindow == eEditorWindow.MAPVIEW )
			{
				Vector3 vWorldMousePos = m_autoTileMap.ViewCamera.ScreenToWorldPoint( new Vector3(Input.mousePosition.x, Input.mousePosition.y) );
				m_autoTileMap.BrushGizmo.UpdateBrushGizmo( vWorldMousePos );

				if( isMouseRight || isMouseLeft )
				{
					m_drawSelectionRect = isMouseRight;

					//+++ Move camera automatically when near bounds
					if( isMouseLeft )
					{
						float fAutoDragDistX = m_rMapViewRect.width/15;
						float fAutoDragDistY = m_rMapViewRect.height/15;
						float fHDist = m_rMapViewRect.center.x - vGuiMouse.x;
						float fVDist = m_rMapViewRect.center.y - vGuiMouse.y;
						float fHSpeed = Mathf.Lerp(0f, -Mathf.Sign(fHDist), Mathf.Abs(fHDist) < (m_rMapViewRect.width/2 - fAutoDragDistX)? 0 : 1f - (m_rMapViewRect.width/2 - Mathf.Abs(fHDist)) / fAutoDragDistX );
						float fVSpeed = Mathf.Lerp(0f, Mathf.Sign(fVDist), Mathf.Abs(fVDist) < (m_rMapViewRect.height/2 - fAutoDragDistY)? 0 : 1f - (m_rMapViewRect.height/2 - Mathf.Abs(fVDist)) / fAutoDragDistY );
						if( fVSpeed != 0f || fHSpeed != 0f )
						{
							if( m_camera2DFollowBehaviour )
							{
								m_camera2DFollowBehaviour.Target = null;
							}
							m_camera2D.transform.position += (new Vector3(fHSpeed, fVSpeed, 0f)/30)/m_camera2D.Zoom;
						}
					}
					//---

					Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
					Plane hPlane = new Plane(Vector3.forward, Vector3.zero);
					float distance = 0; 
					if (hPlane.Raycast(ray, out distance))
					{
						// get the hit point:
						Vector3 vPos = ray.GetPoint(distance);
						int tile_x = (int)(vPos.x / m_autoTileMap.Tileset.TileWorldWidth);
						int tile_y = (int)(-vPos.y / m_autoTileMap.Tileset.TileWorldHeight);
					
						// for optimization, is true when mouse is over a diffent tile during the first update
						bool isMouseTileChanged = (tile_x != m_prevMouseTileX) || (tile_y != m_prevMouseTileY);

						//if ( m_autoTileMap.IsValidAutoTilePos(tile_x, tile_y)) // commented to allow drawing outside map, useful when brush has a lot of copied tiles
						{
							int gndTileType = m_autoTileMap.GetAutoTile( tile_x, tile_y, (int)AutoTileMap.eTileLayer.GROUND ).Idx;
							int gndOverlayTileType = m_autoTileMap.GetAutoTile( tile_x, tile_y, (int)AutoTileMap.eTileLayer.GROUND_OVERLAY ).Idx;

							// mouse right for tile selection
							if( isMouseRightDown || isMouseRight && isMouseTileChanged )
							{
								if( isMouseRightDown )
								{
									m_startDragTileX = tile_x;
									m_startDragTileY = tile_y;

									// copy tile
									if( m_isCtrlKeyHold )
									{
										m_selectedTileIdx = -2; //NOTE: -2 means, ignore this tile when painting
									}
									else
									{
										m_selectedTileIdx = gndTileType >= 0? gndTileType : gndOverlayTileType;
									}
								}
								m_dragTileX = tile_x;
								m_dragTileY = tile_y;

								// Remove Brush
								m_autoTileMap.BrushGizmo.Clear();
								m_tilesetSelStart = m_tilesetSelEnd = -1;
							}
							// isMouseLeft
							else if( isMouseLeftDown || isMouseTileChanged ) // avoid Push the same action twice during mouse drag
							{
								AutoTileBrush.TileAction action = new AutoTileBrush.TileAction();
								if( m_autoTileMap.BrushGizmo.BrushAction != null )
								{
									//+++ case of multiple tiles painting
									action.CopyRelative( m_autoTileMap, m_autoTileMap.BrushGizmo.BrushAction, tile_x, tile_y );
									if(m_isCtrlKeyHold)
									{
										// ground tiles become ground overlay, ground overlay are removed, overlay tiles remains
										action.BecomeOverlay();
									}
								}
								else 
								{
									//+++ case of single tile painting

									if( m_isCtrlKeyHold || m_autoTileMap.IsAutoTileHasAlpha( m_selectedTileIdx ) )
									{
										// Put tiles with alpha in the overlay layer
										action.Push( m_autoTileMap, tile_x, tile_y, m_selectedTileIdx, (int)AutoTileMap.eTileLayer.GROUND_OVERLAY );
									}
									else
									{
										action.Push( m_autoTileMap, tile_x, tile_y, m_selectedTileIdx, (int)AutoTileMap.eTileLayer.GROUND );
									}
								}

								m_autoTileMap.BrushGizmo.PerformAction( action );
							}
						}

						m_prevMouseTileX = tile_x;
						m_prevMouseTileY = tile_y;
					}
				}
				else
				{
					// Copy selected tiles
					if( m_dragTileX != -1 && m_dragTileY != -1 )
					{
						m_autoTileMap.BrushGizmo.BrushAction = new AutoTileBrush.TileAction();
						int startTileX = Mathf.Min( m_startDragTileX, m_dragTileX );
						int startTileY = Mathf.Min( m_startDragTileY, m_dragTileY );
						int endTileX = Mathf.Max( m_startDragTileX, m_dragTileX );
						int endTileY = Mathf.Max( m_startDragTileY, m_dragTileY );

						for( int tile_x = startTileX; tile_x <= endTileX; ++tile_x  )
						{
							for( int tile_y = startTileY; tile_y <= endTileY; ++tile_y  )
							{
								int gndTileType = m_autoTileMap.GetAutoTile( tile_x, tile_y, (int)AutoTileMap.eTileLayer.GROUND ).Idx;
								int gndOverlayTileType = m_autoTileMap.GetAutoTile( tile_x, tile_y, (int)AutoTileMap.eTileLayer.GROUND_OVERLAY ).Idx;
								int overlayTileType = m_autoTileMap.GetAutoTile( tile_x, tile_y, (int)AutoTileMap.eTileLayer.OVERLAY ).Idx;

								// Tile position is relative to last released position ( m_dragTile )
								if( m_isCtrlKeyHold )
								{
									// Copy overlay only
									if( gndOverlayTileType >= 0 ) // this allow paste overlay tiles without removing ground or ground overlay
										m_autoTileMap.BrushGizmo.BrushAction.Push( m_autoTileMap, tile_x - m_dragTileX, tile_y - m_dragTileY, gndOverlayTileType, (int)AutoTileMap.eTileLayer.GROUND_OVERLAY);
									m_autoTileMap.BrushGizmo.BrushAction.Push( m_autoTileMap, tile_x - m_dragTileX, tile_y - m_dragTileY, overlayTileType, (int)AutoTileMap.eTileLayer.OVERLAY);
								}
								else
								{
									m_autoTileMap.BrushGizmo.BrushAction.Push( m_autoTileMap, tile_x - m_dragTileX, tile_y - m_dragTileY, gndTileType, (int)AutoTileMap.eTileLayer.GROUND);
									m_autoTileMap.BrushGizmo.BrushAction.Push( m_autoTileMap, tile_x - m_dragTileX, tile_y - m_dragTileY, gndOverlayTileType, (int)AutoTileMap.eTileLayer.GROUND_OVERLAY);
									m_autoTileMap.BrushGizmo.BrushAction.Push( m_autoTileMap, tile_x - m_dragTileX, tile_y - m_dragTileY, overlayTileType, (int)AutoTileMap.eTileLayer.OVERLAY);
								}
							}
						}

						m_autoTileMap.BrushGizmo.RefreshBrushGizmo( startTileX, startTileY, endTileX, endTileY, m_dragTileX, m_dragTileY, m_isCtrlKeyHold );

						m_dragTileX = m_dragTileY = -1;
					}

					if (Input.GetAxis("Mouse ScrollWheel") < 0) // back
					{
						if( m_camera2D.Zoom > 1f )
							m_camera2D.Zoom = Mathf.Max(m_camera2D.Zoom-1, 1);
						else
							m_camera2D.Zoom = Mathf.Max(m_camera2D.Zoom/2f, 0.05f);
					}
					else if (Input.GetAxis("Mouse ScrollWheel") > 0) // forward
					{
						if( m_camera2D.Zoom >= 1f )
							m_camera2D.Zoom = Mathf.Min(m_camera2D.Zoom+1, 10);
						else
							m_camera2D.Zoom*=2f;
					}
				}
			}
		}