#ifndef VIDEOOUT_OPENGL_H_
#define VIDEOOUT_OPENGL_H_

#include <DisplayRes.h>
#include "videooutbase.h"
#include "NuppelVideoPlayer.h"
#include "util-opengl.h"

#define GL_GLEXT_PROTOTYPES
#define GLX_GLXEXT_PROTOTYPES
#define XMD_H 1
#include <GL/glx.h>

#include <GL/gl.h>
#undef GLX_ARB_get_proc_address
#include <GL/glxext.h>
#include <GL/glext.h>

class VideoOutputOpengl : public VideoOutput
{
  public:
    VideoOutputOpengl();
   ~VideoOutputOpengl();
    bool  Init(int width, int height, float aspect, WId winid,
              int winx, int winy, int winw, int winh, WId embedid = 0);
    void  SetOffscreen(void) { render_onscreen = false; };
    void  GetOSDBounds(QRect &visible, QRect &total,
                              float &pixelAspect, float &fontScale) const;
    void  PrepareFrame(VideoFrame *buffer, FrameScanType);
    void  ShowPip(VideoFrame *frame, NuppelVideoPlayer *pipplayer);
    QRect GetPIPRect(int location, NuppelVideoPlayer *pipplayer);
    int   DisplayOSD(VideoFrame *frame, OSD *osd,
                   int stride = -1, int revision = -1);
    void  Show(FrameScanType );
    void  MoveResize();
    void  InputChanged(int width, int height,
                      float aspect, MythCodecID codec_id);
    void  Zoom(int direction);
    void  AspectChanged(float aspect);
    void  EmbedInWidget(WId wid, int x, int y, int w, int h);
    void  StopEmbedding(void);
    void  ResizeForGui(void);
    void  ResizeForVideo(uint width, uint height);
    void  ResizeForVideo(void);
    int   GetRefreshRate(void);
    void  DrawUnusedRects(bool sync = true);
    float GetDisplayAspect(void);
    void  UpdatePauseFrame(void);
    void  ProcessFrame(VideoFrame *frame, OSD *osd,
                      FilterChain *filterList,
                      NuppelVideoPlayer *pipPlayer);
    int   SetPictureAttribute(int attributeType, int newValue);
    bool  hasOpenGLAcceleration(void) const { return true; }
    unsigned char* GetARGBFrame(QSize &size);
    void  ShutdownVideoResize(void);

    bool  SetDeinterlacingEnabled(bool);
    bool  SetupDeinterlace(bool i, const QString& ovrf="");

  private:
    void InitDisplayMeasurements(uint width, uint height);
    bool InitSetupBuffers(void);
    void CreateBuffers(void);
    void CreatePauseFrame(void);
    void DeleteBuffers(bool delete_pause_frame);

    // Misc.
    DisplayRes      *display_res;
    QMutex           global_lock;

    // Opengl
    OpenglContext   *gl;
    OpenglVideo     *videochain;
    OpenglVideo     *pipchain;
    OpenglVideo     *osdchain;

    // General
    bool             render_onscreen;
    bool             use_colourcontrols;
    bool             gl_osd;
    VideoFrame       av_pause_frame;
    bool             actually_draw_pip;
    bool             actually_draw_osd;
    unsigned char   *argb_frame;

};

enum OpenglFilter
{
    kNOFILT = 0,
    kYUV2RGB,
    kYUV2RGBA,
    kLINBLEND,
    kKDEINT,
    kONEFIELD,
    kBOBDEINT,
    kPROGLINBLEND,
    kPROGKDEINT,
    kPROGONEFIELD,
    kRESIZE
};

enum DisplayBuffer
{
    kNoBuffer = 0,    // disable filter
    kDefaultBuffer,
    kFrameBufferObject
};

typedef struct Filter
{
    GLuint  fragmentProgram;
    uint    numInputs;
    bool    rotateFrameBuffers;
    vector<GLuint> frameBuffers;
    vector<GLuint> frameBufferTextures;
    DisplayBuffer  outputBuffer;
};

class OpenglVideo
{
  public:
    OpenglVideo();
   ~OpenglVideo();
    bool Init(OpenglContext *glcontext, bool colour_control, bool onscreen,
              QSize video_size, QRect visible_rect,
              QRect video_rect, bool viewport_control, bool osd = FALSE);
    bool ReInit(OpenglContext *gl, bool colour_control, bool onscreen,
              QSize video_size, QRect visible_rect,
              QRect video_rect, bool viewport_control, bool osd = FALSE);
    void UpdateInputFrame(VideoFrame *frame);
    void UpdateInput(unsigned char *buf, uint texture_num,
                     int format, QSize size);
    bool AddFilter(QString filter)
         { return AddFilter(StringToFilter(filter)); };
    bool RemoveFilter(QString filter)
         { return RemoveFilter(StringToFilter(filter)); };
    bool AddDeinterlacer(QString filter);
    void SetDeinterlacing(bool deinterlacing);
    QString GetDeinterlacer(void)
         { return FilterToString(GetDeintFilter()); };
    void Show(FrameScanType scan, bool softwareDeinterlacing, long long frame);
    void SetSoftwareDeinterlacer(QString filter)
         { softwareDeinterlacer = filter; };
    void SetMasterViewport(QSize size)
         { masterViewportSize = size; };
    QSize GetViewPort(void) { return viewportSize; };
    void SetVideoRect(QRect rect) { videoRect = rect; };
    QSize GetVideoSize(void) { return videoSize; };
    void SetVideoResize(QRect *size);
    void SetPictureAttribute(int attributeType, int newValue);

  private:
    void Cleanup(void);
    void SetViewPort(uint width, uint height);
    void ViewPort(uint width, uint height);
    bool AddFilter(OpenglFilter filter);
    bool RemoveFilter(OpenglFilter filter);
    bool OptimiseFilters(void);
    OpenglFilter GetDeintFilter(void);
    bool AddFrameBuffer(GLuint *framebuffer, GLuint *texture, QSize size);
    GLuint AddFragmentProgram(OpenglFilter name);
    GLuint CreateVideoTexture(QSize size, QSize *tex_size, bool YUV12);
    QString GetProgramString(OpenglFilter filter);
    void CalculateResize(float *left, float *top,
                         float *right, float *bottom);
    void Rotate(vector<GLuint> *target);
    QString FilterToString(OpenglFilter filter);
    OpenglFilter StringToFilter(QString filter);
    void ShutDownYUV2RGB(void);
    void SetViewPort(bool last_stage);
    void InitOpengl(void);
    void GetTextureSize(QSize *temp, QSize size);
    void SetFiltering(void);
    void SetTextureFilters(vector<GLuint> *textures, int filt);

    OpenglContext *gl;
    QSize          videoSize;
    QSize          viewportSize;
    QSize          masterViewportSize;
    QRect          visibleRect;
    QRect          videoRect;
    QRect          frameBufferRect;
    bool           invertVideo;
    QString        softwareDeinterlacer;
    bool           hardwareDeinterlacing;
    bool           useColourControl;
    bool           viewportControl;
    GLuint         frameBuffer;
    GLuint         frameBufferTexture;
    vector<GLuint> inputTextures;
    QSize          inputTextureSize;
    map<OpenglFilter,Filter> filters;
    long long      currentFrameNum;
    bool           inputUpdated;

    QSize            convertSize;
    unsigned char   *convertBuf;

    bool             videoResize;
    QRect            videoResizeRect;

    static QMap<int,float> pictureAttribs;
};

#endif

