<commit_before>/****************************************************************************************/
/*                                                                                */
/*                                       Pegasus                                        */
/*                                                                                */
/****************************************************************************************/

//! \file	TimelineScript.cpp
//! \author	Kleber Garcia
//! \date	1st November 2014
//! \brief	Script helper for scripting callbacks
#include "Pegasus/Timeline/TimelineManager.h"
#include "Pegasus/Timeline/TimelineScript.h"
#include "Pegasus/Timeline/Timeline.h"
#include "Pegasus/Core/IApplicationContext.h"
#include "Pegasus/Core/Assertion.h"
#include "Pegasus/BlockScript/BlockLib.h"
#include "Pegasus/BlockScript/FunCallback.h"
#include "Pegasus/BlockScript/BlockScriptManager.h"
#include "Pegasus/BlockScript/IFileIncluder.h"
#include "Pegasus/Utils/String.h"
#include "Pegasus/Utils/Memset.h"
#include "Pegasus/Utils/Vector.h"
#include "Pegasus/Core/Log.h"
#include "Pegasus/AssetLib/Asset.h"

#if PEGASUS_ENABLE_PROXIES
#include "Pegasus/BlockScript/SymbolTable.h"
#include "Pegasus/BlockScript/TypeDesc.h"
#endif

using namespace Pegasus;
using namespace Pegasus::Timeline;
using namespace Pegasus::Io;
using namespace Pegasus::BlockScript;
using namespace Pegasus::Alloc;
using namespace Pegasus::Core;

//Helper class to do importing of scripts
class ScriptIncluder : public IFileIncluder
{
public:
    ScriptIncluder(TimelineScript* timelineScript, Pegasus::Timeline::TimelineManager* timelineManager)
    : mTimelineScript(timelineScript), mTimelineManager(timelineManager) {}

    virtual ~ScriptIncluder(){}

    virtual bool Open (const char* filePath, const char** outBuffer, int& outBufferSize);

    virtual void Close(const char* buffer);

private:
    TimelineScript* mTimelineScript;
    Pegasus::Timeline::TimelineManager* mTimelineManager;
};

bool ScriptIncluder::Open(const char* filePath, const char** outBuffer, int& outBufferSize)
{
    TimelineSourceRef t = mTimelineManager->LoadHeader(filePath);
    if (t != nullptr)
    {
        mTimelineScript->AddHeader(t);
        t->RegisterParent(mTimelineScript);
        t->GetSource(outBuffer, outBufferSize);
        return true;
    }
    return false;
}

void ScriptIncluder::Close(const char* buffer)
{
    //do nothing
}

static int Pegasus_PrintString(const char * str)
{
    PG_LOG('TMLN', " {script-echo} %s", str);
    return 0;
}

static int Pegasus_PrintInt(int i)
{
    PG_LOG('TMLN', " {script-echo} %d", i);
    return 0;
}

static int Pegasus_PrintFloat(float f)
{
    PG_LOG('TMLN', " {script-echo} %f", f);
    return 0;
}

void TimelineScript::RegisterTypes(Pegasus::BlockScript::BlockLib* lib)
{
    const Pegasus::BlockScript::StructDeclarationDesc descriptionList[] = {
        {
            "UpdateInfo",
            {"float", "float", nullptr},
            {"beat", "relativeBeat", nullptr}
        },
        {
            "RenderInfo",
            {"float", "float",        "int",      "int",           "int",            "float",          "float",           "float", "float", nullptr},
            {"beat",  "relativeBeat", "windowId", "viewportWidth", "viewportHeight", "viewportWidthF", "viewportHeightF", "aspect", "aspectInv", nullptr}
        }
    };

    lib->CreateStructTypes(descriptionList, sizeof(descriptionList)/sizeof(descriptionList[0]));
#if PEGASUS_ENABLE_PROXIES

    //Sanity check, that the programmer has not forgotten to update the blockscript meta types
    const Pegasus::BlockScript::TypeDesc* updateTypeDesc = lib->GetSymbolTable()->GetTypeTable()->GetTypeByName("UpdateInfo");
    const Pegasus::BlockScript::TypeDesc* renderTypeDesc = lib->GetSymbolTable()->GetTypeTable()->GetTypeByName("RenderInfo");
    PG_ASSERT(updateTypeDesc != nullptr && updateTypeDesc->GetByteSize() == sizeof(UpdateInfo));
    PG_ASSERT(renderTypeDesc != nullptr && renderTypeDesc->GetByteSize() == sizeof(RenderInfo));
#endif
}

TimelineScript::TimelineScript(IAllocator* allocator, Core::IApplicationContext* appContext)
    :
    TimelineSource(allocator),
    mSerialVersion(0),
    mScript(nullptr),
    mIsDirty(true),
    mScriptActive(false),
    mAppContext(appContext),
    mHeaders(allocator)
#if PEGASUS_ENABLE_PROXIES
    ,mCompilationObservers(allocator)
#endif
{

    PG_ASSERT(allocator != nullptr);

    ClearBindPoints();

    //setup the global system callbacks, if not initialized
    if (Pegasus::BlockScript::SystemCallbacks::gPrintStrCallback == nullptr)
    {
        Pegasus::BlockScript::SystemCallbacks::gPrintStrCallback = Pegasus_PrintString;
    }

    if (Pegasus::BlockScript::SystemCallbacks::gPrintIntCallback == nullptr)
    {
        Pegasus::BlockScript::SystemCallbacks::gPrintIntCallback  = Pegasus_PrintInt;
    }

    if (Pegasus::BlockScript::SystemCallbacks::gPrintFloatCallback == nullptr)
    {
        Pegasus::BlockScript::SystemCallbacks::gPrintFloatCallback = Pegasus_PrintFloat;
    }
    mScript = appContext->GetBlockScriptManager()->CreateBlockScript();
    Utils::Vector<BlockScript::BlockLib*>& libs = appContext->GetTimelineManager()->GetLibs();
    for (unsigned int i = 0; i < libs.GetSize(); ++i)
    {
        mScript->IncludeLib(libs[i]);
    }
    mScript->IncludeLib(appContext->GetTimelineManager()->GetTimelineLib());
    mScript->AddCompilerEventListener(this);
}

void TimelineScript::ClearBindPoints()
{
    //Initialize all bind points to invalid
    for (unsigned int i = 0; i < BIND_POINT_COUNT; ++i)
    {
        mBindPoints[i] = Pegasus::BlockScript::FUN_INVALID_BIND_POINT;
    }
}

void TimelineScript::Shutdown()
{
    mScript->Reset();
    ClearBindPoints();
    mScriptActive = false;

}

void TimelineScript::AddHeader(TimelineSourceIn header)
{
    mHeaders.PushEmpty() = header;
}

void TimelineScript::ClearHeaderList()
{
    for (unsigned int i = 0; i < mHeaders.GetSize(); ++i)
    {
        mHeaders[i]->UnregisterParent(this);
        mHeaders[i] = nullptr;
    }

    mHeaders.Clear();
}

void TimelineScript::CallGlobalScopeInit(BsVmState* state)
{
    if (mScriptActive)
    {
        mScript->Run(state);
    }
}

void TimelineScript::CallGlobalScopeDestroy(BsVmState* state)
{
    if (IsValidBindPoint(BIND_POINT_DESTROY))
    {
       int output = -1; //the dummy output
       bool res = mScript->ExecuteFunction(state, mBindPoints[BIND_POINT_DESTROY], nullptr, 0, &output, sizeof(output));
       if (!res)
       {
    #if PEGASUS_ENABLE_PROXIES
           PG_LOG('ERR_', "Error executing Timeline_Destroy function of script %s.", GetDisplayName());
    #endif
       }
    }
}

bool TimelineScript::CompileInternal()
{
    if (mScriptActive == false)
    {
		#define __Q(x) #x
        #define STRINGIFY(x) __Q(x)
        static const char* defNames[] = {
            "MAX_WINDOW_COUNT"
        };
        static const char* defValues[] = {
            STRINGIFY(PEGASUS_MAX_WORLD_WINDOW_COUNT)
        };
        #undef STRINGIFY
		#undef __Q

        ClearHeaderList();
        ScriptIncluder includer(this, mAppContext->GetTimelineManager());
        mScript->SetTitle(
           GetOwnerAsset() != nullptr ? GetOwnerAsset()->GetName() : "<Untilted>"
        );
        mScript->SetFileIncluder(&includer);
        mScript->RegisterDefinitions(defNames, defValues, sizeof(defNames)/sizeof(defNames[0]));
        mScriptActive = mScript->Compile(&mFileBuffer);
        mScript->SetFileIncluder(nullptr);
        const char* types[] = { "float" }; //the only type of this functions is the beat

        const struct BindPointDesc {
            const char* functionName;
            const char* types[10];
            int typesCount;
        } bindPointDescs[BIND_POINT_COUNT] = {
            /***********************************************************************************/
            /**/// Function name                |  parameter list     | parameter list count /**/
            /***********************************************************************************/
            /**/{ "Timeline_OnWindowCreated",   {"int"        },        1},                  /**/
            /**/{ "Timeline_OnWindowDestroyed", {"int"        },        1},                  /**/
            /**/{ "Timeline_Update",            {"UpdateInfo" },        1},                  /**/
            /**/{ "Timeline_Render",            {"RenderInfo" },        1},                  /**/
            /**/{ "Timeline_PostRender",        {"RenderInfo" },        1},                  /**/
            /**/{ "Timeline_Destroy",           {/*empty*/},            0}                   /**/
            /***********************************************************************************/
        };

        if (mScriptActive)
        {

            for (unsigned int bp = 0; bp < BIND_POINT_COUNT; ++bp)
            {
                const BindPointDesc& desc = bindPointDescs[bp];
                mBindPoints[bp] = mScript->GetFunctionBindPoint(desc.functionName, desc.types, desc.typesCount);
           }

            ++mSerialVersion;
        }
        else
        {
            mScript->Reset(); //cleanup, ready for next compilation attempt
        }
    }
    mIsDirty = false;
    return mScriptActive;
}

void TimelineScript::Compile()
{
#if PEGASUS_ENABLE_PROXIES
    //Once compilation is done, go ahead and call all observers
    for (unsigned int i = 0; i < mCompilationObservers.GetSize(); ++i)
    {
        mCompilationObservers[i]->OnCompilationBegin();
    }
#endif

    if (mIsDirty)
    {
        Shutdown();
        CompileInternal();
    }

#if PEGASUS_ENABLE_PROXIES
    //Once compilation is done, go ahead and call all observers
    for (unsigned int i = 0; i < mCompilationObservers.GetSize(); ++i)
    {
        mCompilationObservers[i]->OnCompilationEnd();
    }
#endif
}

void TimelineScript::CallFunction(BsVmState* state, TimelineScript::BindPoint funct, const void* inputBuffer, unsigned inputBufferSz, void* outputBuffer, unsigned outputBufferSz)
{
    if (IsValidBindPoint(funct))
    {
        bool res = mScript->ExecuteFunction(state, mBindPoints[funct], inputBuffer, inputBufferSz, &outputBuffer, outputBufferSz);
        if (!res)
       {
#if PEGASUS_ENABLE_PROXIES
            PG_LOG('ERR_', "Error executing function %d of script %s.", funct, GetDisplayName());
#endif
       }
    }
}

void TimelineScript::CallUpdate(const UpdateInfo& updateInfo, BsVmState* state)
{
    int output = -1;
    CallFunction(state, BIND_POINT_UPDATE, &updateInfo, sizeof(updateInfo), &output, sizeof(output));
}

void TimelineScript::CallRender(const RenderInfo& renderInfo, BsVmState* state)
{
    int output = -1;
    CallFunction(state, BIND_POINT_RENDER, &renderInfo, sizeof(renderInfo), &output, sizeof(output));
}

void TimelineScript::CallWindowCreated(int windowIndex, BsVmState* state)
{
    int output = -1;
    CallFunction(state, BIND_POINT_WINDOW_CREATED, &windowIndex, sizeof(windowIndex), &output, sizeof(output));
}

void TimelineScript::CallWindowDestroyed(int windowIndex, BsVmState* state)
{
    int output = -1;
    CallFunction(state, BIND_POINT_WINDOW_DESTROYED, &windowIndex, sizeof(windowIndex), &output, sizeof(output));
}

TimelineScript::~TimelineScript()
{
    ClearHeaderList();
    mAppContext->GetBlockScriptManager()->DestroyBlockScript(mScript);
}

