/**
* @file perspective_api.h
* @brief Interface principale de la bibliothèque.
* @mainpage Perspective3D API
* @author Florian Joncour
* @date 2013-2018
* @copyright Ces sources font partie de l'interface de programmation pour la bibliothèque Perspective3D,
un outil de modélisation 3D à partir de vues orthographiques 2D.
Ces sources sont fournies à titre gracieux, l'utilisateur a la liberté de les exploiter
pour créer des applications dérivées à condition de respecter les conditions suivantes:

    1) Ces sources ne peuvent être modifiées.
    2) Le dérivé ne peut être exploité à des fins commerciaux.
    3) Aucune licence commerciale de la bibliothèque dont est tiré ce fichier ne peut être rendue publique.
    4) Toute application exploitant la présente bibliothèque doit explicitement faire mention de l'usage et du rôle de Perspective3D.

Ces conditions peuvent toutefois être modifiées avec l'accord de l'auteur.
*/

#ifndef PERSPECTIVE_API
#define PERSPECTIVE_API

#include <string>
#include "perspective_sys.h" /* Fera planter la compilation si l'on est pas sur un système ou une architecture supportée. */
#include "perspective_def.h"
#include "perspective_types.h"
#include "perspective_div2.h"

/**
 * @brief Espace de nom de l'API.
 */
namespace libPerspective
{
    /**
     * @return Dénomination de la bibliothèque.
     */
    DLL_API const char *Nom();

    /**
     * @return La version de la bibliothèque.
     */
    DLL_API const char *VersionStr();

    /**
     * @return La version de la bibliothèque sous forme entière.
     */
    DLL_API pint VersionInt();

    /**
     * @return La description de la plateforme sur laquelle est basée la bibliothèque.
     */
    DLL_API const char *Plateforme();

    /**
     * @return La description des logiciels inclus dans la bibliothèque.
     */
    DLL_API const char *APropos();

    /**
     * @return Le texte de la licence de la bibliothèque Perspective3D.
     */
    DLL_API const char *TexteLicence();

    /**
     * @brief Contrôle si le support du multithreading est inclu dans cette distribution.
     * @return Renvoi true si le multithreading est supporté par la distribution actuelle, sinon false.
     */
    DLL_API bool SupportMultiThreading();

    /**
     * @return La longueur nécessaire pour stocker une clé d'activation chiffrée.
     */
    DLL_API puint LongueurCleActivationChiffre();

    /**
     * @return La longueur nécessaire pour stocker une clé d'activation non chiffrée.
     */
    DLL_API puint LongueurCleActivationClair();

    /**
     * @brief ChiffrementLicence Chiffre une clé de licence (La taille du tampon source doit au moins valoir LongueurCleActivationClair()), place le résultat dans dest, qui doit avoir une taille d'au moins LongueurCleActivationChiffre().
        La valeur de salage donnée en argument doit être supérieure à 0xFFFF
     */
    DLL_API void ChiffrementLicence(const pint8 *source, pint8 *dest, puint64 sel);

    /**
     * @brief GenID Génère un nombre pouvant servir de salage pour la fonction de chiffrement (doit être la même entre le chiffrement et le déchiffrement).
     */
    DLL_API puint64 GenID();

    /**
     * @brief Renvoi un code barre généré depuis la clé de licence (en principe chiffrée avec la fonction ChiffrementLicence()).
     */
    DLL_API Perspective3D::PImage CodeBarreLicence(const pint8 *cle);

} /* namespace libPerspective */

/**
 * @brief Espace de nom de l'API 3D.
 */
namespace Perspective3D
{
    class Pjournal;
    class PerspectiveVuesAuto;

    /**
     * @brief Classe principale Perspective3D pour la conversion de plan 2D vers la 3D.
     */
    class DLL_API Perspective
    {
        public:
            /**
             * @brief Initialise la bibliothèque (tous les paramètres ont une valeur par défaut)
             * @param parametres Les paramètres de génération.
             * @param scene Si un pointeur vers une scène est donnée en argument, Perspective3D l'utilisera pour y placer le résultat de la génération. Sinon la scène sera allouée et libérée par Perspective.
             */
            static Perspective *Construct(const ParametresPerspective &parametres, PScene3D *scene = nullptr);

            virtual ~Perspective() = 0;

