public UpDownSpinner()
        {
            DaggerfallUnity dfUnity = DaggerfallUnity.Instance;
            if (!dfUnity.IsReady)
                return;

            // Load IMG texture
            ImgFile imgFile = new ImgFile(Path.Combine(dfUnity.Arena2Path, nativeImgName), FileUsage.UseMemory, true);
            imgFile.LoadPalette(Path.Combine(dfUnity.Arena2Path, imgFile.PaletteName));
            nativeTexture = TextureReader.CreateFromAPIImage(imgFile, 0, 0, 0);
            nativeTexture.filterMode = DaggerfallUI.Instance.GlobalFilterMode;

            // Setup spinner panel
            Size = new Vector2(nativeTexture.width, nativeTexture.height);
            backgroundTexture = nativeTexture;

            // Add up/down buttons
            Components.Add(upButton);
            Components.Add(downButton);
            upButton.Position = new Vector2(0, 0);
            upButton.Size = new Vector2(15, 7);
            upButton.OnMouseClick += UpButton_OnMouseClick;
            downButton.Position = new Vector2(0, 13);
            downButton.Size = new Vector2(15, 7);
            downButton.OnMouseClick += DownButton_OnMouseClick;

            // Add value label
            Components.Add(valueLabel);
            valueLabel.Position = new Vector2(0, 7);
            valueLabel.Size = new Vector2(15, 6);
            valueLabel.HorizontalAlignment = HorizontalAlignment.Center;
            valueLabel.ShadowColor = DaggerfallUI.DaggerfallAlternateShadowColor1;
            SetValue(this.value);
        }
示例#2
0
        Texture2D GetTextureFromImg(ImgFile img)
        {
            DFBitmap bitmap = img.GetDFBitmap();
            Texture2D texture = new Texture2D(bitmap.Width, bitmap.Height, TextureFormat.ARGB32, false);
            texture.SetPixels32(img.GetColor32(bitmap, 0));
            texture.Apply(false, true);

            return texture;
        }
        /// <summary>
        /// Get extracted PAK data as a managed bitmap.
        /// </summary>
        /// <returns>Bitmap object.</returns>
        public Bitmap GetManagedBitmap()
        {
            DFBitmap    bmp = GetDFBitmap();
            DFImageFile img = new ImgFile();
            DFPalette   pal = new DFPalette();

            pal.MakeGrayscale();
            img.Palette = pal;
            return(img.GetManagedBitmap(ref bmp, true, false));
        }
        /// <summary>
        /// Reads any Daggerfall image file to ImageData package.
        /// </summary>
        /// <param name="filename">Name of standalone file as it appears in arena2 folder.</param>
        /// <param name="record">Which image record to read for multi-image files.</param>
        /// <param name="frame">Which frame to read for multi-frame images.</param>
        /// <param name="hasAlpha">Enable this for image cutouts.</param>
        /// <param name="createTexture">Create a Texture2D.</param>
        /// <returns>ImageData. If result.type == ImageTypes.None then read failed.</returns>
        public static ImageData GetImageData(string filename, int record = 0, int frame = 0, bool hasAlpha = false, bool createTexture = true)
        {
            // Check API ready
            DaggerfallUnity dfUnity = DaggerfallUnity.Instance;
            if (!dfUnity.IsReady)
                return new ImageData();

            // Parse image file type
            ImageTypes fileType;
            try
            {
                fileType = ParseFileType(filename);
            }
            catch
            {
                return new ImageData();
            }

            // Create base image data
            ImageData imageData = new ImageData();
            imageData.type = fileType;
            imageData.filename = filename;
            imageData.record = record;
            imageData.frame = frame;
            imageData.hasAlpha = hasAlpha;

            // Read supported image files
            DFBitmap dfBitmap = null;
            switch (fileType)
            {
                case ImageTypes.TEXTURE:
                    TextureFile textureFile = new TextureFile(Path.Combine(dfUnity.Arena2Path, filename), FileUsage.UseMemory, true);
                    textureFile.LoadPalette(Path.Combine(dfUnity.Arena2Path, textureFile.PaletteName));
                    dfBitmap = textureFile.GetDFBitmap(record, frame);
                    imageData.offset = textureFile.GetOffset(record);
                    imageData.scale = textureFile.GetScale(record);
                    imageData.size = textureFile.GetSize(record);
                    break;

                case ImageTypes.IMG:
                    ImgFile imgFile = new ImgFile(Path.Combine(dfUnity.Arena2Path, filename), FileUsage.UseMemory, true);
                    imgFile.LoadPalette(Path.Combine(dfUnity.Arena2Path, imgFile.PaletteName));
                    dfBitmap = imgFile.GetDFBitmap();
                    imageData.offset = imgFile.ImageOffset;
                    imageData.scale = new DFSize();
                    imageData.size = imgFile.GetSize(0);
                    break;

                case ImageTypes.CIF:
                case ImageTypes.RCI:
                    CifRciFile cifFile = new CifRciFile(Path.Combine(dfUnity.Arena2Path, filename), FileUsage.UseMemory, true);
                    cifFile.LoadPalette(Path.Combine(dfUnity.Arena2Path, cifFile.PaletteName));
                    dfBitmap = cifFile.GetDFBitmap(record, frame);
                    imageData.offset = cifFile.GetOffset(record);
                    imageData.scale = new DFSize();
                    imageData.size = cifFile.GetSize(record);
                    break;

                default:
                    return new ImageData();
            }

            // Store bitmap
            imageData.dfBitmap = dfBitmap;
            imageData.width = dfBitmap.Width;
            imageData.height = dfBitmap.Height;

            // Create Texture2D
            if (createTexture)
            {
                // Get colors array
                Color32[] colors = GetColors(imageData);
                if (colors == null)
                    return new ImageData();

                // Create new Texture2D
                imageData.texture = GetTexture(colors, imageData.width, imageData.height);
            }

            return imageData;
        }
