public EditTilesetTileInputAction(Tileset tileset, int tileIndex, TileInput tileInput)
        {
            if (tileset == null) throw new ArgumentNullException("tileset");

            this.tileset = tileset;

            this.tileInput = new RawList<TileInput>(tileIndex + 1);
            this.tileInput.Count = tileIndex + 1;
            this.tileInput.Data[tileIndex] = tileInput;

            this.tileInputMask = new RawList<bool>(tileIndex + 1);
            this.tileInputMask.Count = tileIndex + 1;
            this.tileInputMask.Data[tileIndex] = true;
        }
Example #2
0
        /// <summary>
        /// Determines the rectangular tile area that is visible to the specified <see cref="IDrawDevice"/>.
        /// </summary>
        /// <param name="device"></param>
        /// <param name="input"></param>
        /// <returns></returns>
        public static TileOutput GetVisibleTileRect(IDrawDevice device, TileInput input)
        {
            TileOutput output;

            // Determine the view space transform of the tilemap
            Vector3 objPos = input.TilemapPos;
            float objScale = input.TilemapScale;
            float cameraScaleAtObj = 1.0f;
            device.PreprocessCoords(ref objPos, ref cameraScaleAtObj);
            objScale *= cameraScaleAtObj;

            // Early-out, if so small that it might break the math behind rendering a single tile.
            if (objScale <= 0.000000001f) return EmptyOutput;

            // Determine transformed X and Y axis in view and world space
            output.XAxisView = Vector2.UnitX;
            output.YAxisView = Vector2.UnitY;
            MathF.TransformCoord(ref output.XAxisView.X, ref output.XAxisView.Y, input.TilemapAngle, objScale);
            MathF.TransformCoord(ref output.YAxisView.X, ref output.YAxisView.Y, input.TilemapAngle, objScale);
            output.XAxisWorld = Vector2.UnitX;
            output.YAxisWorld = Vector2.UnitY;
            MathF.TransformCoord(ref output.XAxisWorld.X, ref output.XAxisWorld.Y, input.TilemapAngle, input.TilemapScale);
            MathF.TransformCoord(ref output.YAxisWorld.X, ref output.YAxisWorld.Y, input.TilemapAngle, input.TilemapScale);

            // Determine which tile is in the center of view space.
            Point2 viewCenterTile = Point2.Zero;
            {
                // Project the view center coordinate (view space zero) into the local space of the rendered tilemap
                Vector2 viewRenderStartPos = objPos.Xy;
                Vector2 localViewCenter = Vector2.Zero - viewRenderStartPos;
                localViewCenter = new Vector2(
                    Vector2.Dot(localViewCenter, output.XAxisView.Normalized),
                    Vector2.Dot(localViewCenter, output.YAxisView.Normalized)) / objScale;
                viewCenterTile = new Point2(
                    (int)MathF.Floor(localViewCenter.X / input.TileSize.X),
                    (int)MathF.Floor(localViewCenter.Y / input.TileSize.Y));
            }

            // Determine the edge length of a square that is big enough to enclose the world space rect of the Camera view
            float visualAngle = input.TilemapAngle - device.RefAngle;
            Vector2 visualBounds = new Vector2(
                device.TargetSize.Y * MathF.Abs(MathF.Sin(visualAngle)) + device.TargetSize.X * MathF.Abs(MathF.Cos(visualAngle)),
                device.TargetSize.X * MathF.Abs(MathF.Sin(visualAngle)) + device.TargetSize.Y * MathF.Abs(MathF.Cos(visualAngle)));
            Vector2 localVisualBounds = visualBounds / cameraScaleAtObj;
            Point2 targetVisibleTileCount = new Point2(
                3 + (int)MathF.Ceiling(localVisualBounds.X / (MathF.Min(input.TileSize.X, input.TileSize.Y) * input.TilemapScale)),
                3 + (int)MathF.Ceiling(localVisualBounds.Y / (MathF.Min(input.TileSize.X, input.TileSize.Y) * input.TilemapScale)));

            // Determine the tile indices (xy) that are visible within that rect
            output.VisibleTileStart = new Point2(
                MathF.Max(viewCenterTile.X - targetVisibleTileCount.X / 2, 0),
                MathF.Max(viewCenterTile.Y - targetVisibleTileCount.Y / 2, 0));
            Point2 tileGridEndPos = new Point2(
                MathF.Min(viewCenterTile.X + targetVisibleTileCount.X / 2, input.TileCount.X),
                MathF.Min(viewCenterTile.Y + targetVisibleTileCount.Y / 2, input.TileCount.Y));
            output.VisibleTileCount = new Point2(
                MathF.Clamp(tileGridEndPos.X - output.VisibleTileStart.X, 0, input.TileCount.X),
                MathF.Clamp(tileGridEndPos.Y - output.VisibleTileStart.Y, 0, input.TileCount.Y));

            // Determine start position for rendering
            output.RenderOriginView = objPos + new Vector3(
                output.VisibleTileStart.X * output.XAxisView * input.TileSize.X +
                output.VisibleTileStart.Y * output.YAxisView * input.TileSize.Y);
            output.RenderOriginWorld = input.TilemapPos + new Vector3(
                output.VisibleTileStart.X * output.XAxisWorld * input.TileSize.X +
                output.VisibleTileStart.Y * output.YAxisWorld * input.TileSize.Y);

            return output;
        }