            /**
              * @brief Valide une clé de licence (chiffrée avec ChiffrementLicence()). La clé doit faire 24 octets de long.
              */
            static bool ValideLicence(const pint8 *cle_crypt, puint64 sel);

            /**
             * @return true si la bibliothèque la licence est active via la clé d'activation donnée à l'initialisation. Sinon false.
             */
            virtual bool LicenceActive() const = 0;

            /**
             * @brief Bloque l'appelant en attendant l'initialisation de la bibliothèque. Le bloquage ne se fera que pendant 5 secondes maximum.
             * Si l'initialisation prend trop de temps en raison d'un blocage, la fonction renverra false.
             */
            virtual bool AttendInit() const = 0;

            /**
             * @return true si l'initialisation de la bibliothèque est terminée, sinon false.
             */
            virtual bool FinInit() const = 0;

            /**
             * @brief (Re)initialise la bibliothèque pour générer un nouveau modèle sur la même instance de Perspective3D.
             */
            virtual void ReInit(PScene3D *scene = nullptr) = 0;

            /**
             * @brief (Re)initialise la bibliothèque pour générer un nouveau modèle sur la même instance de Perspective3D, mais avec assignation de nouveaux paramètres
             */
            virtual void ReInit(const ParametresPerspective &parametres, PScene3D *scene = nullptr) = 0;

            /**
             * @brief Renvoi les paramètres de cette instance Perspective3D.
             */
            virtual const ParametresPerspective &Parametres() const = 0;

            /**
             * @brief Ajoute les entités de la scène 2D englobées par le cadre de vue.
             * @return Renvoi le nombre d'entités ajoutées.
             */
            virtual pint AjoutEntitesVue(const Prect2D &rect_vue, const vues2D_t vue, const PScene2D &scene) = 0;

            /**
             * @brief Ajoute un point 2D.
             * @param p le point à ajouter
             * @param vue la vue concernée
             */
            virtual void AjoutPoint2D(const Ppoint2D &p, vues2D_t vue) = 0;

            /**
             * @brief Ajoute une ligne 2D.
             * @param l la ligne à ajouter
             * @param vue la vue concernée
             */
            virtual void AjoutLigne2D(const Pligne2D &l, vues2D_t vue) = 0;

            /**
             * @brief Ajoute une ligne 2D d'après ses coordonnées et ses propriétées.
             */
            virtual void AjoutLigne2D(pfloat x1, pfloat y1, pfloat x2, pfloat y2, vues2D_t vue, bool cache=false, bool point=false, const PCouleur&couleur=PCouleur()) = 0;

            /**
             * @brief Ajoute une ellipse 2D.
             * @param e l'ellipse à ajouter
             * @param vue la vue concernée
             */
            virtual void AjoutEllipse2D(const Pellipse2D &e, vues2D_t vue) = 0;

            /**
             * @brief Ajoute une ellipse 2D d'après ses coordonnées et ses propriétés.
             */
            virtual void AjoutEllipse2D(pfloat x, pfloat y, pfloat longueur, pfloat hauteur, pfloat angledebut, pfloat anglefin, pfloat angle_rotation, vues2D_t vue, bool cache=false, const PCouleur&couleur=PCouleur()) = 0;

            /**
             * @brief Assigne l'origine de la vue de face (optionnel, si non défini, elle sera cherchée automatiquement au point inférieur en X et en Y des entitées de la vue de face).
             */
            virtual void defOrigineFace(const Ppoint2D &p) = 0;

            /**
             * @brief Assigne l'origine de la vue de côté (optionnel, si non défini, elle sera cherchée automatiquement au point inférieur en X et en Y des entitées de la vue de côté).
             */
            virtual void defOrigineCote(const Ppoint2D &p) = 0;

            /**
             * @brief Assigne l'origine de la vue de dessus (optionnel, si non défini, elle sera cherchée automatiquement au point inférieur en X et en Y des entitées de la vue de dessus).
             */
            virtual void defOrigineHaut(const Ppoint2D &p) = 0;

            /**
             * @brief Assigne l'origine de la vue donnée en argument.
             */
            virtual bool defOrigineVue(const Ppoint2D &p, vues2D_t vue) = 0;

