/***************************************************************************
  qgsskyboxentity.h
  --------------------------------------
  Date                 : August 2020
  Copyright            : (C) 2020 by Belgacem Nedjima
  Email                : gb uderscore nedjima at esi dot dz
 ***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef QGSSKYBOXENTITY_H
#define QGSSKYBOXENTITY_H

#include "qgis.h"
#include "qgis_3d.h"

#include <QMap>
#include <QString>
#include <QVector>
#include <Qt3DCore/QEntity>
#include <Qt3DRender/QTexture>

#define SIP_NO_FILE

class QgsEnvironmentLight;

namespace Qt3DExtras
{
  class QCuboidMesh;
}

namespace Qt3DRender
{
  class QEffect;
  class QFilterKey;
  class QMaterial;
  class QParameter;
  class QRenderPass;
  class QShaderProgram;
  class QTechnique;
  class QTexture;
} //namespace Qt3DRender

class QgsImageTexture;

// this is broken for z-up coordinate system
#define ENABLE_PANORAMIC_SKYBOX 0

/**
 * \brief Base class for all skybox types.
 *
 * It holds the common member data between different skybox entity types
 * \ingroup qgis_3d
 * \since QGIS 3.16
 */
class _3D_EXPORT QgsSkyboxEntity : public Qt3DCore::QEntity
{
    Q_OBJECT

  public:
    //! Constructor
    QgsSkyboxEntity( QNode *parent = nullptr );

    //! Returns the background type of skybox entity
    virtual Qgis::Map3DBackgroundType type() const = 0;

    /**
     * Updates the specified environment \a light to match the skybox settings.
     *
     * \since QGIS 4.2
     */
    virtual void updateEnvironmentLight( QgsEnvironmentLight *light ) const = 0;

  protected:
    Qt3DRender::QEffect *mEffect = nullptr;
    Qt3DRender::QMaterial *mMaterial = nullptr;
    Qt3DRender::QTechnique *mGl3Technique = nullptr;
    Qt3DRender::QFilterKey *mFilterKey = nullptr;
    Qt3DRender::QRenderPass *mGl3RenderPass = nullptr;
    Qt3DExtras::QCuboidMesh *mMesh = nullptr;
    Qt3DRender::QParameter *mGammaStrengthParameter = nullptr;
    Qt3DRender::QParameter *mTextureParameter = nullptr;
};


#if ENABLE_PANORAMIC_SKYBOX

/**
 * \brief A skybox constructed from a panoramic image.
 *
 * \ingroup qgis_3d
 * \since QGIS 3.16
 */
class _3D_EXPORT QgsPanoramicSkyboxEntity : public QgsSkyboxEntity
{
    Q_OBJECT

  public:
    //! Construct a skybox from a panoramic 360 image
    QgsPanoramicSkyboxEntity( const QString &texturePath, Qt3DCore::QNode *parent = nullptr );

    //! Returns the path of the current texture in use
    QString texturePath() const { return mTexturePath; }
    Qgis::Map3DBackgroundType type() const override { return Qgis::Map3DBackgroundType::NoBackground; } // this will have to be changed if panoramic skybox is fixed

  private:
    void reloadTexture();

  private:
    QString mTexturePath;
    Qt3DRender::QTextureLoader *mLoadedTexture = nullptr;
    Qt3DRender::QShaderProgram *mGlShader = nullptr;
};
#endif


/**
 * \brief A skybox constructed from 6 cube faces.
 *
 * \ingroup qgis_3d
 * \since QGIS 3.16
 */
class _3D_EXPORT QgsCubeFacesSkyboxEntity : public QgsSkyboxEntity
{
    Q_OBJECT

  public:
    //! Constructs a skybox from 6 different images
    QgsCubeFacesSkyboxEntity(
      Qgis::SkyboxCubeMapping mapping,
      const QString &posX,
      const QString &posY,
      const QString &posZ,
      const QString &negX,
      const QString &negY,
      const QString &negZ,
      bool enableEnvironmentalLighting,
      Qt3DCore::QNode *parent = nullptr
    );
    Qgis::Map3DBackgroundType type() const override { return Qgis::Map3DBackgroundType::DistinctTextureSkybox; }
    void updateEnvironmentLight( QgsEnvironmentLight *light ) const override;

  private:
    void init();
    void reloadTexture();

  private:
    struct FaceTransformation
    {
        QString path;
        bool mirrorHorizontal = false;
        bool mirrorVertical = false;
    };

    QMap<Qt3DRender::QTextureCubeMap::CubeMapFace, FaceTransformation> generateFaceTransformation() const;

    Qgis::SkyboxCubeMapping mMappingType = Qgis::SkyboxCubeMapping::NativeZUp;
    QString mSourcePosX;
    QString mSourcePosY;
    QString mSourcePosZ;
    QString mSourceNegX;
    QString mSourceNegY;
    QString mSourceNegZ;
    bool mEnableEnvironmentalLighting = true;

    Qt3DRender::QShaderProgram *mGlShader = nullptr;
    QVector<Qt3DRender::QAbstractTextureImage *> mFacesTextureImages;
    Qt3DRender::QTextureCubeMap *mCubeMap = nullptr;
};

#endif // QGSSKYBOXENTITY_H