void TimelineScript::OnCompilationBegin()
{
#if PEGASUS_ENABLE_PROXIES
    PG_LOG('TMLN', "Compilation started for blockscript: %s", GetDisplayName());
#endif

    PEGASUS_EVENT_DISPATCH(
        this,
        CompilerEvents::CompilationNotification,
        // Event specific arguments:
        CompilerEvents::CompilationNotification::COMPILATION_BEGIN,
        "", // unused
        0, // unused
        "" // unused
    );
}

void TimelineScript::OnCompilationError(const char* compilationUnitTitle, int line, const char* errorMessage, const char* token)
{
    PG_LOG('CERR', "[%s:%d]: %s. Around token %s", compilationUnitTitle, line, errorMessage, token);

    PEGASUS_EVENT_DISPATCH(
        this,
        CompilerEvents::CompilationNotification,
        // Shader Event specific arguments
        CompilerEvents::CompilationNotification::COMPILATION_ERROR,
        compilationUnitTitle,
        line,
        errorMessage
    );
}

void TimelineScript::OnCompilationEnd(bool success)
{
    if (success)
    {
#if PEGASUS_ENABLE_PROXIES
        PG_LOG('TMLN', "Compilation succeeded for script %s", GetDisplayName());
#endif
    }
    else
    {
#if PEGASUS_ENABLE_PROXIES
        PG_LOG('CERR', "Compilation failed for script %s", GetDisplayName());
#endif
    }

    PEGASUS_EVENT_DISPATCH (
        this,
        CompilerEvents::CompilationEvent,
        // Event specific arguments
        success ? true : false, //compilation success status
        success ? "" : "Blockscript Compilation Failed."
    );

}

#if PEGASUS_ENABLE_PROXIES
void TimelineScript::RegisterObserver(ITimelineObserver* observer)
{
    mCompilationObservers.PushEmpty() = observer;
}

void TimelineScript::UnregisterObserver(ITimelineObserver* observer)
{
    for (unsigned int i = 0; i < mCompilationObservers.GetSize(); ++i)
    {
        if (observer == mCompilationObservers[i])
        {
            mCompilationObservers.Delete(i);
            return;
        }
    }

    PG_FAILSTR("Failed to delete observer from registration list.");
}
#endif

<commit_msg>Adding simple optimization which significantly speeds up compilation time: If we keep a copy of the child header files, before clearing and recompiling, a copy of the file's contents is kept on memory since the asset is not deallocated. This speeds up compilation time significantly.<commit_after>/****************************************************************************************/
/*                                                                                */
/*                                       Pegasus                                        */
/*                                                                                */
/****************************************************************************************/

//! \file	TimelineScript.cpp
//! \author	Kleber Garcia
//! \date	1st November 2014
//! \brief	Script helper for scripting callbacks
#include "Pegasus/Timeline/TimelineManager.h"
#include "Pegasus/Timeline/TimelineScript.h"
#include "Pegasus/Timeline/Timeline.h"
#include "Pegasus/Core/IApplicationContext.h"
#include "Pegasus/Core/Assertion.h"
#include "Pegasus/BlockScript/BlockLib.h"
#include "Pegasus/BlockScript/FunCallback.h"
#include "Pegasus/BlockScript/BlockScriptManager.h"
#include "Pegasus/BlockScript/IFileIncluder.h"
#include "Pegasus/Utils/String.h"
#include "Pegasus/Utils/Memset.h"
#include "Pegasus/Utils/Vector.h"
#include "Pegasus/Core/Log.h"
#include "Pegasus/AssetLib/Asset.h"

#if PEGASUS_ENABLE_PROXIES
#include "Pegasus/BlockScript/SymbolTable.h"
#include "Pegasus/BlockScript/TypeDesc.h"
#endif

using namespace Pegasus;
using namespace Pegasus::Timeline;
using namespace Pegasus::Io;
using namespace Pegasus::BlockScript;
using namespace Pegasus::Alloc;
using namespace Pegasus::Core;

//Helper class to do importing of scripts
class ScriptIncluder : public IFileIncluder
{
public:
    ScriptIncluder(TimelineScript* timelineScript, Pegasus::Timeline::TimelineManager* timelineManager)
    : mTimelineScript(timelineScript), mTimelineManager(timelineManager) {}

    virtual ~ScriptIncluder(){}

    virtual bool Open (const char* filePath, const char** outBuffer, int& outBufferSize);

    virtual void Close(const char* buffer);

private:
    TimelineScript* mTimelineScript;
    Pegasus::Timeline::TimelineManager* mTimelineManager;
};

bool ScriptIncluder::Open(const char* filePath, const char** outBuffer, int& outBufferSize)
{
    TimelineSourceRef t = mTimelineManager->LoadHeader(filePath);
    if (t != nullptr)
    {
        mTimelineScript->AddHeader(t);
        t->RegisterParent(mTimelineScript);
        t->GetSource(outBuffer, outBufferSize);
        return true;
    }
    return false;
}

void ScriptIncluder::Close(const char* buffer)
{
    //do nothing
}

static int Pegasus_PrintString(const char * str)
{
    PG_LOG('TMLN', " {script-echo} %s", str);
    return 0;
}

static int Pegasus_PrintInt(int i)
{
    PG_LOG('TMLN', " {script-echo} %d", i);
    return 0;
}

static int Pegasus_PrintFloat(float f)
{
    PG_LOG('TMLN', " {script-echo} %f", f);
    return 0;
}

void TimelineScript::RegisterTypes(Pegasus::BlockScript::BlockLib* lib)
{
    const Pegasus::BlockScript::StructDeclarationDesc descriptionList[] = {
        {
            "UpdateInfo",
            {"float", "float", nullptr},
            {"beat", "relativeBeat", nullptr}
        },
        {
            "RenderInfo",
            {"float", "float",        "int",      "int",           "int",            "float",          "float",           "float", "float", nullptr},
            {"beat",  "relativeBeat", "windowId", "viewportWidth", "viewportHeight", "viewportWidthF", "viewportHeightF", "aspect", "aspectInv", nullptr}
        }
    };

    lib->CreateStructTypes(descriptionList, sizeof(descriptionList)/sizeof(descriptionList[0]));
#if PEGASUS_ENABLE_PROXIES

    //Sanity check, that the programmer has not forgotten to update the blockscript meta types
    const Pegasus::BlockScript::TypeDesc* updateTypeDesc = lib->GetSymbolTable()->GetTypeTable()->GetTypeByName("UpdateInfo");
    const Pegasus::BlockScript::TypeDesc* renderTypeDesc = lib->GetSymbolTable()->GetTypeTable()->GetTypeByName("RenderInfo");
    PG_ASSERT(updateTypeDesc != nullptr && updateTypeDesc->GetByteSize() == sizeof(UpdateInfo));
    PG_ASSERT(renderTypeDesc != nullptr && renderTypeDesc->GetByteSize() == sizeof(RenderInfo));
#endif
}

TimelineScript::TimelineScript(IAllocator* allocator, Core::IApplicationContext* appContext)
    :
    TimelineSource(allocator),
    mSerialVersion(0),
    mScript(nullptr),
    mIsDirty(true),
    mScriptActive(false),
    mAppContext(appContext),
    mHeaders(allocator)
#if PEGASUS_ENABLE_PROXIES
    ,mCompilationObservers(allocator)
#endif
{

    PG_ASSERT(allocator != nullptr);

    ClearBindPoints();

    //setup the global system callbacks, if not initialized
    if (Pegasus::BlockScript::SystemCallbacks::gPrintStrCallback == nullptr)
    {
        Pegasus::BlockScript::SystemCallbacks::gPrintStrCallback = Pegasus_PrintString;
    }

    if (Pegasus::BlockScript::SystemCallbacks::gPrintIntCallback == nullptr)
    {
        Pegasus::BlockScript::SystemCallbacks::gPrintIntCallback  = Pegasus_PrintInt;
    }

    if (Pegasus::BlockScript::SystemCallbacks::gPrintFloatCallback == nullptr)
    {
        Pegasus::BlockScript::SystemCallbacks::gPrintFloatCallback = Pegasus_PrintFloat;
    }
    mScript = appContext->GetBlockScriptManager()->CreateBlockScript();
    Utils::Vector<BlockScript::BlockLib*>& libs = appContext->GetTimelineManager()->GetLibs();
    for (unsigned int i = 0; i < libs.GetSize(); ++i)
    {
        mScript->IncludeLib(libs[i]);
    }
    mScript->IncludeLib(appContext->GetTimelineManager()->GetTimelineLib());
    mScript->AddCompilerEventListener(this);
}

void TimelineScript::ClearBindPoints()
{
    //Initialize all bind points to invalid
    for (unsigned int i = 0; i < BIND_POINT_COUNT; ++i)
    {
        mBindPoints[i] = Pegasus::BlockScript::FUN_INVALID_BIND_POINT;
    }
}

void TimelineScript::Shutdown()
{
    mScript->Reset();
    ClearBindPoints();
    mScriptActive = false;

}

void TimelineScript::AddHeader(TimelineSourceIn header)
{
    mHeaders.PushEmpty() = header;
}

void TimelineScript::ClearHeaderList()
{
    for (unsigned int i = 0; i < mHeaders.GetSize(); ++i)
    {
        mHeaders[i]->UnregisterParent(this);
        mHeaders[i] = nullptr;
    }

    mHeaders.Clear();
}

void TimelineScript::CallGlobalScopeInit(BsVmState* state)
{
    if (mScriptActive)
    {
        mScript->Run(state);
    }
}

void TimelineScript::CallGlobalScopeDestroy(BsVmState* state)
{
    if (IsValidBindPoint(BIND_POINT_DESTROY))
    {
       int output = -1; //the dummy output
       bool res = mScript->ExecuteFunction(state, mBindPoints[BIND_POINT_DESTROY], nullptr, 0, &output, sizeof(output));
       if (!res)
       {
    #if PEGASUS_ENABLE_PROXIES
           PG_LOG('ERR_', "Error executing Timeline_Destroy function of script %s.", GetDisplayName());
    #endif
       }
    }
}

bool TimelineScript::CompileInternal()
{
    if (mScriptActive == false)
    {
		#define __Q(x) #x
        #define STRINGIFY(x) __Q(x)
        static const char* defNames[] = {
            "MAX_WINDOW_COUNT"
        };
        static const char* defValues[] = {
            STRINGIFY(PEGASUS_MAX_WORLD_WINDOW_COUNT)
        };
        #undef STRINGIFY
		#undef __Q

        //Compilation speed optimization!
        //So, if we keep a reference of the headers before clearing the header list, it will speed up compilation since it will keep a copy of the file in memory. Otherwise it will have to re-open and parse the file underneath, which slows down compilation significantly.
        Utils::Vector<TimelineSourceRef> headersCopy = mHeaders;

        ClearHeaderList();
        ScriptIncluder includer(this, mAppContext->GetTimelineManager());
        mScript->SetTitle(
           GetOwnerAsset() != nullptr ? GetOwnerAsset()->GetName() : "<Untilted>"
        );
        mScript->SetFileIncluder(&includer);
        mScript->RegisterDefinitions(defNames, defValues, sizeof(defNames)/sizeof(defNames[0]));
        mScriptActive = mScript->Compile(&mFileBuffer);

        headersCopy.Clear(); //don't need the copy anymore.

        mScript->SetFileIncluder(nullptr);
        const char* types[] = { "float" }; //the only type of this functions is the beat

        const struct BindPointDesc {
            const char* functionName;
            const char* types[10];
            int typesCount;
        } bindPointDescs[BIND_POINT_COUNT] = {
            /***********************************************************************************/
            /**/// Function name                |  parameter list     | parameter list count /**/
            /***********************************************************************************/
            /**/{ "Timeline_OnWindowCreated",   {"int"        },        1},                  /**/
            /**/{ "Timeline_OnWindowDestroyed", {"int"        },        1},                  /**/
            /**/{ "Timeline_Update",            {"UpdateInfo" },        1},                  /**/
            /**/{ "Timeline_Render",            {"RenderInfo" },        1},                  /**/
            /**/{ "Timeline_PostRender",        {"RenderInfo" },        1},                  /**/
            /**/{ "Timeline_Destroy",           {/*empty*/},            0}                   /**/
            /***********************************************************************************/
        };

        if (mScriptActive)
        {

            for (unsigned int bp = 0; bp < BIND_POINT_COUNT; ++bp)
            {
                const BindPointDesc& desc = bindPointDescs[bp];
                mBindPoints[bp] = mScript->GetFunctionBindPoint(desc.functionName, desc.types, desc.typesCount);
           }

            ++mSerialVersion;
        }
        else
        {
            mScript->Reset(); //cleanup, ready for next compilation attempt
        }
    }
    mIsDirty = false;
    return mScriptActive;
}