            /**
             * @brief Génère le solide 3D en fonction de mode de fonctionnement. Bien entendu il faut avant avoir complété la/les vue(s) avec les fonctions Ajout***2D.
             * @param mode Le mode de fonctionnement. Voir l'enum ::modeperspective_t.
             * @param param1 Le paramètre de hauteur d'extrusion pour le mode Extrusion, ou l'angle pour le mode révolution. Ignoré avec le mode 3 vues.
             * @return true si tout s'est bien passé, sinon false.
             */
            virtual bool Generation3D(modeperspective_t mode=modeperspective_t::PMODE_3VUES, pfloat param1=0.) = 0;

            /**
             * @brief Renvoi l'identifiant du résultat de la génération (voir l'enum ::resultat_gen3d_t).
             */
            virtual resultat_gen3d_t ResultatGeneration() const = 0;

            /**
             * @brief Renvoi true si la génération s'est achevée (quelqu'en soit le résultat).
             * @return
             */
            virtual bool FinGeneration() const = 0;

            /**
             * @brief Genère un patron de l'ensemble des segments du modèle.
             * @param ignore_non_developpable Défini si l'on ignore les segments développables car entrant en collision avec ses voisins.
             * @return true si tout s'est bien passé, sinon false.
             */
            virtual bool GenPatron(bool ignore_non_developpable=true) = 0;

            /**
             * @brief Scène contenant le solide.
             * @return La scène.
             */
            virtual PScene3D &Scene() const = 0;

            /**
             * @brief Scène contenant le solide.
             * @return La scène (*).
             */
            virtual PScene3D *ScenePtr() const = 0;

            /**
             * @brief Scène contenant le solide.
             * @return La scène (const).
             */
            virtual const PScene3D &SceneConst() const = 0;

            /**
             * @brief Scène contenant le solide.
             * @return La scène (const *).
             */
            virtual const PScene3D *SceneConstPtr() const = 0;

            /**
             * @brief Re-génère le modèle des projections avec de nouveaux paramètres.
             * @param projs les vues à projeter.
             * @param infos Les informations à afficher.
             * @param tailletxt_pct Taille du texte 3D en pourcentage de la taille de la scène.
             */
            virtual void RegenProjections(vues2D_t projs, infos3d_t infos, pint tailletxt_pct) = 0;
            /* Regenère le modèle des projections d'après les paramètres. */

            /**
             * @brief Re-génère le modèle des projections sans toucher aux paramètres.
             */
            virtual void RegenProjections() = 0;
            /* Regenère le modèle des projections (sans toucher aux paramètres) */

            /**
             * @return true si le modèle a été correctement généré et prêt à l'affichage. Sinon false.
             */
            virtual bool ModelePret() const = 0;

            /**
             * @brief (A appeler régulièrement pendant la génération afin de contrôler l'avancement).
             * @return L'état d'avancement en pourcents.
             */
            virtual puint Avancement() const = 0;

            /**
             * @brief Arrête (brutalement mais proprement) la génération du modèle.
             */
            virtual void Stop() = 0;

            /**
             * @brief (Peut être appelé régulièrement pendant la génération afin de contrôler le status).
             * @return true si la génération est en cours, sinon false.
             */
            virtual bool ContinueGeneration() const = 0;

            /**
             * @brief Journal de génération.
             * @return Renvoi le journal (en vue de l'afficher).
             */
            virtual const Pjournal &JournalConst() const = 0;

            /**
             * @brief AssigneTolerances Assigne les valeurs de tolérance utilisés pour la génération du solide
             */
            virtual void AssigneTolerances(pfloat &t1, pfloat &t2, pfloat &t3, pfloat &v, pfloat &a) const = 0;
    };

    /**
     * @brief Accès au journal de génération d'une instance Perspective3D.
     */
    class DLL_API Pjournal
    {
        public:
            virtual ~Pjournal()=0;

            /**
             * @brief Renvoi la dernière entrée du journal.
             */
            virtual const std::string &DerniereEntreeConst() const = 0;

            /**
             * @brief Renvoi l'ensemble du contenu du journal.
             */
            virtual const std::string &StrConst() const = 0;
    };

    /**
     * @brief Séparatrice de vues (repère automatiquement les vues de face, côté, dessus) sur un plan 2D
     */
    class DLL_API PerspectiveVuesAuto
    {
        public:
            /**
             * @brief Constructeur, initialisation de l'objet.
             */
            static PerspectiveVuesAuto *Construct();

