<commit_before>/**
 *  For conditions of distribution and use, see copyright notice in license.txt
 *
 *  @file   SceneStructureModule.cpp
 *  @brief  Provides Scene Structure and Assets windows and raycast drag-and-drop import of
 *          .mesh, .scene, .xml and .nbf files to the main window.
 */

#include "StableHeaders.h"
#include "DebugOperatorNew.h"

#include "SceneStructureModule.h"
#include "SceneStructureWindow.h"
#include "AssetsWindow.h"
#include "SupportedFileTypes.h"
#include "AddContentWindow.h"

#include "IAsset.h"
#include "IAssetTransfer.h"

#include "SceneManager.h"
#include "Console.h"
#include "UiServiceInterface.h"
#include "Input.h"
#include "RenderServiceInterface.h"
#include "SceneImporter.h"
#include "EC_OgreCamera.h"
#include "EC_Placeable.h"
#include "EC_Mesh.h"
#include "NaaliUi.h"
#include "NaaliGraphicsView.h"
#include "NaaliMainWindow.h"
#include "LoggingFunctions.h"
#include "SceneDesc.h"

#include <OgreEntity.h>
#include <OgreMesh.h>

DEFINE_POCO_LOGGING_FUNCTIONS("SceneStructure");

#ifdef ASSIMP_ENABLED
#include <OpenAssetImport.h>
#endif

//#include <OgreCamera.h>

#include "MemoryLeakCheck.h"

SceneStructureModule::SceneStructureModule() :
    IModule("SceneStructure"),
    sceneWindow(0),
    assetsWindow(0)
{
}

SceneStructureModule::~SceneStructureModule()
{
    SAFE_DELETE(sceneWindow);
}

void SceneStructureModule::PostInitialize()
{
    framework_->Console()->RegisterCommand("scenestruct", "Shows the Scene Structure window.", this, SLOT(ShowSceneStructureWindow()));
    framework_->Console()->RegisterCommand("assets", "Shows the Assets window.", this, SLOT(ShowAssetsWindow()));

    inputContext = framework_->GetInput()->RegisterInputContext("SceneStructureInput", 90);
    connect(inputContext.get(), SIGNAL(KeyPressed(KeyEvent *)), this, SLOT(HandleKeyPressed(KeyEvent *)));

    connect(framework_->Ui()->GraphicsView(), SIGNAL(DragEnterEvent(QDragEnterEvent *)), SLOT(HandleDragEnterEvent(QDragEnterEvent *)));
    connect(framework_->Ui()->GraphicsView(), SIGNAL(DragMoveEvent(QDragMoveEvent *)), SLOT(HandleDragMoveEvent(QDragMoveEvent *)));
    connect(framework_->Ui()->GraphicsView(), SIGNAL(DropEvent(QDropEvent *)), SLOT(HandleDropEvent(QDropEvent *)));
}

QList<Scene::Entity *> SceneStructureModule::InstantiateContent(const QString &filename, Vector3df worldPos, bool clearScene)
{
    return InstantiateContent(filename, worldPos, SceneDesc(), clearScene);
}

QList<Scene::Entity *> SceneStructureModule::InstantiateContent(const QString &filename, Vector3df worldPos, const SceneDesc &desc, bool clearScene)
{
    return InstantiateContent(QStringList(QStringList() << filename), worldPos, desc, clearScene);
}