示例#5
0
        void SetupControl()
        {
            dfUnity = DaggerfallUnity.Instance;
            if (!dfUnity.IsReady)
                return;

            // Load highlight texture
            ImgFile imgFile = new ImgFile(Path.Combine(dfUnity.Arena2Path, highlightImgName), FileUsage.UseMemory, true);
            imgFile.LoadPalette(Path.Combine(dfUnity.Arena2Path, imgFile.PaletteName));
            highlightTexture = TextureReader.CreateFromAPIImage(imgFile, 0, 0, 0);
            highlightTexture.filterMode = DaggerfallUI.Instance.GlobalFilterMode;

            // Add buttons
            Vector2 buttonPos = new Vector2(0, 0);
            Vector2 buttonSize = new Vector2(66, 9);
            for (int i = 0; i < 5; i++)
            {
                selectButtons[i] = new Button();
                this.Components.Add(selectButtons[i]);
                selectButtons[i].Position = buttonPos;
                selectButtons[i].Size = buttonSize;
                selectButtons[i].Tag = i;
                selectButtons[i].OnMouseClick += ReflexButton_OnMouseClick;
                buttonPos.y += buttonSize.y;
            }

            // Set size of this panel
            Size = new Vector2(66, 45);

            // Set starting value
            PlayerReflexes = PlayerReflexes.Average;
        }
        private void LoadNightSky()
        {
            const int width = 512;
            const int height = 219;

            // Get night sky matching sky index
            int nightSky;
            if (SkyIndex >= 0 && SkyIndex <= 7)
                nightSky = 3;
            else if (SkyIndex >= 8 && SkyIndex <= 15)
                nightSky = 1;
            else if (SkyIndex >= 16 && SkyIndex <= 23)
                nightSky = 2;
            else
                nightSky = 0;

            string filename = string.Format("NITE{0:00}I0.IMG", nightSky);
            imgFile = new ImgFile(Path.Combine(dfUnity.Arena2Path, filename), FileUsage.UseMemory, true);
            imgFile.Palette.Load(Path.Combine(dfUnity.Arena2Path, imgFile.PaletteName));

            // Get sky bitmap
            DFBitmap dfBitmap = imgFile.GetDFBitmap(0, 0);

            // Draw stars
            if (ShowStars)
            {
                for (int i = 0; i < dfBitmap.Data.Length; i++)
                {
                    // Stars should only be drawn over clear sky indices
                    int index = dfBitmap.Data[i];
                    if (index > 16 && index < 32)
                    {
                        if (random.NextDouble() < starChance)
                            dfBitmap.Data[i] = starColorIndices[random.Next(0, starColorIndices.Length)];
                    }
                }
            }

            // Get sky colour array
            Color32[] colors = imgFile.GetColors32(dfBitmap);

            // Fix seam on right side of night skies
            for (int y = 0; y < height; y++)
            {
                int pos = y * width + width - 2;
                colors[pos + 1] = colors[pos];
            }

            skyColors.west = colors;
            skyColors.east = colors;
            skyColors.clearColor = skyColors.west[0];
        }