            virtual ~PerspectiveVuesAuto() = 0;

            /**
             * @brief Réinitialisation de la séparatrice.
             */
            virtual void Reinit() = 0;

            /**
             * @brief Ajoute les entités de la scène d'après le rectangle (englobant) donné en argument.
             */
            virtual pint AjoutEntites(const PScene2D &scene, const Prect2D &rect) = 0;

            /**
             * @brief Ajoute une ligne 2D dans l'ensemble des entitées à traiter.
             */
            virtual void AjoutLigne2D(const Pligne2D &l) = 0;

            /**
             * @brief Ajoute une ellipse 2D dans l'ensemble des entitées à traiter.
             */
            virtual void AjoutEllipse2D(const Pellipse2D &e) = 0;

            /**
             * @brief Separation des vues (a utiliser après ajout des entitées).
             * @return true si la séparation a pu être faite, sinon false.
             */
            virtual bool Separation(normevues_t norme=normevues_t::NORME_VUES_ISO) = 0;

            /**
             * @brief RectFace
             * @return Le rectangle de la vue de face (si Separation() a réussi).
             */
            virtual const Prect2D &RectFace() const = 0;

            /**
             * @brief RectCote
             * @return Le rectangle de la vue de côté (si Separation() a réussi).
             */
            virtual const Prect2D &RectCote() const = 0;

            /**
             * @brief RectHaut
             * @return Le rectangle de la vue de dessus (si Separation() a réussi).
             */
            virtual const Prect2D &RectHaut() const = 0;
    };

    /**
     * @brief Mode automatique.
     * @details Interface à Perspective3D, ouvre un fichier DXF, génère automatiquement le modèle et enregistre le tout dans un fichier.
       La classe peut être un simple initialisateur, après la génération du modèle il est possible d'appeler la méthode LiberePerspective3D(),
       cela désactivera la libération de la mémoire et renvera le pointeur de l'instance Perspective3D laissant l'utilisateur se débrouiller avec
       (utile par exemple pour l'affichage avec GLUT, qui s'accapare le flot d'exécution empéchant l'appel du destructeur à la fermeture du programme).
     */
    class DLL_API PerspectiveAuto
    {
        public:
            /**
             * @brief Constructeur, initialise l'objet, ouvre le fichier DXF et extrait la/les vues en fonction du mode
             */
            static PerspectiveAuto *Construct(const char *dxf_source, modeperspective_t mode=modeperspective_t::PMODE_3VUES, const pint8 *licence=nullptr, puint64 salage_licence=0);

            virtual ~PerspectiveAuto() = 0;

            /**
             * @brief InitValide
             * @return true si l'initialisation s'est bien passée (ouverture du fichier, extraction des vues, etc...);
             */
            virtual bool InitValide() const = 0;

            /**
             * @brief Génère le modèle
             * @return true si tout se passe bien, sinon false.
             */
            virtual bool Genere() = 0;

            /**
             * @brief Perspective3DConst
             * @return Pointeur vers l'instance Perspective3D si l'initialisation s'est bien passée. Sinon un pointeur nul.
             */
            virtual const Perspective* Perspective3DConst() const = 0;

            /**
             * @brief Libère Perspective3D, renvoi son pointeur et desactive la libération de la mémoire dans le destructeur pour laisser l'utilisateur s'en charger.
             */
            virtual Perspective* LiberePerspective3D() = 0;
    };

#ifdef SUPPORT_VISION2D
    /**
     * @brief Classe de conversion d'image matricielle vers une scéne 2D (vectorielle).
     */
    class DLL_API Vision
    {
        public:
            /**
             * @brief Construit un objet Vision depuis une PImage.
             * @param image L'image à convertir.
             * @param parametres Les paramètres de conversion.
             * @param origine Origine de la scène, décalage à appliquer pour placer les entités générées dans la scène.
             * @param scene Si un pointeur vers une scène est donné en argument, Vision l'utilisera pour y placer le résultat de la conversion. Sinon la scène sera allouée et libérée par Vision.
             * @param nouveau_groupe_scene Défini si les entités générés doivent être placés dans un nouveau groupe dans la scène.
             */
            static Vision *Construct(const PImage &image, const ParametresVision &parametres, const Ppoint2D &origine=Ppoint2D(0,0), PScene2D *scene = nullptr, bool nouveau_groupe_scene=false);