void TimelineScript::Compile()
{
#if PEGASUS_ENABLE_PROXIES
    //Once compilation is done, go ahead and call all observers
    for (unsigned int i = 0; i < mCompilationObservers.GetSize(); ++i)
    {
        mCompilationObservers[i]->OnCompilationBegin();
    }
#endif

    if (mIsDirty)
    {
        Shutdown();
        CompileInternal();
    }

#if PEGASUS_ENABLE_PROXIES
    //Once compilation is done, go ahead and call all observers
    for (unsigned int i = 0; i < mCompilationObservers.GetSize(); ++i)
    {
        mCompilationObservers[i]->OnCompilationEnd();
    }
#endif
}

void TimelineScript::CallFunction(BsVmState* state, TimelineScript::BindPoint funct, const void* inputBuffer, unsigned inputBufferSz, void* outputBuffer, unsigned outputBufferSz)
{
    if (IsValidBindPoint(funct))
    {
        bool res = mScript->ExecuteFunction(state, mBindPoints[funct], inputBuffer, inputBufferSz, &outputBuffer, outputBufferSz);
        if (!res)
       {
#if PEGASUS_ENABLE_PROXIES
            PG_LOG('ERR_', "Error executing function %d of script %s.", funct, GetDisplayName());
#endif
       }
    }
}

void TimelineScript::CallUpdate(const UpdateInfo& updateInfo, BsVmState* state)
{
    int output = -1;
    CallFunction(state, BIND_POINT_UPDATE, &updateInfo, sizeof(updateInfo), &output, sizeof(output));
}

void TimelineScript::CallRender(const RenderInfo& renderInfo, BsVmState* state)
{
    int output = -1;
    CallFunction(state, BIND_POINT_RENDER, &renderInfo, sizeof(renderInfo), &output, sizeof(output));
}

void TimelineScript::CallWindowCreated(int windowIndex, BsVmState* state)
{
    int output = -1;
    CallFunction(state, BIND_POINT_WINDOW_CREATED, &windowIndex, sizeof(windowIndex), &output, sizeof(output));
}

void TimelineScript::CallWindowDestroyed(int windowIndex, BsVmState* state)
{
    int output = -1;
    CallFunction(state, BIND_POINT_WINDOW_DESTROYED, &windowIndex, sizeof(windowIndex), &output, sizeof(output));
}

TimelineScript::~TimelineScript()
{
    ClearHeaderList();
    mAppContext->GetBlockScriptManager()->DestroyBlockScript(mScript);
}

void TimelineScript::OnCompilationBegin()
{
#if PEGASUS_ENABLE_PROXIES
    PG_LOG('TMLN', "Compilation started for blockscript: %s", GetDisplayName());
#endif

    PEGASUS_EVENT_DISPATCH(
        this,
        CompilerEvents::CompilationNotification,
        // Event specific arguments:
        CompilerEvents::CompilationNotification::COMPILATION_BEGIN,
        "", // unused
        0, // unused
        "" // unused
    );
}

void TimelineScript::OnCompilationError(const char* compilationUnitTitle, int line, const char* errorMessage, const char* token)
{
    PG_LOG('CERR', "[%s:%d]: %s. Around token %s", compilationUnitTitle, line, errorMessage, token);

    PEGASUS_EVENT_DISPATCH(
        this,
        CompilerEvents::CompilationNotification,
        // Shader Event specific arguments
        CompilerEvents::CompilationNotification::COMPILATION_ERROR,
        compilationUnitTitle,
        line,
        errorMessage
    );
}

void TimelineScript::OnCompilationEnd(bool success)
{
    if (success)
    {
#if PEGASUS_ENABLE_PROXIES
        PG_LOG('TMLN', "Compilation succeeded for script %s", GetDisplayName());
#endif
    }
    else
    {
#if PEGASUS_ENABLE_PROXIES
        PG_LOG('CERR', "Compilation failed for script %s", GetDisplayName());
#endif
    }

    PEGASUS_EVENT_DISPATCH (
        this,
        CompilerEvents::CompilationEvent,
        // Event specific arguments
        success ? true : false, //compilation success status
        success ? "" : "Blockscript Compilation Failed."
    );

}

#if PEGASUS_ENABLE_PROXIES
void TimelineScript::RegisterObserver(ITimelineObserver* observer)
{
    mCompilationObservers.PushEmpty() = observer;
}

void TimelineScript::UnregisterObserver(ITimelineObserver* observer)
{
    for (unsigned int i = 0; i < mCompilationObservers.GetSize(); ++i)
    {
        if (observer == mCompilationObservers[i])
        {
            mCompilationObservers.Delete(i);
            return;
        }
    }

    PG_FAILSTR("Failed to delete observer from registration list.");
}
#endif

<|endoftext|>


<commit_before>// Copyright (c) 2014 Bauhaus-Universitaet Weimar
// This Software is distributed under the Modified BSD License, see license.txt.
//
// Virtual Reality and Visualization Research Group
// Faculty of Media, Bauhaus-Universitaet Weimar
// http://www.uni-weimar.de/medien/vr

#include <lamure/pre/reduction_pair_contraction.h>
#include <lamure/pre/surfel.h>
#include <set>
#include <functional>
#include <queue>
#include <map>

namespace lamure {

bool operator==(const surfel_id_t& a, const surfel_id_t& b) {
  return a.node_idx == b.node_idx && a.surfel_idx == b.surfel_idx;
}

bool operator<(const surfel_id_t& a, const surfel_id_t& b) {
  if(a.node_idx < b.node_idx) {
    return true;
  }
  else {
    if(a.node_idx == b.node_idx) {
      return a.surfel_idx < b.surfel_idx;
    }
    else return false;
  }
}

namespace pre {
struct edge_t
{
  edge_t(surfel_id_t p1, surfel_id_t p2)
   :a{p1.surfel_idx < p2.surfel_idx ? p1 : p2}
   ,b{p1.surfel_idx >= p2.surfel_idx ? p1 : p2}
   {};

   // operator<(const edge_t& e) const {
   //  return
   // }

  surfel_id_t a;
  surfel_id_t b;
};

bool operator==(const edge_t& e1, const edge_t& e2) {
  if(e1.a == e2.a)   {
    return e1.b == e2.b;
  }
  return false;
}

struct contraction_op;

struct contraction {
  contraction(edge_t e, mat4r quad, real err, surfel surf)
   :edge{e}
   ,quadric{quad}
   ,error{err}
   ,new_surfel{surf}
  {}

  edge_t edge;
  mat4r quadric;
  real error;
  surfel new_surfel;

  contraction_op* cont_op;
};

bool operator<(const contraction& c1, const contraction& c2) {
  return c1.error < c2.error;
}

struct contraction_op {
  contraction_op(contraction* c)
   :cont{c}
  {};

  contraction* cont;
};

bool operator<(const contraction_op& c1, const contraction_op& c2) {
  // return c1.cont->error < c2.cont->error;
  return c1.cont->error > c2.cont->error;
}

}
}

const size_t num_surfels_per_node = 3000;
const size_t num_nodes_per_level = 14348907;
namespace std {
template <> struct hash<lamure::pre::edge_t>
{
  size_t operator()(lamure::pre::edge_t const & e) const noexcept
  {
    uint16_t h1 = e.a.node_idx * num_surfels_per_node + e.a.surfel_idx;
    uint16_t h2 = e.b.node_idx * num_surfels_per_node + e.b.surfel_idx;
    size_t hash = h1;
    hash += h2 >> 16;
    return hash;
  }
};
}
namespace lamure {
namespace pre {

size_t num_neighbours = 20;

surfel_mem_array reduction_pair_contraction::
create_lod(bvh* tree,
          real& reduction_error,
          const std::vector<surfel_mem_array*>& input,
          const uint32_t surfels_per_node) const
{
  std::list<surfel> output_surfels{};

  const uint32_t fan_factor = input.size();
  size_t num_points = 0;
  size_t min_num_surfels = input[0]->length();
  //compute max total number of surfels from all nodes
  for (size_t node_idx = 0; node_idx < fan_factor; ++node_idx) {
    num_points += input[node_idx]->length();

    if (input[node_idx]->length() < min_num_surfels) {
      min_num_surfels = input[node_idx]->length();
    }
  }

  std::map<surfel_id_t, mat4r> quadrics{};
  std::map<surfel_id_t, std::vector<surfel_id_t>> neighbours{};
  std::vector<std::vector<surfel>> surfels{input.size() + 1, std::vector<surfel>{}};
  std::unordered_set<edge_t> edges{};

  // accumulate edges and point quadrics
  size_t offset = 0;
  for (node_id_type node_idx = 0; node_idx < fan_factor; ++node_idx) {
    for (size_t surfel_idx = 0; surfel_idx < input[node_idx]->length(); ++surfel_idx) {

      surfel curr_surfel = input[node_idx]->read_surfel(surfel_idx);
      // save surfel
      surfels[node_idx].push_back(curr_surfel);

      surfel_id_t curr_id = surfel_id_t{node_idx, surfel_idx};
      assert(node_idx < num_nodes_per_level && surfel_idx < num_surfels_per_node);
      // get and store neighbours
      auto nearest_neighbours = get_local_nearest_neighbours(input, num_neighbours, curr_id);
      std::vector<surfel_id_t> neighbour_ids{};
      for(size_t i = 0; i < nearest_neighbours.size(); ++i) {
        const auto& pair = nearest_neighbours[i];
        neighbour_ids.push_back(pair.first);
      }
      neighbours[curr_id] = neighbour_ids;

      mat4r curr_quadric = mat4r::zero();
      for (auto const& neighbour : nearest_neighbours) {
        // store edge
        edge_t curr_edge = edge_t(curr_id, neighbour.first);
        if (edges.find(curr_edge) == edges.end()) {
          assert(neighbour.first.node_idx < num_nodes_per_level && neighbour.first.surfel_idx <num_surfels_per_node);
          edges.insert(curr_edge);
        }
        // accumulate quadric
        surfel neighbour_surfel = input[neighbour.first.node_idx]->read_surfel(neighbour.first.surfel_idx);
        curr_quadric += edge_quadric(curr_surfel.normal(), curr_surfel.pos(), neighbour_surfel.pos());
      }
      quadrics[curr_id] = curr_quadric;
    }
    offset += input[node_idx]->length();
  }

  auto create_contraction = [&input, &quadrics](const edge_t& edge)->contraction {
    surfel surfel1 = input[edge.a.node_idx]->read_surfel(edge.a.surfel_idx);
    surfel surfel2 = input[edge.b.node_idx]->read_surfel(edge.b.surfel_idx);
    // new surfel is mean of both old surfels
    surfel new_surfel = surfel{(surfel1.pos() + surfel2.pos()) * 0.5f,
                          (surfel1.color() + surfel2.color()) * 0.5f,
                          (surfel1.radius() + surfel2.radius()) * 0.5f,
                          (surfel1.normal() + surfel2.normal()) * 0.5f
                          };
    mat4r new_quadric = quadrics.at(edge.a) + quadrics.at(edge.b);
    real error = quadric_error(new_surfel.pos(), new_quadric);
    return contraction{edge, new_quadric, error, new_surfel};
  };

  // store contractions and queue
  std::vector<std::shared_ptr<contraction>> contractions{};
  std::vector<std::shared_ptr<contraction_op>> contraction_queue{};
  for(const auto& edge : edges) {
    contractions.push_back(std::make_shared<contraction>(create_contraction(edge)));

    contraction_op op{std::addressof(*contractions.back())};
    contraction_queue.push_back(std::make_shared<contraction_op>(op));

    contractions.back()->cont_op = std::addressof(*contraction_queue.back());
  }

  // std::list<
  // work off queue until target num of surfels is reached
  size_t new_num_points = num_points;
  while(new_num_points > min_num_surfels) {
    // get next contraction
    contraction curr_contraction = *(contraction_queue.back()->cont);
    // contractions.pop();

    // save new surfel
    const surfel& new_surfel = curr_contraction.new_surfel;
    size_t idx = surfels[fan_factor + 1].size();
    surfels[fan_factor + 1].push_back(new_surfel);

    // invalidate old surfels
    surfels[curr_contraction.edge.a.node_idx][curr_contraction.edge.a.surfel_idx].radius() = 0.0f;
    surfels[curr_contraction.edge.b.node_idx][curr_contraction.edge.b.surfel_idx].radius() = 0.0f;

    for(const auto& neighbour : neighbours[curr_contraction.edge.a]) {
    // get neighbours
    // remove edge quadric from them
    // add new edge quadric
    // recalculate contractions for neighbours
    }
    // update queue, cheapest contraction at the back
    std::sort(contraction_queue.begin(), contraction_queue.end());
  }

  // save valid surfels in mem array
  surfel_mem_array mem_array(std::make_shared<surfel_vector>(surfel_vector()), 0, 0);
  for (const auto& node : surfels) {
    for (const auto& surfel : node) {
      if (surfel.radius() > 0.0f) {
        mem_array.mem_data()->push_back(surfel);
      }
    }
  }
  mem_array.set_length(mem_array.mem_data()->size());

  reduction_error = 0.0;

  return mem_array;
}

lamure::mat4r edge_quadric(const vec3f& normal_p1, const vec3r& p1, const vec3r& p2)
{
    vec3r edge_dir = normalize(p2 - p1);
    vec3r tangent = normalize(cross(vec3r(normal_p1), edge_dir));

    vec3r normal = normalize(cross(tangent, edge_dir));
    vec4r hessian = vec4r{normal, dot(p1, normal)};

    lamure::mat4r quadric = mat4r{hessian * hessian.x,
                                  hessian * hessian.y,
                                  hessian * hessian.z,
                                  hessian * hessian.w};

    return quadric;
}

lamure::real quadric_error(const vec3r& p, const mat4r& quadric)
{
  vec4r p_transformed = quadric * p;
  return dot(p, vec3r{p_transformed} / p_transformed.w);
}

// get k nearest neighbours in simplification nodes
std::vector<std::pair<surfel_id_t, real>>
get_local_nearest_neighbours(const std::vector<surfel_mem_array*>& input,
                             size_t num_local_neighbours,
                             surfel_id_t const& target_surfel) {

    //size_t current_node = target_surfel.node_idx;
    vec3r center = input[target_surfel.node_idx]->read_surfel(target_surfel.surfel_idx).pos();

    std::vector<std::pair<surfel_id_t, real>> candidates;
    real max_candidate_distance = std::numeric_limits<real>::infinity();

    for (size_t local_node_id = 0; local_node_id < input.size(); ++local_node_id) {
        for (size_t surfel_id = 0; surfel_id < input[local_node_id]->length(); ++surfel_id) {
            if (surfel_id != target_surfel.surfel_idx) {
                const surfel& current_surfel = input[local_node_id]->read_surfel(surfel_id);
                real distance_to_center = scm::math::length_sqr(center - current_surfel.pos());

                if (candidates.size() < num_local_neighbours || (distance_to_center < max_candidate_distance)) {
                    if (candidates.size() == num_local_neighbours)
                        candidates.pop_back();

                    candidates.push_back(std::make_pair(surfel_id_t(local_node_id, surfel_id), distance_to_center));

                    for (uint16_t k = candidates.size() - 1; k > 0; --k) {
                        if (candidates[k].second < candidates[k - 1].second) {
                            std::swap(candidates[k], candidates[k - 1]);
                        }
                        else
                            break;
                    }

                    max_candidate_distance = candidates.back().second;
                }
            }
        }
    }

    return candidates;
}

} // namespace pre
} // namespace lamure
<commit_msg>theoretical implementation done except for neighbour quadric update<commit_after>// Copyright (c) 2014 Bauhaus-Universitaet Weimar
// This Software is distributed under the Modified BSD License, see license.txt.
//
// Virtual Reality and Visualization Research Group
// Faculty of Media, Bauhaus-Universitaet Weimar
// http://www.uni-weimar.de/medien/vr

