internal void LoadDefaults()
        {
            var spr = FindResource("PathPoint") as BitmapImage;

            WindowAPI.RegisterTexture(renderer, "roaam_path", System.AppDomain.CurrentDomain.BaseDirectory + spr.UriSource.LocalPath, 1, out int texture);
            LoadedImages["roaam_path"] = new TexData(true, texture, WindowAPI.BitmapImageToBitmap(spr), new Point(12, 12));

            spr = FindResource("EmptyImage") as BitmapImage;
            WindowAPI.RegisterTexture(renderer, "roaam_empty", System.AppDomain.CurrentDomain.BaseDirectory + spr.UriSource.LocalPath, 1, out texture);
            LoadedImages["roaam_empty"] = new TexData(true, texture, WindowAPI.BitmapImageToBitmap(spr), new Point(9, 9));

            spr = FindResource("WhitePixel") as BitmapImage;
            WindowAPI.RegisterTexture(renderer, "roaam_zone", System.AppDomain.CurrentDomain.BaseDirectory + spr.UriSource.LocalPath, 1, out texture);
            LoadedImages["roaam_zone"] = new TexData(true, texture, WindowAPI.BitmapImageToBitmap(spr));

            spr = FindResource("TargetSprite") as BitmapImage;
            WindowAPI.RegisterTexture(renderer, "roaam_target", System.AppDomain.CurrentDomain.BaseDirectory + spr.UriSource.LocalPath, 1, out texture);
            LoadedImages["roaam_target"] = new TexData(true, texture, WindowAPI.BitmapImageToBitmap(spr));

            spr = FindResource("Arrows") as BitmapImage;
            WindowAPI.RegisterTexture(renderer, "roaam_arrows", System.AppDomain.CurrentDomain.BaseDirectory + spr.UriSource.LocalPath, 1, out texture);
            LoadedImages["roaam_arrows"] = new TexData(true, texture, WindowAPI.BitmapImageToBitmap(spr), new Point(56, 56));

            spr = FindResource("Square") as BitmapImage;
            WindowAPI.RegisterTexture(renderer, "roaam_square", System.AppDomain.CurrentDomain.BaseDirectory + spr.UriSource.LocalPath, 1, out texture);
            LoadedImages["roaam_square"] = new TexData(true, texture, WindowAPI.BitmapImageToBitmap(spr), new Point(18, 18));

            spr = FindResource("Respawn") as BitmapImage;
            WindowAPI.RegisterTexture(renderer, "roaam_respawn", System.AppDomain.CurrentDomain.BaseDirectory + spr.UriSource.LocalPath, 1, out texture);
            LoadedImages["roaam_respawn"] = new TexData(true, texture, WindowAPI.BitmapImageToBitmap(spr), new Point(16, 32));
        }
 private void OnLoaded(object sender, RoutedEventArgs e)
 {
     if (HwndControl.Hwnd != IntPtr.Zero && renderer == IntPtr.Zero)
     {
         WindowAPI.InitRenderer(HwndControl.Hwnd, out renderer);
         CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
     }
 }
        protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
        {
            double dpiScale = 1.0; // default value for 96 dpi

            // determine DPI
            // (as of .NET 4.6.1, this returns the DPI of the primary monitor, if you have several different DPIs)
            var hwndTarget = PresentationSource.FromVisual(this).CompositionTarget as HwndTarget;

            if (hwndTarget != null)
            {
                dpiScale = hwndTarget.TransformToDevice.M11;
            }

            int surfWidth  = (int)(ActualWidth < 0 ? 0 : Math.Ceiling(ActualWidth * dpiScale));
            int surfHeight = (int)(ActualHeight < 0 ? 0 : Math.Ceiling(ActualHeight * dpiScale));

            if (renderer != IntPtr.Zero)
            {
                HRESULT.Check(WindowAPI.SetSize(renderer, surfWidth, surfHeight));
            }
        }
        unsafe void CompositionTarget_Rendering(object sender, EventArgs e)
        {
            RenderingEventArgs args = (RenderingEventArgs)e;

            // It's possible for Rendering to call back twice in the same frame
            // so only render when we haven't already rendered in this frame.
            if (_lastRender != args.RenderingTime)
            {
                if (!LoadedImages.ContainsKey("roaam_path"))
                {
                    LoadDefaults();
                }

                foreach (Article art in articles)
                {
                    string spriteName = art.Sprite;
                    // Check if the sprite is loaded
                    if (!LoadedImages.ContainsKey(spriteName))
                    {
                        // If spritename is set, attempt to load sprite
                        bool hasSprite = false;
                        if (!string.IsNullOrEmpty(spriteName))
                        {
                            hasSprite = WindowAPI.LoadImage(spriteName, renderer, out TexData data);
                            LoadedImages.Add(spriteName, data);
                        }

                        // If no sprite is found, use EmptyImage for this article
                        if (!hasSprite)
                        {
                            BitmapImage overrideSpr = FindResource("EmptyImage") as BitmapImage;
                            WindowAPI.RegisterTexture(renderer, spriteName, AppDomain.CurrentDomain.BaseDirectory + overrideSpr.UriSource.LocalPath, 1, out int texture);
                            LoadedImages[spriteName] = new TexData(false, texture, null);
                        }
                    }

                    // Get texture data for this article
                    TexData sprite             = LoadedImages[spriteName];
                    Point   offset             = art.RealPoint - new Vector(sprite.offset.X, sprite.offset.Y);
                    Point   scale              = new Point(1, 1);
                    System.Drawing.Color color = System.Drawing.Color.White;

                    switch (art.ArticleNum)
                    {
                    case ArticleType.Terrain:
                        scale = new Point(2, 2);
                        break;

                    case ArticleType.Zone:
                        if (art is Zone zone)
                        {
                            scale = new Point(zone.TriggerWidth, zone.TriggerHeight);
                            // Set the color based on event type
                            switch (zone.EventID)
                            {
                            //blastzone
                            case 4:
                                color = System.Drawing.Color.Red;
                                break;
                            }
                            // Make semi-transparent
                            color = System.Drawing.Color.FromArgb(64, color.R, color.G, color.B);

                            // Show transform handles
                            if (SelectedObj == art)
                            {
                                // Push a box at each corner of the zone for scale handles
                                TexData spr = LoadedImages["roaam_square"];
                                foreach (Point point in ROAAM_CONST.ZONE_POINTS)
                                {
                                    PushArticle(new DX_Article(
                                                    spr.texture,
                                                    zone.RealPoint + new Vector(point.X * zone.TriggerWidth, point.Y * zone.TriggerHeight) - (Vector)spr.offset / zoomLevel,
                                                    new Point(1 / zoomLevel, 1 / zoomLevel),
                                                    -15));
                                }
                            }
                        }
                        break;

                    case ArticleType.Target:
                        if (SelectedObj == art && (art as Target).Path.Any())
                        {
                            Vector prev = (Vector)(art as Target).Path.Last();
                            for (int i = 0; i < (art as Target).Path.Count; i++)
                            {
                                Vector  point   = (Vector)(art as Target).Path[i];
                                TexData targSpr = LoadedImages["roaam_path"];

                                // Push path point sprite to renderer
                                PushArticle(new DX_Article(
                                                targSpr.texture,
                                                (Point)((point * ROAAM_CONST.GRID_SIZE) - (Vector)targSpr.offset),
                                                new Point(1, 1),
                                                -10));
                                // Push semi-transparent target sprite to renderer
                                PushArticle(new DX_Article(
                                                sprite.texture,
                                                (Point)((point * ROAAM_CONST.GRID_SIZE) - (Vector)sprite.offset),
                                                scale,
                                                art.Depth,
                                                unchecked ((int)0x40FFFFFF)));

                                // Push transform handles if this path point is selected
                                if (SelectedPath == i)
                                {
                                    TexData arrowSpr = LoadedImages["roaam_arrows"];
                                    PushArticle(new DX_Article(
                                                    arrowSpr.texture,
                                                    (Point)((point * ROAAM_CONST.GRID_SIZE) - ((Vector)arrowSpr.offset / zoomLevel)),
                                                    new Point(1 / zoomLevel, 1 / zoomLevel),
                                                    -15));
                                }

                                // Push path line to renderer, and highlight orange if selected in editor panel
                                IntPtr pathColor = WhiteBrush;
                                float  width     = 2;
                                if (i == ObjViewer.Instance.HighlightedPath)
                                {
                                    pathColor = OrangeBrush;
                                    width     = 4;
                                }
                                PushLine(new DX_Line((Point)(prev * ROAAM_CONST.GRID_SIZE),
                                                     (Point)(point * ROAAM_CONST.GRID_SIZE),
                                                     width,
                                                     art.Depth - 0.1f,
                                                     pathColor));
                                // Store this point for line drawing
                                prev = point;
                            }
                        }
                        break;

                    case ArticleType.Tilemap:
                        if (art is Tilemap tilemap)
                        {
                            Tileset tileset = tilemap.Tileset;
                            if (tileset == null || string.IsNullOrEmpty(tileset.SpritePath))
                            {
                                continue;
                            }
                            // Check if the sprite is loaded
                            if (!LoadedImages.ContainsKey(tileset.SpritePath))
                            {
                                // If spritename is set, attempt to load sprite
                                bool hasSprite = false;
                                if (!string.IsNullOrEmpty(tileset.SpritePath))
                                {
                                    hasSprite = WindowAPI.LoadImage(tileset.SpritePath, renderer, out TexData data);
                                    LoadedImages.Add(tileset.SpritePath, data);
                                }

                                // If no sprite is found, use EmptyImage for this article
                                if (!hasSprite)
                                {
                                    BitmapImage overrideSpr = FindResource("EmptyImage") as BitmapImage;
                                    WindowAPI.RegisterTexture(renderer, tileset.SpritePath, AppDomain.CurrentDomain.BaseDirectory + overrideSpr.UriSource.LocalPath, 1, out int texture);
                                    LoadedImages[tileset.SpritePath] = new TexData(false, texture, null);
                                }
                            }

                            TexData tex = LoadedImages[tileset.SpritePath];
                            foreach (var tilegrid in tilemap.Tilegrid)
                            {
                                Point pos = new Point(tileset.TileWidth * 2 * TilegridArray.ChunkSizeX * tilegrid.Key.Item1 + tilemap.RealPoint.X,
                                                      tileset.TileHeight * 2 * TilegridArray.ChunkSizeY * tilegrid.Key.Item2 + tilemap.RealPoint.Y);
                                PushTilemap(new DX_Tilemap(tex.texture, pos, tileset.TileWidth, tileset.TileHeight, tilegrid.Value, tilemap.Depth, new Point(2, 2)));
                            }
                        }
                        break;
                    }

                    if (art.ArticleNum != ArticleType.Tilemap)
                    {
                        var c = color.ToArgb();
                        // Push the article sprite to the renderer
                        PushArticle(new DX_Article(
                                        sprite.texture,
                                        new Point(offset.X, offset.Y),
                                        scale,
                                        art.Depth,
                                        SelectedObj == art ? System.Drawing.Color.Orange.ToArgb() : color.ToArgb()));
                    }

                    if (SelectedObj == art && SelectedPath == -1 && Overlay.Visibility != Visibility.Visible)
                    {
                        TexData arrowSpr = LoadedImages["roaam_arrows"];
                        if (art is Zone zone)
                        {
                            offset = new Point(offset.X + zone.TriggerWidth / 2, offset.Y + zone.TriggerHeight / 2);
                        }

                        // Push the transform handles to the renderer if selected
                        PushArticle(new DX_Article(
                                        arrowSpr.texture,
                                        offset - ((Vector)arrowSpr.offset / zoomLevel),
                                        new Point(1 / zoomLevel, 1 / zoomLevel),
                                        -15));
                    }
                }

                if (ApplicationSettings.Instance.ActiveProject != null)
                {
                    TexData respawnSpr = LoadedImages["roaam_respawn"];
                    PushArticle(new DX_Article(
                                    respawnSpr.texture,
                                    ApplicationSettings.Instance.ActiveProject.RespawnPoint - (Vector)respawnSpr.offset,
                                    new Point(1, 1),
                                    5));
                }

                WindowAPI.PrepareForRender(renderer);
                WindowAPI.SetCameraTransform(renderer, new Point(RenderOffset.X, RenderOffset.Y), zoomLevel);
                WindowAPI.Render(renderer, articles_internal, articles_count_internal, lines_internal, lines_count_internal, tilemap_internal, tilemap_count_internal);

                ClearArticles();
                ClearLines();
                ClearTilemaps();

                _lastRender = args.RenderingTime;
            }
        }
        public static bool LoadImage(string name, IntPtr renderer, out TexData texData)
        {
            Point           offset   = new Point();
            string          loadFile = Path.Combine(Path.GetDirectoryName(ApplicationSettings.Instance.ActiveProject.ProjectPath), "scripts", "load.gml");
            MatchCollection matches  = null;

            if (File.Exists(loadFile))
            {
                string lines = File.ReadAllText(loadFile);
                matches = Regex.Matches(lines, "sprite_change_offset\\s*\\(\\s*\"([\\w\\d]+)\",\\s*(\\d+),\\s*(\\d+)\\s*\\)");
            }
            string directory;

            if (ApplicationSettings.Instance.ActiveProject.Type == ProjectType.AdventureMode)
            {
                directory = Path.Combine(Path.GetDirectoryName(ApplicationSettings.Instance.ActiveProject.ProjectPath), "sprites", "articles");
            }
            else
            {
                directory = Path.Combine(Path.GetDirectoryName(ApplicationSettings.Instance.ActiveProject.ProjectPath), "sprites");
            }
            if (File.Exists(Path.Combine(directory, name + ".png")))
            {
                string path = Path.Combine(directory, name + ".png");
                System.Drawing.Bitmap img = null;
                using (FileStream file = new FileStream(path, FileMode.Open))
                {
                    MemoryStream stream = new MemoryStream();
                    file.CopyTo(stream);
                    img = new System.Drawing.Bitmap(stream);
                }
                WindowAPI.RegisterTexture(renderer, name, path, 1, out int texture);
                if (matches != null)
                {
                    Match match = matches.OfType <Match>().FirstOrDefault(m => m.Groups[1].Value == name);
                    if (match != null)
                    {
                        offset.X = Double.Parse(match.Groups[2].Value);
                        offset.Y = Double.Parse(match.Groups[3].Value);
                    }
                }
                texData = new TexData(true, texture, img, offset);
                return(true);
            }

            var files = Directory.EnumerateFiles(directory, name + "*.png");

            if (files.Any())
            {
                string file = files.FirstOrDefault(f => Regex.Match(f, name + "_strip(\\d+)").Success);
                if (!string.IsNullOrEmpty(file))
                {
                    Match match = Regex.Match(file, "strip(\\d+)");
                    int   count = int.Parse(match.Groups[1].Value);
                    System.Drawing.Bitmap img = null;
                    using (FileStream fstream = new FileStream(file, FileMode.Open))
                    {
                        MemoryStream stream = new MemoryStream();
                        fstream.CopyTo(stream);
                        img = new System.Drawing.Bitmap(stream);
                    }
                    WindowAPI.RegisterTexture(renderer, name, file, count, out int texture);
                    int index = file.IndexOf("_strip");
                    if (matches != null)
                    {
                        Match offsetMatch = matches.OfType <Match>().FirstOrDefault(m => m.Groups[1].Value == file.Substring(0, index));
                        if (offsetMatch != null)
                        {
                            offset.X = Double.Parse(offsetMatch.Groups[2].Value);
                            offset.Y = Double.Parse(offsetMatch.Groups[3].Value);
                        }
                    }
                    texData = new TexData(true, texture, img, offset);
                    return(true);
                }
            }
            texData = new TexData(false, 0);
            return(false);
        }