#ifdef ENABLE_GL

// subtitleeditor -- a tool to create or edit subtitle
//
// https://kitone.github.io/subtitleeditor/
// https://github.com/kitone/subtitleeditor/
//
// Copyright @ 2005-2018, kitone
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// 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 General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

#include <GL/gl.h>
#include <gtkglmm.h>

#include "document.h"
#include "keyframes.h"
#include "player.h"
#include "subtitleeditorwindow.h"
#include "utility.h"
#include "waveformrenderer.h"

#define FONT_SIZE 256

// OpenGL Waveform renderer
class WaveformRendererGL : public Gtk::GL::DrawingArea,
                           public WaveformRenderer {
 public:
  WaveformRendererGL();

  ~WaveformRendererGL();

  // Return the widget attached to the renderer.
  Gtk::Widget *widget();

  // Create GdkGLConfig (RGB | DEPTH | DOUBLE | STENCIL)
  Glib::RefPtr<Gdk::GL::Config> create_glconfig();

  // Try to create OpenGL font (with support of display list)
  bool create_gl_font(const Glib::ustring &font_desc);

  // Use pango to get the size of the text (pixel)
  int get_text_width(const Glib::ustring &text);

  // Use the Raster Position to display text
  void draw_text(float x, float y, const Glib::ustring &text);

  // Generate font
  void on_realize();

  // Just redisplay with redraw_all
  bool on_configure_event(GdkEventConfigure *ev);

  // Expose widget
  // Clear buffer
  // Draw timeline, channels and markers
  // Swap Buffer
  bool on_expose_event(GdkEventExpose *ev);

  // Display all scene:
  // - timeline (draw_timeline)
  // - waveform (draw_waveform)
  // - subtitle (draw_subtitles)
  // - time info (display_time_info)
  void draw(GdkEventExpose *ev);

  // Draw the left and the right marker of the subtitle selected.
  void draw_marker(const Gdk::Rectangle &rect);

  // Draw subtitles visible
  void draw_subtitles(const Gdk::Rectangle &rect);

  // Draw the text of the subtitles visible
  void draw_subtitles_text(const Gdk::Rectangle &rect);

  // Draw the channel in the area with the lines methods
  void draw_channel_with_line_strip(const Gdk::Rectangle &area, int channel);

  // Draw the channel in the area with the quad methods
  void draw_channel_with_quad_strip(const Gdk::Rectangle &area, int channel);

  // Display all of timeline: Time, seconds
  void draw_timeline(const Gdk::Rectangle &area);

  // Display the time every X seconds ("msec") with "upper" height
  void draw_timeline_msecs(const Gdk::Rectangle &area, long msec, int upper);

  // Display the time text every X seconds (msec)
  void draw_timeline_time(const Gdk::Rectangle &area, long msec);

  // Display the time of the mouse
  // and the duration of the selected subtitle
  void display_time_info(const Gdk::Rectangle &area);

  // Draw the keyframes position.
  void draw_keyframes(const Gdk::Rectangle &area);

  // Delete the OpenGL Display List (Waveform)
  void delete_display_lists();

  // The Waveform used a display list for optimize the render.
  // If the OpenGL display list (waveform) is not yet create:
  // - Create the display list and draw the waveform inside.
  // Call the display list for drawing the waveform.
  void draw_waveform(const Gdk::Rectangle &rect);

  // The waveform is changed.
  // Need to force to redisplay the waveform.
  // Delete the display list
  void waveform_changed();

  // The keyframe is changed.
  // Need to redisplay the waveform.
  void keyframes_changed();

  // Call queue_draw
  void redraw_all();

  // Delete display list and redraw
  void force_redraw_all();

 protected:
  Pango::FontDescription m_fontDescription;
  GLuint m_fontListBase;
  int m_fontHeight;

  // waveform
  Gdk::Rectangle m_displayListRect;
  GLuint m_displayList;
  GLsizei m_displayListSize;
};

// Constructor
WaveformRendererGL::WaveformRendererGL()
    : WaveformRenderer(),
      m_fontListBase(0),
      m_fontHeight(0),
      m_displayList(0),
      m_displayListSize(0) {
  Glib::RefPtr<Gdk::GL::Config> glconfig = create_glconfig();
  if (glconfig)
    set_gl_capability(glconfig);
}