QList<Scene::Entity *> SceneStructureModule::InstantiateContent(const QStringList &filenames, Vector3df worldPos, const SceneDesc &desc, bool clearScene)
{
    QList<Scene::Entity *> ret;

    const Scene::ScenePtr &scene = framework_->GetDefaultWorldScene();
    if (!scene)
    {
        LogError("Could not retrieve default world scene.");
        return ret;
    }

    QList<SceneDesc> sceneDescs;

    foreach(QString filename, filenames)
    {
        if (!IsSupportedFileType(filename))
        {
            LogError("Unsupported file extension: " + filename.toStdString());
            continue;
        }

        if (filename.endsWith(cOgreSceneFileExtension, Qt::CaseInsensitive))
        {
            //\todo Implement ogre.scene url drops at some point?
            TundraLogic::SceneImporter importer(scene);
            sceneDescs.append(importer.GetSceneDescForScene(filename));
        }
        else if (filename.endsWith(cOgreMeshFileExtension, Qt::CaseInsensitive))
        {
            TundraLogic::SceneImporter importer(scene);
            if (IsUrl(filename))
                sceneDescs.append(importer.GetSceneDescForMesh(QUrl(filename)));
            else
                sceneDescs.append(importer.GetSceneDescForMesh(filename));
        }
        else if (filename.toLower().indexOf(cTundraXmlFileExtension) != -1 && filename.toLower().indexOf(cOgreMeshFileExtension) == -1)
        {
            if (IsUrl(filename))
            {
                AssetTransferPtr transfer = framework_->Asset()->RequestAsset(filename);
                if (transfer.get())
                {
                    connect(transfer.get(), SIGNAL(Loaded(AssetPtr)), SLOT(HandleSceneDescLoaded(AssetPtr)));
                    connect(transfer.get(), SIGNAL(Failed(IAssetTransfer*, QString)), SLOT(HandleSceneDescFailed(IAssetTransfer*, QString)));
                    break; // Only allow one .txml drop at a time
                }
            }
            else
                sceneDescs.append(scene->GetSceneDescFromXml(filename));
        }
        else if (filename.toLower().indexOf(cTundraBinFileExtension) != -1)
        {
            if (IsUrl(filename))
            {
                AssetTransferPtr transfer = framework_->Asset()->RequestAsset(filename);
                if (transfer.get())
                {
                    connect(transfer.get(), SIGNAL(Loaded(AssetPtr)), SLOT(HandleSceneDescLoaded(AssetPtr)));
                    connect(transfer.get(), SIGNAL(Failed(IAssetTransfer*, QString)), SLOT(HandleSceneDescFailed(IAssetTransfer*, QString)));
                    break; // Only allow one .tbin drop at a time
                }
            }
            else
            {
                sceneDescs.append(scene->GetSceneDescFromBinary(filename));
            }
        }
        else
        {
#ifdef ASSIMP_ENABLED
            boost::filesystem::path path(filename.toStdString());
            AssImp::OpenAssetImport assimporter;
            QString extension = QString(path.extension().c_str()).toLower();
            if (assimporter.IsSupportedExtension(extension))
            {
                std::string dirname = path.branch_path().string();
                std::vector<AssImp::MeshData> meshNames;
                assimporter.GetMeshData(filename, meshNames);

                TundraLogic::SceneImporter sceneimporter(scene);
                for (size_t i=0 ; i<meshNames.size() ; ++i)
                {
                    Scene::EntityPtr entity = sceneimporter.ImportMesh(meshNames[i].file_.toStdString(), dirname, meshNames[i].transform_,
                        std::string(), "local://", AttributeChange::Default, false, meshNames[i].name_.toStdString());
                    if (entity)
                        ret.append(entity.get());
                }

                return ret;
            }
#endif
        }
    }

    if (!sceneDescs.isEmpty())
    {
        AddContentWindow *addContent = new AddContentWindow(framework_, scene);
        addContent->AddDescription(sceneDescs[0]);
        if (worldPos != Vector3df())
            addContent->AddPosition(worldPos);
        addContent->show();
    }

    // \todo: this is always empty list of entities, remove (?!) as we actually dont know the entity count yet.
    // it is known only after the add content window selectios and processing has been done
    return ret; 
}

