bitmap test pattern working
authordrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Fri, 19 Oct 2012 23:22:35 +0000 (23:22 +0000)
committerdrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Fri, 19 Oct 2012 23:22:35 +0000 (23:22 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@781 01035d8c-6547-0410-b346-abe4f91aad63

fdmdv2/src/Makefile.linux
fdmdv2/src/fdmdv2_main.cpp
fdmdv2/src/fdmdv2_main.h
fdmdv2/src/fdmdv2_plot.cpp
fdmdv2/src/fdmdv2_plot_waterfall_linux.cpp [new file with mode: 0644]
fdmdv2/src/fdmdv2_plot_waterfall_linux.h [new file with mode: 0644]

index 96d5318abcc0a5a89b3dbda1e7dc21aeff37d302..75f92a5598d40071495805bde9a363b8b37f3294 100644 (file)
@@ -23,7 +23,7 @@ fdmdv2_plot.o \
 fdmdv2_plot_scalar.o \
 fdmdv2_plot_scatter.o \
 fdmdv2_plot_spectrum.o \
-fdmdv2_plot_waterfall.o \
+fdmdv2_plot_waterfall_linux.o \
 fdmdv2_pa_wrapper.o \
 dlg_about.o \
 dlg_audio.o \
index 9634ec4690990dcff4a8ca1074134da4b9d87243..0ca6a000b14a4347341a91339b14aeb790a5da74 100644 (file)
@@ -244,8 +244,8 @@ void MainFrame::OnTimer(wxTimerEvent &evt)
 {
     m_panelWaterfall->m_newdata = true;
     m_panelWaterfall->Refresh();
-    m_panelSpectrum->m_newdata = true;
-    m_panelSpectrum->Refresh();
+    //m_panelSpectrum->m_newdata = true;
+    //m_panelSpectrum->Refresh();
 }
 #endif
 
index f269f71a719dc9262b6ccd5f03ff57137c8c0f5b..117970f4bc1f87f291b63fe8017f007f4518867d 100644 (file)
 #include "fdmdv2_plot.h"
 #include "fdmdv2_plot_scalar.h"
 #include "fdmdv2_plot_scatter.h"
+#ifdef __LINUX__
+#include "fdmdv2_plot_waterfall_linux.h"
+#else
 #include "fdmdv2_plot_waterfall.h"
+#endif
 #include "fdmdv2_plot_spectrum.h"
 #include "fdmdv2_pa_wrapper.h"
 #include "sndfile.h"
index 5406394b918550c0c0d471701bb997486b6f2906..1dc1b3ba2c931a3d4cd6bfa53d6222b203276601 100644 (file)
@@ -106,10 +106,12 @@ void PlotPanel::OnErase(wxEraseEvent& event)
 //-------------------------------------------------------------------------
 void PlotPanel::OnSize(wxSizeEvent& event)
 {
+    printf("PlotPanel::OnSize\n");
     m_rCtrlPrev = m_rCtrl;
     m_rCtrl     = GetClientRect();
     if(m_use_bitmap)
     {
+       printf("  m_use_bitmap\n");
         if(!m_oImage.IsOk())
         {
             m_oImage.Create(m_rCtrl.GetWidth(), m_rCtrl.GetHeight(), true);
@@ -119,6 +121,10 @@ void PlotPanel::OnSize(wxSizeEvent& event)
             m_oImage.Rescale(m_rCtrl.GetWidth(), m_rCtrl.GetHeight());
         }
         m_pBmp = new wxBitmap(m_oImage, wxBITMAP_SCREEN_DEPTH);
+        //m_pBmp = new wxBitmap(m_rCtrl.GetWidth(), m_rCtrl.GetHeight(), 24);
+       
+       printf("  create bitmap m_pBmp 0x%x width: %d height: %d\n", 
+              (unsigned int)m_pBmp, m_rCtrl.GetWidth(), m_rCtrl.GetHeight());
         m_firstPass = true;
     }
     this->Refresh();
diff --git a/fdmdv2/src/fdmdv2_plot_waterfall_linux.cpp b/fdmdv2/src/fdmdv2_plot_waterfall_linux.cpp
new file mode 100644 (file)
index 0000000..8b01e5d
--- /dev/null
@@ -0,0 +1,474 @@
+//==========================================================================
+// Name:            fdmdv2_plot_waterfall.cpp
+// Purpose:         Implements a waterfall plot derivative of fdmdv2_plot.
+// Created:         June 22, 2012
+// Initial author:  David Witten
+// Derived from:    code written by David Rowe
+// License:
+//
+//  Copyright (C) 2012 David Witten
+//
+//  All rights reserved.
+//
+//  This program is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU Lesser General Public License version 2.1,
+//  as published by the Free Software Foundation.  This program is
+//  distributed in the hope that it will be useful, but WITHOUT ANY
+//  WARRANTY; without even the implied warranty of MERCHANTABILITY or
+//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+//  License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public License
+//  along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+#include <string.h>
+#include "wx/wx.h"
+#include "fdmdv2_main.h"
+#include "fdmdv2_plot_waterfall_linux.h"
+
+/*
+
+  Notes:
+
+  The height h() pixels represents WATERFALL_SECS_Y of data.  Every DT
+  seconds we get a vector of FDMDV_NSPEC spectrum samples which we use
+  to update the last row.  The height of each row is dy pixels, which
+  maps to DT seconds.  We call each dy high rectangle of pixels a
+  block.
+
+*/
+
+extern float g_avmag[];
+
+BEGIN_EVENT_TABLE(PlotWaterfall, PlotPanel)
+    EVT_PAINT           (PlotWaterfall::OnPaint)
+    EVT_MOTION          (PlotWaterfall::OnMouseMove)
+    EVT_LEFT_DOWN       (PlotWaterfall::OnMouseDown)
+    EVT_LEFT_UP         (PlotWaterfall::OnMouseUp)
+    EVT_MOUSEWHEEL      (PlotWaterfall::OnMouseWheelMoved)
+    EVT_SIZE            (PlotWaterfall::OnSize)
+    EVT_SHOW            (PlotWaterfall::OnShow)
+//    EVT_ERASE_BACKGROUND(PlotWaterfall::OnErase)
+END_EVENT_TABLE()
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// Class WaterfallPlot
+//
+// @class   WaterfallPlot
+// @author  David Witten
+// @date    $(Date)
+// @file    $(CurrentFileName).$(CurrentFileExt)
+// @brief
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+PlotWaterfall::PlotWaterfall(wxFrame* parent): PlotPanel(parent)
+{
+
+    for(int i = 0; i < 255; i++)
+    {
+        m_heatmap_lut[i] = heatmap((float)i, 0.0, 255.0);
+    }
+    m_greyscale     = 0;
+    m_Bufsz         = GetMaxClientSize();
+    m_newdata       = false;
+    m_firstPass     = true;
+    m_line_color    = 0;
+    SetLabelSize(10.0);
+}
+
+void PlotWaterfall::InitBitmap(int xsize, int ysize)
+    {
+        // draw some colourful stripes without alpha
+       //printf("m_pBitmap 0x%x\n", (unsigned int)m_pBitmap);
+        wxNativePixelData data(*m_pBitmap);
+        if ( !data )
+        {
+            wxLogError(wxT("InitBitmap: Failed to gain raw access to bitmap data"));
+            return;
+        }
+
+        wxNativePixelData::Iterator p(data);
+        for ( int y = 0; y < ysize; ++y )
+        {
+            wxNativePixelData::Iterator rowStart = p;
+
+            int r = y < ysize/3 ? 255 : 0,
+                g = (ysize/3 <= y) && (y < 2*(ysize/3)) ? 255 : 0,
+                b = 2*(ysize/3) <= y ? 255 : 0;
+
+            for ( int x = 0; x < xsize; ++x )
+            {
+                p.Red() = r;
+                p.Green() = g;
+                p.Blue() = b;
+                ++p; // same as p.OffsetX(1)
+            }
+
+            p = rowStart;
+            p.OffsetY(data, 1);
+        }
+    }
+
+//----------------------------------------------------------------
+// paintEvent()
+//
+// @class $(Name)
+// @author $(User)
+// @date $(Date)
+// @file $(CurrentFileName).$(CurrentFileExt)
+// @brief
+//
+// Called by the system of by wxWidgets when the panel needs
+// to be redrawn. You can also trigger this call by calling
+// Refresh()/Update().
+//----------------------------------------------------------------
+void PlotWaterfall::OnPaint(wxPaintEvent & evt)
+{
+    printf("OnPaint\n");
+    wxAutoBufferedPaintDC pdc(this);
+    draw(pdc);
+}
+
+//----------------------------------------------------------------
+// OnShow()
+//----------------------------------------------------------------
+void PlotWaterfall::OnShow(wxShowEvent& event)
+{
+}
+
+//----------------------------------------------------------------
+// ~PlotWaterfall()
+//----------------------------------------------------------------
+PlotWaterfall::~PlotWaterfall()
+{
+}
+
+//----------------------------------------------------------------
+// heatmap()
+// map val to a rgb colour
+// from http://eddiema.ca/2011/01/21/c-sharp-heatmaps/
+//----------------------------------------------------------------
+unsigned PlotWaterfall::heatmap(float val, float min, float max)
+{
+    unsigned r = 0;
+    unsigned g = 0;
+    unsigned b = 0;
+
+    val = (val - min) / (max - min);
+    if(val <= 0.2)
+    {
+        b = (unsigned)((val / 0.2) * 255);
+    }
+    else if(val >  0.2 &&  val <= 0.7)
+    {
+        b = (unsigned)((1.0 - ((val - 0.2) / 0.5)) * 255);
+    }
+    if(val >= 0.2 &&  val <= 0.6)
+    {
+        g = (unsigned)(((val - 0.2) / 0.4) * 255);
+    }
+    else if(val >  0.6 &&  val <= 0.9)
+    {
+        g = (unsigned)((1.0 - ((val - 0.6) / 0.3)) * 255);
+    }
+    if(val >= 0.5)
+    {
+        r = (unsigned)(((val - 0.5) / 0.5) * 255);
+    }
+    //printf("%f %x %x %x\n", val, r, g, b);
+    return  (b << 16) + (g << 8) + r;
+}
+
+#define PLOT_BOTTOM     0
+#define PLOT_TOP        1
+
+//static long paint_count;
+
+//----------------------------------------------------------------
+// draw()
+//----------------------------------------------------------------
+void PlotWaterfall::draw(wxAutoBufferedPaintDC& pDC)
+{
+    printf("  draw m_pBmp 0x%x\n", (unsigned int)m_pBmp);
+
+    //m_pBitmap = new wxBitmap(SIZE, SIZE, 24);
+    
+    { 
+       wxRect m_rCtrl  = GetClientRect();
+       printf("%d %d\n", m_rCtrl.GetWidth(), m_rCtrl.GetHeight());
+       m_pBitmap = new wxBitmap(m_rCtrl.GetWidth(), m_rCtrl.GetHeight(), 24);
+       InitBitmap(m_rCtrl.GetWidth(), m_rCtrl.GetHeight());
+   }
+    
+    printf("m_pBitmap 0x%x\n", (unsigned int)m_pBitmap);
+
+    wxMemoryDC m_mDC;
+    m_mDC.SelectObject(*m_pBmp);
+    m_rCtrl  = GetClientRect();
+    m_rGrid  = m_rCtrl;
+
+    m_rGrid = m_rGrid.Deflate(PLOT_BORDER + (XLEFT_OFFSET/2), (PLOT_BORDER + (YBOTTOM_OFFSET/2)));
+    m_rGrid.Offset(PLOT_BORDER + XLEFT_OFFSET, PLOT_BORDER);
+
+    pDC.Clear();
+//    m_mDC.Clear();
+    m_rPlot = wxRect(PLOT_BORDER + XLEFT_OFFSET, PLOT_BORDER, m_rGrid.GetWidth(), m_rGrid.GetHeight());
+//    if(m_firstPass)
+//    {
+//        m_firstPass = false;
+//        m_mDC.FloodFill(0, 0, VERY_LTGREY_COLOR);
+
+        // Draw a filled rectangle with aborder
+//        wxBrush ltGraphBkgBrush = wxBrush(DARK_BLUE_COLOR);
+//        m_mDC.SetBrush(ltGraphBkgBrush);
+//        m_mDC.SetPen(wxPen(BLACK_COLOR, 0));
+//        m_mDC.DrawRectangle(m_rPlot);
+
+//    }
+    wxBrush ltGraphBkgBrush = wxBrush(DARK_BLUE_COLOR);
+    pDC.SetBrush(ltGraphBkgBrush);
+    pDC.SetPen(wxPen(BLACK_COLOR, 0));
+    pDC.DrawRectangle(m_rPlot);
+    drawGraticule(pDC);
+
+    if(m_newdata)
+    {
+       printf("  m_newdata\n");
+        m_newdata = false;
+        //plotPixelData(pDC);
+//#ifdef _USE_TIMER
+        int t = m_rPlot.GetTop();
+        int l = m_rPlot.GetLeft();
+        int h = m_rPlot.GetHeight();
+        int w = m_rPlot.GetWidth();
+        int t2 = t + 1;
+        int w2 = w - 1;
+        int ht = (h - DATA_LINE_HEIGHT);
+
+       printf("t %d l %d h %d w %d t2 %d w2 %d ht %d\n", t,l,h,w,t2,w2,ht);
+        drawData();     //  m_mDC, PLOT_BOTTOM);
+       pDC.DrawLine(0,0,100,100);
+       pDC.DrawBitmap( *m_pBitmap, 0, 0/*SIZE+5+pDC.GetCharHeight()*/);
+       //pDC.DrawBitmap(*m_pBmp, 0, 0, true);
+       pDC.DrawLine(200,200,0,200);
+        //m_mDC.StretchBlit(l, t2, w2, ht, &m_mDC, l, t2 + DATA_LINE_HEIGHT, w2, ht - 2);
+        //pDC.Blit(l, t, w, h, &m_mDC, l, t);                                                   // Scroll Up from Bottom
+//        pDC.StretchBlit(l, (h - t) + 4, w, (-h) + 4, &m_mDC, l, t, w, h);                       // Scroll Down from top
+//        pDC.StretchBlit(l, (h - t) + 4, w, h - 4, &m_mDC, l, t, w, h);                       // Scroll Down from top
+//#endif
+#ifdef TMP
+#endif
+        //drawGraticule(pDC);
+    }
+    m_mDC.SetBrush(wxNullBrush);
+    m_mDC.SelectObject(wxNullBitmap);
+
+    delete m_pBitmap;
+}
+
+//-------------------------------------------------------------------------
+// drawData()
+//-------------------------------------------------------------------------
+void PlotWaterfall::drawData()  //wxMemoryDC&  pDC)
+{
+    int w = m_rPlot.GetWidth();
+    int h = m_rPlot.GetHeight();
+    printf("  drawData w = %d h = %d\n", w, h);
+    wxNativePixelData data(*m_pBmp);
+    if ( !data )
+        {
+            wxLogError(wxT("Failed to gain raw access to bitmap data"));
+            return;
+        }
+
+    wxNativePixelData::Iterator p(data);
+    p.Offset(data, 100, 100);
+    for ( int y = 0; y < 20; ++y )
+        {
+            wxNativePixelData::Iterator rowStart = p;
+
+            int r = y < h/3 ? 255 : 0,
+                g = (h/3 <= y) && (y < 2*(h/3)) ? 255 : 0,
+                b = 2*(h/3) <= y ? 255 : 0;
+           r=g=b=128;
+
+            for ( int x = 0; x < 20; ++x )
+               {
+                   p.Red() = r;
+                   p.Green() = g;
+                   p.Blue() = b;
+                   //printf("%d %d %d\n", r, g, b);
+                   ++p; // same as p.OffsetX(1)
+               }
+
+            p = rowStart;
+            p.OffsetY(data, 1);
+        }
+
+#ifdef PREV
+    wxNativePixelData dPix = wxNativePixelData(*m_pBmp, m_rCtrl);
+    m_pPix = &dPix;
+    if(m_pPix == NULL)
+    {
+        return;
+    }
+    wxNativePixelData::Iterator p(*m_pPix);
+
+    int w = m_rPlot.GetWidth();
+    int h = m_rPlot.GetHeight();
+    p.Offset(*m_pPix, XLEFT_OFFSET + 3, h - (DATA_LINE_HEIGHT - 2));
+    for(int y = 0; y < DATA_LINE_HEIGHT; ++y)
+    {
+        wxNativePixelData::Iterator rowStart = p;
+        for(int x = 0; x < (w - 1); ++x, ++p)
+        {
+//            p.Red()     = m_pTopFrame->m_rxPa->m_av_mag[x];
+//            p.Green()   = m_pTopFrame->m_rxPa->m_av_mag[x];
+//            p.Blue()    = m_pTopFrame->m_rxPa->m_av_mag[x];
+/*
+
+           p.Red()     = g_avmag[x];
+            p.Green()   = g_avmag[x];
+            p.Blue()    = g_avmag[x];
+*/
+           p.Red()     = 0;
+            p.Green()   = 0;
+            p.Blue()    = 255;
+        }
+        p = rowStart;
+        p.OffsetY(*m_pPix, 1);
+    }
+#endif
+}
+
+//-------------------------------------------------------------------------
+// drawGraticule()
+//-------------------------------------------------------------------------
+void PlotWaterfall::drawGraticule(wxAutoBufferedPaintDC&  pDC)
+{
+    int p;
+    char buf[15];
+
+    wxString s;
+
+    wxBrush ltGraphBkgBrush;
+    ltGraphBkgBrush.SetStyle(wxBRUSHSTYLE_TRANSPARENT);
+    ltGraphBkgBrush.SetColour(*wxBLACK);
+    pDC.SetBrush(ltGraphBkgBrush);
+    pDC.SetPen(wxPen(BLACK_COLOR, 1));
+
+    // Vertical gridlines
+    pDC.SetPen(m_penShortDash);
+    for(p = (PLOT_BORDER + XLEFT_OFFSET + GRID_INCREMENT); p < ((m_rGrid.GetWidth() - XLEFT_OFFSET) + GRID_INCREMENT); p += GRID_INCREMENT)
+    {
+        pDC.DrawLine(p, (m_rGrid.GetHeight() + PLOT_BORDER), p, PLOT_BORDER);
+    }
+    // Horizontal gridlines
+    pDC.SetPen(m_penDotDash);
+    for(p = (m_rGrid.GetHeight() - GRID_INCREMENT); p > PLOT_BORDER; p -= GRID_INCREMENT)
+    {
+        pDC.DrawLine(PLOT_BORDER + XLEFT_OFFSET, (p + PLOT_BORDER), (m_rGrid.GetWidth() + PLOT_BORDER + XLEFT_OFFSET), (p + PLOT_BORDER));
+    }
+    // Label the X-Axis
+    pDC.SetPen(wxPen(GREY_COLOR, 1));
+    for(p = GRID_INCREMENT; p < (m_rGrid.GetWidth() - YBOTTOM_OFFSET); p += GRID_INCREMENT)
+    {
+        sprintf(buf, "%1.1f Hz",(double)(p / 10));
+        pDC.DrawText(buf, p - PLOT_BORDER + XLEFT_OFFSET, m_rGrid.GetHeight() + YBOTTOM_OFFSET/3);
+    }
+    // Label the Y-Axis
+    for(p = (m_rGrid.GetHeight() - GRID_INCREMENT); p > PLOT_BORDER; p -= GRID_INCREMENT)
+    {
+        sprintf(buf, "%1.0f", (double)((m_rGrid.GetHeight() - p) * 10));
+        pDC.DrawText(buf, XLEFT_TEXT_OFFSET, p);
+    }
+}
+
+//-------------------------------------------------------------------------
+// plotPixelData()
+//-------------------------------------------------------------------------
+void PlotWaterfall::plotPixelData(wxAutoBufferedPaintDC&  dc)
+{
+    float       spec_index_per_px;
+    float       intensity_per_dB;
+    int         px_per_sec;
+    int         index;
+    int         dy;
+    int         dy_blocks;
+    int         bytes_in_row_of_blocks;
+    int         b;
+    int         px;
+    int         py;
+    int         intensity;
+    unsigned    *last_row;
+    unsigned    *pdest;
+    unsigned    *psrc;
+
+    // determine dy, the height of one "block"
+    px_per_sec = (float)m_rCtrl.GetHeight() / WATERFALL_SECS_Y;
+    dy = DT * px_per_sec;
+    // number of dy high blocks in spectrogram
+    dy_blocks = m_rCtrl.GetHeight()/ dy;
+    // shift previous bit map
+    bytes_in_row_of_blocks = dy * m_rCtrl.GetWidth() * sizeof(unsigned);
+    for(b = 0; b < dy_blocks - 1; b++)
+    {
+        pdest = (unsigned int *)m_pBmp + b * m_rCtrl.GetWidth() * dy;
+        psrc  = (unsigned int *)m_pBmp + (b + 1) * m_rCtrl.GetWidth() * dy;
+        memcpy(pdest, psrc, bytes_in_row_of_blocks);
+    }
+    // create a new row of blocks at bottom
+    spec_index_per_px = (float)FDMDV_NSPEC / (float) m_rCtrl.GetWidth();
+    intensity_per_dB  = (float)256 /(MAX_DB - MIN_DB);
+    last_row = (unsigned int *)m_pBmp + dy *(dy_blocks - 1)* m_rCtrl.GetWidth();
+
+    wxNativePixelData data(*m_pBmp);
+    if(!data)
+    {
+        wxMessageBox(wxT("Unable to access Bitmap Data"), wxT("Error"));
+        return;
+    }
+    if(data.GetWidth() < 20 || data.GetHeight() < 20)
+    {
+        wxMessageBox(wxT("Bitmap is too small to use"), wxT("Warning"));
+        return;
+    }
+    wxNativePixelData::Iterator p(data);
+    // we draw a (10, 10)-(20, 20) rect manually using the given r, g, b
+    p.Offset(data, 10, 10);
+    for(px = 0; px < m_rCtrl.GetWidth(); px++)
+    {
+        index = px * spec_index_per_px;
+        // intensity = intensity_per_dB * (m_av_mag[index] - MIN_DB);
+        intensity = intensity_per_dB * (g_avmag[index] - MIN_DB);
+//        intensity = intensity_per_dB * (((MainFrame *)GetParent())->m_rxPa->m_av_mag[index] - MIN_DB);
+//        intensity = intensity_per_dB * (((MainFrame *)GetParent())->m_av_mag[index] - MIN_DB);
+        if(intensity > 255)
+        {
+            intensity = 255;
+        }
+        if(intensity > 255)
+        {
+            intensity = 255;
+        }
+        if (intensity < 0)
+        {
+            intensity = 0;
+        }
+        if(m_greyscale)
+        {
+            for(py = 0; py < dy; py++)
+            {
+                last_row[px + py * m_rCtrl.GetWidth()] = intensity << 8;
+            }
+        }
+        else
+        {
+            for(py = 0; py < dy; py++)
+            {
+                last_row[px + py * m_rCtrl.GetWidth()] = m_heatmap_lut[intensity];
+            }
+        }
+    }
+}
diff --git a/fdmdv2/src/fdmdv2_plot_waterfall_linux.h b/fdmdv2/src/fdmdv2_plot_waterfall_linux.h
new file mode 100644 (file)
index 0000000..2c01797
--- /dev/null
@@ -0,0 +1,75 @@
+//==========================================================================
+// Name:            fdmdv2_plot_waterfall.h
+// Purpose:         Defines a waterfall plot derivative of fdmdv2_plot.
+// Created:         June 22, 2012
+// Initial author:  David Witten
+// Derived from:    code written by David Rowe
+// License:
+//
+//  Copyright (C) 2012 David Witten
+//
+//  All rights reserved.
+//
+//  This program is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU Lesser General Public License version 2.1,
+//  as published by the Free Software Foundation.  This program is
+//  distributed in the hope that it will be useful, but WITHOUT ANY
+//  WARRANTY; without even the implied warranty of MERCHANTABILITY or
+//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+//  License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public License
+//  along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+#ifndef __FDMDV2_PLOT_WATERFALL__
+#define __FDMDV2_PLOT_WATERFALL__
+
+#include "fdmdv2_plot.h"
+#include "fdmdv2_defines.h"
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// Class PlotWaterfall
+//
+// @class $(Name)
+// @author $(User)
+// @date $(Date)
+// @file $(CurrentFileName).$(CurrentFileExt)
+// @brief
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+class PlotWaterfall : public PlotPanel
+{
+    public:
+        PlotWaterfall(wxFrame* parent);
+        ~PlotWaterfall();
+//        bool                m_newdata;
+
+    enum
+    {
+        BORDER = 15,
+        SIZE = 150,
+        REAL_SIZE = SIZE - 2*BORDER
+    };
+    protected:
+    //    unsigned    *m_pixel_buf;
+        unsigned    m_heatmap_lut[256];
+        wxMemoryDC  m_mDC;
+        wxBitmap   *m_pBitmap;
+
+        unsigned    heatmap(float val, float min, float max);
+
+       void        InitBitmap(int xsize, int ysize);
+        void        OnPaint(wxPaintEvent & evt);
+        //void        OnSize(wxSizeEvent& event);
+        void        OnShow(wxShowEvent& event);
+        void        drawGraticule(wxAutoBufferedPaintDC&  dc);
+        void        draw(wxAutoBufferedPaintDC& pdc);
+        void        plotPixelData(wxAutoBufferedPaintDC&  dc);
+        void        drawData();     // wxMemoryDC&  pDC);
+        void        drawData2(wxMemoryDC&  pDC, int barpos, int l, int t, int w, int h);
+
+        DECLARE_EVENT_TABLE()
+};
+
+#endif //__FDMDV2_PLOT_WATERFALL__