WaveformRendererGL::~WaveformRendererGL() {
  // Display lists are deleted with the opengl context
}

// Return the widget attached to the renderer.
Gtk::Widget *WaveformRendererGL::widget() {
  return this;
}

// Create GdkGLConfig (RGB | DEPTH | DOUBLE | STENCIL)
Glib::RefPtr<Gdk::GL::Config> WaveformRendererGL::create_glconfig() {
  Glib::RefPtr<Gdk::GL::Config> glconfig;

  glconfig = Gdk::GL::Config::create(
      Gdk::GL::MODE_RGB | Gdk::GL::MODE_DEPTH | Gdk::GL::MODE_DOUBLE |
      Gdk::GL::MODE_STENCIL /* | Gdk::GL::MODE_MULTISAMPLE*/);
  if (!glconfig) {
    std::cerr << "Gtk::GL::Config Failed To create double-buffered visual."
              << std::endl;

    glconfig = Gdk::GL::Config::create(Gdk::GL::MODE_RGB | Gdk::GL::MODE_DEPTH |
                                       Gdk::GL::MODE_STENCIL);
    if (!glconfig) {
      std::cerr << "Gtk::GL::Config Failed To create single-buffered visual."
                << std::endl;
      std::cerr << "Used another Waveform Renderer" << std::endl;

      return Glib::RefPtr<Gdk::GL::Config>(NULL);
    }
  }

  return glconfig;
}

// Try to create OpenGL font (with display list)
bool WaveformRendererGL::create_gl_font(const Glib::ustring &font_desc_str) {
  if (m_fontListBase > 0) {
    // destroy font list
    glDeleteLists(m_fontListBase, FONT_SIZE);
    m_fontListBase = 0;
    m_fontHeight = 0;
    m_fontDescription = Pango::FontDescription();
  }

  // OpenGL list
  m_fontListBase = glGenLists(FONT_SIZE);

  Pango::FontDescription font_desc(font_desc_str);

  Glib::RefPtr<Pango::Font> font =
      Gdk::GL::Font::use_pango_font(font_desc, 0, FONT_SIZE, m_fontListBase);
  if (!font) {
    std::cerr << "*** Can't load font :" << font_desc_str << std::endl;

    glDeleteLists(m_fontListBase, FONT_SIZE);
    return false;
  }

  Pango::FontMetrics font_metrics = font->get_metrics();

  m_fontHeight = font_metrics.get_ascent() + font_metrics.get_descent();
  m_fontHeight = PANGO_PIXELS(m_fontHeight);

  m_fontDescription = font_desc;

  return true;
}

// Use pango to get the size of the text (pixel)
int WaveformRendererGL::get_text_width(const Glib::ustring &text) {
  Glib::RefPtr<Pango::Layout> layout = create_pango_layout(text);
  if (layout) {
    int text_width = 0, text_height = 0;

    layout->set_font_description(m_fontDescription);
    layout->get_pixel_size(text_width, text_height);

    return text_width;
  }
  return 0;
}

// Use the Raster Position to display text
void WaveformRendererGL::draw_text(float x, float y,
                                   const Glib::ustring &text) {
  glRasterPos2f(x, y);

  glListBase(m_fontListBase);
  glCallLists(text.length(), GL_UNSIGNED_BYTE, text.c_str());
}

// Generate OpenGL font
void WaveformRendererGL::on_realize() {
  Gtk::DrawingArea::on_realize();

  if (!is_gl_capable())
    return;

  Glib::RefPtr<Gdk::GL::Window> gl = get_gl_window();

  if (!gl->gl_begin(get_gl_context()))
    return;

  if (!create_gl_font("courier bold 10")) {
    create_gl_font(get_pango_context()->get_font_description().to_string());
  }

  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glEnable(GL_LINE_SMOOTH);
  glEnable(GL_MULTISAMPLE);

  gl->gl_end();
}

// Just redisplay with redraw_all
bool WaveformRendererGL::on_configure_event(GdkEventConfigure *ev) {
  Gtk::DrawingArea::on_configure_event(ev);

  redraw_all();

  // return false IMPORTANT!!!
  return false;
}