            /**
             * @brief Construit un objet vision à partir de données brutes (représentant une image bitmap)
             * @param data Données
             * @param taille_tampon Taille du tampon de données
             * @param octets_ligne Nombre d'octets par lignes
             * @param taille_pixel Taille (en octets) des pixels
             * @param parametres Les paramètres de conversion.
             * @param origine Origine de la scène, décalage à appliquer pour placer les entités générées dans la scène.
             * @param scene Si un pointeur vers une scène est donné en argument, Vision l'utilisera pour y placer le résultat de la conversion. Sinon la scène sera allouée et libérée par Vision.
             * @param nouveau_groupe_scene Défini si les entités générés doivent être placés dans un nouveau groupe dans la scène.
             */
            static Vision *Construct(const Poctet_t *data, pint taille_tampon, pint octets_ligne, pint taille_pixel, const ParametresVision &parametres, const Ppoint2D &origine=Ppoint2D(0,0), PScene2D *scene = nullptr, bool nouveau_groupe_scene=false);

            /**
             * @brief Construit un objet Vision à partir d'un fichier.
             * @param chemin_image Le chemin vers l'image.
             * @param parametres Les paramètres de conversion.
             * @param origine Origine de la scène, décalage à appliquer pour placer les entités générées dans la scène.
             * @param scene Si un pointeur vers une scène est donné en argument, Vision l'utilisera pour y placer le résultat de la conversion. Sinon la scène sera allouée et libérée par Vision.
             * @param nouveau_groupe_scene Défini si les entités générés doivent être placés dans un nouveau groupe dans la scène.
             * @return
             */
            static Vision *Construct(const char *chemin_image, const ParametresVision &parametres, const Ppoint2D &origine=Ppoint2D(0,0), PScene2D *scene = nullptr, bool nouveau_groupe_scene=false);

            /**
             * @brief Construit un objet Vision à partir d'un trajet (liste de points qui se suivent).
             * @param trajet Tracé à convertir.
             * @param echelle Echelle à appliquer aux entités générées.
             * @param parametres Les paramètres de conversion.
             * @param origine Origine de la scène, décalage à appliquer pour placer les entités générées dans la scène.
             * @param scene Si un pointeur vers une scène est donné en argument, Vision l'utilisera pour y placer le résultat de la conversion. Sinon la scène sera allouée et libérée par Vision.
             * @param nouveau_groupe_scene Défini si les entités générés doivent être placés dans un nouveau groupe dans la scène.
             * @return
             */
            static Vision *Construct(const Perspective3D::PStdVectPointsPixels &trajet, pfloat echelle, const ParametresVision &parametres, const Ppoint2D &origine=Ppoint2D(0,0), PScene2D *scene = nullptr, bool nouveau_groupe_scene=false);

            virtual ~Vision() = 0;

            /**
             * @brief Valide une clé de licence (chiffrée avec ChiffrementLicence()). La clé doit faire 24 octets de long.
             */
            static bool ValideLicence(const pint8 *cle_crypt, puint64 sel);

            /**
             * @return true si la bibliothèque la licence est active via la clé d'activation donnée à l'initialisation. Sinon false.
             */
            virtual bool LicenceActive() const = 0;

            /**
             * @brief (Re)initialise la bibliothèque pour générer un nouveau plan sur la même instance de Vision2D.
             */
            virtual void ReInit(const PImage &image, const Ppoint2D &origine, PScene2D *scene = nullptr) = 0;

            /**
             * @brief (Re)initialise la bibliothèque pour générer un nouveau plan sur la même instance de Vision2D, mais avec assignation de nouveaux paramètres.
             */
            virtual void ReInit(const PImage &image, const ParametresVision &parametres, const Ppoint2D &origine, PScene2D *scene = nullptr) = 0;

            /**
             * @brief (Re)initialise la bibliothèque pour générer un nouveau plan sur la même instance de Vision2D, mais avec assignation de nouveaux paramètres.
             */
            virtual void ReInit(const Perspective3D::PStdVectPointsPixels &trajet, pfloat echelle, const Perspective3D::ParametresVision &parametres, const Ppoint2D &origine, PScene2D *scene = nullptr) = 0;