#include <lamure/pre/reduction_pair_contraction.h>
#include <lamure/pre/surfel.h>
#include <set>
#include <functional>
#include <queue>
#include <map>
#include <unordered_map>

namespace lamure {

bool operator==(const surfel_id_t& a, const surfel_id_t& b) {
  return a.node_idx == b.node_idx && a.surfel_idx == b.surfel_idx;
}

bool operator<(const surfel_id_t& a, const surfel_id_t& b) {
  if(a.node_idx < b.node_idx) {
    return true;
  }
  else {
    if(a.node_idx == b.node_idx) {
      return a.surfel_idx < b.surfel_idx;
    }
    else return false;
  }
}

namespace pre {
struct edge_t
{
  edge_t(surfel_id_t p1, surfel_id_t p2)
   :a{p1.surfel_idx < p2.surfel_idx ? p1 : p2}
   ,b{p1.surfel_idx >= p2.surfel_idx ? p1 : p2}
   {};

   // operator<(const edge_t& e) const {
   //  return
   // }

  surfel_id_t a;
  surfel_id_t b;
};

bool operator==(const edge_t& e1, const edge_t& e2) {
  if(e1.a == e2.a)   {
    return e1.b == e2.b;
  }
  return false;
}

struct contraction_op;

struct contraction {
  contraction(edge_t e, mat4r quad, real err, surfel surf)
   :edge{e}
   ,quadric{quad}
   ,error{err}
   ,new_surfel{surf}
  {}

  edge_t edge;
  mat4r quadric;
  real error;
  surfel new_surfel;

  contraction_op* cont_op;
};

bool operator<(const contraction& c1, const contraction& c2) {
  return c1.error < c2.error;
}

struct contraction_op {
  contraction_op(contraction* c)
   :cont{c}
  {};

  contraction* cont;
};

bool operator<(const contraction_op& c1, const contraction_op& c2) {
  // return c1.cont->error < c2.cont->error;
  return c1.cont->error > c2.cont->error;
}

}
}

const size_t num_surfels_per_node = 3000;
const size_t num_nodes_per_level = 14348907;
namespace std {
template <> struct hash<lamure::pre::edge_t>
{
  size_t operator()(lamure::pre::edge_t const & e) const noexcept
  {
    uint16_t h1 = e.a.node_idx * num_surfels_per_node + e.a.surfel_idx;
    uint16_t h2 = e.b.node_idx * num_surfels_per_node + e.b.surfel_idx;
    size_t hash = h1;
    hash += h2 >> 16;
    return hash;
  }
};
}
namespace lamure {
namespace pre {

size_t num_neighbours = 20;

surfel_mem_array reduction_pair_contraction::
create_lod(bvh* tree,
          real& reduction_error,
          const std::vector<surfel_mem_array*>& input,
          const uint32_t surfels_per_node) const
{
  std::list<surfel> output_surfels{};

  const uint32_t fan_factor = input.size();
  size_t num_points = 0;
  size_t min_num_surfels = input[0]->length();
  //compute max total number of surfels from all nodes
  for (size_t node_idx = 0; node_idx < fan_factor; ++node_idx) {
    num_points += input[node_idx]->length();

    if (input[node_idx]->length() < min_num_surfels) {
      min_num_surfels = input[node_idx]->length();
    }
  }

  std::map<surfel_id_t, mat4r> quadrics{};
  std::map<surfel_id_t, std::vector<surfel_id_t>> neighbours{};
  std::vector<std::vector<surfel>> surfels{input.size() + 1, std::vector<surfel>{}};
  std::unordered_set<edge_t> edges{};

  // accumulate edges and point quadrics
  size_t offset = 0;
  for (node_id_type node_idx = 0; node_idx < fan_factor; ++node_idx) {
    for (size_t surfel_idx = 0; surfel_idx < input[node_idx]->length(); ++surfel_idx) {

      surfel curr_surfel = input[node_idx]->read_surfel(surfel_idx);
      // save surfel
      surfels[node_idx].push_back(curr_surfel);

      surfel_id_t curr_id = surfel_id_t{node_idx, surfel_idx};
      assert(node_idx < num_nodes_per_level && surfel_idx < num_surfels_per_node);
      // get and store neighbours
      auto nearest_neighbours = get_local_nearest_neighbours(input, num_neighbours, curr_id);
      std::vector<surfel_id_t> neighbour_ids{};
      for(size_t i = 0; i < nearest_neighbours.size(); ++i) {
        const auto& pair = nearest_neighbours[i];
        neighbour_ids.push_back(pair.first);
      }
      neighbours[curr_id] = neighbour_ids;

      mat4r curr_quadric = mat4r::zero();
      for (auto const& neighbour : nearest_neighbours) {
        // store edge
        edge_t curr_edge = edge_t(curr_id, neighbour.first);
        if (edges.find(curr_edge) == edges.end()) {
          assert(neighbour.first.node_idx < num_nodes_per_level && neighbour.first.surfel_idx <num_surfels_per_node);
          edges.insert(curr_edge);
        }
        // accumulate quadric
        surfel neighbour_surfel = input[neighbour.first.node_idx]->read_surfel(neighbour.first.surfel_idx);
        curr_quadric += edge_quadric(curr_surfel.normal(), curr_surfel.pos(), neighbour_surfel.pos());
      }
      quadrics[curr_id] = curr_quadric;
    }
    offset += input[node_idx]->length();
  }

  auto create_contraction = [&surfels, &quadrics](const edge_t& edge)->contraction {
    surfel surfel1 = surfels[edge.a.node_idx][edge.a.surfel_idx];
    surfel surfel2 = surfels[edge.b.node_idx][edge.b.surfel_idx];
    // new surfel is mean of both old surfels
    surfel new_surfel = surfel{(surfel1.pos() + surfel2.pos()) * 0.5f,
                          (surfel1.color() + surfel2.color()) * 0.5f,
                          (surfel1.radius() + surfel2.radius()) * 0.5f,
                          (surfel1.normal() + surfel2.normal()) * 0.5f
                          };
    mat4r new_quadric = quadrics.at(edge.a) + quadrics.at(edge.b);
    real error = quadric_error(new_surfel.pos(), new_quadric);
    return contraction{edge, new_quadric, error, new_surfel};
  };

  // store contractions and operations in queue
  std::unordered_map<edge_t, std::shared_ptr<contraction>> contractions{};
  std::vector<std::shared_ptr<contraction_op>> contraction_queue{};
  for(const auto& edge : edges) {
    contractions[edge] = std::make_shared<contraction>(create_contraction(edge));

    contraction_op op{std::addressof(*contractions.at(edge))};
    contraction_queue.push_back(std::make_shared<contraction_op>(op));

    contractions.at(edge)->cont_op = std::addressof(*contraction_queue.back());
  }

  // work off queue until target num of surfels is reached
  size_t new_num_points = num_points;
  while(new_num_points > min_num_surfels) {
    // get next contraction
    contraction curr_contraction = *(contraction_queue.back()->cont);
    const edge_t& curr_edge = curr_contraction.edge;
    // save new surfel
    surfel_id_t new_id = surfel_id_t{fan_factor + 1, surfels[fan_factor + 1].size()};
    const surfel& new_surfel = curr_contraction.new_surfel;
    surfels[new_id.node_idx].push_back(new_surfel);

    // delete old point quadrics
    quadrics.erase(curr_contraction.edge.a);
    quadrics.erase(curr_contraction.edge.b);
    // add new point quadric
    quadrics[new_id] = curr_contraction.quadric;

    // invalidate old surfels
    surfels[curr_contraction.edge.a.node_idx][curr_contraction.edge.a.surfel_idx].radius() = 0.0f;
    surfels[curr_contraction.edge.b.node_idx][curr_contraction.edge.b.surfel_idx].radius() = 0.0f;

    auto update_contraction = [&contractions, &contraction_queue](const edge_t& old_edge, const edge_t& new_edge){
      // get contraction
      contraction cont = *(contractions.at(old_edge));
      cont.edge = new_edge;
    // remove edge quadric from them
    // add new edge quadric
      // remove old contraction
      contractions.erase(old_edge);
      // insert new one
      contractions[new_edge] = std::make_shared<contraction>(cont);
      // update attached operation
      contraction_op& operation = *cont.cont_op;
      operation.cont = std::addressof(*(contractions.at(new_edge)));
    };

    for(const auto& neighbour : neighbours[curr_contraction.edge.a]) {
      update_contraction(edge_t{curr_contraction.edge.a, neighbour}, curr_edge);
    }
    for(const auto& neighbour : neighbours[curr_contraction.edge.b]) {
      update_contraction(edge_t{curr_contraction.edge.b, neighbour}, curr_edge);
    }
    // update queue, cheapest contraction at the back
    std::sort(contraction_queue.begin(), contraction_queue.end());
  }

  // save valid surfels in mem array
  surfel_mem_array mem_array(std::make_shared<surfel_vector>(surfel_vector()), 0, 0);
  for (const auto& node : surfels) {
    for (const auto& surfel : node) {
      if (surfel.radius() > 0.0f) {
        mem_array.mem_data()->push_back(surfel);
      }
    }
  }
  mem_array.set_length(mem_array.mem_data()->size());

  reduction_error = 0.0;

  return mem_array;
}

lamure::mat4r edge_quadric(const vec3f& normal_p1, const vec3r& p1, const vec3r& p2)
{
    vec3r edge_dir = normalize(p2 - p1);
    vec3r tangent = normalize(cross(vec3r(normal_p1), edge_dir));

    vec3r normal = normalize(cross(tangent, edge_dir));
    vec4r hessian = vec4r{normal, dot(p1, normal)};

    lamure::mat4r quadric = mat4r{hessian * hessian.x,
                                  hessian * hessian.y,
                                  hessian * hessian.z,
                                  hessian * hessian.w};

    return quadric;
}

lamure::real quadric_error(const vec3r& p, const mat4r& quadric)
{
  vec4r p_transformed = quadric * p;
  return dot(p, vec3r{p_transformed} / p_transformed.w);
}

// get k nearest neighbours in simplification nodes
std::vector<std::pair<surfel_id_t, real>>
get_local_nearest_neighbours(const std::vector<surfel_mem_array*>& input,
                             size_t num_local_neighbours,
                             surfel_id_t const& target_surfel) {

    //size_t current_node = target_surfel.node_idx;
    vec3r center = input[target_surfel.node_idx]->read_surfel(target_surfel.surfel_idx).pos();

    std::vector<std::pair<surfel_id_t, real>> candidates;
    real max_candidate_distance = std::numeric_limits<real>::infinity();

    for (size_t local_node_id = 0; local_node_id < input.size(); ++local_node_id) {
        for (size_t surfel_id = 0; surfel_id < input[local_node_id]->length(); ++surfel_id) {
            if (surfel_id != target_surfel.surfel_idx) {
                const surfel& current_surfel = input[local_node_id]->read_surfel(surfel_id);
                real distance_to_center = scm::math::length_sqr(center - current_surfel.pos());

                if (candidates.size() < num_local_neighbours || (distance_to_center < max_candidate_distance)) {
                    if (candidates.size() == num_local_neighbours)
                        candidates.pop_back();

                    candidates.push_back(std::make_pair(surfel_id_t(local_node_id, surfel_id), distance_to_center));

                    for (uint16_t k = candidates.size() - 1; k > 0; --k) {
                        if (candidates[k].second < candidates[k - 1].second) {
                            std::swap(candidates[k], candidates[k - 1]);
                        }
                        else
                            break;
                    }

                    max_candidate_distance = candidates.back().second;
                }
            }
        }
    }

    return candidates;
}

} // namespace pre
} // namespace lamure
<|endoftext|>