示例#7
0
        public static Texture2D GetTextureFromImg(ImgFile img, TextureFormat format = TextureFormat.ARGB32)
        {
            DFBitmap bitmap = img.GetDFBitmap();
            Texture2D texture = new Texture2D(bitmap.Width, bitmap.Height, format, false);
            texture.SetPixels32(img.GetColor32(bitmap, 0));
            texture.Apply(false, true);
            texture.filterMode = DaggerfallUI.Instance.GlobalFilterMode;

            return texture;
        }
示例#8
0
        public static Texture2D GetTextureFromImg(string name, out DFPosition offset, TextureFormat format = TextureFormat.ARGB32)
        {
            offset = new DFPosition();

            DaggerfallUnity dfUnity = DaggerfallUnity.Instance;
            if (!dfUnity.IsReady)
                return null;

            ImgFile imgFile = new ImgFile(Path.Combine(dfUnity.Arena2Path, name), FileUsage.UseMemory, true);
            imgFile.LoadPalette(Path.Combine(dfUnity.Arena2Path, imgFile.PaletteName));
            Texture2D texture = GetTextureFromImg(imgFile, format);
            texture.filterMode = DaggerfallUI.Instance.GlobalFilterMode;

            offset = imgFile.ImageOffset;

            return texture;
        }
示例#9
0
        /// <summary>
        /// Loads IMG file to texture using a subrect of source image.
        /// Origin of source image (0,0) is bottom-left corner.
        /// </summary>
        public static Texture2D GetTextureFromImg(string name, Rect subRect, TextureFormat format = TextureFormat.ARGB32)
        {
            ImgFile imgFile = new ImgFile(Path.Combine(DaggerfallUnity.Instance.Arena2Path, name), FileUsage.UseMemory, true);
            imgFile.LoadPalette(Path.Combine(DaggerfallUnity.Instance.Arena2Path, imgFile.PaletteName));

            DFBitmap bitmap = imgFile.GetDFBitmap();
            Color32[] colors = imgFile.GetColor32(bitmap, 0);

            Color32[] newColors = new Color32[(int)subRect.width * (int)subRect.height];
            ImageProcessing.CopyColors(
                ref colors,
                ref newColors,
                new DFSize(bitmap.Width, bitmap.Height),
                new DFSize((int)subRect.width, (int)subRect.height),
                new DFPosition((int)subRect.x, (int)subRect.y),
                new DFPosition(0, 0),
                new DFSize((int)subRect.width, (int)subRect.height));

            Texture2D texture = new Texture2D((int)subRect.width, (int)subRect.height, format, false);
            texture.SetPixels32(newColors, 0);
            texture.Apply(false, true);
            texture.filterMode = DaggerfallUI.Instance.GlobalFilterMode;

            return texture;
        }