// Expose widget
// Clear buffer
// Draw timeline, channels and markers
// Swap Buffer
bool WaveformRendererGL::on_expose_event(GdkEventExpose *ev) {
  static Glib::Timer m_timer;

  // check minimum size
  if (get_width() < 20 || get_height() < 10)
    return false;

  if (se_dbg_check_flags(SE_DBG_WAVEFORM))
    m_timer.start();

  // If window system doesn't support OpenGL
  // display in the area a message
  if (!is_gl_capable()) {
    Glib::ustring error_msg(
        _("Window system doesn't support OpenGL.\n"
          "Please try with another renderer."));

    Glib::RefPtr<Pango::Layout> layout = create_pango_layout(error_msg);

    layout->set_alignment(Pango::ALIGN_CENTER);

    Pango::FontDescription desc = get_pango_context()->get_font_description();
    desc.set_weight(Pango::WEIGHT_BOLD);
    layout->set_font_description(desc);

    // display the message at the center
    int x, y, w, h;
    layout->get_pixel_size(w, h);

    x = (get_width() - w) / 2;
    y = (get_height() - h) / 2;

    get_window()->draw_layout(get_style()->get_black_gc(), x, y, layout);

    return true;
  }

  Glib::RefPtr<Gdk::GL::Window> gl = get_gl_window();

  if (!gl->gl_begin(get_gl_context()))
    return false;

  glClearColor(m_color_background[0], m_color_background[1],
               m_color_background[2], m_color_background[3]);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

  glClearStencil(0);
  glStencilMask(1);

  // Reshape
  int width = get_width();
  int height = get_height();

  glViewport(0, 0, width, height);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  glOrtho(0, width, 0, height, -10, 10);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

  // Display Scene
  if (m_waveform && is_sensitive()) {
    draw(ev);

    if (se_dbg_check_flags(SE_DBG_WAVEFORM)) {
      double seconds = m_timer.elapsed();
      m_timer.reset();

      Glib::ustring fps =
          build_message("%d frames in %f seconds = %.3f FPS", 1, seconds,
                        static_cast<float>(1 / seconds));

      glColor4fv(m_color_text);
      draw_text(10, 10, fps);
    }
  }

  // Swap Buffer
  if (gl->is_double_buffered())
    gl->swap_buffers();
  else
    glFlush();

  gl->gl_end();
  return true;
}

// Display all scene:
// - timeline (draw_timeline)
// - waveform (draw_waveform)
// - subtitle (draw_subtitles)
// - time info (display_time_info)
void WaveformRendererGL::draw(GdkEventExpose *ev) {
  Gdk::Rectangle timeline_area(0, 0, get_width(), 30);
  Gdk::Rectangle waveform_area(0, 0, get_width(), get_height() - 30);

  // waveform
  glPushMatrix();
  draw_waveform(waveform_area);
  glPopMatrix();

  if (document()) {
    glEnable(GL_BLEND);

    draw_subtitles(waveform_area);

    glDisable(GL_BLEND);

    // draw_subtitles_text(waveform_area);

    draw_marker(waveform_area);
  }

  // time line
  glPushMatrix();
  glTranslatef(-get_start_area(), get_height() - timeline_area.get_height(), 0);
  draw_timeline(timeline_area);
  glPopMatrix();

  // FIXME: test it
  // keyframes
  // draw_keyframes(waveform_area);

  // player position
  {
    glColor4fv(m_color_player_position);

    int player_position = get_pos_by_time(player_time());

    glPushMatrix();
    glTranslatef(-get_start_area(), 0, 0);
    glBegin(GL_LINES);
    glVertex2f(player_position, 0);
    glVertex2f(player_position, waveform_area.get_height());
    glEnd();
    glPopMatrix();
  }

  if (document() && m_display_time_info)
    display_time_info(waveform_area);
}

// Draw the channel in the area with the lines methods
void WaveformRendererGL::draw_channel_with_line_strip(
    const Gdk::Rectangle &area, int channel) {
  if (!m_waveform)
    return;

  std::vector<double> &peaks = m_waveform->m_channels[channel];

  float skip = static_cast<float>(area.get_width()) / peaks.size();

  float px = 0;

  glColor4fv(m_color_wave_fill);

  glBegin(GL_LINE_STRIP);

  for (const auto it = peaks.begin(); it != peaks.end(); ++it, px += skip)
    glVertex2d(px, *it);

  glEnd();
}