<commit_before>/* -*- Mode: C++; c-basic-offset: 2; tab-width: 2; indent-tabs-mode: nil -*-
 *
 * Quadra, an action puzzle game
 * Copyright (C) 1998-2000  Ludus Design
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "input.h"

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "SDL.h"

#include "video.h"
#include "cursor.h"

Input *input = NULL;

Input::Input()
  : key_pending(0),
    pause(false) {
  mouse.quel = -1;
  for (int i = 0; i < 4; ++i)
    mouse.button[i] = RELEASED;
  mouse.wheel = 0;
  clear_key();
}

void Input::clear_key() {
  clear_last_keysym();
  key_pending = 0;
  memset(keys, 0, sizeof(keys));
}

void Input::clear_last_keysym() {
  last_keysym.scancode = SDL_SCANCODE_UNKNOWN;
  last_keysym.sym = SDLK_UNKNOWN;
  last_keysym.mod = 0;
}

class Input_SDL : public Input {
public:
  Input_SDL()
    : israw(true) {
  }

  virtual void check() {
    SDL_Event event;

    while (SDL_PollEvent(&event) > 0) {
      switch (event.type) {
        case SDL_QUIT:
          exit(0);

        case SDL_MOUSEMOTION:
          if (cursor)
            cursor->set_pos(event.motion.x, event.motion.y);
          break;

        case SDL_MOUSEBUTTONDOWN:
          switch (event.button.button) {
            case 1:
              if (mouse.button[event.button.button - 1] == RELEASED)
                mouse.quel = event.button.button - 1;
              mouse.button[event.button.button - 1] = PRESSED;
              break;

            default:
              SDL_Log("unknown button down: %i", event.button.button);
          }
          break;

        case SDL_MOUSEBUTTONUP:
          switch (event.button.button) {
            case 1:
              mouse.button[event.button.button - 1] = RELEASED;
              break;

            default:
              SDL_Log("unknown button up: %i", event.button.button);
          }
          break;

        case SDL_KEYDOWN:
          keys[event.key.keysym.scancode] |= PRESSED;
          last_keysym = event.key.keysym;

          if (!israw && key_pending < MAXKEY) {
            key_buf[key_pending].special = true;
            key_buf[key_pending].c = 0;
            key_buf[key_pending].sym = event.key.keysym.sym;
            key_buf[key_pending].mod = event.key.keysym.mod;
            ++key_pending;
          }

          break;

        case SDL_KEYUP:
          keys[event.key.keysym.scancode] = RELEASED;
          break;

        case SDL_TEXTINPUT:
          if (!israw && key_pending < MAXKEY && event.text.text[0] && !event.text.text[1]) {
            key_buf[key_pending].special = false;
            key_buf[key_pending].c = event.text.text[0];
            ++key_pending;
          }
          break;

        case SDL_WINDOWEVENT:
          switch (event.window.event) {
            case SDL_WINDOWEVENT_LEAVE:
              if (cursor)
                cursor->set_pos(-1, -1);
              break;

            default:
              SDL_Log("unknown window event: %i", event.window.event);
          }
          break;

	case SDL_MOUSEWHEEL:
	  mouse.wheel = event.wheel.y;
	  break;

        // Ignore these events.
        case SDL_FINGERDOWN:
        case SDL_FINGERUP:
        case SDL_FINGERMOTION:
        case SDL_MULTIGESTURE:
          break;

        default:
          SDL_Log("unknown event: 0x%x", event.type);
      }
    }
  }

  virtual void deraw() {
    israw = false;
  }

  virtual void reraw() {
    israw = true;
  }

private:
  bool israw;
};

class Input_Dumb: public Input {
public:
  virtual void check() {}
  virtual void deraw() {}
  virtual void reraw() {}
};

Input* Input::New(bool dumb) {
  if (dumb)
    return new Input_Dumb;
  else
    return new Input_SDL;
}

<commit_msg>Input_SDL::pause is now set to true when Pause key is pressed<commit_after>/* -*- Mode: C++; c-basic-offset: 2; tab-width: 2; indent-tabs-mode: nil -*-
 *
 * Quadra, an action puzzle game
 * Copyright (C) 1998-2000  Ludus Design
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "input.h"

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "SDL.h"

#include "video.h"
#include "cursor.h"

Input *input = NULL;

Input::Input()
  : key_pending(0),
    pause(false) {
  mouse.quel = -1;
  for (int i = 0; i < 4; ++i)
    mouse.button[i] = RELEASED;
  mouse.wheel = 0;
  clear_key();
}

void Input::clear_key() {
  clear_last_keysym();
  key_pending = 0;
  memset(keys, 0, sizeof(keys));
}

void Input::clear_last_keysym() {
  last_keysym.scancode = SDL_SCANCODE_UNKNOWN;
  last_keysym.sym = SDLK_UNKNOWN;
  last_keysym.mod = 0;
}

class Input_SDL : public Input {
public:
  Input_SDL()
    : israw(true) {
  }

  virtual void check() {
    SDL_Event event;

    while (SDL_PollEvent(&event) > 0) {
      switch (event.type) {
        case SDL_QUIT:
          exit(0);

        case SDL_MOUSEMOTION:
          if (cursor)
            cursor->set_pos(event.motion.x, event.motion.y);
          break;

        case SDL_MOUSEBUTTONDOWN:
          switch (event.button.button) {
            case 1:
              if (mouse.button[event.button.button - 1] == RELEASED)
                mouse.quel = event.button.button - 1;
              mouse.button[event.button.button - 1] = PRESSED;
              break;

            default:
              SDL_Log("unknown button down: %i", event.button.button);
          }
          break;

        case SDL_MOUSEBUTTONUP:
          switch (event.button.button) {
            case 1:
              mouse.button[event.button.button - 1] = RELEASED;
              break;

            default:
              SDL_Log("unknown button up: %i", event.button.button);
          }
          break;

        case SDL_KEYDOWN:
          keys[event.key.keysym.scancode] |= PRESSED;
          last_keysym = event.key.keysym;

          if (event.key.keysym.sym == SDLK_PAUSE)
              pause = true;

          if (!israw && key_pending < MAXKEY) {
            key_buf[key_pending].special = true;
            key_buf[key_pending].c = 0;
            key_buf[key_pending].sym = event.key.keysym.sym;
            key_buf[key_pending].mod = event.key.keysym.mod;
            ++key_pending;
          }

          break;

        case SDL_KEYUP:
          keys[event.key.keysym.scancode] = RELEASED;
          break;

        case SDL_TEXTINPUT:
          if (!israw && key_pending < MAXKEY && event.text.text[0] && !event.text.text[1]) {
            key_buf[key_pending].special = false;
            key_buf[key_pending].c = event.text.text[0];
            ++key_pending;
          }
          break;

        case SDL_WINDOWEVENT:
          switch (event.window.event) {
            case SDL_WINDOWEVENT_LEAVE:
              if (cursor)
                cursor->set_pos(-1, -1);
              break;

            default:
              SDL_Log("unknown window event: %i", event.window.event);
          }
          break;

	case SDL_MOUSEWHEEL:
	  mouse.wheel = event.wheel.y;
	  break;

        // Ignore these events.
        case SDL_FINGERDOWN:
        case SDL_FINGERUP:
        case SDL_FINGERMOTION:
        case SDL_MULTIGESTURE:
          break;

        default:
          SDL_Log("unknown event: 0x%x", event.type);
      }
    }
  }

  virtual void deraw() {
    israw = false;
  }

  virtual void reraw() {
    israw = true;
  }

private:
  bool israw;
};

class Input_Dumb: public Input {
public:
  virtual void check() {}
  virtual void deraw() {}
  virtual void reraw() {}
};

Input* Input::New(bool dumb) {
  if (dumb)
    return new Input_Dumb;
  else
    return new Input_SDL;
}

<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX64M/RX71M/RX651/RX65N/RX66T/RX72T/RX72N/RX72M グループ・システム制御 @n
			※RX24T は構成が大きく異なるので、RX24T/system_io.hpp に分離しています。@n
			※ USB を使う場合：96MHz, 144MHz, 192MHz, 240MHz のいづれか @n
			※ 通常ベースクロックは、12MHz、24MHz を使います。@n
			RX72x 系では、内部 PLL 回路が追加され、Ethernet などに必要な 25MHz を得る為 @n
			16MHz を使います。@n
			(16MHz x 12.5 -> 200MHz, 16MHz x 15 -> 240MHz)
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017, 2020 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "RX600/system.hpp"

#if defined(F_ICLK) && defined(F_PCLKA) && defined(F_PCLKB) && defined(F_PCLKC) && defined(F_PCLKD) && defined(F_FCLK) && defined(F_BCLK)
#else
#  error "system_io.hpp requires F_[IFB]CLK and F_PCLK[ABCD] to be defined"
#endif

#if defined(SIG_RX24T)
#  error "system_io.hpp: Not available on RX24T"
#endif

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  systen_io クラス @n
				INTR_CLOCK は、内部 PLL で扱える最大速度です、@n
				外部クリスタルを微妙な周波数にする場合、その整数倍にしなければなりません。@n
		@param[in]	BASE_CLOCK	ベース・クロック周波数（１２ＭＨｚ）
		@param[in]	INTR_CLOCK	内臓クロック周波数（２４０ＭＨｚ）@n
								※USB を使う場合、「INTR_CLOCK」は48の倍数である事
		@param[in]	EXT_CLOCK	外部クロックに入力を行う場合「true」
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <uint32_t BASE_CLOCK = 12'000'000, uint32_t INTR_CLOCK = 240'000'000, bool EXT_CLOCK = false>
	struct system_io {

		static uint8_t clock_div_(uint32_t clk) noexcept
		{
			uint8_t div = 0;
			while(clk < INTR_CLOCK) {
				++div;
				clk <<= 1;
			}
			return div;
		}

		//-------------------------------------------------------------//
		/*!
			@brief  システム・クロックの設定
		*/
		//-------------------------------------------------------------//
		static void setup_system_clock() noexcept
		{
			device::SYSTEM::PRCR = 0xA50B;	// クロック、低消費電力、関係書き込み許可

			device::SYSTEM::MOSCWTCR = 9;	// 1ms wait
			// メインクロック強制発振とドライブ能力設定
			uint8_t modrv2 = 0b11;
			if(BASE_CLOCK > 20'000'000) modrv2 = 0b00;
			else if(BASE_CLOCK > 16'000'000) modrv2 = 0b01;
			else if(BASE_CLOCK > 8'000'000) modrv2 = 0b10;
			device::SYSTEM::MOFCR = device::SYSTEM::MOFCR.MODRV2.b(modrv2)
						  | device::SYSTEM::MOFCR.MOSEL.b(EXT_CLOCK);
///						  device::SYSTEM::MOFCR.MOFXIN.b(1)
			device::SYSTEM::MOSCCR.MOSTP = 0;		// メインクロック発振器動作
			while(device::SYSTEM::OSCOVFSR.MOOVF() == 0) { asm("nop"); }

			// RX71M、240MHz 時の MEMWAIT はスーパーバイザモードでの設定が必須なので、
			// device::SYSTEM::MEMWAIT = 1; は、start.s で設定される。

#if defined(SIG_RX65N)
			if(F_ICLK >= 120'000'000) {  // 120MHz 以上の場合設定
				device::SYSTEM::ROMWT = 0b10;
			} else if(F_ICLK >= 100'000'000) {
				device::SYSTEM::ROMWT = 0b01;
			} else if(F_ICLK >= 50'000'000) {
				device::SYSTEM::ROMWT = 0b00;
			}
#endif
#if defined(SIG_RX66T) || defined(SIG_RX72M) || defined(SIG_RX72T) || defined(SIG_RX72N)
			if(F_ICLK > 120'000'000) {  // 120MHz 以上の場合設定
				device::SYSTEM::MEMWAIT = 1;
			}
#endif
			// (x10.0) 0b010011, (x10.5) 0b010100, (x11.0) 0b010101, (x11.5) 0b010110
			// ... MAX x30.0
			uint32_t n = INTR_CLOCK * 2 / BASE_CLOCK;
			if(n < 20) n = 20;
			else if(n > 60) n = 60;
			n -= 20;
			device::SYSTEM::PLLCR.STC = n + 0b010011;  // base x10
			device::SYSTEM::PLLCR2.PLLEN = 0;			// PLL 動作
			while(device::SYSTEM::OSCOVFSR.PLOVF() == 0) { asm("nop"); }

			device::SYSTEM::SCKCR = device::SYSTEM::SCKCR.FCK.b(clock_div_(F_FCLK))
								  | device::SYSTEM::SCKCR.ICK.b(clock_div_(F_ICLK))
								  | device::SYSTEM::SCKCR.BCK.b(clock_div_(F_BCLK))
								  | device::SYSTEM::SCKCR.PCKA.b(clock_div_(F_PCLKA))
								  | device::SYSTEM::SCKCR.PCKB.b(clock_div_(F_PCLKB))
								  | device::SYSTEM::SCKCR.PCKC.b(clock_div_(F_PCLKC))
								  | device::SYSTEM::SCKCR.PCKD.b(clock_div_(F_PCLKD));
			{  // USB Master Clock の設定
				auto usb_div = INTR_CLOCK / 48000000;
				if(usb_div >= 2 && usb_div <= 5) {
					// 1/2, 1/3, 1/4, 1/5
					device::SYSTEM::SCKCR2.UCK = usb_div - 1;
				}
			}
			device::SYSTEM::SCKCR3.CKSEL = 0b100;	///< PLL 選択

			device::SYSTEM::LOCOCR.LCSTP = 1;  ///< 低速オンチップオシレータ停止
			device::SYSTEM::HOCOCR.HCSTP = 1;  ///< 高速オンチップオシレータ停止

			// クロック関係書き込み不許可
			device::SYSTEM::PRCR = 0xA500;

#if defined(SIG_RX65N) || defined(SIG_RX66T) || defined(SIG_RX72M) || defined(SIG_RX72T) || defined(SIG_RX72N)
			// ROM キャッシュを有効（標準）
			device::SYSTEM::ROMCE = 1;
#endif
		}
	};

	//-------------------------------------------------------------//
	/*!
		@brief  ソフト・リセットの起動
	*/
	//-------------------------------------------------------------//
	inline void assert_soft_reset()
	{
		device::SYSTEM::PRCR = 0xA502;
		device::SYSTEM::SWRR = 0xA501;
		device::SYSTEM::PRCR = 0xA500;
	}