            /**
             * @brief Génère la scène (exécution de la conversion).
             * @return true si tout se passe bien, sinon false.
             */
            virtual resultat_vision2d_t Genere() = 0;

            /**
             * @brief Renvoi le niveau d'avancement de la génération de la scène (en %).
             */
            virtual pint Avancement() const = 0;

            /**
             * @brief Renvoi true si la génération s'est achevée (quelqu'en soit le résultat).
             * @return
             */
            virtual bool FinGeneration() const = 0;

            /**
             * @brief Scène contenant le plan.
             * @return La scène (const).
             */
            virtual const PScene2D &SceneConst() const = 0;

            /**
             * @brief Scène contenant le plan.
             * @return La scène (const *).
             */
            virtual const PScene2D *SceneConstPtr() const = 0;

            /**
             * @brief MatriceActive Contrôle si la matrice est utilisable pour l'affichage.
             */
            virtual bool MatriceActive() const = 0;

            /**
             * @brief Matrice initiale.
             */
            virtual PImage Matrice() const = 0;

#ifdef DEBUG_API_P3D
            virtual PImage MatriceDebug(pint n=0) const = 0;
            virtual pint EtatVerrou() const = 0;
            virtual void RepriseGeneration() = 0;
#endif // DEBUG_API_P3D

    };
#endif // SUPPORT_VISION2D

    /**
     * @brief RAL Espace de nom spécifique au nuancier RAL classique.
     */
    namespace RAL
    {
        /**
         * @brief Nombre Renvoi le nombre de couleurs dans le nuancier RAL.
         */
        DLL_API puint Nombre();

        /**
         * @brief Index Renvoi un RAL d'après sa position dans le nuancier (connu par exemple en utilisant un itérateur 0->RAL::Nombre()). Si il y a un débordement, une couleur nulle sera renvoyée.
         */
        DLL_API const Perspective3D::PCouleur_RAL &Index(puint pos);

        /**
         * @return Renvoi un RAL d'après son identifiant dans le nuancier (par exemple 9010 pour le blanc pur). Si rien n'a été trouvé, une couleur nulle sera renvoyée.
         */
        DLL_API const Perspective3D::PCouleur_RAL &Recherche(puint id);

        /**
         * @return Renvoi la position d'un RAL dans le nuancier d'après son identifiant. Renvoi 0 (considéré comme couleur nulle) si rien n'a été trouvé.
         */
        DLL_API puint RechercheIndex(puint id);

    } // namespace Perspective3D::RAL

    /**
     * @brief Module de traduction interne à Perspective3D.
     */
    namespace i18n
    {
        /**
         * @brief defLangue Assigne la langue pour Perspective3D (concerne les informations renvoyées par Perspective3D et le nuancier RAL).
         * Le paramètre est global et ne concerne donc pas une instance particulière de Perspective3D.
         * Il vaut mieux définir la langue avant l'initialisation d'une instance Perspective3D.
         * @details Voir l'enum ::lang_p3d_t pour avoir un index des langues disponibles.
         */
        DLL_API void defLangue(lang_p3d_t langue);

        /**
         * @brief Renvoi la langue actuellement définie dans Perspective3D.
         */
        DLL_API lang_p3d_t Langue();
    } // namespace Perspective3D::i18n

    /**
     * @brief Renvoi le nom de la vue donnée en argument.
     */
    DLL_API const char * NomVue(vues2D_t vue);

    /**
     * @brief Renvoi le logo de Perspective3D.
     * @param taille_128 Si le paramètre vaut true, l'icône renvoyée fera 128x128, sinon 64x64.
     */
    DLL_API PImage LogoPerspective3D(bool taille_128=true);

#ifdef SUPPORT_VISION2D
    /**
     * @brief Renvoi le logo de Vision2D.
     * @param taille_128 Si le paramètre vaut true, l'icône renvoyée fera 128x128, sinon 64x64.
     */
    DLL_API PImage LogoVision2D(bool taille_128=true);
#endif // SUPPORT_VISION2D

    /**
     * @brief Renvoi le nombre d'images dans le logo animé.
     */
    DLL_API pint NombreLogosAnime();

    /**
     * @brief Renvoi l'image du logo animé dont l'id est donné en argument.
     */
    DLL_API PImage LogoAnime(pint id);

} /* namespace Perspective3D */

#endif // PERSPECTIVE_API