// Draw the channel in the area with the lines methods
void WaveformRendererGL::draw_channel_with_quad_strip(
    const Gdk::Rectangle &area, int channel) {
  if (!m_waveform)
    return;

  std::vector<double> &peaks = m_waveform->m_channels[channel];

  float skip = static_cast<float>(area.get_width()) / peaks.size();

  float px = 0;

  glColor4fv(m_color_wave);

  glBegin(GL_QUAD_STRIP);
  for (const auto it it = peaks.begin(); it != peaks.end(); ++it, px += skip) {
    glVertex2d(px, 0);
    glVertex2d(px, *it);
  }
  glEnd();
}

// Delete the OpenGL Display List (Waveform)
void WaveformRendererGL::delete_display_lists() {
  if (m_displayListSize > 0) {
    glDeleteLists(m_displayList, m_displayListSize);

    m_displayList = m_displayListSize = 0;
  }
}

// The Waveform used a display list for optimize the render.
// If the OpenGL display list (waveform) is not yet create:
// - Create the display list and draw the waveform inside.
// Call the display list for drawing the waveform.
void WaveformRendererGL::draw_waveform(const Gdk::Rectangle &rect) {
  if (!m_waveform)
    return;

  unsigned int n_channels = m_waveform->get_n_channels();

  int h = rect.get_height() / n_channels;

  if (m_displayListSize == 0) {
    // display to rectangle 10x10
    // after is scale to the widget area (size + zoom)
    Gdk::Rectangle area(0, 0, 10, 10);
    m_displayListRect = area;

    m_displayListSize = n_channels;

    m_displayList = glGenLists(m_displayListSize);
    for (unsigned int i = 0; i < n_channels; ++i) {
      glNewList(m_displayList + i, GL_COMPILE);

      draw_channel_with_quad_strip(area, i);
      draw_channel_with_line_strip(area, i);

      glEndList();
    }
  }

  glEnable(GL_SCISSOR_TEST);
  glEnable(GL_BLEND);

  float d = m_displayListRect.get_width();
  float r = rect.get_width();

  float s = r / d;

  for (unsigned int i = 0; i < n_channels; ++i) {
    // clamp in waveform area
    glScissor(0, h * i, rect.get_width(), h);

    // position to channel area
    glPushMatrix();
    glTranslatef(-get_start_area(), h * i, 0);
    // apply scale and zoom
    glScalef(s * zoom(), scale() * rect.get_height(), 1);
    // display the channel
    glCallList(m_displayList + i);

    glPopMatrix();
  }
  glDisable(GL_SCISSOR_TEST);
  glDisable(GL_BLEND);
}

// Display all of timeline: Time, seconds
void WaveformRendererGL::draw_timeline(const Gdk::Rectangle &area) {
  long start = 0;
  long end = get_width() * zoom();

  // horizontal line
  glColor4fv(m_color_text);

  glBegin(GL_LINES);
  glVertex2f(start, 0);
  glVertex2f(end, 0);
  glEnd();

  // seconds
  long sec_1 = SubtitleTime(0, 0, 1, 0).totalmsecs;
  long sec_5 = SubtitleTime(0, 0, 5, 0).totalmsecs;
  long sec_10 = SubtitleTime(0, 0, 10, 0).totalmsecs;

  if (get_pos_by_time(sec_1) <= 0)
    return;

  int text_width = get_text_width("0:00:00");

  float margin = text_width + text_width * 0.5;
  while (get_pos_by_time(sec_1) < margin) {
    // for a sufficiently long duration sec_* will overflow before
    // the loop terminates. check the largest of them.
    if (sec_10 > (LONG_MAX / 2))
      break;
    sec_1 *= 2;
    sec_5 *= 2;
    sec_10 *= 2;
  }

  draw_timeline_msecs(area, sec_1, 3);
  draw_timeline_msecs(area, sec_5, 6);
  draw_timeline_msecs(area, sec_10, 10);

  draw_timeline_time(area, sec_1);
}