#if defined(SIG_RX72M) || defined(SIG_RX72N)
	//-------------------------------------------------------------//
	/*!
		@brief  PPLL 制御を使って PHY 向け 25MHz を出力する。
		@return 成功なら「true」
	*/
	//-------------------------------------------------------------//
	bool setup_phy25()
	{

		return true;
	}

#endif

	//-------------------------------------------------------------//
	/*!
		@brief  MTU マスタークロック取得
		@return MTU マスタークロック
	*/
	//-------------------------------------------------------------//
	inline uint32_t get_mtu_master_clock() noexcept
	{
#if defined(SIG_RX66T)
		return F_PCLKC;
#else
		return F_PCLKA;
#endif
	}
}
<commit_msg>Update: MEMWAIT dummy read<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX64M/RX71M/RX651/RX65N/RX66T/RX72T/RX72N/RX72M グループ・システム制御 @n
			※RX24T は構成が大きく異なるので、RX24T/system_io.hpp に分離しています。@n
			※ USB を使う場合：96MHz, 144MHz, 192MHz, 240MHz のいづれか @n
			※ 通常ベースクロックは、12MHz、24MHz を使います。@n
			RX72x 系では、内部 PLL 回路が追加され、Ethernet などに必要な 25MHz を得る為 @n
			16MHz を使います。@n
			(16MHz x 12.5 -> 200MHz, 16MHz x 15 -> 240MHz)
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017, 2020 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "RX600/system.hpp"

#if defined(F_ICLK) && defined(F_PCLKA) && defined(F_PCLKB) && defined(F_PCLKC) && defined(F_PCLKD) && defined(F_FCLK) && defined(F_BCLK)
#else
#  error "system_io.hpp requires F_[IFB]CLK and F_PCLK[ABCD] to be defined"
#endif

#if defined(SIG_RX24T)
#  error "system_io.hpp: Not available on RX24T"
#endif

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  systen_io クラス @n
				INTR_CLOCK は、内部 PLL で扱える最大速度です、@n
				外部クリスタルを微妙な周波数にする場合、その整数倍にしなければなりません。@n
		@param[in]	BASE_CLOCK	ベース・クロック周波数（１２ＭＨｚ）
		@param[in]	INTR_CLOCK	内臓クロック周波数（２４０ＭＨｚ）@n
								※USB を使う場合、「INTR_CLOCK」は48の倍数である事
		@param[in]	EXT_CLOCK	外部クロックに入力を行う場合「true」
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <uint32_t BASE_CLOCK = 12'000'000, uint32_t INTR_CLOCK = 240'000'000, bool EXT_CLOCK = false>
	struct system_io {

		static uint8_t clock_div_(uint32_t clk) noexcept
		{
			uint8_t div = 0;
			while(clk < INTR_CLOCK) {
				++div;
				clk <<= 1;
			}
			return div;
		}

		//-------------------------------------------------------------//
		/*!
			@brief  システム・クロックの設定
		*/
		//-------------------------------------------------------------//
		static void setup_system_clock() noexcept
		{
			device::SYSTEM::PRCR = 0xA50B;	// クロック、低消費電力、関係書き込み許可

			device::SYSTEM::MOSCWTCR = 9;	// 1ms wait
			// メインクロック強制発振とドライブ能力設定
			uint8_t modrv2 = 0b11;
			if(BASE_CLOCK > 20'000'000) modrv2 = 0b00;
			else if(BASE_CLOCK > 16'000'000) modrv2 = 0b01;
			else if(BASE_CLOCK > 8'000'000) modrv2 = 0b10;
			device::SYSTEM::MOFCR = device::SYSTEM::MOFCR.MODRV2.b(modrv2)
						  | device::SYSTEM::MOFCR.MOSEL.b(EXT_CLOCK);
///						  device::SYSTEM::MOFCR.MOFXIN.b(1)
			device::SYSTEM::MOSCCR.MOSTP = 0;		// メインクロック発振器動作
			while(device::SYSTEM::OSCOVFSR.MOOVF() == 0) { asm("nop"); }

			// RX71M、240MHz 時の MEMWAIT はスーパーバイザモードでの設定が必須なので、
			// device::SYSTEM::MEMWAIT = 1; は、start.s で設定される。

#if defined(SIG_RX65N)
			if(F_ICLK >= 120'000'000) {  // 120MHz 以上の場合設定
				device::SYSTEM::ROMWT = 0b10;
			} else if(F_ICLK >= 100'000'000) {
				device::SYSTEM::ROMWT = 0b01;
			} else if(F_ICLK >= 50'000'000) {
				device::SYSTEM::ROMWT = 0b00;
			}
#endif
#if defined(SIG_RX66T) || defined(SIG_RX72M) || defined(SIG_RX72T) || defined(SIG_RX72N)
			if(F_ICLK > 120'000'000) {  // 120MHz 以上の場合設定
				device::SYSTEM::MEMWAIT = 1;
				volatile auto tmp = device::SYSTEM::MEMWAIT();  // 読み出しを行う
			}
#endif
			// (x10.0) 0b010011, (x10.5) 0b010100, (x11.0) 0b010101, (x11.5) 0b010110
			// ... MAX x30.0
			uint32_t n = INTR_CLOCK * 2 / BASE_CLOCK;
			if(n < 20) n = 20;
			else if(n > 60) n = 60;
			n -= 20;
			device::SYSTEM::PLLCR.STC = n + 0b010011;  // base x10
			device::SYSTEM::PLLCR2.PLLEN = 0;			// PLL 動作
			while(device::SYSTEM::OSCOVFSR.PLOVF() == 0) { asm("nop"); }

			device::SYSTEM::SCKCR = device::SYSTEM::SCKCR.FCK.b(clock_div_(F_FCLK))
								  | device::SYSTEM::SCKCR.ICK.b(clock_div_(F_ICLK))
								  | device::SYSTEM::SCKCR.BCK.b(clock_div_(F_BCLK))
								  | device::SYSTEM::SCKCR.PCKA.b(clock_div_(F_PCLKA))
								  | device::SYSTEM::SCKCR.PCKB.b(clock_div_(F_PCLKB))
								  | device::SYSTEM::SCKCR.PCKC.b(clock_div_(F_PCLKC))
								  | device::SYSTEM::SCKCR.PCKD.b(clock_div_(F_PCLKD));
			{  // USB Master Clock の設定
				auto usb_div = INTR_CLOCK / 48000000;
				if(usb_div >= 2 && usb_div <= 5) {
					// 1/2, 1/3, 1/4, 1/5
					device::SYSTEM::SCKCR2.UCK = usb_div - 1;
				}
			}
			device::SYSTEM::SCKCR3.CKSEL = 0b100;	///< PLL 選択

			device::SYSTEM::LOCOCR.LCSTP = 1;  ///< 低速オンチップオシレータ停止
			device::SYSTEM::HOCOCR.HCSTP = 1;  ///< 高速オンチップオシレータ停止

			// クロック関係書き込み不許可
			device::SYSTEM::PRCR = 0xA500;

#if defined(SIG_RX65N) || defined(SIG_RX66T) || defined(SIG_RX72M) || defined(SIG_RX72T) || defined(SIG_RX72N)
			// ROM キャッシュを有効（標準）
			device::SYSTEM::ROMCE = 1;
#endif
		}
	};

	//-------------------------------------------------------------//
	/*!
		@brief  ソフト・リセットの起動
	*/
	//-------------------------------------------------------------//
	inline void assert_soft_reset()
	{
		device::SYSTEM::PRCR = 0xA502;
		device::SYSTEM::SWRR = 0xA501;
		device::SYSTEM::PRCR = 0xA500;
	}

#if defined(SIG_RX72M) || defined(SIG_RX72N)
	//-------------------------------------------------------------//
	/*!
		@brief  PPLL 制御を使って PHY 向け 25MHz を出力する。
		@return 成功なら「true」
	*/
	//-------------------------------------------------------------//
	bool setup_phy25()
	{

		return true;
	}

#endif

	//-------------------------------------------------------------//
	/*!
		@brief  MTU マスタークロック取得
		@return MTU マスタークロック
	*/
	//-------------------------------------------------------------//
	inline uint32_t get_mtu_master_clock() noexcept
	{
#if defined(SIG_RX66T)
		return F_PCLKC;
#else
		return F_PCLKA;
#endif
	}
}
<|endoftext|>


