/***************************************************************************
 *   Copyright (c) 2005 Werner Mayer <wmayer[at]users.sourceforge.net>     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  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 Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#ifndef GUI_SOFCOFFSCREENRENDERER_H
#define GUI_SOFCOFFSCREENRENDERER_H

#include <Inventor/SbColor4f.h>
#include <Inventor/SbMatrix.h>
#include <Inventor/SoOffscreenRenderer.h>

#include <FCConfig.h>

#ifdef FC_OS_MACOSX
# include <OpenGL/gl.h>
#else
# ifdef FC_OS_WIN32
#  include <windows.h>
# endif  // FC_OS_WIN32
# include <GL/gl.h>
#endif  // FC_OS_MACOSX

#include <QImage>
#include <QStringList>

#include <FCGlobal.h>

class QOpenGLFramebufferObject;

namespace Gui
{

/**
 * The SoFCOffscreenRenderer class is used for rendering scenes in offscreen buffers.
 * @author Werner Mayer
 */
class GuiExport SoFCOffscreenRenderer: public SoOffscreenRenderer
{
public:
    /** The SoOffscreenRenderer base class seems to have a huge memory leak. Whenever
     * an instance is created internal memory doesn't get freed when destroying it.
     * Thus, SoFCOffscreenRenderer is implemented as singleton to allow one to create only
     * one global instance. So, the memory is leaking for this instance only.
     */
    static SoFCOffscreenRenderer& instance();

    SoFCOffscreenRenderer(const SoFCOffscreenRenderer&) = delete;
    SoFCOffscreenRenderer& operator=(const SoFCOffscreenRenderer&) = delete;

private:
    static SoFCOffscreenRenderer* inst;

protected:
    /**
     * Constructor. Argument is the \a viewportregion we should use when rendering. An internal
     * SoGLRenderAction will be constructed.
     */
    SoFCOffscreenRenderer(const SbViewportRegion& viewportregion);
    /**
     * Constructor. Argument is the \a action we should apply to the scene graph when rendering the
     * scene. Information about the viewport is extracted from the \a action.
     */
    SoFCOffscreenRenderer(SoGLRenderAction* action);
    /**
     * Destructor.
     */
    ~SoFCOffscreenRenderer();

public:
    /**
     * Writes the rendered image buffer directly into a QImage object
     * instead of an image file.
     */
    void writeToImage(QImage&) const;
    /**
     * Saves the buffer to \a filename, in the filetype specified by \a filetypeextensions.
     *
     * Note that you must still specify the full filename for the first argument, i.e. the second
     * argument will not automatically be attached to the filename -- it is only used to decide the
     * filetype.
     *
     * If \a comment is set to '$MIBA' information regarding the MIBA standard is
     * embedded to the picture, otherwise the \a comment is embedded as is.
     * The appropriate file format must support embedding meta information which
     * is provided by JPEG or PNG.
     *
     * This does basically the same as writeToFile() unless that all QImage file formats are
     * supported if not directly supported by Coin3D.
     */
    void writeToImageFile(
        const char* filename,
        const char* comment,
        const SbMatrix& mat,
        const QImage& img
    );
    /**
     * This method returns all image file formats supported by Coin3D (see getWriteFiletypeInfo())
     * with all QImage file formats that are not directly supported by Coin3D, if so.
     */
    QStringList getWriteImageFiletypeInfo();

    std::string createMIBA(const SbMatrix& mat) const;
};

class GuiExport SoQtOffscreenRenderer
{
public:
    SoQtOffscreenRenderer(const SbViewportRegion& viewportregion);
    SoQtOffscreenRenderer(SoGLRenderAction* action);
    ~SoQtOffscreenRenderer();

    void setViewportRegion(const SbViewportRegion& region);
    const SbViewportRegion& getViewportRegion() const;

    void setBackgroundColor(const SbColor4f& color);
    const SbColor4f& getBackgroundColor() const;

    void setGLRenderAction(SoGLRenderAction* action);
    SoGLRenderAction* getGLRenderAction() const;

    void setNumPasses(const int num);
    int getNumPasses() const;

    void setInternalTextureFormat(GLenum internalTextureFormat);
    GLenum internalTextureFormat() const;

    SbBool render(SoNode* scene);
    SbBool render(SoPath* scene);

    void writeToImage(QImage&) const;
    QStringList getWriteImageFiletypeInfo() const;

private:
    void init(const SbViewportRegion& vpr, SoGLRenderAction* glrenderaction = nullptr);
    static void pre_render_cb(void* userdata, SoGLRenderAction* action);
    SbBool renderFromBase(SoBase* base);
    void makeFrameBuffer(int width, int height, int samples);

    QOpenGLFramebufferObject* framebuffer;
    uint32_t cache_context;  // our unique context id

    SbViewportRegion viewport;
    SbColor4f backgroundcolor;
    SbColor4f backgroundopaque;
    SoGLRenderAction* renderaction;
    SbBool didallocation;
    int numSamples;
    GLenum texFormat;
    QImage glImage;
};

}  // namespace Gui


#endif  // GUI_SOFCOFFSCREENRENDERER_H