// Display the time every X seconds ("msec") with "upper" height
void WaveformRendererGL::draw_timeline_msecs(const Gdk::Rectangle &area,
                                             long msec, int upper) {
  long start = 0;
  long end = get_time_by_pos(get_width() * zoom());

  glBegin(GL_LINES);
  for (long t = start; t < end; t += msec) {
    int x = get_pos_by_time(t);

    glVertex2f(x, 0);
    glVertex2f(x, upper);
  }
  glEnd();
}

// Display the time text every X seconds (msec)
void WaveformRendererGL::draw_timeline_time(const Gdk::Rectangle &area,
                                            long msec) {
  int height = area.get_height();

  long start = 0;
  long end = get_time_by_pos(get_width() * zoom());

  // make the list for text
  glListBase(m_fontListBase);

  Glib::ustring text = "0:00:00";

  // center the text
  float middle = get_text_width(text) * 0.5;

  glPushMatrix();
  glTranslatef(-middle, height - 15, 0);

  for (long t = start; t < end; t += msec) {
    int x = get_pos_by_time(t);

    text = SubtitleTime(t).str().substr(0, 7);

    glRasterPos2f(x, 0);
    glCallLists(text.length(), GL_UNSIGNED_BYTE, text.c_str());
  }
  glPopMatrix();
}

// Display the time of the mouse
// and the duration of the selected subtitle
void WaveformRendererGL::display_time_info(const Gdk::Rectangle &area) {
  int text_width = get_text_width(SubtitleTime::null());

  int xpos = 0, ypos = 0;
  Gdk::ModifierType mod;

  get_window()->get_pointer(xpos, ypos, mod);
  // opengl
  ypos = area.get_height() - ypos;

  int xpos_area = get_mouse_coords(xpos);

  // display the time of the mouse in the area
  Glib::ustring time = SubtitleTime(get_time_by_pos(xpos_area)).str();

  glColor4fv(m_color_text);
  draw_text(xpos - text_width * 0.5, ypos, time);

  // display the duration of the current subtitle
  Subtitle selected = document()->subtitles().get_first_selected();
  if (selected) {
    SubtitleTime start = selected.get_start();
    SubtitleTime duration = selected.get_duration();

    int sub_center =
        get_pos_by_time(start.totalmsecs + duration.totalmsecs / 2);

    glColor4fv(m_color_text);
    draw_text(sub_center - get_start_area() - text_width * 0.5,
              ypos - m_fontHeight, duration.str());
  }
}

void WaveformRendererGL::draw_keyframes(const Gdk::Rectangle &rect) {
  Player *player = SubtitleEditorWindow::get_instance()->get_player();
  if (player == NULL)
    return;

  Glib::RefPtr<KeyFrames> keyframes = player->get_keyframes();
  if (!keyframes)
    return;

  int height = rect.get_height();

  glColor4fv(m_color_keyframe);

  long start_clip = get_time_by_pos(get_start_area());
  long end_clip = get_time_by_pos(get_end_area());

  glBegin(GL_LINES);
  for (KeyFrames::const_iterator it = keyframes->begin();
       it != keyframes->end(); ++it) {
    // display only if it's in the area
    if (*it < start_clip && *it < end_clip)
      continue;
    if (*it > end_clip)
      break;  // the next keyframes are out of the area

    long pos = get_pos_by_time(*it);
    glVertex2f(pos, 0);
    glVertex2f(pos, height);
  }
  glEnd();
}

// Draw the left and the right marker of the subtitle selected.
void WaveformRendererGL::draw_marker(const Gdk::Rectangle &rect) {
  Subtitle selected = document()->subtitles().get_first_selected();
  if (!selected)
    return;

  int height = rect.get_height();

  int start =
      get_pos_by_time(selected.get_start().totalmsecs) - get_start_area();
  int end = get_pos_by_time(selected.get_end().totalmsecs) - get_start_area();

  glBegin(GL_LINES);
  // start line
  glColor3f(1, 0, 0);
  glVertex2f(start, 0);
  glVertex2f(start, height);
  // end line
  glColor3f(1, .6, 0);
  glVertex2f(end, 0);
  glVertex2f(end, height);
  glEnd();

  // triangle size (top and bottom)
  int size = 10;

  glBegin(GL_TRIANGLES);

  glColor3f(1, 0, 0);
  // start + bottom
  glVertex2f(start, 0);
  glVertex2f(start, size);
  glVertex2f(start + size, 0);
  // start + top
  glVertex2f(start, height);
  glVertex2f(start + size, height);
  glVertex2f(start, height - size);

  glColor3f(1, .6, 0);
  // end + bottom
  glVertex2f(end, 0);
  glVertex2f(end - size, 0);
  glVertex2f(end, size);
  // end + top
  glVertex2f(end, height);
  glVertex2f(end, height - size);
  glVertex2f(end - size, height);
  glEnd();
}

