Inheritance: MyAbstractMemoryBlockObserver
        private void ProcessMyMemoryBlockObserverPeekLabel(MyMemoryBlockObserver mbObserver, float2 pixelPos)
        {
            int px = (int)pixelPos.x;
            int py = (int)pixelPos.y;

            int index = GetPositionInMemoryBlock(mbObserver, px, py);

            if (index < 0)
            {
                peekLabel.Text = "N/A";
                return;
            }

            if (index >= mbObserver.Target.Count)
                return;

            peekLabel.Visible = true;

            float result = 0;
            mbObserver.Target.GetValueAt(ref result, index);

            string formattedValue;
            if (mbObserver.Method == RenderingMethod.Raw)
            {
                IEnumerable<string> channels = BitConverter.GetBytes(result).Reverse()  // Get the byte values.
                    .Select(channel => channel.ToString())
                    .Select(channel => new String(' ', 3 - channel.Length) + channel);  // Indent with spaces.

                // Zip labels and values, join with a separator.
                formattedValue = String.Join(", ", "ARGB".Zip(channels, (label, channel) => label + ":" + channel));
            }
            else
            {
                formattedValue = result.ToString("0.0000");
            }

            // Show coordinates or index.
            string formattedIndex = mbObserver.ShowCoordinates ? px + ", " + py : index.ToString();

            peekLabel.Text = mbObserver.Target.Name + @"[" + formattedIndex + @"] = " + formattedValue;
        }
        private void SetObserver()
        {
            if (m_showObserver && m_school != null)
            {
                if (m_observer == null)
                {
                    try
                    {
                        MyMemoryBlockObserver observer = new MyMemoryBlockObserver();
                        observer.Target = m_school.VisualFOV;

                        m_observer = new ObserverForm(m_mainForm, observer, m_school);

                        m_observer.TopLevel = false;
                        dockPanelObserver.Controls.Add(m_observer);

                        m_observer.CloseButtonVisible = false;
                        m_observer.MaximizeBox = false;
                        m_observer.Size = dockPanelObserver.Size + new System.Drawing.Size(16, 38);
                        m_observer.Location = new System.Drawing.Point(-8, -30);

                        m_observer.Show();
                    }
                    catch (Exception e)
                    {
                        MyLog.ERROR.WriteLine("Error creating observer: " + e.Message);
                    }
                }
                else
                {
                    m_observer.Show();
                    dockPanelObserver.Show();

                    m_observer.Observer.GenericTarget = m_school.VisualFOV;
                }
            }
            else
            {
                if (m_observer != null)
                {
                    //(m_observer.Observer as MyMemoryBlockObserver).Target = null;
                    m_observer.Close();
                    m_observer.Dispose();
                    m_observer = null;
                    dockPanelObserver.Hide();
                }
            }
        }
 private int GetPositionInMemoryBlock(MyMemoryBlockObserver mbObserver, int px, int py)
 {
     if (mbObserver.ObserveTensors == true)
     {
         if (mbObserver.Method == RenderingMethod.RedGreenScale)
         {
             int tw = mbObserver.TileWidth;
             int th = mbObserver.TileHeight;
             int ta = tw * th;
             int tilesInRow = mbObserver.TilesInRow;
             if (((px + 1) % (tw + 1) == 0) || ((py + 1) % (th + 1) == 0)) // it is point between tiles
             {
                 return -1;
             }
             int tile_row = py / (th + 1);                             // in which tile-row it is
             int tile_col = px / (tw + 1);                             // in which tile-column it is
             int id_tile = tile_col + tile_row * tilesInRow;              // which tile it is
             int values_row = py % (th + 1);                        // id int he tile
             int values_col = px % (tw + 1);                        // id in the tile
             return id_tile * ta + values_col + values_row * tw;
         }
         else // RGB here
         {
             return -1;
         }
     }
     else
     {
         return py * Observer.TextureWidth + px; // Normal value if not tensor observ is used (tiles + borders between tiles)
     }
 }