<commit_before>/*
    Copyright 2015 Ahnaf Siddiqui

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

#include <memory>

#include "Q_QuantumWorld2D.h"
using namespace Quantum2D;

#include "D_AudioManager2D.h"
#include "D_Game.h"
#include "D_GameObject2D.h"
#include "D_Graphics2D.h"
#include "D_Input.h"
#include "D_Launcher.h"
#include "D_Time.h"
using namespace Diamond;

class Demo : public Game {
	public:
	const float movespeed = 0.75f;
	const float spinspeed = 0.75f;
	const float growspeed = 0.00075f;

	std::unique_ptr<GameObject2D> spike;

	std::shared_ptr<Texture> spike_sprite;
	std::shared_ptr<Texture> cloud_sprite;

	RGBA spike_color = RGBA{255, 255, 255, 255};

	std::unique_ptr<Sound2D> haha;

	void init() override {
		spike_sprite = std::shared_ptr<Texture>(Graphics2D::loadTexture("spike.png"));
		cloud_sprite = std::shared_ptr<Texture>(Graphics2D::loadTexture("cloud.png"));

		spike = std::unique_ptr<GameObject2D>(new GameObject2D(cloud_sprite));
		spike->setTransform(500, 400);
		spike->setScale(0.1f);

		haha = std::unique_ptr<Sound2D>(AudioManager2D::loadSound("haha.wav"));
	}

	void update(uint32_t delta) override {
		// Coloring
		if (Input::keydown[Input::K_R]) {
			spike_color = {255, 0, 0, 255};
			spike->getSprite()->setColor(spike_color);
		}
		if (Input::keydown[Input::K_T]) {
			spike_color = {255, 255, 255, 255};
			spike->getSprite()->setColor(spike_color);
		}
		if (Input::keyup[Input::K_Y]) {
			RGBA sc = spike->getSprite()->getColor();
			sc.a -= 32;
			spike->getSprite()->setColor(sc);
		}

		// Sprite switching
		if (Input::keyup[Input::K_1]) {
			spike->setSprite(spike_sprite);
		}
		if (Input::keyup[Input::K_2]) {
			spike->setSprite(cloud_sprite);
		}

		// Visibility
		if (Input::keyup[Input::K_SPACE]) {
			spike->toggleVisibility();
		}

		// Stretching
		if (Input::keydown[Input::K_LSHIFT]) {
			spike->setScale(spike->getScale() + growspeed * delta);
		}
		if (Input::keydown[Input::K_LCTRL]) {
			spike->setScale(spike->getScale() - growspeed * delta);
		}

		// Flipping
		if (Input::keyup[Input::K_DOWN]) {
			spike->flipX();
		}
		if (Input::keyup[Input::K_UP]) {
			spike->flipY();
		}

		// Movement
		if (Input::keydown[Input::K_W]) {
//			Transform2i trans = spike->getTransform();
//			trans.position.y -= movespeed * delta;
//			spike->setTransform(trans);
			spike->getTransform().position.y -= movespeed * delta;
		}
		if (Input::keydown[Input::K_S]) {
//			Transform2i trans = spike->getTransform();
//			trans.position.y += movespeed * delta;
//			spike->setTransform(trans);
			spike->getTransform().position.y += movespeed * delta;
		}
		if (Input::keydown[Input::K_A]) {
//			Transform2i trans = spike->getTransform();
//			trans.position.x -= movespeed * delta;
//			spike->setTransform(trans);
			spike->getTransform().position.x -= movespeed * delta;
		}
		if (Input::keydown[Input::K_D]) {
//			Transform2i trans = spike->getTransform();
//			trans.position.x += movespeed * delta;
//			spike->setTransform(trans);
			spike->getTransform().position.x += movespeed * delta;
		}

		// Rotation
		if (Input::keydown[Input::K_LEFT]) {
			spike->setRotation(spike->getTransform().rotation - spinspeed * delta);
		}
		if (Input::keydown[Input::K_RIGHT]) {
			spike->setRotation(spike->getTransform().rotation + spinspeed * delta);
		}

		// Sound
		if (Input::keyup[Input::K_F]) {
			haha->play();
		}

//		std::cout << "x flip: " << spike->isFlippedX() << "; y flip: " << spike->isFlippedY() << std::endl;
//		std::cout << "Delta = " << delta << "ms; FPS = " << Time::fps << std::endl;
	}

	void quit() override {};
};

int main(int argc, char *argv[]) {
	Demo demo;

	Launcher::config.vsync = true;
	Launcher::config.bg_color = {0, 128, 255, 255};
	Launcher::launch(demo);

	return 0;
}
<commit_msg>Deleted Diamond folder<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
 *           (C) 2001 Dirk Mueller (mueller@kde.org)
 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
 *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
 *
 * 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., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 *
 */

#include "config.h"
#include "core/html/FormAssociatedElement.h"

#include "core/HTMLNames.h"
#include "core/dom/IdTargetObserver.h"
#include "core/dom/NodeTraversal.h"
#include "core/html/HTMLFormControlElement.h"
#include "core/html/HTMLFormElement.h"
#include "core/html/HTMLLabelElement.h"
#include "core/html/HTMLObjectElement.h"
#include "core/html/ValidityState.h"

namespace blink {

using namespace HTMLNames;

class FormAttributeTargetObserver : public IdTargetObserver {
    WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED;
public:
    static PassOwnPtrWillBeRawPtr<FormAttributeTargetObserver> create(const AtomicString& id, FormAssociatedElement*);
    virtual void trace(Visitor*) override;
    virtual void idTargetChanged() override;

private:
    FormAttributeTargetObserver(const AtomicString& id, FormAssociatedElement*);

    RawPtrWillBeMember<FormAssociatedElement> m_element;
};

FormAssociatedElement::FormAssociatedElement()
    : m_formWasSetByParser(false)
{
}

FormAssociatedElement::~FormAssociatedElement()
{
    // We can't call setForm here because it contains virtual calls.
}

void FormAssociatedElement::trace(Visitor* visitor)
{
    visitor->trace(m_formAttributeTargetObserver);
    visitor->trace(m_form);
    visitor->trace(m_validityState);
}

ValidityState* FormAssociatedElement::validity()
{
    if (!m_validityState)
        m_validityState = ValidityState::create(this);

    return m_validityState.get();
}

void FormAssociatedElement::didMoveToNewDocument(Document& oldDocument)
{
    HTMLElement* element = toHTMLElement(this);
    if (element->fastHasAttribute(formAttr))
        setFormAttributeTargetObserver(nullptr);
}

void FormAssociatedElement::insertedInto(ContainerNode* insertionPoint)
{
    if (!m_formWasSetByParser || !m_form || NodeTraversal::highestAncestorOrSelf(*insertionPoint) != NodeTraversal::highestAncestorOrSelf(*m_form.get()))
        resetFormOwner();

    if (!insertionPoint->inDocument())
        return;

    HTMLElement* element = toHTMLElement(this);
    if (element->fastHasAttribute(formAttr))
        resetFormAttributeTargetObserver();
}

void FormAssociatedElement::removedFrom(ContainerNode* insertionPoint)
{
    HTMLElement* element = toHTMLElement(this);
    if (insertionPoint->inDocument() && element->fastHasAttribute(formAttr))
        setFormAttributeTargetObserver(nullptr);
    // If the form and element are both in the same tree, preserve the connection to the form.
    // Otherwise, null out our form and remove ourselves from the form's list of elements.
    if (m_form && NodeTraversal::highestAncestorOrSelf(*element) != NodeTraversal::highestAncestorOrSelf(*m_form.get()))
        resetFormOwner();
}

HTMLFormElement* FormAssociatedElement::findAssociatedForm(const HTMLElement* element)
{
    const AtomicString& formId(element->fastGetAttribute(formAttr));
    // 3. If the element is reassociateable, has a form content attribute, and
    // is itself in a Document, then run these substeps:
    if (!formId.isNull() && element->inDocument()) {
        // 3.1. If the first element in the Document to have an ID that is
        // case-sensitively equal to the element's form content attribute's
        // value is a form element, then associate the form-associated element
        // with that form element.
        // 3.2. Abort the "reset the form owner" steps.
        Element* newFormCandidate = element->treeScope().getElementById(formId);
        return isHTMLFormElement(newFormCandidate) ? toHTMLFormElement(newFormCandidate) : 0;
    }
    // 4. Otherwise, if the form-associated element in question has an ancestor
    // form element, then associate the form-associated element with the nearest
    // such ancestor form element.
    return element->findFormAncestor();
}

void FormAssociatedElement::formRemovedFromTree(const Node& formRoot)
{
    ASSERT(m_form);
    if (NodeTraversal::highestAncestorOrSelf(toHTMLElement(*this)) == formRoot)
        return;
    resetFormOwner();
}

void FormAssociatedElement::associateByParser(HTMLFormElement* form)
{
    if (form && form->inDocument()) {
        m_formWasSetByParser = true;
        setForm(form);
        form->didAssociateByParser();
    }
}

void FormAssociatedElement::setForm(HTMLFormElement* newForm)
{
    if (m_form.get() == newForm)
        return;
    willChangeForm();
    if (m_form)
        m_form->disassociate(*this);
    if (newForm) {
#if ENABLE(OILPAN)
        m_form = newForm;
#else
        m_form = newForm->createWeakPtr();
#endif
        m_form->associate(*this);
    } else {
#if ENABLE(OILPAN)
        m_form = nullptr;
#else
        m_form = WeakPtr<HTMLFormElement>();
#endif
    }
    didChangeForm();
}

void FormAssociatedElement::willChangeForm()
{
}

void FormAssociatedElement::didChangeForm()
{
}

void FormAssociatedElement::resetFormOwner()
{
    m_formWasSetByParser = false;
    HTMLElement* element = toHTMLElement(this);
    const AtomicString& formId(element->fastGetAttribute(formAttr));
    HTMLFormElement* nearestForm = element->findFormAncestor();
    // 1. If the element's form owner is not null, and either the element is not
    // reassociateable or its form content attribute is not present, and the
    // element's form owner is its nearest form element ancestor after the
    // change to the ancestor chain, then do nothing, and abort these steps.
    if (m_form && formId.isNull() && m_form.get() == nearestForm)
        return;

    HTMLFormElement* originalForm = m_form.get();
    setForm(findAssociatedForm(element));
    // FIXME: Move didAssociateFormControl call to didChangeForm or
    // HTMLFormElement::associate.
    if (m_form && m_form.get() != originalForm && m_form->inDocument())
        element->document().didAssociateFormControl(element);
}

void FormAssociatedElement::formAttributeChanged()
{
    resetFormOwner();
    resetFormAttributeTargetObserver();
}

bool FormAssociatedElement::customError() const
{
    const HTMLElement* element = toHTMLElement(this);
    return element->willValidate() && !m_customValidationMessage.isEmpty();
}

bool FormAssociatedElement::hasBadInput() const
{
    return false;
}

bool FormAssociatedElement::patternMismatch() const
{
    return false;
}

bool FormAssociatedElement::rangeOverflow() const
{
    return false;
}

bool FormAssociatedElement::rangeUnderflow() const
{
    return false;
}

bool FormAssociatedElement::stepMismatch() const
{
    return false;
}

bool FormAssociatedElement::tooLong() const
{
    return false;
}

bool FormAssociatedElement::tooShort() const
{
    return false;
}

bool FormAssociatedElement::typeMismatch() const
{
    return false;
}

bool FormAssociatedElement::valid() const
{
    bool someError = typeMismatch() || stepMismatch() || rangeUnderflow() || rangeOverflow()
        || tooLong() || tooShort() || patternMismatch() || valueMissing() || hasBadInput()
        || customError();
    return !someError;
}

bool FormAssociatedElement::valueMissing() const
{
    return false;
}

String FormAssociatedElement::customValidationMessage() const
{
    return m_customValidationMessage;
}

String FormAssociatedElement::validationMessage() const
{
    return customError() ? m_customValidationMessage : String();
}

void FormAssociatedElement::setCustomValidity(const String& error)
{
    m_customValidationMessage = error;
}

void FormAssociatedElement::setFormAttributeTargetObserver(PassOwnPtrWillBeRawPtr<FormAttributeTargetObserver> newObserver)
{
    if (m_formAttributeTargetObserver)
        m_formAttributeTargetObserver->unregister();
    m_formAttributeTargetObserver = newObserver;
}

void FormAssociatedElement::resetFormAttributeTargetObserver()
{
    HTMLElement* element = toHTMLElement(this);
    const AtomicString& formId(element->fastGetAttribute(formAttr));
    if (!formId.isNull() && element->inDocument())
        setFormAttributeTargetObserver(FormAttributeTargetObserver::create(formId, this));
    else
        setFormAttributeTargetObserver(nullptr);
}

void FormAssociatedElement::formAttributeTargetChanged()
{
    resetFormOwner();
}

const AtomicString& FormAssociatedElement::name() const
{
    const AtomicString& name = toHTMLElement(this)->getNameAttribute();
    return name.isNull() ? emptyAtom : name;
}

bool FormAssociatedElement::isFormControlElementWithState() const
{
    return false;
}

const HTMLElement& toHTMLElement(const FormAssociatedElement& associatedElement)
{
    if (associatedElement.isFormControlElement())
        return toHTMLFormControlElement(associatedElement);
    else if (associatedElement.isLabelElement())
        return toHTMLLabelElement(associatedElement);
    else
        return toHTMLObjectElement(associatedElement);
}

const HTMLElement* toHTMLElement(const FormAssociatedElement* associatedElement)
{
    ASSERT(associatedElement);
    return &toHTMLElement(*associatedElement);
}

HTMLElement* toHTMLElement(FormAssociatedElement* associatedElement)
{
    return const_cast<HTMLElement*>(toHTMLElement(static_cast<const FormAssociatedElement*>(associatedElement)));
}

HTMLElement& toHTMLElement(FormAssociatedElement& associatedElement)
{
    return const_cast<HTMLElement&>(toHTMLElement(static_cast<const FormAssociatedElement&>(associatedElement)));
}

PassOwnPtrWillBeRawPtr<FormAttributeTargetObserver> FormAttributeTargetObserver::create(const AtomicString& id, FormAssociatedElement* element)
{
    return adoptPtrWillBeNoop(new FormAttributeTargetObserver(id, element));
}

FormAttributeTargetObserver::FormAttributeTargetObserver(const AtomicString& id, FormAssociatedElement* element)
    : IdTargetObserver(toHTMLElement(element)->treeScope().idTargetObserverRegistry(), id)
    , m_element(element)
{
}

void FormAttributeTargetObserver::trace(Visitor* visitor)
{
    visitor->trace(m_element);
    IdTargetObserver::trace(visitor);
}

void FormAttributeTargetObserver::idTargetChanged()
{
    m_element->formAttributeTargetChanged();
}

} // namespace blink
<commit_msg>Call didAssociateFormControl() from FormAssociatedElement::didChangeForm().<commit_after>/*
 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
 *           (C) 2001 Dirk Mueller (mueller@kde.org)
 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
 *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
 *
 * 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., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 *
 */

