/********************************************************************
 KWin - the KDE window manager
 This file is part of the KDE project.

Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org>

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 2 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/>.
*********************************************************************/

#ifndef KWIN_SCENE_OPENGL_H
#define KWIN_SCENE_OPENGL_H

#include "scene.h"

#include "kwinglutils.h"

#ifdef KWIN_HAVE_OPENGL_COMPOSITING

#ifdef HAVE_XSHM
#include <X11/extensions/XShm.h>
#endif

namespace KWin
{

class SceneOpenGL
    : public Scene
    {
    public:
        class EffectFrame;
        class Texture;
        class Window;
        SceneOpenGL( Workspace* ws );
        virtual ~SceneOpenGL();
        virtual bool initFailed() const;
        virtual CompositingType compositingType() const { return OpenGLCompositing; }
        virtual void paint( QRegion damage, ToplevelList windows );
        virtual void windowGeometryShapeChanged( Toplevel* );
        virtual void windowOpacityChanged( Toplevel* );
        virtual void windowAdded( Toplevel* );
        virtual void windowClosed( Toplevel*, Deleted* );
        virtual void windowDeleted( Deleted* );
    protected:
        virtual void paintGenericScreen( int mask, ScreenPaintData data );
        virtual void paintBackground( QRegion region );
    private:
        bool selectMode();
        bool initTfp();
        bool initShm();
        void cleanupShm();
        bool initBuffer();
        bool initRenderingContext();
        bool initBufferConfigs();
        bool initDrawableConfigs();
        void waitSync();
        void flushBuffer( int mask, QRegion damage );
        bool selfCheck();
        void selfCheckSetup();
        bool selfCheckFinish();
        GC gcroot;
        class FBConfigInfo
            {
            public:
                GLXFBConfig fbconfig;
                int bind_texture_format;
                int texture_targets;
                int y_inverted;
                int mipmap;
            };
        Drawable buffer;
        GLXFBConfig fbcbuffer;
        static bool db;
        static GLXFBConfig fbcbuffer_db;
        static GLXFBConfig fbcbuffer_nondb;
        static FBConfigInfo fbcdrawableinfo[ 32 + 1 ];
        static GLXDrawable glxbuffer;
        static GLXContext ctxbuffer;
        static GLXContext ctxdrawable;
        static GLXDrawable last_pixmap; // for a workaround in bindTexture()
        static bool tfp_mode;
        static bool shm_mode;
        QHash< Toplevel*, Window* > windows;
#ifdef HAVE_XSHM
        static XShmSegmentInfo shm;
#endif
        bool init_ok;
        bool selfCheckDone;
    };

class SceneOpenGL::Texture
    : public GLTexture
    {
    public:
        Texture();
        Texture( const Pixmap& pix, const QSize& size, int depth );
        virtual ~Texture();

        using GLTexture::load;
        virtual bool load( const Pixmap& pix, const QSize& size, int depth,
            QRegion region );
        virtual bool load( const Pixmap& pix, const QSize& size, int depth );
        virtual bool load( const QImage& image, GLenum target = GL_TEXTURE_2D );
        virtual bool load( const QPixmap& pixmap, GLenum target = GL_TEXTURE_2D );
        virtual void discard();
        virtual void release(); // undo the tfp_mode binding
        virtual void bind();
        virtual void unbind();

    protected:
        void findTarget();
        QRegion optimizeBindDamage( const QRegion& reg, int limit );
        void createTexture();

    private:
        void init();

        GLXPixmap glxpixmap; // the glx pixmap the texture is bound to, only for tfp_mode
    };

class SceneOpenGL::Window
    : public Scene::Window
    {
    public:
        Window( Toplevel* c );
        virtual ~Window();
        virtual void performPaint( int mask, QRegion region, WindowPaintData data );
        virtual void pixmapDiscarded();
        bool bindTexture();
        void discardTexture();
        void checkTextureSize();

    protected:
        enum TextureType
            {
            Content,
            DecorationTop,
            DecorationLeft,
            DecorationRight,
            DecorationBottom
            };
        void paintDecoration( const QPixmap* decoration, TextureType decorationType, const QRegion& region, const QRect& rect, const WindowPaintData& data, const WindowQuadList& quads, bool updateDeco );
        void makeDecorationArrays( float** vertices, float** texcoords, const WindowQuadList& quads, const QRect& rect  ) const;
        void renderQuads( int mask, const QRegion& region, const WindowQuadList& quads );
        void prepareStates( TextureType type, double opacity, double brightness, double saturation, GLShader* shader );
        void prepareRenderStates( TextureType type, double opacity, double brightness, double saturation );
        void prepareShaderRenderStates( TextureType type, double opacity, double brightness, double saturation, GLShader* shader );
        void restoreStates( TextureType type, double opacity, double brightness, double saturation, GLShader* shader );
        void restoreRenderStates( TextureType type, double opacity, double brightness, double saturation );
        void restoreShaderRenderStates( TextureType type, double opacity, double brightness, double saturation, GLShader* shader );

    private:
        Texture texture;
        Texture topTexture;
        Texture leftTexture;
        Texture rightTexture;
        Texture bottomTexture;
    };

class SceneOpenGL::EffectFrame
    : public Scene::EffectFrame
    {
    public:
        EffectFrame( EffectFrameImpl* frame );
        virtual ~EffectFrame();

        virtual void free();
        virtual void freeIconFrame();
        virtual void freeTextFrame();
        virtual void freeSelection();

        virtual void render(QRegion region, double opacity, double frameOpacity);

        virtual void crossFadeIcon();
        virtual void crossFadeText();

        static void cleanup();

    private:
        void updateTexture();
        void updateTextTexture();

        GLTexture* m_texture;
        GLTexture* m_textTexture;
        GLTexture* m_oldTextTexture;
        QPixmap* m_textPixmap; // need to keep the pixmap around to workaround some driver problems
        GLTexture* m_iconTexture;
        GLTexture* m_oldIconTexture;
        GLTexture* m_selectionTexture;
        GLVertexBuffer* m_unstyledVBO;

        static GLTexture* m_unstyledTexture;
        static QPixmap* m_unstyledPixmap; // need to keep the pixmap around to workaround some driver problems
        static void updateUnstyledTexture(); // Update OpenGL unstyled frame texture
    };

} // namespace

#endif

#endif