void SceneStructureModule::CentralizeEntitiesTo(const Vector3df &pos, const QList<Scene::Entity *> &entities)
{
    Vector3df minPos(1e9f, 1e9f, 1e9f);
    Vector3df maxPos(-1e9f, -1e9f, -1e9f);

    foreach(Scene::Entity *e, entities)
    {
        EC_Placeable *p = e->GetComponent<EC_Placeable>().get();
        if (p)
        {
            Vector3df pos = p->transform.Get().position;
            minPos.x = std::min(minPos.x, pos.x);
            minPos.y = std::min(minPos.y, pos.y);
            minPos.z = std::min(minPos.z, pos.z);
            maxPos.x = std::max(maxPos.x, pos.x);
            maxPos.y = std::max(maxPos.y, pos.y);
            maxPos.z = std::max(maxPos.z, pos.z);
        }
    }

    // We assume that world's up axis is Z-coordinate axis.<commit_msg>Fixed todo comments for previous<commit_after>/**
 *  For conditions of distribution and use, see copyright notice in license.txt
 *
 *  @file   SceneStructureModule.cpp
 *  @brief  Provides Scene Structure and Assets windows and raycast drag-and-drop import of
 *          .mesh, .scene, .xml and .nbf files to the main window.
 */

#include "StableHeaders.h"
#include "DebugOperatorNew.h"

#include "SceneStructureModule.h"
#include "SceneStructureWindow.h"
#include "AssetsWindow.h"
#include "SupportedFileTypes.h"
#include "AddContentWindow.h"

#include "IAsset.h"
#include "IAssetTransfer.h"

#include "SceneManager.h"
#include "Console.h"
#include "UiServiceInterface.h"
#include "Input.h"
#include "RenderServiceInterface.h"
#include "SceneImporter.h"
#include "EC_OgreCamera.h"
#include "EC_Placeable.h"
#include "EC_Mesh.h"
#include "NaaliUi.h"
#include "NaaliGraphicsView.h"
#include "NaaliMainWindow.h"
#include "LoggingFunctions.h"
#include "SceneDesc.h"

#include <OgreEntity.h>
#include <OgreMesh.h>

DEFINE_POCO_LOGGING_FUNCTIONS("SceneStructure");

#ifdef ASSIMP_ENABLED
#include <OpenAssetImport.h>
#endif

//#include <OgreCamera.h>

#include "MemoryLeakCheck.h"

SceneStructureModule::SceneStructureModule() :
    IModule("SceneStructure"),
    sceneWindow(0),
    assetsWindow(0)
{
}

SceneStructureModule::~SceneStructureModule()
{
    SAFE_DELETE(sceneWindow);
}

void SceneStructureModule::PostInitialize()
{
    framework_->Console()->RegisterCommand("scenestruct", "Shows the Scene Structure window.", this, SLOT(ShowSceneStructureWindow()));
    framework_->Console()->RegisterCommand("assets", "Shows the Assets window.", this, SLOT(ShowAssetsWindow()));

    inputContext = framework_->GetInput()->RegisterInputContext("SceneStructureInput", 90);
    connect(inputContext.get(), SIGNAL(KeyPressed(KeyEvent *)), this, SLOT(HandleKeyPressed(KeyEvent *)));

    connect(framework_->Ui()->GraphicsView(), SIGNAL(DragEnterEvent(QDragEnterEvent *)), SLOT(HandleDragEnterEvent(QDragEnterEvent *)));
    connect(framework_->Ui()->GraphicsView(), SIGNAL(DragMoveEvent(QDragMoveEvent *)), SLOT(HandleDragMoveEvent(QDragMoveEvent *)));
    connect(framework_->Ui()->GraphicsView(), SIGNAL(DropEvent(QDropEvent *)), SLOT(HandleDropEvent(QDropEvent *)));
}

QList<Scene::Entity *> SceneStructureModule::InstantiateContent(const QString &filename, Vector3df worldPos, bool clearScene)
{
    return InstantiateContent(filename, worldPos, SceneDesc(), clearScene);
}

QList<Scene::Entity *> SceneStructureModule::InstantiateContent(const QString &filename, Vector3df worldPos, const SceneDesc &desc, bool clearScene)
{
    return InstantiateContent(QStringList(QStringList() << filename), worldPos, desc, clearScene);
}

QList<Scene::Entity *> SceneStructureModule::InstantiateContent(const QStringList &filenames, Vector3df worldPos, const SceneDesc &desc, bool clearScene)
{
    QList<Scene::Entity *> ret;

    const Scene::ScenePtr &scene = framework_->GetDefaultWorldScene();
    if (!scene)
    {
        LogError("Could not retrieve default world scene.");
        return ret;
    }

    QList<SceneDesc> sceneDescs;

    foreach(QString filename, filenames)
    {
        if (!IsSupportedFileType(filename))
        {
            LogError("Unsupported file extension: " + filename.toStdString());
            continue;
        }

        if (filename.endsWith(cOgreSceneFileExtension, Qt::CaseInsensitive))
        {
            ///\todo Implement ogre.scene url drops at some point?
            TundraLogic::SceneImporter importer(scene);
            sceneDescs.append(importer.GetSceneDescForScene(filename));
        }
        else if (filename.endsWith(cOgreMeshFileExtension, Qt::CaseInsensitive))
        {
            TundraLogic::SceneImporter importer(scene);
            if (IsUrl(filename))
                sceneDescs.append(importer.GetSceneDescForMesh(QUrl(filename)));
            else
                sceneDescs.append(importer.GetSceneDescForMesh(filename));
        }
        else if (filename.toLower().indexOf(cTundraXmlFileExtension) != -1 && filename.toLower().indexOf(cOgreMeshFileExtension) == -1)
        {
            if (IsUrl(filename))
            {
                AssetTransferPtr transfer = framework_->Asset()->RequestAsset(filename);
                if (transfer.get())
                {
                    connect(transfer.get(), SIGNAL(Loaded(AssetPtr)), SLOT(HandleSceneDescLoaded(AssetPtr)));
                    connect(transfer.get(), SIGNAL(Failed(IAssetTransfer*, QString)), SLOT(HandleSceneDescFailed(IAssetTransfer*, QString)));
                    break; // Only allow one .txml drop at a time
                }
            }
            else
                sceneDescs.append(scene->GetSceneDescFromXml(filename));
        }
        else if (filename.toLower().indexOf(cTundraBinFileExtension) != -1)
        {
            if (IsUrl(filename))
            {
                AssetTransferPtr transfer = framework_->Asset()->RequestAsset(filename);
                if (transfer.get())
                {
                    connect(transfer.get(), SIGNAL(Loaded(AssetPtr)), SLOT(HandleSceneDescLoaded(AssetPtr)));
                    connect(transfer.get(), SIGNAL(Failed(IAssetTransfer*, QString)), SLOT(HandleSceneDescFailed(IAssetTransfer*, QString)));
                    break; // Only allow one .tbin drop at a time
                }
            }
            else
            {
                sceneDescs.append(scene->GetSceneDescFromBinary(filename));
            }
        }
        else
        {
#ifdef ASSIMP_ENABLED
            boost::filesystem::path path(filename.toStdString());
            AssImp::OpenAssetImport assimporter;
            QString extension = QString(path.extension().c_str()).toLower();
            if (assimporter.IsSupportedExtension(extension))
            {
                std::string dirname = path.branch_path().string();
                std::vector<AssImp::MeshData> meshNames;
                assimporter.GetMeshData(filename, meshNames);

                TundraLogic::SceneImporter sceneimporter(scene);
                for (size_t i=0 ; i<meshNames.size() ; ++i)
                {
                    Scene::EntityPtr entity = sceneimporter.ImportMesh(meshNames[i].file_.toStdString(), dirname, meshNames[i].transform_,
                        std::string(), "local://", AttributeChange::Default, false, meshNames[i].name_.toStdString());
                    if (entity)
                        ret.append(entity.get());
                }

                return ret;
            }
#endif
        }
    }

    if (!sceneDescs.isEmpty())
    {
        AddContentWindow *addContent = new AddContentWindow(framework_, scene);
        addContent->AddDescription(sceneDescs[0]);
        if (worldPos != Vector3df())
            addContent->AddPosition(worldPos);
        addContent->show();
    }

    /** \todo this is always empty list of entities, remove (?!) as we actually dont know the entity count yet.
     *  it is known only after the add content window selectios and processing has been done 
     */
    return ret; 
}

void SceneStructureModule::CentralizeEntitiesTo(const Vector3df &pos, const QList<Scene::Entity *> &entities)
{
    Vector3df minPos(1e9f, 1e9f, 1e9f);
    Vector3df maxPos(-1e9f, -1e9f, -1e9f);

    foreach(Scene::Entity *e, entities)
    {
        EC_Placeable *p = e->GetComponent<EC_Placeable>().get();
        if (p)
        {
            Vector3df pos = p->transform.Get().position;
            minPos.x = std::min(minPos.x, pos.x);
            minPos.y = std::min(minPos.y, pos.y);
            minPos.z = std::min(minPos.z, pos.z);
            maxPos.x = std::max(maxPos.x, pos.x);
            maxPos.y = std::max(maxPos.y, pos.y);
            maxPos.z = std::max(maxPos.z, pos.z);
        }
    }

    // We assume that world's up axis is Z-coordinate axis.
{'fraction_non_alphanumeric': 0.12517438173747622, 'fraction_numerical': 0.0036778693722257453, 'mean_word_length': 2.900816225575068, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 75, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4660153', 'n_tokens_mistral': 4604, 'n_tokens_neox': 4482, 'n_words': 871}