示例#10
0
        public static DFBitmap GetImgBitmap(string name)
        {
            DaggerfallUnity dfUnity = DaggerfallUnity.Instance;
            if (!dfUnity.IsReady)
                return null;

            ImgFile imgFile = new ImgFile(Path.Combine(dfUnity.Arena2Path, name), FileUsage.UseMemory, true);
            return imgFile.GetDFBitmap();
        }
示例#11
0
        void LoadAssets()
        {
            const string compassFilename = "COMPASS.IMG";
            const string compassBoxFilename = "COMPBOX.IMG";

            if (!dfUnity.IsReady)
                return;

            if (!compassTexture)
            {
                ImgFile file = new ImgFile(Path.Combine(dfUnity.Arena2Path, compassFilename), FileUsage.UseMemory, true);
                file.LoadPalette(Path.Combine(dfUnity.Arena2Path, file.PaletteName));
                compassTexture = GetTextureFromImg(file);
                compassTexture.filterMode = dfUnity.MaterialReader.MainFilterMode;
            }

            if (!compassBoxTexture)
            {
                ImgFile file = new ImgFile(Path.Combine(dfUnity.Arena2Path, compassBoxFilename), FileUsage.UseMemory, true);
                file.LoadPalette(Path.Combine(dfUnity.Arena2Path, file.PaletteName));
                compassBoxTexture = GetTextureFromImg(file);
                compassBoxTexture.filterMode = dfUnity.MaterialReader.MainFilterMode;
            }

            assetsLoaded = true;
        }
        /// <summary>
        /// initial window setup of the automap window
        /// </summary>
        protected override void Setup()
        {
            ImgFile imgFile = null;
            DFBitmap bitmap = null;

            if (isSetup) // don't setup twice!
                return;

            initGlobalResources(); // initialize gameobjectAutomap, daggerfallAutomap and layerAutomap

            // Load native texture
            imgFile = new ImgFile(Path.Combine(DaggerfallUnity.Instance.Arena2Path, nativeImgName), FileUsage.UseMemory, false);
            imgFile.LoadPalette(Path.Combine(DaggerfallUnity.Instance.Arena2Path, imgFile.PaletteName));
            bitmap = imgFile.GetDFBitmap();
            nativeTexture = new Texture2D(bitmap.Width, bitmap.Height, TextureFormat.ARGB32, false);
            nativeTexture.SetPixels32(imgFile.GetColor32(bitmap, 0));
            nativeTexture.Apply(false, false); // make readable
            nativeTexture.filterMode = DaggerfallUI.Instance.GlobalFilterMode;
            if (!nativeTexture)
                throw new Exception("DaggerfallAutomapWindow: Could not load native texture (AMAP00I0.IMG).");

            // Load alternative Grid Icon (3D View Grid graphics)
            imgFile = new ImgFile(Path.Combine(DaggerfallUnity.Instance.Arena2Path, nativeImgNameGrid3D), FileUsage.UseMemory, false);
            imgFile.LoadPalette(Path.Combine(DaggerfallUnity.Instance.Arena2Path, imgFile.PaletteName));
            bitmap = imgFile.GetDFBitmap();
            Texture2D nativeTextureGrid3D = new Texture2D(bitmap.Width, bitmap.Height, TextureFormat.ARGB32, false);
            nativeTextureGrid3D.SetPixels32(imgFile.GetColor32(bitmap, 0));
            nativeTextureGrid3D.Apply(false, false); // make readable
            nativeTextureGrid3D.filterMode = DaggerfallUI.Instance.GlobalFilterMode;
            if (!nativeTextureGrid3D)
                throw new Exception("DaggerfallAutomapWindow: Could not load native texture (AMAP01I0.IMG).");
            pixelsGrid3D = nativeTextureGrid3D.GetPixels(0, 0, 27, 19);

            // Cut out 2D View Grid graphics from background image
            pixelsGrid2D = nativeTexture.GetPixels(78, nativeTexture.height - 171 - 19, 27, 19);

            // store background graphics from from background image
            backgroundOriginal = nativeTexture.GetPixels(0, 29, nativeTexture.width, nativeTexture.height - 29);

            backgroundAlternative1 = new Color[backgroundOriginal.Length];
            for (int i = 0; i < backgroundOriginal.Length; ++i)
            {
                backgroundAlternative1[i].r = 0.0f;
                backgroundAlternative1[i].g = 0.0f;
                backgroundAlternative1[i].b = 0.0f;
                backgroundAlternative1[i].a = 1.0f;
            }

            backgroundAlternative2 = new Color[backgroundOriginal.Length];
            for (int i = 0; i < backgroundOriginal.Length; ++i)
            {
                backgroundAlternative2[i].r = 0.2f;
                backgroundAlternative2[i].g = 0.1f;
                backgroundAlternative2[i].b = 0.3f;
                backgroundAlternative2[i].a = 1.0f;
            }

            backgroundAlternative3 = new Color[backgroundOriginal.Length];
            for (int i = 0; i < backgroundOriginal.Length; ++i)
            {
                backgroundAlternative3[i].r = 0.3f;
                backgroundAlternative3[i].g = 0.1f;
                backgroundAlternative3[i].b = 0.2f;
                backgroundAlternative3[i].a = 1.0f;
            }

            // Always dim background
            ParentPanel.BackgroundColor = ScreenDimColor;

            // Setup native panel background
            NativePanel.BackgroundTexture = nativeTexture;

            oldPositionNativePanel = NativePanel.Rectangle;

            // dummyPanelAutomap is used to get correct size for panelRenderAutomap
            Rect rectDummyPanelAutomap = new Rect();
            rectDummyPanelAutomap.position = new Vector2(1, 1);
            rectDummyPanelAutomap.size = new Vector2(318, 169);

            dummyPanelAutomap = DaggerfallUI.AddPanel(rectDummyPanelAutomap, NativePanel);

            // Setup automap render panel (into this the level geometry is rendered) - use dummyPanelAutomap to get size
            Rect positionPanelRenderAutomap = dummyPanelAutomap.Rectangle;
            panelRenderAutomap = DaggerfallUI.AddPanel(positionPanelRenderAutomap, ParentPanel);
            panelRenderAutomap.AutoSize = AutoSizeModes.None;

            panelRenderAutomap.OnMouseScrollUp += PanelAutomap_OnMouseScrollUp;
            panelRenderAutomap.OnMouseScrollDown += PanelAutomap_OnMouseScrollDown;
            panelRenderAutomap.OnMouseDown += PanelAutomap_OnMouseDown;
            panelRenderAutomap.OnMouseUp += PanelAutomap_OnMouseUp;
            panelRenderAutomap.OnRightMouseDown += PanelAutomap_OnRightMouseDown;
            panelRenderAutomap.OnRightMouseUp += PanelAutomap_OnRightMouseUp;

            // Grid button (toggle 2D <-> 3D view)
            gridButton = DaggerfallUI.AddButton(new Rect(78, 171, 27, 19), NativePanel);
            gridButton.OnMouseClick += GridButton_OnMouseClick;
            gridButton.OnRightMouseClick += GridButton_OnRightMouseClick;
            gridButton.OnMouseScrollUp += GridButton_OnMouseScrollUp;
            gridButton.OnMouseScrollDown += GridButton_OnMouseScrollDown;
            gridButton.ToolTip = defaultToolTip;
            gridButton.ToolTipText = "left click: switch between 2D top view and 3D view (hotkey: space key)\rright click: reset rotation center to player position (hotkey: control+backspace)\rmouse wheel up while over this button: increase perspective (only 3D mode)\rmouse wheel down while over this button: decrease perspective (only 3D mode)";
            gridButton.ToolTip.ToolTipDelay = toolTipDelay;

            // forward button
            forwardButton = DaggerfallUI.AddButton(new Rect(105, 171, 21, 19), NativePanel);
            forwardButton.OnMouseDown += ForwardButton_OnMouseDown;
            forwardButton.OnMouseUp += ForwardButton_OnMouseUp;
            forwardButton.OnRightMouseDown += ForwardButton_OnRightMouseDown;
            forwardButton.OnRightMouseUp += ForwardButton_OnRightMouseUp;
            forwardButton.ToolTip = defaultToolTip;
            forwardButton.ToolTipText = "left click: move viewpoint forward (hotkey: up arrow)\rright click: move rotation center axis forward (hotkey: control+up arrow)";
            forwardButton.ToolTip.ToolTipDelay = toolTipDelay;

            // backward button
            backwardButton = DaggerfallUI.AddButton(new Rect(126, 171, 21, 19), NativePanel);
            backwardButton.OnMouseDown += BackwardButton_OnMouseDown;
            backwardButton.OnMouseUp += BackwardButton_OnMouseUp;
            backwardButton.OnRightMouseDown += BackwardButton_OnRightMouseDown;
            backwardButton.OnRightMouseUp += BackwardButton_OnRightMouseUp;
            backwardButton.ToolTip = defaultToolTip;
            backwardButton.ToolTipText = "left click: move viewpoint backwards (hotkey: down arrow)\rright click: move rotation center axis backwards (hotkey: control+down arrow)";
            backwardButton.ToolTip.ToolTipDelay = toolTipDelay;

            // left button
            leftButton = DaggerfallUI.AddButton(new Rect(149, 171, 21, 19), NativePanel);
            leftButton.OnMouseDown += LeftButton_OnMouseDown;
            leftButton.OnMouseUp += LeftButton_OnMouseUp;
            leftButton.OnRightMouseDown += LeftButton_OnRightMouseDown;
            leftButton.OnRightMouseUp += LeftButton_OnRightMouseUp;
            leftButton.ToolTip = defaultToolTip;
            leftButton.ToolTipText = "left click: move viewpoint to the left (hotkey: left arrow)\rright click: move rotation center axis to the left (hotkey: control+left arrow)";
            leftButton.ToolTip.ToolTipDelay = toolTipDelay;

            // right button
            rightButton = DaggerfallUI.AddButton(new Rect(170, 171, 21, 19), NativePanel);
            rightButton.OnMouseDown += RightButton_OnMouseDown;
            rightButton.OnMouseUp += RightButton_OnMouseUp;
            rightButton.OnRightMouseDown += RightButton_OnRightMouseDown;
            rightButton.OnRightMouseUp += RightButton_OnRightMouseUp;
            rightButton.ToolTip = defaultToolTip;
            rightButton.ToolTipText = "left click: move viewpoint to the right (hotkey: right arrow)\rright click: move rotation center axis to the right (hotkey: control+right arrow)";
            rightButton.ToolTip.ToolTipDelay = toolTipDelay;

            // rotate left button
            rotateLeftButton = DaggerfallUI.AddButton(new Rect(193, 171, 21, 19), NativePanel);
            rotateLeftButton.OnMouseDown += RotateLeftButton_OnMouseDown;
            rotateLeftButton.OnMouseUp += RotateLeftButton_OnMouseUp;
            rotateLeftButton.OnRightMouseDown += RotateLeftButton_OnRightMouseDown;
            rotateLeftButton.OnRightMouseUp += RotateLeftButton_OnRightMouseUp;
            rotateLeftButton.ToolTip = defaultToolTip;
            rotateLeftButton.ToolTipText = "left click: rotate dungeon model to the left (hotkey: alt+right arrow)\rright click: rotate camera view to the left (hotkey: shift+right arrow)";
            rotateLeftButton.ToolTip.ToolTipDelay = toolTipDelay;

            // rotate right button
            rotateRightButton = DaggerfallUI.AddButton(new Rect(214, 171, 21, 19), NativePanel);
            rotateRightButton.OnMouseDown += RotateRightButton_OnMouseDown;
            rotateRightButton.OnMouseUp += RotateRightButton_OnMouseUp;
            rotateRightButton.OnRightMouseDown += RotateRightButton_OnRightMouseDown;
            rotateRightButton.OnRightMouseUp += RotateRightButton_OnRightMouseUp;
            rotateRightButton.ToolTip = defaultToolTip;
            rotateRightButton.ToolTipText = "left click: rotate dungeon model to the right (hotkey: alt+right arrow)\rright click: rotate camera view to the right (hotkey: shift+right arrow)";
            rotateRightButton.ToolTip.ToolTipDelay = toolTipDelay;

            // upstairs button
            upstairsButton = DaggerfallUI.AddButton(new Rect(237, 171, 21, 19), NativePanel);
            upstairsButton.OnMouseDown += UpstairsButton_OnMouseDown;
            upstairsButton.OnMouseUp += UpstairsButton_OnMouseUp;
            upstairsButton.OnRightMouseDown += UpstairsButton_OnRightMouseDown;
            upstairsButton.OnRightMouseUp += UpstairsButton_OnRightMouseUp;
            upstairsButton.ToolTip = defaultToolTip;
            upstairsButton.ToolTipText = "left click: increase viewpoint (hotkey: page up)\rright click: increase slice level (hotkey: control+page up)\r\rhint: different render modes may show hidden geometry:\rhotkey F2: cutout mode\rhotkey F3: wireframe mode\rhotkey F4: transparent mode\rswitch between modes with return key";
            upstairsButton.ToolTip.ToolTipDelay = toolTipDelay;

            // downstairs button
            downstairsButton = DaggerfallUI.AddButton(new Rect(258, 171, 21, 19), NativePanel);
            downstairsButton.OnMouseDown += DownstairsButton_OnMouseDown;
            downstairsButton.OnMouseUp += DownstairsButton_OnMouseUp;
            downstairsButton.OnRightMouseDown += DownstairsButton_OnRightMouseDown;
            downstairsButton.OnRightMouseUp += DownstairsButton_OnRightMouseUp;
            downstairsButton.ToolTip = defaultToolTip;
            downstairsButton.ToolTipText = "left click: decrease viewpoint (hotkey: page down)\rright click: decrease slice level (hotkey: control+page down)\r\rhint: different render modes may show hidden geometry:\rhotkey F2: cutout mode\rhotkey F3: wireframe mode\rhotkey F4: transparent mode\rswitch between modes with return key";
            downstairsButton.ToolTip.ToolTipDelay = toolTipDelay;

            // Exit button
            Button exitButton = DaggerfallUI.AddButton(new Rect(281, 171, 28, 19), NativePanel);
            exitButton.OnMouseClick += ExitButton_OnMouseClick;

            // dummyPanelCompass is used to get correct size for compass
            Rect rectDummyPanelCompass = new Rect();
            rectDummyPanelCompass.position = new Vector2(3, 172);
            rectDummyPanelCompass.size = new Vector2(76, 17);
            dummyPanelCompass = DaggerfallUI.AddPanel(rectDummyPanelCompass, NativePanel);
            dummyPanelCompass.OnMouseClick += Compass_OnMouseClick;
            dummyPanelCompass.OnRightMouseClick += Compass_OnRightMouseClick;
            dummyPanelCompass.ToolTip = defaultToolTip;
            dummyPanelCompass.ToolTipText = "left click: toggle focus (hotkey: tab)\rred beacon: player, green beacon: entrance, blue beacon: rotation center\r\rright click: reset view (hotkey: backspace)";
            dummyPanelCompass.ToolTip.ToolTipDelay = toolTipDelay;

            // compass
            compass = new HUDCompass();
            Vector2 scale = NativePanel.LocalScale;
            compass.Position = dummyPanelCompass.Rectangle.position;
            compass.Scale = scale;
            NativePanel.Components.Add(compass);

            isSetup = true;
        }