// Draw subtitles visible
void WaveformRendererGL::draw_subtitles(const Gdk::Rectangle &rect) {
  if (!document())
    return;

  SubtitleTime start_clip(get_time_by_pos(get_start_area()));
  SubtitleTime end_clip(get_time_by_pos(get_end_area()));

  int height = rect.get_height();

  Subtitles subs = document()->subtitles();
  Subtitle selected = subs.get_first_selected();

  glPushMatrix();
  glTranslatef(-get_start_area(), 0, 0);

  if (selected) {
    for (Subtitle sub = subs.get_first(); sub; ++sub) {
      SubtitleTime start = sub.get_start();
      SubtitleTime end = sub.get_end();

      if (start < start_clip && end < start_clip)
        continue;
      if (start > end_clip && end > end_clip)
        break;

      int s = get_pos_by_time(start.totalmsecs);
      int e = get_pos_by_time(end.totalmsecs);

      if (s > e)
        glColor4fv(m_color_subtitle_invalid);
      else if (selected == sub)
        glColor4fv(m_color_subtitle_selected);
      else
        glColor4fv(m_color_subtitle);

      glRectf(s, 0, e, height);
    }
  } else {
    for (Subtitle sub = subs.get_first(); sub; ++sub) {
      SubtitleTime start = sub.get_start();
      SubtitleTime end = sub.get_end();

      if (start < start_clip && end < start_clip)
        continue;
      if (start > end_clip && end > end_clip)
        break;

      int s = get_pos_by_time(start.totalmsecs);
      int e = get_pos_by_time(end.totalmsecs);

      if (s > e)
        glColor4fv(m_color_subtitle_invalid);
      else
        glColor4fv(m_color_subtitle);

      glRectf(s, 0, e, height);
    }
  }
  glPopMatrix();
}

// Draw the text of the subtitles visible
void WaveformRendererGL::draw_subtitles_text(const Gdk::Rectangle &rect) {
  if (!document())
    return;

  SubtitleTime start_clip(get_time_by_pos(get_start_area()));
  SubtitleTime end_clip(get_time_by_pos(get_end_area()));

  float height = rect.get_height() - m_fontHeight * 2;

  Subtitles subs = document()->subtitles();
  Subtitle selected = subs.get_first_selected();

  glPushMatrix();
  glTranslatef(-get_start_area(), 0, 0);

  glColor4fv(m_color_text);
  glListBase(m_fontListBase);

  for (Subtitle sub = subs.get_first(); sub; ++sub) {
    SubtitleTime start = sub.get_start();
    SubtitleTime end = sub.get_end();

    if (start < start_clip && end < start_clip)
      continue;
    if (start > end_clip && end > end_clip)
      break;

    int s = get_pos_by_time(start.totalmsecs);
    // int e = get_pos_by_time(end.totalmsecs);

    glRasterPos2f(s, height);

    std::string text = sub.get_text();
    // glRectf(s, 0, e, height);
    glCallLists(text.length(), GL_UNSIGNED_BYTE, text.c_str());
  }

  glPopMatrix();
}

// The waveform is changed.
// Need to force to redisplay the waveform.
// Delete the display list
void WaveformRendererGL::waveform_changed() {
  delete_display_lists();

  queue_draw();
}

void WaveformRendererGL::keyframes_changed() {
  queue_draw();
}

// Call queue_draw
void WaveformRendererGL::redraw_all() {
  queue_draw();
}

// Delete display list and redraw
void WaveformRendererGL::force_redraw_all() {
  delete_display_lists();

  queue_draw();
}

// HACK!
WaveformRenderer *create_waveform_renderer_gl() {
  return manage(new WaveformRendererGL());
}

#endif  // ENABLE_GL