#include "config.h"
#include "core/html/FormAssociatedElement.h"

#include "core/HTMLNames.h"
#include "core/dom/IdTargetObserver.h"
#include "core/dom/NodeTraversal.h"
#include "core/html/HTMLFormControlElement.h"
#include "core/html/HTMLFormElement.h"
#include "core/html/HTMLLabelElement.h"
#include "core/html/HTMLObjectElement.h"
#include "core/html/ValidityState.h"

namespace blink {

using namespace HTMLNames;

class FormAttributeTargetObserver : public IdTargetObserver {
    WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED;
public:
    static PassOwnPtrWillBeRawPtr<FormAttributeTargetObserver> create(const AtomicString& id, FormAssociatedElement*);
    virtual void trace(Visitor*) override;
    virtual void idTargetChanged() override;

private:
    FormAttributeTargetObserver(const AtomicString& id, FormAssociatedElement*);

    RawPtrWillBeMember<FormAssociatedElement> m_element;
};

FormAssociatedElement::FormAssociatedElement()
    : m_formWasSetByParser(false)
{
}

FormAssociatedElement::~FormAssociatedElement()
{
    // We can't call setForm here because it contains virtual calls.
}

void FormAssociatedElement::trace(Visitor* visitor)
{
    visitor->trace(m_formAttributeTargetObserver);
    visitor->trace(m_form);
    visitor->trace(m_validityState);
}

ValidityState* FormAssociatedElement::validity()
{
    if (!m_validityState)
        m_validityState = ValidityState::create(this);

    return m_validityState.get();
}

void FormAssociatedElement::didMoveToNewDocument(Document& oldDocument)
{
    HTMLElement* element = toHTMLElement(this);
    if (element->fastHasAttribute(formAttr))
        setFormAttributeTargetObserver(nullptr);
}

void FormAssociatedElement::insertedInto(ContainerNode* insertionPoint)
{
    if (!m_formWasSetByParser || !m_form || NodeTraversal::highestAncestorOrSelf(*insertionPoint) != NodeTraversal::highestAncestorOrSelf(*m_form.get()))
        resetFormOwner();

    if (!insertionPoint->inDocument())
        return;

    HTMLElement* element = toHTMLElement(this);
    if (element->fastHasAttribute(formAttr))
        resetFormAttributeTargetObserver();
}

void FormAssociatedElement::removedFrom(ContainerNode* insertionPoint)
{
    HTMLElement* element = toHTMLElement(this);
    if (insertionPoint->inDocument() && element->fastHasAttribute(formAttr))
        setFormAttributeTargetObserver(nullptr);
    // If the form and element are both in the same tree, preserve the connection to the form.
    // Otherwise, null out our form and remove ourselves from the form's list of elements.
    if (m_form && NodeTraversal::highestAncestorOrSelf(*element) != NodeTraversal::highestAncestorOrSelf(*m_form.get()))
        resetFormOwner();
}

HTMLFormElement* FormAssociatedElement::findAssociatedForm(const HTMLElement* element)
{
    const AtomicString& formId(element->fastGetAttribute(formAttr));
    // 3. If the element is reassociateable, has a form content attribute, and
    // is itself in a Document, then run these substeps:
    if (!formId.isNull() && element->inDocument()) {
        // 3.1. If the first element in the Document to have an ID that is
        // case-sensitively equal to the element's form content attribute's
        // value is a form element, then associate the form-associated element
        // with that form element.
        // 3.2. Abort the "reset the form owner" steps.
        Element* newFormCandidate = element->treeScope().getElementById(formId);
        return isHTMLFormElement(newFormCandidate) ? toHTMLFormElement(newFormCandidate) : 0;
    }
    // 4. Otherwise, if the form-associated element in question has an ancestor
    // form element, then associate the form-associated element with the nearest
    // such ancestor form element.
    return element->findFormAncestor();
}

void FormAssociatedElement::formRemovedFromTree(const Node& formRoot)
{
    ASSERT(m_form);
    if (NodeTraversal::highestAncestorOrSelf(toHTMLElement(*this)) == formRoot)
        return;
    resetFormOwner();
}

void FormAssociatedElement::associateByParser(HTMLFormElement* form)
{
    if (form && form->inDocument()) {
        m_formWasSetByParser = true;
        setForm(form);
        form->didAssociateByParser();
    }
}

void FormAssociatedElement::setForm(HTMLFormElement* newForm)
{
    if (m_form.get() == newForm)
        return;
    willChangeForm();
    if (m_form)
        m_form->disassociate(*this);
    if (newForm) {
#if ENABLE(OILPAN)
        m_form = newForm;
#else
        m_form = newForm->createWeakPtr();
#endif
        m_form->associate(*this);
    } else {
#if ENABLE(OILPAN)
        m_form = nullptr;
#else
        m_form = WeakPtr<HTMLFormElement>();
#endif
    }
    didChangeForm();
}

void FormAssociatedElement::willChangeForm()
{
}

void FormAssociatedElement::didChangeForm()
{
    if (!m_formWasSetByParser && m_form && m_form->inDocument()) {
        HTMLElement* element = toHTMLElement(this);
        element->document().didAssociateFormControl(element);
    }
}

void FormAssociatedElement::resetFormOwner()
{
    m_formWasSetByParser = false;
    HTMLElement* element = toHTMLElement(this);
    const AtomicString& formId(element->fastGetAttribute(formAttr));
    HTMLFormElement* nearestForm = element->findFormAncestor();
    // 1. If the element's form owner is not null, and either the element is not
    // reassociateable or its form content attribute is not present, and the
    // element's form owner is its nearest form element ancestor after the
    // change to the ancestor chain, then do nothing, and abort these steps.
    if (m_form && formId.isNull() && m_form.get() == nearestForm)
        return;

    setForm(findAssociatedForm(element));
}

void FormAssociatedElement::formAttributeChanged()
{
    resetFormOwner();
    resetFormAttributeTargetObserver();
}

bool FormAssociatedElement::customError() const
{
    const HTMLElement* element = toHTMLElement(this);
    return element->willValidate() && !m_customValidationMessage.isEmpty();
}

bool FormAssociatedElement::hasBadInput() const
{
    return false;
}

bool FormAssociatedElement::patternMismatch() const
{
    return false;
}

bool FormAssociatedElement::rangeOverflow() const
{
    return false;
}

bool FormAssociatedElement::rangeUnderflow() const
{
    return false;
}

bool FormAssociatedElement::stepMismatch() const
{
    return false;
}

bool FormAssociatedElement::tooLong() const
{
    return false;
}

bool FormAssociatedElement::tooShort() const
{
    return false;
}

bool FormAssociatedElement::typeMismatch() const
{
    return false;
}

bool FormAssociatedElement::valid() const
{
    bool someError = typeMismatch() || stepMismatch() || rangeUnderflow() || rangeOverflow()
        || tooLong() || tooShort() || patternMismatch() || valueMissing() || hasBadInput()
        || customError();
    return !someError;
}

bool FormAssociatedElement::valueMissing() const
{
    return false;
}

String FormAssociatedElement::customValidationMessage() const
{
    return m_customValidationMessage;
}

String FormAssociatedElement::validationMessage() const
{
    return customError() ? m_customValidationMessage : String();
}

void FormAssociatedElement::setCustomValidity(const String& error)
{
    m_customValidationMessage = error;
}

void FormAssociatedElement::setFormAttributeTargetObserver(PassOwnPtrWillBeRawPtr<FormAttributeTargetObserver> newObserver)
{
    if (m_formAttributeTargetObserver)
        m_formAttributeTargetObserver->unregister();
    m_formAttributeTargetObserver = newObserver;
}

void FormAssociatedElement::resetFormAttributeTargetObserver()
{
    HTMLElement* element = toHTMLElement(this);
    const AtomicString& formId(element->fastGetAttribute(formAttr));
    if (!formId.isNull() && element->inDocument())
        setFormAttributeTargetObserver(FormAttributeTargetObserver::create(formId, this));
    else
        setFormAttributeTargetObserver(nullptr);
}

void FormAssociatedElement::formAttributeTargetChanged()
{
    resetFormOwner();
}

const AtomicString& FormAssociatedElement::name() const
{
    const AtomicString& name = toHTMLElement(this)->getNameAttribute();
    return name.isNull() ? emptyAtom : name;
}

bool FormAssociatedElement::isFormControlElementWithState() const
{
    return false;
}

const HTMLElement& toHTMLElement(const FormAssociatedElement& associatedElement)
{
    if (associatedElement.isFormControlElement())
        return toHTMLFormControlElement(associatedElement);
    else if (associatedElement.isLabelElement())
        return toHTMLLabelElement(associatedElement);
    else
        return toHTMLObjectElement(associatedElement);
}

const HTMLElement* toHTMLElement(const FormAssociatedElement* associatedElement)
{
    ASSERT(associatedElement);
    return &toHTMLElement(*associatedElement);
}

HTMLElement* toHTMLElement(FormAssociatedElement* associatedElement)
{
    return const_cast<HTMLElement*>(toHTMLElement(static_cast<const FormAssociatedElement*>(associatedElement)));
}

HTMLElement& toHTMLElement(FormAssociatedElement& associatedElement)
{
    return const_cast<HTMLElement&>(toHTMLElement(static_cast<const FormAssociatedElement&>(associatedElement)));
}

PassOwnPtrWillBeRawPtr<FormAttributeTargetObserver> FormAttributeTargetObserver::create(const AtomicString& id, FormAssociatedElement* element)
{
    return adoptPtrWillBeNoop(new FormAttributeTargetObserver(id, element));
}

FormAttributeTargetObserver::FormAttributeTargetObserver(const AtomicString& id, FormAssociatedElement* element)
    : IdTargetObserver(toHTMLElement(element)->treeScope().idTargetObserverRegistry(), id)
    , m_element(element)
{
}

void FormAttributeTargetObserver::trace(Visitor* visitor)
{
    visitor->trace(m_element);
    IdTargetObserver::trace(visitor);
}

void FormAttributeTargetObserver::idTargetChanged()
{
    m_element->formAttributeTargetChanged();
}

} // namespace blink
<|endoftext|>