#ifdef ENABLE_GL

/*
 *	subtitleeditor -- a tool to create or edit subtitle
 *
 *	https://kitone.github.io/subtitleeditor/
 *	https://github.com/kitone/subtitleeditor/
 *
 *	Copyright @ 2005-2009, 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 "utility.h"
#include "document.h"
#include "waveformrenderer.h"
#include "subtitleeditorwindow.h"
#include "keyframes.h"
#include "player.h"

#include <gtkglmm.h>
#include <GL/gl.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_debug_check_flags(SE_DEBUG_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_debug_check_flags(SE_DEBUG_WAVEFORM))
		{
			double seconds = m_timer.elapsed();
			m_timer.reset();

			Glib::ustring fps = build_message("%d frames in %f seconds = %.3f FPS", 1, seconds, (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);

/*
	// time line
	DisplayArea da = get_display_area(30);

	glEnable(GL_STENCIL_TEST);

	glStencilFunc(GL_ALWAYS, 1, 1);
	glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

	Gdk::Rectangle waveform_area(0, 0, get_width(), get_height() - 30);

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

	// waveform with subtitles are prelight
	glStencilFunc(GL_EQUAL, 1, 1);
	glStencilOp(GL_INCR, GL_KEEP, GL_DECR);

	glColor4fv(m_color_subtitle_selected);
	draw_subtitles(waveform_area);

	
	// rectangle for subtitle
	glStencilFunc(GL_EQUAL, 1, 1);
	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

	glColor3f(0.8,0.8,0.8);
	draw_subtitles(waveform_area);
	

	glDisable(GL_STENCIL_TEST);

	draw_marker(waveform_area);

	// timeline
	glPushMatrix();
		glTranslatef(-get_start_area(), get_height() - 30, 0);
		draw_timeline(da);
	glPopMatrix();
*/
}


/*
 * 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 = (float)(area.get_width()) / peaks.size();

	float px=0;

	glColor4fv(m_color_wave_fill);

	glBegin(GL_LINE_STRIP);

	for(std::vector<double>::const_iterator 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 = (float)(area.get_width()) / peaks.size();

	float px=0;

	glColor4fv(m_color_wave);

	glBegin(GL_QUAD_STRIP);
		for(std::vector<double>::const_iterator 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
