Merge branch 'main' into ly-as-sdk/LYN-2948
This commit is contained in:
@@ -1,629 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "BackgroundScheduleManager.h"
|
||||
|
||||
namespace BackgroundScheduleManager
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CScheduleItem::CScheduleItem(const char* szName)
|
||||
: m_name(szName)
|
||||
, m_refCount(1)
|
||||
, m_state(eScheduleItemState_Pending)
|
||||
{
|
||||
}
|
||||
|
||||
CScheduleItem::~CScheduleItem()
|
||||
{
|
||||
CRY_ASSERT(m_refCount == 0);
|
||||
|
||||
for (TWorkItems::const_iterator it = m_workItems.begin();
|
||||
it != m_workItems.end(); ++it)
|
||||
{
|
||||
(*it)->Release();
|
||||
}
|
||||
}
|
||||
|
||||
const char* CScheduleItem::GetDescription() const
|
||||
{
|
||||
return m_name.c_str();
|
||||
}
|
||||
|
||||
EScheduleItemState CScheduleItem::GetState() const
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
const float CScheduleItem::GetProgress() const
|
||||
{
|
||||
if (m_workItems.empty())
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
float totalProgress = 0.0f;
|
||||
|
||||
for (TWorkItems::const_iterator it = m_workItems.begin();
|
||||
it != m_workItems.end(); ++it)
|
||||
{
|
||||
totalProgress += (*it)->GetProgress();
|
||||
}
|
||||
|
||||
return totalProgress / (float)m_workItems.size();
|
||||
}
|
||||
}
|
||||
|
||||
const uint32 CScheduleItem::GetNumWorkItems() const
|
||||
{
|
||||
return m_workItems.size();
|
||||
}
|
||||
|
||||
IBackgroundScheduleItemWork* CScheduleItem::GetWorkItem(const uint32 index) const
|
||||
{
|
||||
return m_workItems[index];
|
||||
}
|
||||
|
||||
void CScheduleItem::AddWorkItem(IBackgroundScheduleItemWork* pWork)
|
||||
{
|
||||
// cannot add new work items when item has finished or failed
|
||||
if (m_state == eScheduleItemState_Failed || m_state == eScheduleItemState_Completed)
|
||||
{
|
||||
CryFatalError("Cannot add new work items when item has finished or failed");
|
||||
return;
|
||||
}
|
||||
|
||||
// add to the work list
|
||||
if (m_state == eScheduleItemState_Processing)
|
||||
{
|
||||
m_addedWorkItems.push_back(pWork);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_workItems.push_back(pWork);
|
||||
}
|
||||
}
|
||||
|
||||
void CScheduleItem::AddRef()
|
||||
{
|
||||
CryInterlockedIncrement(&m_refCount);
|
||||
}
|
||||
|
||||
void CScheduleItem::Release()
|
||||
{
|
||||
const int nCount = CryInterlockedDecrement(&m_refCount);
|
||||
assert(nCount >= 0);
|
||||
if (nCount == 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
else if (nCount < 0)
|
||||
{
|
||||
assert(0);
|
||||
CryFatalError("Deleting Reference Counted Object Twice");
|
||||
}
|
||||
}
|
||||
|
||||
void CScheduleItem::RequestStop()
|
||||
{
|
||||
if (m_state == eScheduleItemState_Pending)
|
||||
{
|
||||
// we can stop right away :)
|
||||
m_state = eScheduleItemState_Failed;
|
||||
}
|
||||
else if (m_state == eScheduleItemState_Processing)
|
||||
{
|
||||
m_state = eScheduleItemState_Stopping;
|
||||
|
||||
// signal all pending work to stop
|
||||
uint32 curIndex = 0;
|
||||
while (curIndex < m_processedWorkItems.size())
|
||||
{
|
||||
IBackgroundScheduleItemWork* pWork = m_processedWorkItems[curIndex];
|
||||
if (pWork->OnStop())
|
||||
{
|
||||
// if the work was stopped remove it from list
|
||||
m_processedWorkItems.erase(m_processedWorkItems.begin() + curIndex);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// this work item cannot be stopped this frame
|
||||
curIndex += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// if all pending work has been stopped we can assume the failed state
|
||||
if (m_processedWorkItems.empty())
|
||||
{
|
||||
m_state = eScheduleItemState_Failed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EScheduleWorkItemStatus CScheduleItem::Update()
|
||||
{
|
||||
EScheduleWorkItemStatus retStatus = eScheduleWorkItemStatus_NotFinished;
|
||||
|
||||
switch (m_state)
|
||||
{
|
||||
// finial state - work failed
|
||||
case eScheduleItemState_Failed:
|
||||
{
|
||||
retStatus = eScheduleWorkItemStatus_Failed;
|
||||
break;
|
||||
}
|
||||
|
||||
// final state - work completed
|
||||
case eScheduleItemState_Completed:
|
||||
{
|
||||
retStatus = eScheduleWorkItemStatus_Finished;
|
||||
break;
|
||||
}
|
||||
|
||||
// first update, start all the work items
|
||||
case eScheduleItemState_Pending:
|
||||
{
|
||||
// start all of the tasks
|
||||
bool bHasFailedStarts = false;
|
||||
for (TWorkItems::const_iterator it = m_workItems.begin();
|
||||
it != m_workItems.end(); ++it)
|
||||
{
|
||||
IBackgroundScheduleItemWork* pWork = (*it);
|
||||
|
||||
if (pWork->OnStart())
|
||||
{
|
||||
m_processedWorkItems.push_back(pWork);
|
||||
}
|
||||
else
|
||||
{
|
||||
bHasFailedStarts = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bHasFailedStarts)
|
||||
{
|
||||
m_state = eScheduleItemState_Stopping;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_state = eScheduleItemState_Processing;
|
||||
/* FALLS THROUGHT TO PROCESSING STATE */
|
||||
}
|
||||
}
|
||||
|
||||
// work processing state
|
||||
case eScheduleItemState_Processing:
|
||||
{
|
||||
// process new work items that were added while the schedule was created
|
||||
if (!m_addedWorkItems.empty())
|
||||
{
|
||||
for (TWorkItems::const_iterator it = m_addedWorkItems.begin();
|
||||
it != m_addedWorkItems.end(); ++it)
|
||||
{
|
||||
IBackgroundScheduleItemWork* pWork = (*it);
|
||||
pWork->OnStart();
|
||||
m_processedWorkItems.push_back(pWork);
|
||||
m_workItems.push_back(pWork);
|
||||
}
|
||||
|
||||
m_addedWorkItems.clear();
|
||||
}
|
||||
|
||||
// update work items
|
||||
bool bHasFailedItems = false;
|
||||
TWorkItems completedItems;
|
||||
for (TWorkItems::const_iterator it = m_processedWorkItems.begin();
|
||||
it != m_processedWorkItems.end(); ++it)
|
||||
{
|
||||
IBackgroundScheduleItemWork* pWork = (*it);
|
||||
|
||||
// update given work item
|
||||
const EScheduleWorkItemStatus status = pWork->OnUpdate();
|
||||
if (status == eScheduleWorkItemStatus_Finished)
|
||||
{
|
||||
completedItems.push_back(pWork);
|
||||
continue;
|
||||
}
|
||||
|
||||
// item failed - we need to stop other tasks
|
||||
if (status == eScheduleWorkItemStatus_Failed)
|
||||
{
|
||||
bHasFailedItems = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// cleanup completed items
|
||||
for (TWorkItems::iterator it = completedItems.begin();
|
||||
it != completedItems.end(); ++it)
|
||||
{
|
||||
IBackgroundScheduleItemWork* pWork = (*it);
|
||||
TWorkItems::iterator jt = std::find(m_processedWorkItems.begin(), m_processedWorkItems.end(), pWork);
|
||||
m_processedWorkItems.erase(jt);
|
||||
}
|
||||
|
||||
if (!bHasFailedItems)
|
||||
{
|
||||
// all work has finished
|
||||
if (m_processedWorkItems.empty())
|
||||
{
|
||||
retStatus = eScheduleWorkItemStatus_Finished;
|
||||
m_state = eScheduleItemState_Completed;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// some of the items failed
|
||||
m_state = eScheduleItemState_Stopping;
|
||||
/* FALL THROUGH TO STOPPING STATE */
|
||||
}
|
||||
}
|
||||
|
||||
// We are stopping failed work
|
||||
case eScheduleItemState_Stopping:
|
||||
{
|
||||
uint32 curIndex = 0;
|
||||
while (curIndex < m_processedWorkItems.size())
|
||||
{
|
||||
IBackgroundScheduleItemWork* pWork = m_processedWorkItems[curIndex];
|
||||
if (pWork->OnStop())
|
||||
{
|
||||
// if the work was stopped remove it from list
|
||||
m_processedWorkItems.erase(m_processedWorkItems.begin() + curIndex);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// this work item cannot be stopped this frame
|
||||
curIndex += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// if all pending work has been stopped we can assume the failed state
|
||||
if (m_processedWorkItems.empty())
|
||||
{
|
||||
m_state = eScheduleItemState_Failed;
|
||||
return eScheduleWorkItemStatus_Failed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retStatus;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CSchedule::CSchedule(const char* szName)
|
||||
: m_name(szName)
|
||||
, m_refCount(1)
|
||||
, m_bCanceled(false)
|
||||
, m_currentItem(0)
|
||||
, m_state(eScheduleState_Pending)
|
||||
{
|
||||
}
|
||||
|
||||
CSchedule::~CSchedule()
|
||||
{
|
||||
CRY_ASSERT(m_refCount == 0);
|
||||
|
||||
for (TItems::const_iterator it = m_items.begin();
|
||||
it != m_items.end(); ++it)
|
||||
{
|
||||
CScheduleItem* pItem = *it;
|
||||
SAFE_RELEASE(pItem);
|
||||
}
|
||||
|
||||
m_items.clear();
|
||||
}
|
||||
|
||||
const char* CSchedule::GetDescription() const
|
||||
{
|
||||
return m_name.c_str();
|
||||
}
|
||||
|
||||
float CSchedule::GetProgress() const
|
||||
{
|
||||
if (m_currentItem >= m_items.size())
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
const float itemProgress = 1.0f / (float)(m_items.size());
|
||||
const IBackgroundScheduleItem* pItem = m_items[m_currentItem];
|
||||
return (m_currentItem + pItem->GetProgress()) * itemProgress;
|
||||
}
|
||||
}
|
||||
|
||||
IBackgroundScheduleItem* CSchedule::GetProcessedItem() const
|
||||
{
|
||||
if (m_currentItem >= m_items.size())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
IBackgroundScheduleItem* pItem = m_items[m_currentItem];
|
||||
return pItem;
|
||||
}
|
||||
}
|
||||
|
||||
const uint32 CSchedule::GetNumItems() const
|
||||
{
|
||||
return m_items.size();
|
||||
}
|
||||
|
||||
IBackgroundScheduleItem* CSchedule::GetItem(const uint32 index) const
|
||||
{
|
||||
return m_items[index];
|
||||
}
|
||||
|
||||
EScheduleState CSchedule::GetState() const
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
void CSchedule::Cancel()
|
||||
{
|
||||
m_bCanceled = true;
|
||||
}
|
||||
|
||||
bool CSchedule::IsCanceled() const
|
||||
{
|
||||
return m_bCanceled;
|
||||
}
|
||||
|
||||
void CSchedule::AddItem(IBackgroundScheduleItem* pItem)
|
||||
{
|
||||
if (NULL == pItem)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// we can add items only in the "pending" state
|
||||
if (pItem->GetState() != eScheduleItemState_Pending)
|
||||
{
|
||||
CryFatalError("Schedule items can be added to schedule only before their work starts");
|
||||
return;
|
||||
}
|
||||
|
||||
// item has no jobs, do not add
|
||||
if (pItem->GetNumWorkItems() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_items.push_back(static_cast<CScheduleItem*>(pItem));
|
||||
pItem->AddRef();
|
||||
}
|
||||
|
||||
void CSchedule::AddRef()
|
||||
{
|
||||
CryInterlockedIncrement(&m_refCount);
|
||||
}
|
||||
|
||||
void CSchedule::Release()
|
||||
{
|
||||
const int nCount = CryInterlockedDecrement(&m_refCount);
|
||||
assert(nCount >= 0);
|
||||
if (nCount == 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
else if (nCount < 0)
|
||||
{
|
||||
assert(0);
|
||||
CryFatalError("Deleting Reference Counted Object Twice");
|
||||
}
|
||||
}
|
||||
|
||||
EScheduleWorkItemStatus CSchedule::Update()
|
||||
{
|
||||
EScheduleWorkItemStatus retStatus = eScheduleWorkItemStatus_NotFinished;
|
||||
|
||||
// we have a cancel request
|
||||
if (m_bCanceled)
|
||||
{
|
||||
CryLog("Schedule '%s' was canceled", GetDescription());
|
||||
|
||||
if (m_state == eScheduleState_Processing && m_currentItem < m_items.size())
|
||||
{
|
||||
// stop the current item
|
||||
CScheduleItem* pItem = m_items[m_currentItem];
|
||||
pItem->RequestStop();
|
||||
m_state = eSccheduleState_Stopping;
|
||||
}
|
||||
else if (m_state != eScheduleState_Completed)
|
||||
{
|
||||
m_state = eScheduleState_Failed;
|
||||
return eScheduleWorkItemStatus_Failed;
|
||||
}
|
||||
}
|
||||
|
||||
// process internal state machine
|
||||
switch (m_state)
|
||||
{
|
||||
// final state - work failed
|
||||
case eScheduleState_Failed:
|
||||
{
|
||||
retStatus = eScheduleWorkItemStatus_Failed;
|
||||
break;
|
||||
}
|
||||
|
||||
// final state - work completed
|
||||
case eScheduleState_Completed:
|
||||
{
|
||||
retStatus = eScheduleWorkItemStatus_Finished;
|
||||
break;
|
||||
}
|
||||
|
||||
// stopping current task
|
||||
case eSccheduleState_Stopping:
|
||||
{
|
||||
if (m_currentItem < m_items.size())
|
||||
{
|
||||
CScheduleItem* pItem = m_items[m_currentItem];
|
||||
if (pItem->Update() != eScheduleWorkItemStatus_NotFinished)
|
||||
{
|
||||
// task was finally stopped
|
||||
m_state = eScheduleState_Failed;
|
||||
retStatus = eScheduleWorkItemStatus_Failed;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// first update, switch to processing
|
||||
case eScheduleState_Pending:
|
||||
{
|
||||
m_state = eScheduleState_Processing;
|
||||
m_currentItem = 0;
|
||||
/* FALLS THROUGHT */
|
||||
}
|
||||
|
||||
// if we were in the processing phase inform the current schedule item to stop all it's work
|
||||
case eScheduleState_Processing:
|
||||
{
|
||||
// update schedule items
|
||||
while (m_currentItem < m_items.size())
|
||||
{
|
||||
CScheduleItem* pItem = m_items[m_currentItem];
|
||||
|
||||
const EScheduleWorkItemStatus itemStatus = pItem->Update();
|
||||
if (itemStatus == eScheduleWorkItemStatus_Finished)
|
||||
{
|
||||
m_currentItem += 1;
|
||||
continue;
|
||||
}
|
||||
else if (itemStatus == eScheduleWorkItemStatus_Failed)
|
||||
{
|
||||
m_state = eScheduleState_Failed;
|
||||
retStatus = eScheduleWorkItemStatus_Failed;
|
||||
gEnv->pLog->LogWarning("Schedule '%s' failed on item '%s'.", GetDescription(), pItem->GetDescription());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// all items updated
|
||||
if (m_currentItem >= m_items.size())
|
||||
{
|
||||
// empty schedule, complete in one tick
|
||||
m_state = eScheduleState_Completed;
|
||||
retStatus = eScheduleWorkItemStatus_Finished;
|
||||
CryLog("Schedule '%s' completed", GetDescription());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return retStatus;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CScheduleManager::CScheduleManager()
|
||||
{
|
||||
GetIEditor()->RegisterNotifyListener(this);
|
||||
}
|
||||
|
||||
CScheduleManager::~CScheduleManager()
|
||||
{
|
||||
GetIEditor()->UnregisterNotifyListener(this);
|
||||
|
||||
for (TSchedules::const_iterator it = m_schedules.begin();
|
||||
it != m_schedules.end(); ++it)
|
||||
{
|
||||
CSchedule* pSchedule = *it;
|
||||
SAFE_RELEASE(pSchedule);
|
||||
}
|
||||
|
||||
m_schedules.clear();
|
||||
}
|
||||
|
||||
IBackgroundSchedule* CScheduleManager::CreateSchedule(const char* szName)
|
||||
{
|
||||
return new CSchedule(szName);
|
||||
}
|
||||
|
||||
IBackgroundScheduleItem* CScheduleManager::CreateScheduleItem(const char* szName)
|
||||
{
|
||||
return new CScheduleItem(szName);
|
||||
}
|
||||
|
||||
void CScheduleManager::SubmitSchedule(IBackgroundSchedule* pSchedule)
|
||||
{
|
||||
if (NULL != pSchedule)
|
||||
{
|
||||
if (pSchedule->GetState() != eScheduleState_Pending)
|
||||
{
|
||||
CryFatalError("Only schedules with pending state can be submitted");
|
||||
return;
|
||||
}
|
||||
|
||||
pSchedule->AddRef();
|
||||
m_schedules.push_back(static_cast<CSchedule*>(pSchedule));
|
||||
}
|
||||
}
|
||||
|
||||
const uint32 CScheduleManager::GetNumSchedules() const
|
||||
{
|
||||
return m_schedules.size();
|
||||
}
|
||||
|
||||
IBackgroundSchedule* CScheduleManager::GetSchedule(const uint32 index) const
|
||||
{
|
||||
return m_schedules[index];
|
||||
}
|
||||
|
||||
void CScheduleManager::Update()
|
||||
{
|
||||
while (!m_schedules.empty())
|
||||
{
|
||||
CSchedule* pSchedule = m_schedules[0];
|
||||
|
||||
const EScheduleWorkItemStatus status = pSchedule->Update();
|
||||
if (status == eScheduleWorkItemStatus_NotFinished)
|
||||
{
|
||||
// we need more work next frame
|
||||
break;
|
||||
}
|
||||
|
||||
// schedule has finished, remove current reference
|
||||
m_schedules.erase(m_schedules.begin());
|
||||
SAFE_RELEASE(pSchedule);
|
||||
}
|
||||
}
|
||||
|
||||
void CScheduleManager::OnEditorNotifyEvent(EEditorNotifyEvent ev)
|
||||
{
|
||||
switch (ev)
|
||||
{
|
||||
case eNotify_OnQuit:
|
||||
GetIEditor()->UnregisterNotifyListener(this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
} // BackgroundScheduleManager
|
||||
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_BACKGROUNDSCHEDULEMANAGER_H
|
||||
#define CRYINCLUDE_EDITOR_BACKGROUNDSCHEDULEMANAGER_H
|
||||
#pragma once
|
||||
|
||||
#include "Include/IBackgroundScheduleManager.h"
|
||||
|
||||
namespace BackgroundScheduleManager
|
||||
{
|
||||
class CScheduleItem
|
||||
: public IBackgroundScheduleItem
|
||||
{
|
||||
private:
|
||||
std::string m_name;
|
||||
volatile int m_refCount;
|
||||
|
||||
EScheduleItemState m_state;
|
||||
|
||||
typedef std::vector<IBackgroundScheduleItemWork*> TWorkItems;
|
||||
TWorkItems m_workItems;
|
||||
TWorkItems m_addedWorkItems;
|
||||
TWorkItems m_processedWorkItems;
|
||||
|
||||
public:
|
||||
CScheduleItem(const char* szName);
|
||||
virtual ~CScheduleItem();
|
||||
|
||||
// IBackgroundScheduleItem interface
|
||||
virtual const char* GetDescription() const;
|
||||
virtual EScheduleItemState GetState() const;
|
||||
virtual const float GetProgress() const;
|
||||
virtual const uint32 GetNumWorkItems() const;
|
||||
virtual IBackgroundScheduleItemWork* GetWorkItem(const uint32 index) const;
|
||||
virtual void AddWorkItem(IBackgroundScheduleItemWork* pWork);
|
||||
virtual void AddRef();
|
||||
virtual void Release();
|
||||
|
||||
// Update schedule item
|
||||
EScheduleWorkItemStatus Update();
|
||||
|
||||
// Request to stop work in this item
|
||||
void RequestStop();
|
||||
};
|
||||
|
||||
class CSchedule
|
||||
: public IBackgroundSchedule
|
||||
{
|
||||
private:
|
||||
std::string m_name;
|
||||
volatile int m_refCount;
|
||||
bool m_bCanceled;
|
||||
|
||||
EScheduleState m_state;
|
||||
|
||||
typedef std::vector<CScheduleItem*> TItems;
|
||||
TItems m_items;
|
||||
|
||||
uint32 m_currentItem;
|
||||
|
||||
public:
|
||||
CSchedule(const char* szName);
|
||||
virtual ~CSchedule();
|
||||
|
||||
// IBackgroundSchedule interface
|
||||
virtual const char* GetDescription() const;
|
||||
virtual float GetProgress() const;
|
||||
virtual IBackgroundScheduleItem* GetProcessedItem() const;
|
||||
virtual const uint32 GetNumItems() const;
|
||||
virtual IBackgroundScheduleItem* GetItem(const uint32 index) const;
|
||||
virtual EScheduleState GetState() const;
|
||||
virtual void Cancel();
|
||||
virtual bool IsCanceled() const;
|
||||
virtual void AddItem(IBackgroundScheduleItem* pItem);
|
||||
virtual void AddRef();
|
||||
virtual void Release();
|
||||
|
||||
// Update schedule item
|
||||
EScheduleWorkItemStatus Update();
|
||||
};
|
||||
|
||||
class CScheduleManager
|
||||
: public IBackgroundScheduleManager
|
||||
, public IEditorNotifyListener
|
||||
{
|
||||
private:
|
||||
typedef std::vector<CSchedule*> TSchedules;
|
||||
TSchedules m_schedules;
|
||||
|
||||
public:
|
||||
CScheduleManager();
|
||||
virtual ~CScheduleManager();
|
||||
|
||||
// IBackgroundScheduleManager interface
|
||||
virtual IBackgroundSchedule* CreateSchedule(const char* szName);
|
||||
virtual IBackgroundScheduleItem* CreateScheduleItem(const char* szName);
|
||||
virtual void SubmitSchedule(IBackgroundSchedule* pSchedule);
|
||||
virtual const uint32 GetNumSchedules() const;
|
||||
virtual IBackgroundSchedule* GetSchedule(const uint32 index) const;
|
||||
virtual void Update();
|
||||
|
||||
// IEditorNotifyListener interface implementation
|
||||
virtual void OnEditorNotifyEvent(EEditorNotifyEvent ev) override;
|
||||
};
|
||||
}
|
||||
#endif // CRYINCLUDE_EDITOR_BACKGROUNDSCHEDULEMANAGER_H
|
||||
@@ -1,410 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "BackgroundTaskManager.h"
|
||||
|
||||
namespace BackgroundTaskManager
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CTaskManager::CThread::CThread(class CTaskManager* pManager, CQueue* pQueue)
|
||||
: m_pManager(pManager)
|
||||
, m_pQueue(pQueue)
|
||||
{
|
||||
start();
|
||||
}
|
||||
|
||||
CTaskManager::CThread::~CThread()
|
||||
{
|
||||
}
|
||||
|
||||
void CTaskManager::CThread::WaitForThread()
|
||||
{
|
||||
wait();
|
||||
}
|
||||
|
||||
void CTaskManager::CThread::run()
|
||||
{
|
||||
CryThreadSetName(-1, "BackgroundTaskThread");
|
||||
|
||||
while (!m_pManager->IsStopped())
|
||||
{
|
||||
STaskHandle taskHandle;
|
||||
|
||||
// This blocks on Semaphore waiting for task from queue
|
||||
m_pQueue->PopTask(taskHandle);
|
||||
|
||||
// Should not happen but it's a stupid way to crash :)
|
||||
if (NULL == taskHandle.pTask)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (taskHandle.pTask->IsCanceled())
|
||||
{
|
||||
// Task was canceled before we got here
|
||||
m_pManager->AddCompletedTask(taskHandle, eTaskResult_Canceled);
|
||||
}
|
||||
else
|
||||
{
|
||||
const ETaskResult state = taskHandle.pTask->Work();
|
||||
|
||||
if (state == eTaskResult_Resume)
|
||||
{
|
||||
// Put it back into queue, so more important task can take over.
|
||||
m_pManager->AddTask(taskHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Finish task
|
||||
m_pManager->AddCompletedTask(taskHandle, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CTaskManager::CQueue::CQueue()
|
||||
: m_semaphore(INT_MAX, 0) // no good maximum value, assume worst case
|
||||
{
|
||||
}
|
||||
|
||||
void CTaskManager::CQueue::AddTask(const STaskHandle& taskHandle)
|
||||
{
|
||||
{
|
||||
CryAutoLock<CryMutex> lock(m_lock);
|
||||
|
||||
// TODO: use heap?
|
||||
m_pendingTasks.insert(m_pendingTasks.begin(), taskHandle);
|
||||
std::stable_sort(m_pendingTasks.begin(), m_pendingTasks.end());
|
||||
}
|
||||
|
||||
taskHandle.pTask->SetState(eTaskState_Pending);
|
||||
|
||||
// release internal semaphore so threads can pick up the work
|
||||
m_semaphore.Release();
|
||||
}
|
||||
|
||||
void CTaskManager::CQueue::PopTask(STaskHandle& outTaskHandle)
|
||||
{
|
||||
// wait for job
|
||||
m_semaphore.Acquire();
|
||||
|
||||
{
|
||||
CryAutoLock<CryMutex> lock(m_lock);
|
||||
|
||||
if (m_pendingTasks.empty())
|
||||
{
|
||||
outTaskHandle.pTask = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
outTaskHandle = m_pendingTasks.back();
|
||||
outTaskHandle.pTask->SetState(eTaskState_Working);
|
||||
m_pendingTasks.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CTaskManager::CQueue::ReleaseSemaphore()
|
||||
{
|
||||
m_semaphore.Release();
|
||||
}
|
||||
|
||||
void CTaskManager::CQueue::Clear()
|
||||
{
|
||||
CryAutoLock<CryMutex> lock(m_lock);
|
||||
for (uint i = 0; i < m_pendingTasks.size(); ++i)
|
||||
{
|
||||
m_pendingTasks[i].pTask->Release();
|
||||
}
|
||||
|
||||
m_pendingTasks.clear();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CTaskManager::CTaskManager()
|
||||
: m_bStop(false)
|
||||
, m_nextTaskID(1)
|
||||
, m_listeners(1)
|
||||
{
|
||||
GetIEditor()->RegisterNotifyListener(this);
|
||||
}
|
||||
|
||||
CTaskManager::~CTaskManager()
|
||||
{
|
||||
if (!m_bStop)
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
|
||||
void CTaskManager::Start(const uint32 threadCount /*=kDefaultThreadCount*/)
|
||||
{
|
||||
m_bStop = false;
|
||||
|
||||
if (m_pThreads.empty())
|
||||
{
|
||||
// Always create one IO thread
|
||||
{
|
||||
CThread* pThread = new CThread(this, &m_pendingTasks[ eTaskThreadMask_IO ]);
|
||||
m_pThreads.push_back(pThread);
|
||||
}
|
||||
|
||||
// We also need at least one generic thread
|
||||
const uint32 numGenericThreads = max<uint32>(threadCount, 1);
|
||||
for (uint32 i = 0; i < numGenericThreads; ++i)
|
||||
{
|
||||
CThread* pThread = new CThread(this, &m_pendingTasks[ eTaskThreadMask_Any ]);
|
||||
m_pThreads.push_back(pThread);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CTaskManager::StartScheduledTasks()
|
||||
{
|
||||
CryAutoLock<CryMutex> lock(m_tasksLock);
|
||||
|
||||
if (!m_scheduledTasks.empty())
|
||||
{
|
||||
const unsigned int time = GetTickCount();
|
||||
while (!m_scheduledTasks.empty())
|
||||
{
|
||||
const int delta = (int)(time - m_scheduledTasks[0].time);
|
||||
if (delta > 0)
|
||||
{
|
||||
// the soonest task on the list is still in the future, no point in looking at the next entries in the list
|
||||
break;
|
||||
}
|
||||
|
||||
// promote the scheduled task to be a full task
|
||||
AddTask(m_scheduledTasks[0].handle);
|
||||
|
||||
// We held a reference to the task on list, release it
|
||||
m_scheduledTasks[0].handle.pTask->Release();
|
||||
|
||||
m_scheduledTasks.erase(m_scheduledTasks.begin());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CTaskManager::Stop()
|
||||
{
|
||||
if (!m_bStop)
|
||||
{
|
||||
m_bStop = true;
|
||||
GetIEditor()->UnregisterNotifyListener(this);
|
||||
|
||||
// clear queues - no new tasks will be processed
|
||||
for (uint32 i = 0; i < eTaskThreadMask_COUNT; ++i)
|
||||
{
|
||||
m_pendingTasks[i].Clear();
|
||||
}
|
||||
|
||||
// kick all the threads to allow them to quit
|
||||
for (uint32 j = 0; j < m_pThreads.size(); ++j)
|
||||
{
|
||||
for (uint32 i = 0; i < eTaskThreadMask_COUNT; ++i)
|
||||
{
|
||||
m_pendingTasks[i].ReleaseSemaphore();
|
||||
}
|
||||
}
|
||||
|
||||
// Stop threads
|
||||
for (TWorkerThreads::iterator it = m_pThreads.begin();
|
||||
it != m_pThreads.end(); ++it)
|
||||
{
|
||||
(*it)->WaitForThread();
|
||||
delete *it;
|
||||
}
|
||||
|
||||
m_pThreads.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void CTaskManager::AddListener(IBackgroundTaskManagerListener* pListener, const char* name)
|
||||
{
|
||||
m_listeners.Add(pListener, name);
|
||||
}
|
||||
|
||||
void CTaskManager::RemoveListener(IBackgroundTaskManagerListener* pListener)
|
||||
{
|
||||
m_listeners.Remove(pListener);
|
||||
}
|
||||
|
||||
void CTaskManager::AddTask(IBackgroundTask* pTask, ETaskPriority priority, ETaskThreadMask threadMask)
|
||||
{
|
||||
MAKE_SURE(pTask != 0, return );
|
||||
|
||||
// keep an extra reference to the task in the manager
|
||||
pTask->AddRef();
|
||||
|
||||
STaskHandle handle;
|
||||
handle.id = CryInterlockedIncrement(&m_nextTaskID);
|
||||
handle.priority = priority;
|
||||
handle.threadMask = threadMask;
|
||||
handle.pTask = pTask;
|
||||
|
||||
AddTask(handle);
|
||||
|
||||
for (TListeners::Notifier notifier(m_listeners); notifier.IsValid(); notifier.Next())
|
||||
{
|
||||
notifier->OnBackgroundTaskAdded(pTask->Description());
|
||||
}
|
||||
}
|
||||
|
||||
void CTaskManager::ScheduleTask(IBackgroundTask* pTask, ETaskPriority priority, int delayMilliseconds, ETaskThreadMask threadMask)
|
||||
{
|
||||
MAKE_SURE(delayMilliseconds >= 0, return );
|
||||
MAKE_SURE(pTask != 0, return );
|
||||
|
||||
// keep an extra reference to the task in the manager
|
||||
pTask->AddRef();
|
||||
|
||||
SScheduledTask task;
|
||||
task.time = GetTickCount() + delayMilliseconds;
|
||||
task.handle.pTask = pTask;
|
||||
task.handle.id = CryInterlockedIncrement(&m_nextTaskID);
|
||||
task.handle.threadMask = threadMask;
|
||||
task.handle.priority = priority;
|
||||
|
||||
{
|
||||
CryAutoLock<CryMutex> lock(m_tasksLock);
|
||||
m_scheduledTasks.push_back(task);
|
||||
}
|
||||
|
||||
for (TListeners::Notifier notifier(m_listeners); notifier.IsValid(); notifier.Next())
|
||||
{
|
||||
notifier->OnBackgroundTaskAdded(pTask->Description());
|
||||
}
|
||||
}
|
||||
|
||||
void CTaskManager::AddTask(const STaskHandle& handle)
|
||||
{
|
||||
MAKE_SURE(handle.pTask != 0, return );
|
||||
MAKE_SURE(handle.id != 0, return );
|
||||
|
||||
// add task to appropriate queue (every thread mask has it's own queue)
|
||||
m_pendingTasks[handle.threadMask].AddTask(handle);
|
||||
}
|
||||
|
||||
void CTaskManager::AddCompletedTask(const STaskHandle& handle, ETaskResult resultState)
|
||||
{
|
||||
CryAutoLock<CryMutex> lock(m_tasksLock);
|
||||
|
||||
CRY_ASSERT(handle.pTask->GetState() == eTaskState_Working);
|
||||
CRY_ASSERT(resultState != eTaskResult_Resume);
|
||||
|
||||
// Update task state
|
||||
switch (resultState)
|
||||
{
|
||||
case eTaskResult_Canceled:
|
||||
{
|
||||
handle.pTask->SetState(eTaskState_Canceled);
|
||||
break;
|
||||
}
|
||||
|
||||
case eTaskResult_Completed:
|
||||
{
|
||||
handle.pTask->SetState(eTaskState_Completed);
|
||||
break;
|
||||
}
|
||||
|
||||
case eTaskResult_Failed:
|
||||
{
|
||||
handle.pTask->SetState(eTaskState_Failed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// add to the list of completed tasks (for calling the Finalize)
|
||||
// TODO: some of the tasks do not require Finalize() and they could be released here instead of the main thread
|
||||
SCompletedTask info;
|
||||
info.pTask = handle.pTask;
|
||||
info.id = handle.id;
|
||||
info.state = resultState;
|
||||
m_completedTasks.push_back(info);
|
||||
}
|
||||
|
||||
void CTaskManager::Update()
|
||||
{
|
||||
std::vector<SCompletedTask> completedTasks;
|
||||
{
|
||||
CryAutoLock<CryMutex> lock(m_tasksLock);
|
||||
m_completedTasks.swap(completedTasks);
|
||||
}
|
||||
|
||||
// call finalize for the completed tasks
|
||||
for (size_t i = 0; i < completedTasks.size(); ++i)
|
||||
{
|
||||
SCompletedTask& handle = completedTasks[i];
|
||||
|
||||
if (NULL != handle.pTask)
|
||||
{
|
||||
string description = handle.pTask->Description(); // copy string as the description is used after pTask is destroyed
|
||||
|
||||
if (handle.state == eTaskResult_Completed)
|
||||
{
|
||||
if (description && description[0] != '\0')
|
||||
{
|
||||
gEnv->pLog->Log("Task Completed: %s", description.c_str());
|
||||
}
|
||||
}
|
||||
else if (handle.state == eTaskResult_Failed)
|
||||
{
|
||||
if (description && description[0] != '\0' && !handle.pTask->FailReported())
|
||||
{
|
||||
gEnv->pLog->LogError("Task Failed: %s ", description.c_str());
|
||||
|
||||
const char* errorMessage = handle.pTask->ErrorMessage();
|
||||
if (errorMessage && errorMessage[0] != '\0')
|
||||
{
|
||||
gEnv->pLog->LogError("\tReason: [%s]", errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handle.pTask->Finalize();
|
||||
|
||||
// release the internal (task manager) reference.
|
||||
// Tthis is usually the last reference to the task so it gets deleted here.
|
||||
handle.pTask->Release();
|
||||
|
||||
for (TListeners::Notifier notifier(m_listeners); notifier.IsValid(); notifier.Next())
|
||||
{
|
||||
notifier->OnBackgroundTaskCompleted(handle.state, description.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CTaskManager::OnEditorNotifyEvent(EEditorNotifyEvent ev)
|
||||
{
|
||||
switch (ev)
|
||||
{
|
||||
case eNotify_OnInit:
|
||||
Start();
|
||||
break;
|
||||
case eNotify_OnIdleUpdate:
|
||||
Update();
|
||||
break;
|
||||
case eNotify_OnQuit:
|
||||
Stop();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_BACKGROUNDTASKMANAGER_H
|
||||
#define CRYINCLUDE_EDITOR_BACKGROUNDTASKMANAGER_H
|
||||
#pragma once
|
||||
|
||||
#include "Include/IBackgroundTaskManager.h"
|
||||
#include "CryListenerSet.h"
|
||||
|
||||
#include <QThread>
|
||||
|
||||
namespace BackgroundTaskManager
|
||||
{
|
||||
typedef int TTaskID;
|
||||
|
||||
struct STaskHandle
|
||||
{
|
||||
ETaskPriority priority;
|
||||
ETaskThreadMask threadMask;
|
||||
TTaskID id;
|
||||
IBackgroundTask* pTask;
|
||||
|
||||
bool operator<(const STaskHandle& rhs) const
|
||||
{
|
||||
if (priority < rhs.priority)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (priority > rhs.priority)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return id < rhs.id;
|
||||
}
|
||||
};
|
||||
|
||||
struct SCompletedTask
|
||||
{
|
||||
ETaskResult state;
|
||||
TTaskID id;
|
||||
ETaskThreadMask threadMask;
|
||||
IBackgroundTask* pTask;
|
||||
};
|
||||
|
||||
struct SScheduledTask
|
||||
{
|
||||
unsigned int time;
|
||||
STaskHandle handle;
|
||||
};
|
||||
|
||||
class CTaskManager
|
||||
: public IBackgroundTaskManager
|
||||
, public IEditorNotifyListener
|
||||
{
|
||||
public:
|
||||
CTaskManager();
|
||||
~CTaskManager();
|
||||
|
||||
// IBackgroundTaskManager interface implementation
|
||||
virtual void AddTask(IBackgroundTask* pTask, ETaskPriority priority, ETaskThreadMask threadMask) override;
|
||||
virtual void ScheduleTask(IBackgroundTask* pTask, ETaskPriority priority, int delayMilliseconds, ETaskThreadMask threadMask) override;
|
||||
void AddListener(IBackgroundTaskManagerListener* pListener, const char* name) override;
|
||||
void RemoveListener(IBackgroundTaskManagerListener* pListener) override;
|
||||
|
||||
private:
|
||||
// IEditorNotifyListener interface implementation
|
||||
virtual void OnEditorNotifyEvent(EEditorNotifyEvent ev) override;
|
||||
|
||||
void Start(const uint32 threadCount = kDefaultThreadCount);
|
||||
void Stop();
|
||||
void StartScheduledTasks();
|
||||
void AddTask(const STaskHandle& outTask);
|
||||
void AddCompletedTask(const STaskHandle& outTask, ETaskResult resultState);
|
||||
void Update();
|
||||
|
||||
inline bool IsStopped() const
|
||||
{
|
||||
return m_bStop;
|
||||
}
|
||||
|
||||
private:
|
||||
// Internal queue (per thread mask)
|
||||
class CQueue
|
||||
{
|
||||
public:
|
||||
CQueue();
|
||||
|
||||
// Add task to list
|
||||
void AddTask(const STaskHandle& taskHandle);
|
||||
|
||||
// Pop task from list
|
||||
void PopTask(STaskHandle& outTaskHandle);
|
||||
|
||||
// Release thread semaphore without adding a task
|
||||
void ReleaseSemaphore();
|
||||
|
||||
// Remove all pending tasks
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
CrySemaphore m_semaphore;
|
||||
std::vector<STaskHandle> m_pendingTasks;
|
||||
CryMutex m_lock;
|
||||
};
|
||||
|
||||
// Worker thread class implementation
|
||||
class CThread : public QThread
|
||||
{
|
||||
public:
|
||||
CThread(CTaskManager* pManager, CQueue* pQueue);
|
||||
~CThread();
|
||||
|
||||
void WaitForThread();
|
||||
|
||||
private:
|
||||
void run() override;
|
||||
|
||||
private:
|
||||
CTaskManager* m_pManager;
|
||||
CQueue* m_pQueue;
|
||||
};
|
||||
|
||||
private:
|
||||
static const uint32 kMaxThreadCloseWaitTime = 10000; // ms
|
||||
static const uint32 kDefaultThreadCount = 4; // good enough for LiveCreate (main user right now), do not set to less than 2
|
||||
|
||||
CQueue m_pendingTasks[ eTaskThreadMask_COUNT ];
|
||||
|
||||
// Task scheduled for execution in the future
|
||||
std::vector<SScheduledTask> m_scheduledTasks;
|
||||
|
||||
// Completed tasks (waiting for the "finalize" call)
|
||||
std::vector<SCompletedTask> m_completedTasks;
|
||||
|
||||
volatile TTaskID m_nextTaskID;
|
||||
|
||||
typedef std::vector<CThread*> TWorkerThreads;
|
||||
TWorkerThreads m_pThreads;
|
||||
|
||||
CryMutex m_tasksLock;
|
||||
bool m_bStop;
|
||||
|
||||
typedef CListenerSet<IBackgroundTaskManagerListener*> TListeners;
|
||||
TListeners m_listeners;
|
||||
};
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_BACKGROUNDTASKMANAGER_H
|
||||
@@ -112,7 +112,6 @@ ly_add_target(
|
||||
3rdParty::zlib
|
||||
3rdParty::AWSNativeSDK::STS
|
||||
Legacy::CryCommon
|
||||
Legacy::CryCommon.EngineSettings.Static
|
||||
Legacy::EditorCommon
|
||||
AZ::AzCore
|
||||
AZ::AzToolsFramework
|
||||
|
||||
@@ -1,821 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "CurveEditorCtrl.h"
|
||||
|
||||
// Qt
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
|
||||
namespace CurveEditor
|
||||
{
|
||||
const int kHandleSize = 6;
|
||||
const int kHandleSizeHalf = kHandleSize / 2;
|
||||
const int kDefaultPadding = 10;
|
||||
const int kInfoFontSize = 7;
|
||||
const int kGrid = 4;
|
||||
const QColor kColor_SelectCross(132, 132, 132);
|
||||
const QColor kColor_DisabledCross(90, 90, 90);
|
||||
const QColor kColor_MiddleLines(80, 80, 80);
|
||||
const QColor kColor_Background(41, 41, 41);
|
||||
const QColor kColor_Disabled(60, 60, 60);
|
||||
const QColor kColor_PaddingBorder(128, 128, 128);
|
||||
const QColor kColor_Text(128, 128, 128);
|
||||
const QColor kColor_TextCrtPos(187, 187, 187);
|
||||
const QColor kColor_Curve(255, 0, 0);
|
||||
const QColor kColor_SelHandle(200, 200, 200);
|
||||
const QColor kColor_NormalHandle(30, 30, 30);
|
||||
const QColor kColor_HandleLight(60, 60, 60);
|
||||
const QColor kColor_HandleShadow(0, 0, 0);
|
||||
const QColor kColor_MarkLines(0, 255, 0);
|
||||
}
|
||||
|
||||
|
||||
CCurveEditorCtrl::CCurveEditorCtrl(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
m_domainMinX = 0.0f;
|
||||
m_domainMinY = 0.0f;
|
||||
m_domainMaxX = 1.0f;
|
||||
m_domainMaxY = 1.0f;
|
||||
m_bMouseDown = m_bDragging = false;
|
||||
m_bAllowMouse = true;
|
||||
m_padding = CurveEditor::kDefaultPadding;
|
||||
m_flags = eFlag_ShowVerticalRuler
|
||||
| eFlag_ShowHorizontalRuler
|
||||
| eFlag_ShowVerticalRulerText
|
||||
| eFlag_ShowHorizontalRulerText
|
||||
| eFlag_ShowPaddingBorder
|
||||
| eFlag_ShowMovingPointAxis
|
||||
| eFlag_ShowPointHandles;
|
||||
m_gridSplits.set(CurveEditor::kGrid, CurveEditor::kGrid);
|
||||
m_fntInfo.setFamily("Arial");
|
||||
m_fntInfo.setPointSize(CurveEditor::kInfoFontSize);
|
||||
m_bHovered = false;
|
||||
m_selCrossPen = QPen(CurveEditor::kColor_SelectCross);
|
||||
|
||||
GenerateDefaultCurve();
|
||||
}
|
||||
|
||||
CCurveEditorCtrl::~CCurveEditorCtrl()
|
||||
{
|
||||
}
|
||||
|
||||
void CCurveEditorCtrl::SetFlags(UINT aFlags)
|
||||
{
|
||||
m_flags = aFlags;
|
||||
}
|
||||
|
||||
UINT CCurveEditorCtrl::GetFlags() const
|
||||
{
|
||||
return m_flags;
|
||||
}
|
||||
|
||||
bool CCurveEditorCtrl::SetDomainBounds(float aMinX, float aMinY, float aMaxX, float aMaxY)
|
||||
{
|
||||
assert(aMinX < aMaxX);
|
||||
assert(aMinY < aMaxY);
|
||||
|
||||
if (aMinX >= aMaxX)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aMinY >= aMaxY)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_domainMinX = aMinX;
|
||||
m_domainMinY = aMinY;
|
||||
m_domainMaxX = aMaxX;
|
||||
m_domainMaxY = aMaxY;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CCurveEditorCtrl::GetDomainBounds(float& rMinX, float& rMinY, float& rMaxX, float& rMaxY) const
|
||||
{
|
||||
rMinX = m_domainMinX;
|
||||
rMinY = m_domainMinY;
|
||||
rMaxX = m_domainMaxX;
|
||||
rMaxY = m_domainMaxY;
|
||||
}
|
||||
|
||||
void CCurveEditorCtrl::SetGrid(UINT aHorizontalSplits, UINT aVerticalSplits, const QStringList& labelsX, const QStringList& labelsY)
|
||||
{
|
||||
assert(aHorizontalSplits);
|
||||
assert(aVerticalSplits);
|
||||
|
||||
if (!aHorizontalSplits)
|
||||
{
|
||||
// defaults
|
||||
aHorizontalSplits = 2;
|
||||
}
|
||||
|
||||
if (!aVerticalSplits)
|
||||
{
|
||||
// defaults
|
||||
aVerticalSplits = 2;
|
||||
}
|
||||
|
||||
m_gridSplits.x = aHorizontalSplits;
|
||||
m_gridSplits.y = aVerticalSplits;
|
||||
|
||||
if (!labelsX.isEmpty())
|
||||
{
|
||||
m_labelsX = labelsX;
|
||||
}
|
||||
|
||||
if (!labelsY.isEmpty())
|
||||
{
|
||||
m_labelsY = labelsY;
|
||||
}
|
||||
}
|
||||
|
||||
QPoint CCurveEditorCtrl::ProjectPoint(float x, float y)
|
||||
{
|
||||
QPoint pt;
|
||||
|
||||
pt.setX(m_padding + (width() - m_padding * 2) * (x - m_domainMinX) / (m_domainMaxX - m_domainMinX));
|
||||
pt.setY(m_padding + (height() - m_padding * 2) * (1.0f - (y - m_domainMinY) / (m_domainMaxY - m_domainMinY)));
|
||||
|
||||
return pt;
|
||||
}
|
||||
|
||||
Vec2 CCurveEditorCtrl::UnprojectPoint(const QPoint& pt)
|
||||
{
|
||||
Vec2 vec;
|
||||
int y = height() - pt.y();
|
||||
float dx = (width() - m_padding * 2);
|
||||
float dy = (height() - m_padding * 2);
|
||||
const float kEpsilon = 0.00000001f;
|
||||
|
||||
if (fabs(dx) <= kEpsilon)
|
||||
{
|
||||
dx = 1.0f;
|
||||
}
|
||||
|
||||
if (fabs(dy) <= kEpsilon)
|
||||
{
|
||||
dy = 1.0f;
|
||||
}
|
||||
|
||||
vec.x = m_domainMinX + (float)(pt.x() - m_padding) / dx * (m_domainMaxX - m_domainMinX);
|
||||
vec.y = m_domainMinY + (float)(y - m_padding) / dy * (m_domainMaxY - m_domainMinY);
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
void CCurveEditorCtrl::SetControlPointCount(UINT aCount)
|
||||
{
|
||||
m_points.resize(aCount);
|
||||
m_projectedPoints.clear();
|
||||
}
|
||||
|
||||
UINT CCurveEditorCtrl::GetControlPointCount() const
|
||||
{
|
||||
return m_points.size();
|
||||
}
|
||||
|
||||
void CCurveEditorCtrl::AddControlPoint(const Vec2& rPosition)
|
||||
{
|
||||
m_points.push_back(CurvePoint(rPosition.x, rPosition.y));
|
||||
}
|
||||
|
||||
void CCurveEditorCtrl::ClearControlPoints()
|
||||
{
|
||||
m_points.clear();
|
||||
}
|
||||
|
||||
void CCurveEditorCtrl::SetControlPoint(UINT aIndex, const Vec2& rPosition)
|
||||
{
|
||||
assert(aIndex < m_points.size());
|
||||
|
||||
if (aIndex >= m_points.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_points[aIndex].pos = rPosition;
|
||||
}
|
||||
|
||||
void CCurveEditorCtrl::SetControlPointTangents(UINT aIndex, const Vec2& rLeft, const Vec2& rRight)
|
||||
{
|
||||
assert(aIndex < m_points.size());
|
||||
|
||||
if (aIndex >= m_points.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_points[aIndex].tanA = rLeft;
|
||||
m_points[aIndex].tanB = rRight;
|
||||
}
|
||||
|
||||
void CCurveEditorCtrl::GetControlPoint(UINT aIndex, Vec2& rOutPosition) const
|
||||
{
|
||||
assert(aIndex < m_points.size());
|
||||
|
||||
if (aIndex >= m_points.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rOutPosition = m_points[aIndex].pos;
|
||||
}
|
||||
|
||||
void CCurveEditorCtrl::GetControlPointTangents(UINT aIndex, Vec2& rOutLeft, Vec2& rOutRight) const
|
||||
{
|
||||
assert(aIndex < m_points.size());
|
||||
|
||||
if (aIndex >= m_points.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rOutLeft = m_points[aIndex].tanA;
|
||||
rOutRight = m_points[aIndex].tanB;
|
||||
}
|
||||
|
||||
void CCurveEditorCtrl::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
QWidget::paintEvent(event);
|
||||
|
||||
QPainter dc(this);
|
||||
|
||||
QRect rc = geometry();
|
||||
QString str;
|
||||
QRect textSize;
|
||||
|
||||
dc.setFont(m_fntInfo);
|
||||
QFontMetrics fntMetrics(m_fntInfo);
|
||||
|
||||
if (m_flags & eFlag_Disabled)
|
||||
{
|
||||
// If disabled, just draw a blank square.
|
||||
dc.fillRect(rc, CurveEditor::kColor_Disabled);
|
||||
|
||||
dc.setPen(CurveEditor::kColor_DisabledCross);
|
||||
dc.drawLine(0, 0, rc.width(), rc.height());
|
||||
|
||||
dc.drawLine(rc.width(), 0, 0, rc.height());
|
||||
return;
|
||||
}
|
||||
|
||||
dc.fillRect(rc, CurveEditor::kColor_Background);
|
||||
|
||||
dc.setPen(CurveEditor::kColor_MiddleLines);
|
||||
|
||||
if (m_flags & eFlag_ShowVerticalRuler)
|
||||
{
|
||||
float y = m_domainMinY;
|
||||
float grid = (m_domainMaxY - m_domainMinY) / m_gridSplits.y;
|
||||
QPoint p;
|
||||
|
||||
for (int i = 0; i <= m_gridSplits.y; ++i)
|
||||
{
|
||||
p = ProjectPoint(0, y);
|
||||
dc.drawLine(m_padding, p.y(), rc.width() - m_padding, p.y());
|
||||
|
||||
if (m_flags & eFlag_ShowVerticalRulerText)
|
||||
{
|
||||
if (m_labelsY.empty())
|
||||
{
|
||||
str.asprintf("%0.2f", y);
|
||||
}
|
||||
else
|
||||
{
|
||||
str = m_labelsY[i];
|
||||
}
|
||||
textSize = fntMetrics.tightBoundingRect(str);
|
||||
dc.drawText(2, p.y(), str);
|
||||
}
|
||||
|
||||
y += grid;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_flags & eFlag_ShowHorizontalRuler)
|
||||
{
|
||||
float x = m_domainMinX;
|
||||
float grid = (m_domainMaxX - m_domainMinX) / m_gridSplits.x;
|
||||
QPoint p;
|
||||
|
||||
for (int i = 0; i <= m_gridSplits.x; ++i)
|
||||
{
|
||||
p = ProjectPoint(x, 0);
|
||||
dc.drawLine(p.x(), m_padding, p.x(), rc.height() - m_padding);
|
||||
|
||||
if (m_flags & eFlag_ShowHorizontalRulerText)
|
||||
{
|
||||
if (m_labelsX.empty())
|
||||
{
|
||||
str.asprintf("%0.2f", x);
|
||||
}
|
||||
else
|
||||
{
|
||||
str = m_labelsX[i];
|
||||
}
|
||||
textSize = fntMetrics.tightBoundingRect(str);
|
||||
|
||||
p.setX(p.x() + 2);
|
||||
|
||||
if (p.x() + textSize.width() > width())
|
||||
{
|
||||
p.setX(width() - textSize.width());
|
||||
}
|
||||
|
||||
dc.drawText(p.x(), height() - m_padding + textSize.height() + 2, str);
|
||||
}
|
||||
|
||||
x += grid;
|
||||
}
|
||||
}
|
||||
|
||||
dc.setPen(CurveEditor::kColor_MarkLines);
|
||||
|
||||
if (m_flags & eFlag_ShowVerticalRuler)
|
||||
{
|
||||
QPoint p;
|
||||
for (size_t i = 0; i < m_marksY.size(); ++i)
|
||||
{
|
||||
float v = m_marksY[i];
|
||||
if (v < m_domainMinY || v > m_domainMaxY)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
p = ProjectPoint(0, v);
|
||||
dc.drawLine(m_padding, p.y(), width() - m_padding, p.y());
|
||||
}
|
||||
}
|
||||
|
||||
if (m_flags & eFlag_ShowHorizontalRuler)
|
||||
{
|
||||
QPoint p;
|
||||
for (size_t i = 0; i < m_marksX.size(); ++i)
|
||||
{
|
||||
float v = m_marksX[i];
|
||||
if (v < m_domainMinX || v > m_domainMaxX)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
p = ProjectPoint(v, 0);
|
||||
dc.drawLine(p.x(), m_padding, p.x(), height() - m_padding);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_flags & eFlag_ShowPaddingBorder)
|
||||
{
|
||||
dc.setPen(CurveEditor::kColor_PaddingBorder);
|
||||
dc.drawRect(m_padding, m_padding, width() - m_padding * 2, height() - m_padding * 2);
|
||||
}
|
||||
|
||||
if (m_bDragging
|
||||
&& !m_selectedIndices.empty()
|
||||
&& (m_flags & eFlag_ShowMovingPointAxis))
|
||||
{
|
||||
const Vec2& crtPos = m_points[m_selectedIndices[0]].pos;
|
||||
|
||||
dc.setBrush(CurveEditor::kColor_TextCrtPos);
|
||||
str.asprintf("(%0.2f,%0.2f)", crtPos.x, crtPos.y);
|
||||
textSize = fntMetrics.tightBoundingRect(str);
|
||||
const int kOffsetFromPointer = 5;
|
||||
QPoint txtPos(m_lastMousePoint.x() + kOffsetFromPointer, m_lastMousePoint.y() + kOffsetFromPointer);
|
||||
|
||||
if (txtPos.x() + textSize.width() > width())
|
||||
{
|
||||
txtPos.setX(width() - textSize.width());
|
||||
}
|
||||
|
||||
if (txtPos.y() + textSize.height() > height())
|
||||
{
|
||||
txtPos.setY(height() - textSize.height());
|
||||
}
|
||||
|
||||
dc.drawText(txtPos, str);
|
||||
}
|
||||
|
||||
ComputeTangents();
|
||||
UpdateProjectedPoints();
|
||||
|
||||
// for curve debug, tangents poly, don't delete
|
||||
// dc.setPen(Qt::black);
|
||||
// dc.drawPolyline(m_projectedPoints.data(), m_projectedPoints.size());
|
||||
|
||||
dc.setPen(CurveEditor::kColor_Curve);
|
||||
|
||||
// curve
|
||||
QPainterPath bezierPath;
|
||||
bezierPath.moveTo(m_projectedPoints[0]);
|
||||
for (int i = 1; i < m_projectedPoints.size(); i += 3)
|
||||
{
|
||||
bezierPath.cubicTo(m_projectedPoints[i], m_projectedPoints[i + 1], m_projectedPoints[i + 2]);
|
||||
}
|
||||
dc.drawPath(bezierPath);
|
||||
|
||||
// curve control point handles
|
||||
if (m_flags & eFlag_ShowPointHandles)
|
||||
{
|
||||
for (size_t i = 0; i < m_points.size(); ++i)
|
||||
{
|
||||
QPoint ptProj = ProjectPoint(m_points[i].pos.x, m_points[i].pos.y);
|
||||
QRect rcHandle(0, 0, CurveEditor::kHandleSize, CurveEditor::kHandleSize);
|
||||
rcHandle.moveCenter(ptProj);
|
||||
|
||||
std::vector<int>::iterator iter =
|
||||
std::find(m_selectedIndices.begin(), m_selectedIndices.end(), i);
|
||||
|
||||
bool bSelected = (iter != m_selectedIndices.end());
|
||||
|
||||
if (bSelected && m_bDragging)
|
||||
{
|
||||
dc.setPen(m_selCrossPen);
|
||||
dc.drawLine(0, ptProj.y(), width(), ptProj.y());
|
||||
dc.drawLine(ptProj.x(), 0, ptProj.x(), height());
|
||||
}
|
||||
|
||||
dc.fillRect(rcHandle, bSelected
|
||||
? CurveEditor::kColor_SelHandle
|
||||
: CurveEditor::kColor_NormalHandle);
|
||||
|
||||
dc.setPen(CurveEditor::kColor_HandleLight);
|
||||
dc.drawLine(ptProj.x() - CurveEditor::kHandleSizeHalf, ptProj.y() - CurveEditor::kHandleSizeHalf,
|
||||
ptProj.x() - CurveEditor::kHandleSizeHalf, ptProj.y() + CurveEditor::kHandleSizeHalf);
|
||||
dc.drawLine(ptProj.x() - CurveEditor::kHandleSizeHalf, ptProj.y() + CurveEditor::kHandleSizeHalf,
|
||||
ptProj.x() + CurveEditor::kHandleSizeHalf, ptProj.y() + CurveEditor::kHandleSizeHalf);
|
||||
dc.setPen(CurveEditor::kColor_HandleShadow);
|
||||
dc.drawLine(ptProj.x() + CurveEditor::kHandleSizeHalf, ptProj.y() + CurveEditor::kHandleSizeHalf,
|
||||
ptProj.x() + CurveEditor::kHandleSizeHalf, ptProj.y() - CurveEditor::kHandleSizeHalf);
|
||||
dc.drawLine(ptProj.x() + CurveEditor::kHandleSizeHalf, ptProj.y() - CurveEditor::kHandleSizeHalf,
|
||||
ptProj.x() - CurveEditor::kHandleSizeHalf, ptProj.y() - CurveEditor::kHandleSizeHalf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CCurveEditorCtrl::ComputeTangents()
|
||||
{
|
||||
for (size_t i = 0; i < m_points.size(); ++i)
|
||||
{
|
||||
m_points[i].tanA = m_points[i].pos;
|
||||
m_points[i].tanB = m_points[i].pos;
|
||||
}
|
||||
|
||||
int maxIndex = m_points.size() - 1;
|
||||
|
||||
for (size_t i = 0; i < m_points.size(); ++i)
|
||||
{
|
||||
if (i > maxIndex)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Vec2& p2 = m_points[i].pos;
|
||||
Vec2& back = m_points[i].tanA;
|
||||
Vec2& forw = m_points[i].tanB;
|
||||
const float kEpsilon = 0.000001f;
|
||||
|
||||
// first point
|
||||
if (i == 0)
|
||||
{
|
||||
back = p2;
|
||||
|
||||
if (maxIndex == 1)
|
||||
{
|
||||
Vec2& p3 = m_points[i + 1].pos;
|
||||
forw = p2 + (p3 - p2) / 3.0f;
|
||||
}
|
||||
else if (maxIndex > 0)
|
||||
{
|
||||
Vec2& p3 = m_points[i + 1].pos;
|
||||
Vec2& pb3 = m_points[i + 1].tanA;
|
||||
|
||||
float lenOsn = (pb3 - p2).GetLength();
|
||||
float lenb = (p3 - p2).GetLength();
|
||||
|
||||
if (lenOsn > kEpsilon && lenb > kEpsilon)
|
||||
{
|
||||
forw = p2 + (pb3 - p2) / (lenOsn / lenb * 3.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
forw = p2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i == maxIndex)
|
||||
{
|
||||
forw = p2;
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
Vec2& p1 = m_points[i - 1].pos;
|
||||
Vec2& pf1 = m_points[i - 1].tanB;
|
||||
|
||||
float lenOsn = (pf1 - p2).GetLength();
|
||||
float lenf = (p1 - p2).GetLength();
|
||||
|
||||
if (lenOsn > kEpsilon && lenf > kEpsilon)
|
||||
{
|
||||
back = p2 + (pf1 - p2) / (lenOsn / lenf * 3.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
back = p2;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (i >= 1 && i <= maxIndex - 1)
|
||||
{
|
||||
Vec2& p1 = m_points[i - 1].pos;
|
||||
Vec2& p3 = m_points[i + 1].pos;
|
||||
|
||||
float lenOsn = (p3 - p1).GetLength();
|
||||
float lenb = (p1 - p2).GetLength();
|
||||
float lenf = (p3 - p2).GetLength();
|
||||
|
||||
if (lenOsn > kEpsilon
|
||||
&& lenf > kEpsilon
|
||||
&& lenb > kEpsilon)
|
||||
{
|
||||
back = p2 + (p1 - p3) * (lenb / lenOsn / 3.0f);
|
||||
forw = p2 + (p3 - p1) * (lenf / lenOsn / 3.0f);
|
||||
}
|
||||
}
|
||||
|
||||
ClampToDomain(back);
|
||||
ClampToDomain(forw);
|
||||
}
|
||||
|
||||
// fix tangents in relation of one to another
|
||||
for (size_t i = 0; i < m_points.size(); ++i)
|
||||
{
|
||||
Vec2& p = m_points[i].pos;
|
||||
Vec2& tanA = m_points[i].tanA;
|
||||
Vec2& tanB = m_points[i].tanB;
|
||||
|
||||
if (i < m_points.size() - 1)
|
||||
{
|
||||
if (tanB.x > m_points[i + 1].tanA.x)
|
||||
{
|
||||
tanB.x = (m_points[i + 1].pos.x + p.x) * 0.5f;
|
||||
}
|
||||
}
|
||||
if (i > 0)
|
||||
{
|
||||
if (tanA.x < m_points[i - 1].tanB.x)
|
||||
{
|
||||
tanA.x = (m_points[i - 1].pos.x + p.x) * 0.5f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CCurveEditorCtrl::UpdateProjectedPoints()
|
||||
{
|
||||
m_projectedPoints.resize(m_points.size() * 3 - 2);
|
||||
|
||||
int numPts = 0;
|
||||
|
||||
for (size_t i = 0; i < m_points.size(); ++i)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
m_projectedPoints[numPts++] = ProjectPoint(m_points[i].pos.x, m_points[i].pos.y);
|
||||
m_projectedPoints[numPts++] = ProjectPoint(m_points[i].tanB.x, m_points[i].tanB.y);
|
||||
}
|
||||
else if (i == m_points.size() - 1)
|
||||
{
|
||||
m_projectedPoints[numPts++] = ProjectPoint(m_points[i].tanA.x, m_points[i].tanA.y);
|
||||
m_projectedPoints[numPts++] = ProjectPoint(m_points[i].pos.x, m_points[i].pos.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_projectedPoints[numPts++] = ProjectPoint(m_points[i].tanA.x, m_points[i].tanA.y);
|
||||
m_projectedPoints[numPts++] = ProjectPoint(m_points[i].pos.x, m_points[i].pos.y);
|
||||
m_projectedPoints[numPts++] = ProjectPoint(m_points[i].tanB.x, m_points[i].tanB.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CCurveEditorCtrl::ClampToDomain(Vec2& rVec)
|
||||
{
|
||||
if (rVec.x < m_domainMinX)
|
||||
{
|
||||
rVec.x = m_domainMinX;
|
||||
}
|
||||
else if (rVec.x > m_domainMaxX)
|
||||
{
|
||||
rVec.x = m_domainMaxX;
|
||||
}
|
||||
|
||||
if (rVec.y < m_domainMinY)
|
||||
{
|
||||
rVec.y = m_domainMinY;
|
||||
}
|
||||
else if (rVec.y > m_domainMaxY)
|
||||
{
|
||||
rVec.y = m_domainMaxY;
|
||||
}
|
||||
}
|
||||
|
||||
void CCurveEditorCtrl::GenerateDefaultCurve()
|
||||
{
|
||||
m_points.clear();
|
||||
m_domainMinX = 0.0f;
|
||||
m_domainMinY = 0.0f;
|
||||
m_domainMaxX = 1.0f;
|
||||
m_domainMaxY = 1.0f;
|
||||
m_points.push_back(CurvePoint(0.00f, 0.00f));
|
||||
m_points.push_back(CurvePoint(0.25f, 0.25f));
|
||||
m_points.push_back(CurvePoint(0.50f, 0.50f));
|
||||
m_points.push_back(CurvePoint(0.75f, 0.75f));
|
||||
m_points.push_back(CurvePoint(1.00f, 1.00f));
|
||||
}
|
||||
|
||||
void CCurveEditorCtrl::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
QWidget::mousePressEvent(event);
|
||||
if (event->button() != Qt::LeftButton)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const QPoint point = event->pos();
|
||||
if (m_bAllowMouse)
|
||||
{
|
||||
bool bSimpleSelect = !(event->modifiers() & Qt::ShiftModifier) && !(event->modifiers() & Qt::ControlModifier);
|
||||
|
||||
if (bSimpleSelect)
|
||||
{
|
||||
m_selectedIndices.clear();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < m_points.size(); ++i)
|
||||
{
|
||||
QPoint ptProj = ProjectPoint(m_points[i].pos.x, m_points[i].pos.y);
|
||||
|
||||
QRect rcHandle(0, 0, CurveEditor::kHandleSize, CurveEditor::kHandleSize);
|
||||
rcHandle.moveCenter(ptProj);
|
||||
|
||||
if (rcHandle.contains(point))
|
||||
{
|
||||
if (bSimpleSelect)
|
||||
{
|
||||
m_selectedIndices.push_back(i);
|
||||
break;
|
||||
}
|
||||
|
||||
if (event->modifiers() & Qt::ShiftModifier)
|
||||
{
|
||||
m_selectedIndices.push_back(i);
|
||||
}
|
||||
else if (event->modifiers() & Qt::ControlModifier)
|
||||
{
|
||||
std::vector<int>::iterator iter =
|
||||
std::find(m_selectedIndices.begin(), m_selectedIndices.end(), i);
|
||||
|
||||
if (iter == m_selectedIndices.end())
|
||||
{
|
||||
m_selectedIndices.push_back(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_selectedIndices.erase(iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_bMouseDown = true;
|
||||
m_lastMousePoint = point;
|
||||
}
|
||||
|
||||
grabMouse();
|
||||
update();
|
||||
}
|
||||
|
||||
void CCurveEditorCtrl::mouseReleaseEvent(QMouseEvent* event)
|
||||
{
|
||||
QWidget::mouseReleaseEvent(event);
|
||||
if (event->button() != Qt::LeftButton)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_bMouseDown = false;
|
||||
m_bDragging = false;
|
||||
m_selectedIndices.clear();
|
||||
|
||||
releaseMouse();
|
||||
update();
|
||||
}
|
||||
|
||||
void CCurveEditorCtrl::mouseMoveEvent(QMouseEvent* event)
|
||||
{
|
||||
if (m_bMouseDown && !m_bDragging)
|
||||
{
|
||||
m_bDragging = true;
|
||||
}
|
||||
|
||||
m_bHovered = true;
|
||||
if (m_flags & eFlag_ShowCursorAlways)
|
||||
{
|
||||
m_bHovered = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bHovered = false;
|
||||
|
||||
for (size_t i = 0; i < m_points.size(); ++i)
|
||||
{
|
||||
QPoint ptProj = ProjectPoint(m_points[i].pos.x, m_points[i].pos.y);
|
||||
QRect rcHandle(0, 0, CurveEditor::kHandleSize, CurveEditor::kHandleSize);
|
||||
rcHandle.moveCenter(ptProj);
|
||||
|
||||
if (rcHandle.contains(event->pos()))
|
||||
{
|
||||
m_bHovered = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_bDragging)
|
||||
{
|
||||
Vec2 v1 = UnprojectPoint(m_lastMousePoint);
|
||||
Vec2 v2 = UnprojectPoint(event->pos());
|
||||
Vec2 v = v1 - v2;
|
||||
|
||||
for (size_t i = 0; i < m_selectedIndices.size(); ++i)
|
||||
{
|
||||
int index = m_selectedIndices[i];
|
||||
CurvePoint& cpt = m_points[index];
|
||||
|
||||
// do not move first and last points on X
|
||||
if (index > 0 && index < m_points.size() - 1)
|
||||
{
|
||||
cpt.pos.x -= v.x;
|
||||
}
|
||||
|
||||
cpt.pos.y -= v.y;
|
||||
|
||||
// lets check if the point is overlapping its neighbours
|
||||
if (index > 0 && (index - 1) > 0)
|
||||
{
|
||||
if (cpt.pos.x < m_points[index - 1].pos.x)
|
||||
{
|
||||
CurvePoint p = m_points[index];
|
||||
|
||||
// swap!
|
||||
m_points[index] = m_points[index - 1];
|
||||
m_points[index - 1] = p;
|
||||
m_selectedIndices[i] = index - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (index < m_points.size() - 1 && (index + 1) < m_points.size() - 1)
|
||||
{
|
||||
if (cpt.pos.x > m_points[index + 1].pos.x)
|
||||
{
|
||||
CurvePoint p = m_points[index];
|
||||
|
||||
// swap!
|
||||
m_points[index] = m_points[index + 1];
|
||||
m_points[index + 1] = p;
|
||||
m_selectedIndices[i] = index + 1;
|
||||
}
|
||||
}
|
||||
|
||||
ClampToDomain(cpt.pos);
|
||||
}
|
||||
|
||||
update();
|
||||
m_lastMousePoint = event->pos();
|
||||
}
|
||||
|
||||
QWidget::mouseMoveEvent(event);
|
||||
}
|
||||
|
||||
void CCurveEditorCtrl::MarkX(float value)
|
||||
{
|
||||
m_marksX.push_back(value);
|
||||
}
|
||||
|
||||
void CCurveEditorCtrl::MarkY(float value)
|
||||
{
|
||||
m_marksY.push_back(value);
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_CONTROLS_CURVEEDITORCTRL_H
|
||||
#define CRYINCLUDE_EDITOR_CONTROLS_CURVEEDITORCTRL_H
|
||||
#pragma once
|
||||
#include "Util/GdiUtil.h"
|
||||
#include <QWidget>
|
||||
#include <QPen>
|
||||
|
||||
|
||||
class CCurveEditorCtrl
|
||||
: public QWidget
|
||||
{
|
||||
public:
|
||||
enum EFlags
|
||||
{
|
||||
eFlag_ShowVerticalRuler = (1 << 0),
|
||||
eFlag_ShowHorizontalRuler = (1 << 1),
|
||||
eFlag_ShowVerticalRulerText = (1 << 2),
|
||||
eFlag_ShowHorizontalRulerText = (1 << 3),
|
||||
eFlag_ShowPaddingBorder = (1 << 4),
|
||||
eFlag_ShowMovingPointAxis = (1 << 5),
|
||||
eFlag_ShowPointHandles = (1 << 6),
|
||||
eFlag_ShowCursorAlways = (1 << 7),
|
||||
eFlag_Disabled = (1 << 8) // special case, when disabling preview window.
|
||||
};
|
||||
|
||||
CCurveEditorCtrl(QWidget* parent);
|
||||
virtual ~CCurveEditorCtrl();
|
||||
|
||||
void SetFlags(UINT aFlags);
|
||||
UINT GetFlags() const;
|
||||
void SetMouseEnable(bool bEnable = true) { m_bAllowMouse = bEnable; }
|
||||
bool GetMouseEnable() const {return m_bAllowMouse; }
|
||||
bool SetDomainBounds(float aMinX, float aMinY, float aMaxX, float aMaxY);
|
||||
void GetDomainBounds(float& rMinX, float& rMinY, float& rMaxX, float& rMaxY) const;
|
||||
// labelsX/labelsY must be null (to use default labels)
|
||||
// or contain aHorizontalSplits+1/aVerticalSplits+1 items.
|
||||
void SetGrid(UINT aHorizontalSplits, UINT aVerticalSplits, const QStringList& labelsX = QStringList(), const QStringList& labelsY = QStringList());
|
||||
void SetPadding(float padding) { m_padding = padding; }
|
||||
void MarkX(float value);
|
||||
void MarkY(float value);
|
||||
void AddControlPoint(const Vec2& rPosition);
|
||||
void ClearControlPoints();
|
||||
void SetControlPointCount(UINT aCount);
|
||||
UINT GetControlPointCount() const;
|
||||
void SetControlPoint(UINT aIndex, const Vec2& rPosition);
|
||||
void SetControlPointTangents(UINT aIndex, const Vec2& rLeft, const Vec2& rRight);
|
||||
void GetControlPoint(UINT aIndex, Vec2& rOutPosition) const;
|
||||
void GetControlPointTangents(UINT aIndex, Vec2& rOutLeft, Vec2& rOutRight) const;
|
||||
QPoint ProjectPoint(float x, float y);
|
||||
Vec2 UnprojectPoint(const QPoint& pt);
|
||||
void UpdateProjectedPoints();
|
||||
|
||||
protected:
|
||||
struct CurvePoint
|
||||
{
|
||||
CurvePoint(float aX = 0.0f, float aY = 0.0f)
|
||||
{
|
||||
pos.x = aX;
|
||||
pos.y = aY;
|
||||
}
|
||||
|
||||
Vec2 pos;
|
||||
Vec2 tanA, tanB;
|
||||
};
|
||||
|
||||
void ComputeTangents();
|
||||
void ClampToDomain(Vec2& rVec);
|
||||
void GenerateDefaultCurve();
|
||||
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
|
||||
std::vector<CurvePoint> m_points;
|
||||
std::vector<QPoint> m_projectedPoints;
|
||||
float m_domainMinX;
|
||||
float m_domainMinY;
|
||||
float m_domainMaxX;
|
||||
float m_domainMaxY;
|
||||
Vec2 m_gridSplits;
|
||||
int m_padding;
|
||||
bool m_bMouseDown, m_bDragging, m_bAllowMouse;
|
||||
bool m_bHovered;
|
||||
QPoint m_lastMousePoint;
|
||||
std::vector<int> m_selectedIndices;
|
||||
QFont m_fntInfo;
|
||||
QPen m_pen, m_selCrossPen;
|
||||
UINT m_flags;
|
||||
QStringList m_labelsX;
|
||||
QStringList m_labelsY;
|
||||
std::vector<float> m_marksX;
|
||||
std::vector<float> m_marksY;
|
||||
|
||||
void mousePressEvent(QMouseEvent* event) override;
|
||||
void mouseReleaseEvent(QMouseEvent* event) override;
|
||||
void mouseMoveEvent(QMouseEvent* event) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_CONTROLS_CURVEEDITORCTRL_H
|
||||
@@ -85,7 +85,6 @@ AZ_POP_DISABLE_WARNING
|
||||
// Editor
|
||||
#include "Settings.h"
|
||||
|
||||
#include "Include/IBackgroundScheduleManager.h"
|
||||
#include "GameExporter.h"
|
||||
#include "GameResourcesExporter.h"
|
||||
|
||||
@@ -2314,15 +2313,6 @@ int CCryEditApp::IdleProcessing(bool bBackgroundUpdate)
|
||||
#endif
|
||||
}
|
||||
|
||||
// process the work schedule - regardless if the app is active or not
|
||||
GetIEditor()->GetBackgroundScheduleManager()->Update();
|
||||
|
||||
// if there are active schedules keep updating the application
|
||||
if (GetIEditor()->GetBackgroundScheduleManager()->GetNumSchedules() > 0)
|
||||
{
|
||||
bActive = true;
|
||||
}
|
||||
|
||||
m_bPrevActive = bActive;
|
||||
|
||||
AZStd::chrono::system_clock::time_point now = AZStd::chrono::system_clock::now();
|
||||
|
||||
@@ -420,7 +420,6 @@ AZ::Outcome<void, AZStd::string> CGameEngine::Init(
|
||||
#else
|
||||
sip.hWnd = hwndForInputSystem;
|
||||
#endif
|
||||
sip.hWndForInputSystem = hwndForInputSystem;
|
||||
|
||||
sip.pLogCallback = &m_logFile;
|
||||
sip.sLogFileName = "@log@/Editor.log";
|
||||
@@ -503,7 +502,6 @@ AZ::Outcome<void, AZStd::string> CGameEngine::Init(
|
||||
|
||||
bool CGameEngine::InitGame(const char*)
|
||||
{
|
||||
// in editor we do it later, bExecuteCommandLine was set to false
|
||||
m_pISystem->ExecuteCommandLine();
|
||||
|
||||
return true;
|
||||
@@ -608,8 +606,6 @@ void CGameEngine::SwitchToInGame()
|
||||
|
||||
GetIEditor()->Notify(eNotify_OnBeginGameMode);
|
||||
|
||||
m_pISystem->SetThreadState(ESubsys_Physics, false);
|
||||
|
||||
m_pISystem->GetIMovieSystem()->EnablePhysicsEvents(true);
|
||||
m_bInGameMode = true;
|
||||
|
||||
@@ -646,8 +642,6 @@ void CGameEngine::SwitchToInEditor()
|
||||
}
|
||||
m_pISystem->GetIMovieSystem()->Reset(false, false);
|
||||
|
||||
m_pISystem->SetThreadState(ESubsys_Physics, false);
|
||||
|
||||
CViewport* pGameViewport = GetIEditor()->GetViewManager()->GetGameViewport();
|
||||
|
||||
m_pISystem->GetIMovieSystem()->EnablePhysicsEvents(m_bSimulationMode);
|
||||
@@ -791,8 +785,6 @@ void CGameEngine::SetSimulationMode(bool enabled, bool bOnlyPhysics)
|
||||
// Enables engine to know about simulation mode.
|
||||
gEnv->SetIsEditorSimulationMode(enabled);
|
||||
|
||||
m_pISystem->SetThreadState(ESubsys_Physics, false);
|
||||
|
||||
if (m_bSimulationMode)
|
||||
{
|
||||
// [Anton] the order of the next 3 calls changed, since, EVENT_INGAME loads physics state (if any),
|
||||
@@ -903,19 +895,6 @@ void CGameEngine::Update()
|
||||
// [marco] check current sound and vis areas for music etc.
|
||||
// but if in game mode, 'cos is already done in the above call to game->update()
|
||||
unsigned int updateFlags = ESYSUPDATE_EDITOR;
|
||||
|
||||
if (!m_bSimulationMode)
|
||||
{
|
||||
updateFlags |= ESYSUPDATE_IGNORE_PHYSICS;
|
||||
}
|
||||
|
||||
bool bUpdateAIPhysics = GetSimulationMode();
|
||||
|
||||
if (bUpdateAIPhysics)
|
||||
{
|
||||
updateFlags |= ESYSUPDATE_EDITOR_AI_PHYSICS;
|
||||
}
|
||||
|
||||
GetIEditor()->GetAnimation()->Update();
|
||||
GetIEditor()->GetSystem()->UpdatePreTickBus(updateFlags);
|
||||
componentApplication->Tick(gEnv->pTimer->GetFrameTime(ITimer::ETIMER_GAME));
|
||||
|
||||
@@ -550,7 +550,6 @@ struct IEditor
|
||||
virtual class CViewManager* GetViewManager() = 0;
|
||||
virtual class CViewport* GetActiveView() = 0;
|
||||
virtual void SetActiveView(CViewport* viewport) = 0;
|
||||
virtual struct IBackgroundTaskManager* GetBackgroundTaskManager() = 0;
|
||||
virtual struct IEditorFileMonitor* GetFileMonitor() = 0;
|
||||
|
||||
// These are needed for Qt integration:
|
||||
@@ -720,7 +719,6 @@ struct IEditor
|
||||
virtual ESystemConfigPlatform GetEditorConfigPlatform() const = 0;
|
||||
virtual void ReloadTemplates() = 0;
|
||||
virtual IResourceSelectorHost* GetResourceSelectorHost() = 0;
|
||||
virtual struct IBackgroundScheduleManager* GetBackgroundScheduleManager() = 0;
|
||||
virtual void ShowStatusText(bool bEnable) = 0;
|
||||
|
||||
// Provides a way to extend the context menu of an object. The function gets called every time the menu is opened.
|
||||
|
||||
@@ -66,12 +66,9 @@ AZ_POP_DISABLE_WARNING
|
||||
#include "Objects/SelectionGroup.h"
|
||||
#include "Objects/ObjectManager.h"
|
||||
|
||||
#include "BackgroundTaskManager.h"
|
||||
#include "BackgroundScheduleManager.h"
|
||||
#include "EditorFileMonitor.h"
|
||||
#include "MainStatusBar.h"
|
||||
|
||||
#include "SettingsBlock.h"
|
||||
#include "ResourceSelectorHost.h"
|
||||
#include "Util/FileUtil_impl.h"
|
||||
#include "Util/ImageUtil_impl.h"
|
||||
@@ -177,8 +174,6 @@ CEditorImpl::CEditorImpl()
|
||||
regCtx.pCommandManager = m_pCommandManager;
|
||||
regCtx.pClassFactory = m_pClassFactory;
|
||||
m_pEditorFileMonitor.reset(new CEditorFileMonitor());
|
||||
m_pBackgroundTaskManager.reset(new BackgroundTaskManager::CTaskManager);
|
||||
m_pBackgroundScheduleManager.reset(new BackgroundScheduleManager::CScheduleManager);
|
||||
m_pUIEnumsDatabase = new CUIEnumsDatabase;
|
||||
m_pDisplaySettings = new CDisplaySettings;
|
||||
m_pDisplaySettings->LoadRegistry();
|
||||
@@ -844,16 +839,6 @@ IIconManager* CEditorImpl::GetIconManager()
|
||||
return m_pIconManager;
|
||||
}
|
||||
|
||||
IBackgroundTaskManager* CEditorImpl::GetBackgroundTaskManager()
|
||||
{
|
||||
return m_pBackgroundTaskManager.get();
|
||||
}
|
||||
|
||||
IBackgroundScheduleManager* CEditorImpl::GetBackgroundScheduleManager()
|
||||
{
|
||||
return m_pBackgroundScheduleManager.get();
|
||||
}
|
||||
|
||||
IEditorFileMonitor* CEditorImpl::GetFileMonitor()
|
||||
{
|
||||
return m_pEditorFileMonitor.get();
|
||||
@@ -1624,8 +1609,6 @@ ESystemConfigPlatform CEditorImpl::GetEditorConfigPlatform() const
|
||||
|
||||
void CEditorImpl::InitFinished()
|
||||
{
|
||||
SProjectSettingsBlock::Load();
|
||||
|
||||
if (!m_bInitialized)
|
||||
{
|
||||
m_bInitialized = true;
|
||||
|
||||
@@ -43,15 +43,12 @@ class CGameEngine;
|
||||
class CExportManager;
|
||||
class CErrorsDlg;
|
||||
class CIconManager;
|
||||
class CBackgroundTaskManager;
|
||||
class CTrackViewSequenceManager;
|
||||
class CEditorFileMonitor;
|
||||
class AzAssetWindow;
|
||||
class AzAssetBrowserRequestHandler;
|
||||
class AssetEditorRequestsHandler;
|
||||
class CAlembicCompiler;
|
||||
struct IBackgroundTaskManager;
|
||||
struct IBackgroundScheduleManager;
|
||||
struct IEditorFileMonitor;
|
||||
class CVegetationMap;
|
||||
|
||||
@@ -61,16 +58,6 @@ namespace Editor
|
||||
class EditorQtApplication;
|
||||
}
|
||||
|
||||
namespace BackgroundScheduleManager
|
||||
{
|
||||
class CScheduleManager;
|
||||
}
|
||||
|
||||
namespace BackgroundTaskManager
|
||||
{
|
||||
class CTaskManager;
|
||||
}
|
||||
|
||||
namespace WinWidget
|
||||
{
|
||||
class WinWidgetManager;
|
||||
@@ -179,8 +166,6 @@ public:
|
||||
IDataBaseManager* GetDBItemManager(EDataBaseItemType itemType);
|
||||
CMusicManager* GetMusicManager() { return m_pMusicManager; };
|
||||
|
||||
IBackgroundTaskManager* GetBackgroundTaskManager() override;
|
||||
IBackgroundScheduleManager* GetBackgroundScheduleManager() override;
|
||||
IEditorFileMonitor* GetFileMonitor() override;
|
||||
void RegisterEventLoopHook(IEventLoopHook* pHook) override;
|
||||
void UnregisterEventLoopHook(IEventLoopHook* pHook) override;
|
||||
@@ -394,8 +379,6 @@ protected:
|
||||
|
||||
//! Export manager for exporting objects and a terrain from the game to DCC tools
|
||||
CExportManager* m_pExportManager;
|
||||
std::unique_ptr<BackgroundTaskManager::CTaskManager> m_pBackgroundTaskManager;
|
||||
std::unique_ptr<BackgroundScheduleManager::CScheduleManager> m_pBackgroundScheduleManager;
|
||||
std::unique_ptr<CEditorFileMonitor> m_pEditorFileMonitor;
|
||||
std::unique_ptr<IResourceSelectorHost> m_pResourceSelectorHost;
|
||||
QString m_selectFileBuffer;
|
||||
|
||||
@@ -1,207 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
//
|
||||
// IBackgroundScheduleManager manages schedule of group of larger operations that should be run in sequence
|
||||
//
|
||||
// Schedules are derived from IBackgroundSchedule and consist of a list of IBackgroundScheduleItems.
|
||||
// Each schedule item is executed IN ORDER for the previous item to complete first.
|
||||
// Each IBackgroundScheduleItems consists of list of user defined work via IBackgroundScheduleItemsWork classes.
|
||||
// Each schedule item work is executed IN PARALEL (they are all started when the item starts).
|
||||
//
|
||||
// Whenever a work item fails to complete the other work items are stopped, the schedule item is marked as "failed"
|
||||
// and so is the whole schedule.
|
||||
//
|
||||
// All logic is performed on the main thread although schedule items are free to use threads.
|
||||
// It is recommended to use IBackgroundTaskManager for dispatching a task list for every schedule work item.
|
||||
//
|
||||
// All objects in the schedule system are reference counted.
|
||||
//
|
||||
|
||||
// State of the whole schedule
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_INCLUDE_IBACKGROUNDSCHEDULEMANAGER_H
|
||||
#define CRYINCLUDE_EDITOR_INCLUDE_IBACKGROUNDSCHEDULEMANAGER_H
|
||||
#pragma once
|
||||
enum EScheduleState
|
||||
{
|
||||
// Item has not started yet but is on the list
|
||||
eScheduleState_Pending,
|
||||
|
||||
// We are processing this item
|
||||
eScheduleState_Processing,
|
||||
|
||||
// We are stopping the schedule
|
||||
eSccheduleState_Stopping,
|
||||
|
||||
// Schedule item has failed
|
||||
eScheduleState_Failed,
|
||||
|
||||
// Schedule item was canceled
|
||||
eScheduleState_Canceled,
|
||||
|
||||
// Schedule item has completed it's work
|
||||
eScheduleState_Completed,
|
||||
};
|
||||
|
||||
// State of the single schedule item
|
||||
enum EScheduleItemState
|
||||
{
|
||||
// Item has not started yet but is on the list
|
||||
eScheduleItemState_Pending,
|
||||
|
||||
// We are processing this item
|
||||
eScheduleItemState_Processing,
|
||||
|
||||
// We are stopping this item
|
||||
eScheduleItemState_Stopping,
|
||||
|
||||
// Schedule item has failed
|
||||
eScheduleItemState_Failed,
|
||||
|
||||
// Schedule item has completed it's work
|
||||
eScheduleItemState_Completed,
|
||||
};
|
||||
|
||||
// Work item status
|
||||
enum EScheduleWorkItemStatus
|
||||
{
|
||||
// Work is still not finished
|
||||
eScheduleWorkItemStatus_NotFinished,
|
||||
|
||||
// Work has failed
|
||||
eScheduleWorkItemStatus_Failed,
|
||||
|
||||
// Work has finished
|
||||
eScheduleWorkItemStatus_Finished,
|
||||
};
|
||||
|
||||
struct IBackgroundScheduleItemWork
|
||||
{
|
||||
// Get human readable description
|
||||
virtual const char* GetDescription() const = 0;
|
||||
|
||||
// Get work item progress
|
||||
virtual float GetProgress() const = 0;
|
||||
|
||||
// Called when the schedule item containing this work piece has started
|
||||
// If the work cannot be started for any reason return false.
|
||||
virtual bool OnStart() = 0;
|
||||
|
||||
// Called when the schedule item containing this work piece has been canceled or failed externally
|
||||
// Not called when schedule item completed without errors.
|
||||
// If the work cannot be stopped this frame return false.
|
||||
virtual bool OnStop() = 0;
|
||||
|
||||
// Called every frame to advance and check the work state
|
||||
// Should return one of the EBackgroundScheduleWorkItemStatus value
|
||||
virtual EScheduleWorkItemStatus OnUpdate() = 0;
|
||||
|
||||
// Reference counting
|
||||
virtual void AddRef() = 0;
|
||||
virtual void Release() = 0;
|
||||
|
||||
protected:
|
||||
virtual ~IBackgroundScheduleItemWork() {};
|
||||
};
|
||||
|
||||
struct IBackgroundScheduleItem
|
||||
{
|
||||
// Get name of the schedule (debug & display)
|
||||
virtual const char* GetDescription() const = 0;
|
||||
|
||||
// Get interal state
|
||||
virtual EScheduleItemState GetState() const = 0;
|
||||
|
||||
// Get overall progress of this schedule item
|
||||
virtual const float GetProgress() const = 0;
|
||||
|
||||
// Get number of work items in this schedule item
|
||||
virtual const uint32 GetNumWorkItems() const = 0;
|
||||
|
||||
// Get n-th work item from the schedule item
|
||||
virtual IBackgroundScheduleItemWork* GetWorkItem(const uint32 index) const = 0;
|
||||
|
||||
// Add work item to the schedule item
|
||||
virtual void AddWorkItem(IBackgroundScheduleItemWork* pWork) = 0;
|
||||
|
||||
// Reference counting
|
||||
virtual void AddRef() = 0;
|
||||
virtual void Release() = 0;
|
||||
|
||||
protected:
|
||||
virtual ~IBackgroundScheduleItem() {};
|
||||
};
|
||||
|
||||
struct IBackgroundSchedule
|
||||
{
|
||||
// Get name of the schedule (debug & display)
|
||||
virtual const char* GetDescription() const = 0;
|
||||
|
||||
// Get overall progress of the whole schedule
|
||||
virtual float GetProgress() const = 0;
|
||||
|
||||
// Get item being currently processed
|
||||
virtual IBackgroundScheduleItem* GetProcessedItem() const = 0;
|
||||
|
||||
// Get number of items in the schedule
|
||||
virtual const uint32 GetNumItems() const = 0;
|
||||
|
||||
// Get single schedule item
|
||||
virtual IBackgroundScheduleItem* GetItem(const uint32 index) const = 0;
|
||||
|
||||
// Get schedule item
|
||||
virtual EScheduleState GetState() const = 0;
|
||||
|
||||
// Cancel the whole schedule
|
||||
virtual void Cancel() = 0;
|
||||
|
||||
// Is the schedule canceled ?
|
||||
virtual bool IsCanceled() const = 0;
|
||||
|
||||
// Add schedule item at the end of the list
|
||||
virtual void AddItem(IBackgroundScheduleItem* pItem) = 0;
|
||||
|
||||
// Reference counting
|
||||
virtual void AddRef() = 0;
|
||||
virtual void Release() = 0;
|
||||
|
||||
protected:
|
||||
virtual ~IBackgroundSchedule() {};
|
||||
};
|
||||
|
||||
struct IBackgroundScheduleManager
|
||||
{
|
||||
virtual ~IBackgroundScheduleManager() {};
|
||||
|
||||
// Create empty schedule
|
||||
virtual IBackgroundSchedule* CreateSchedule(const char* szName) = 0;
|
||||
|
||||
// Create empty schedule item
|
||||
virtual IBackgroundScheduleItem* CreateScheduleItem(const char* szName) = 0;
|
||||
|
||||
// Issue a schedule to the list (will start processing it)
|
||||
virtual void SubmitSchedule(IBackgroundSchedule* pSchedule) = 0;
|
||||
|
||||
// Get number of schedules on the list
|
||||
virtual const uint32 GetNumSchedules() const = 0;
|
||||
|
||||
// Get n-th schedule
|
||||
virtual IBackgroundSchedule* GetSchedule(const uint32 index) const = 0;
|
||||
|
||||
// Advance work on the schedules
|
||||
virtual void Update() = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_INCLUDE_IBACKGROUNDSCHEDULEMANAGER_H
|
||||
@@ -1,230 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
//
|
||||
// IBackgroundTaskManager runs background tasks in worker thread.
|
||||
//
|
||||
// Tasks are derived from IBackgroundTask. Each task is split in two parts for:
|
||||
// Work - done in background thread.
|
||||
// Finalize - called afterward in main thread to apply results.
|
||||
//
|
||||
// Task objects are reference counted. Task manager will hold its own reference to the task object
|
||||
// for as long as the task is pending or being executed. If you want to keep the task object around
|
||||
// in your code you will have to call AddRef() and Release() on the task object by yourself so there
|
||||
// will be an extra reference to the task object held by your code.
|
||||
//
|
||||
// Work returns the state of the task. Task can be resumed, then the Work
|
||||
// method will be called again. Other tasks can work between calls to Work.
|
||||
// It is possible to Cancel task. Work method is not invoked any more for
|
||||
// Canceled tasks.
|
||||
//
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_INCLUDE_IBACKGROUNDTASKMANAGER_H
|
||||
#define CRYINCLUDE_EDITOR_INCLUDE_IBACKGROUNDTASKMANAGER_H
|
||||
#pragma once
|
||||
|
||||
enum ETaskPriority
|
||||
{
|
||||
eTaskPriority_FileUpdateFinal,
|
||||
eTaskPriority_BackgroundScan,
|
||||
eTaskPriority_FileUpdate,
|
||||
eTaskPriority_RealtimePreview
|
||||
};
|
||||
|
||||
// Result code returned by task Work() function
|
||||
enum ETaskResult
|
||||
{
|
||||
// Task has not yet completed, add it back to the task queue with the same parameters (priority and thread mask)
|
||||
eTaskResult_Resume,
|
||||
|
||||
// Task has completed without errors (it's assumed that the result the task was supposed to achieve was achieved)
|
||||
eTaskResult_Completed,
|
||||
|
||||
// Task was canceled
|
||||
eTaskResult_Canceled,
|
||||
|
||||
// Task has failed to complete it's work
|
||||
eTaskResult_Failed,
|
||||
};
|
||||
|
||||
// Internal task tracking state
|
||||
enum ETaskState
|
||||
{
|
||||
// Task was just created.
|
||||
eTaskState_Created,
|
||||
|
||||
// Task was scheduled to be executed in the future.
|
||||
eTaskState_Scheduled,
|
||||
|
||||
// Task was added to the task queue and is waiting for it's time to be executed.
|
||||
eTaskState_Pending,
|
||||
|
||||
// Task is being processed right now.
|
||||
eTaskState_Working,
|
||||
|
||||
// Task was canceled before it has finished (indication that TaskManager has seen the Cancel() call).
|
||||
eTaskState_Canceled,
|
||||
|
||||
// Task Work() function was called but it ended with an error code.
|
||||
eTaskState_Failed,
|
||||
|
||||
// Task has completed it's Work() function without errors.
|
||||
eTaskState_Completed,
|
||||
};
|
||||
|
||||
// Thread mask controls which on which threads given task can be executed.
|
||||
enum ETaskThreadMask
|
||||
{
|
||||
// Task can run only on the IO thread (default)
|
||||
// There is only one IO thread so all task with this flag are run in a sequence.
|
||||
eTaskThreadMask_IO,
|
||||
|
||||
// Task can run on any thread (concurrent tasks allowed)
|
||||
// There can be many threads with this mask so there's no limit on the concurrent task count.
|
||||
eTaskThreadMask_Any,
|
||||
|
||||
eTaskThreadMask_COUNT,
|
||||
};
|
||||
|
||||
struct IBackgroundTask
|
||||
{
|
||||
public:
|
||||
IBackgroundTask()
|
||||
: m_bCanceled(false)
|
||||
, m_state(eTaskState_Created)
|
||||
, m_progress(-1.0f)
|
||||
, m_refCount(0)
|
||||
, m_bFailReported(false)
|
||||
{}
|
||||
|
||||
void Cancel()
|
||||
{
|
||||
m_bCanceled = true;
|
||||
}
|
||||
|
||||
bool IsCanceled() const
|
||||
{
|
||||
return m_bCanceled;
|
||||
}
|
||||
|
||||
bool HasFinished() const
|
||||
{
|
||||
return (m_state == eTaskState_Canceled) ||
|
||||
(m_state == eTaskState_Completed) ||
|
||||
(m_state == eTaskState_Failed);
|
||||
}
|
||||
|
||||
bool HasFinishedWithoutError() const
|
||||
{
|
||||
return (m_state == eTaskState_Completed);
|
||||
}
|
||||
|
||||
ETaskState GetState() const
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
void SetState(ETaskState state)
|
||||
{
|
||||
m_state = state;
|
||||
}
|
||||
|
||||
float GetProgress() const
|
||||
{
|
||||
return m_progress;
|
||||
}
|
||||
|
||||
int AddRef()
|
||||
{
|
||||
return CryInterlockedIncrement(&m_refCount);
|
||||
}
|
||||
|
||||
int Release()
|
||||
{
|
||||
const int nCount = CryInterlockedDecrement(&m_refCount);
|
||||
assert(nCount >= 0);
|
||||
if (nCount == 0)
|
||||
{
|
||||
Delete();
|
||||
}
|
||||
else if (nCount < 0)
|
||||
{
|
||||
assert(0);
|
||||
CryFatalError("Deleting Reference Counted Object Twice");
|
||||
}
|
||||
return nCount;
|
||||
}
|
||||
|
||||
bool FailReported() const{ return m_bFailReported; }
|
||||
|
||||
// Get the user readable description (name) of this task, used for logging
|
||||
virtual const char* Description() const { return ""; }
|
||||
|
||||
// Get the user readable error message (in case when the task fails), used for logging the errors
|
||||
virtual const char* ErrorMessage() const { return ""; }
|
||||
|
||||
// Called from main thread after task is completed just before the task gets destroyed
|
||||
virtual void Finalize() {}
|
||||
|
||||
// Since there's a possibility that task object were created using different allocator
|
||||
// we need a way to delete the task object once we are done with it
|
||||
virtual void Delete() = 0;
|
||||
|
||||
// Invoked from worker thread, actual work is done here
|
||||
virtual ETaskResult Work() = 0;
|
||||
|
||||
protected:
|
||||
void SetProgress(float progress) { m_progress = progress; }
|
||||
void SetFailReported() { m_bFailReported = true; }
|
||||
|
||||
// destructor is hidden to indicate that we should use Release() method
|
||||
virtual ~IBackgroundTask() {}
|
||||
|
||||
private:
|
||||
volatile int m_refCount;
|
||||
ETaskState m_state;
|
||||
float m_progress;
|
||||
bool m_bCanceled;
|
||||
bool m_bFailReported;
|
||||
};
|
||||
|
||||
struct IBackgroundTaskManagerListener
|
||||
{
|
||||
virtual ~IBackgroundTaskManagerListener() {}
|
||||
|
||||
virtual void OnBackgroundTaskAdded(const char* description) = 0;
|
||||
virtual void OnBackgroundTaskCompleted(ETaskResult taskResult, const char* description) = 0;
|
||||
};
|
||||
|
||||
struct IBackgroundTaskManager
|
||||
{
|
||||
enum
|
||||
{
|
||||
BACKGROUND_TASK_ID_INVALID = 0
|
||||
};
|
||||
|
||||
virtual ~IBackgroundTaskManager() {}
|
||||
|
||||
// Add task to the queue with given priority and thread mask
|
||||
virtual void AddTask(IBackgroundTask* pTask, ETaskPriority priority, ETaskThreadMask threadMask) = 0;
|
||||
|
||||
// Schedule task to be executed in the future
|
||||
virtual void ScheduleTask(IBackgroundTask* pTask, ETaskPriority priority, int delayMilliseconds, ETaskThreadMask threadMask) = 0;
|
||||
|
||||
virtual void AddListener(IBackgroundTaskManagerListener* pListener, const char* name) = 0;
|
||||
|
||||
virtual void RemoveListener(IBackgroundTaskManagerListener* pListener) = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_INCLUDE_IBACKGROUNDTASKMANAGER_H
|
||||
@@ -28,16 +28,6 @@
|
||||
// }
|
||||
// REGISTER_RESOURCE_SELECTOR("Sound", SoundFileSelector, "Icons/sound_16x16.png")
|
||||
//
|
||||
// To expose it to serialization:
|
||||
//
|
||||
// #include "Serialization/Decorators/Resources.h"
|
||||
// template<class TString>
|
||||
// ResourceSelector<TString> SoundName(TString& s) { return ResourceSelector<TString>(s, "Sound"); }
|
||||
//
|
||||
// To use in serialization:
|
||||
//
|
||||
// ar(Serialization::SoundName(soundString), "soundString", "Sound String");
|
||||
//
|
||||
// Here is how it can be invoked directly:
|
||||
//
|
||||
// SResourceSelectorContext x;
|
||||
@@ -56,19 +46,7 @@
|
||||
//
|
||||
// QString SoundFileSelector(const SResourceSelectorContext& x, const QString& previousValue,
|
||||
// SoundFileList* list) // your context argument
|
||||
//
|
||||
// And provide this value through serialization context:
|
||||
//
|
||||
// struct SourceFileList
|
||||
// {
|
||||
// void Serialize(IArchive& ar)
|
||||
// {
|
||||
// Serialization::SContext<SourceFileList> context(ar, this);
|
||||
// ...
|
||||
// }
|
||||
// }
|
||||
|
||||
#include <Serialization/TypeID.h>
|
||||
#include <QString>
|
||||
|
||||
class QWidget;
|
||||
@@ -82,7 +60,6 @@ struct SResourceSelectorContext
|
||||
|
||||
unsigned int entityId;
|
||||
void* contextObject;
|
||||
Serialization::TypeID contextObjectType;
|
||||
|
||||
SResourceSelectorContext()
|
||||
: parentWidget(0)
|
||||
@@ -107,7 +84,6 @@ struct IResourceSelectorHost
|
||||
virtual ~IResourceSelectorHost() = default;
|
||||
virtual QString SelectResource(const SResourceSelectorContext& context, const QString& previousValue) = 0;
|
||||
virtual const char* ResourceIconPath(const char* typeName) const = 0;
|
||||
virtual Serialization::TypeID ResourceContextType(const char* typeName) const = 0;
|
||||
|
||||
virtual void RegisterResourceSelector(const SStaticResourceSelectorEntry* entry) = 0;
|
||||
|
||||
@@ -128,7 +104,6 @@ struct SStaticResourceSelectorEntry
|
||||
TResourceSelectionFunction function;
|
||||
TResourceSelectionFunctionWithContext functionWithContext;
|
||||
const char* iconPath;
|
||||
Serialization::TypeID contextType;
|
||||
|
||||
static SStaticResourceSelectorEntry*& GetFirst() { static SStaticResourceSelectorEntry* first; return first; }
|
||||
SStaticResourceSelectorEntry* next;
|
||||
@@ -150,7 +125,6 @@ struct SStaticResourceSelectorEntry
|
||||
, functionWithContext(TResourceSelectionFunctionWithContext(function))
|
||||
, iconPath(icon)
|
||||
{
|
||||
contextType = Serialization::TypeID::get<T>();
|
||||
next = GetFirst();
|
||||
GetFirst() = this;
|
||||
}
|
||||
|
||||
@@ -97,10 +97,6 @@ void CLevelInfo::ValidateObjects()
|
||||
|
||||
pObject->Validate(m_pReport);
|
||||
|
||||
CUsedResources rs;
|
||||
pObject->GatherUsedResources(rs);
|
||||
rs.Validate(m_pReport);
|
||||
|
||||
m_pReport->SetCurrentValidatorObject(NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +102,6 @@ public:
|
||||
MOCK_METHOD0(GetViewManager, class CViewManager* ());
|
||||
MOCK_METHOD0(GetActiveView, class CViewport* ());
|
||||
MOCK_METHOD1(SetActiveView, void(CViewport*));
|
||||
MOCK_METHOD0(GetBackgroundTaskManager, struct IBackgroundTaskManager* ());
|
||||
MOCK_METHOD0(GetFileMonitor, struct IEditorFileMonitor* ());
|
||||
MOCK_METHOD1(RegisterEventLoopHook, void(IEventLoopHook* ));
|
||||
MOCK_METHOD1(UnregisterEventLoopHook, void(IEventLoopHook* ));
|
||||
@@ -184,7 +183,6 @@ public:
|
||||
MOCK_CONST_METHOD0(GetEditorConfigPlatform, ESystemConfigPlatform());
|
||||
MOCK_METHOD0(ReloadTemplates, void());
|
||||
MOCK_METHOD0(GetResourceSelectorHost, IResourceSelectorHost* ());
|
||||
MOCK_METHOD0(GetBackgroundScheduleManager, struct IBackgroundScheduleManager* ());
|
||||
MOCK_METHOD1(ShowStatusText, void(bool ));
|
||||
MOCK_METHOD1(RegisterObjectContextMenuExtension, void(TContextMenuExtensionFunc ));
|
||||
MOCK_METHOD0(GetEnv, SSystemGlobalEnvironment* ());
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <MainStatusBar.h>
|
||||
#include <IBackgroundTaskManager.h>
|
||||
#include <IRenderer.h>
|
||||
#include <QMutex>
|
||||
#include <QString>
|
||||
|
||||
@@ -92,7 +92,6 @@ AZ_POP_DISABLE_WARNING
|
||||
#include "ErrorReportDialog.h"
|
||||
|
||||
#include "Dialogs/PythonScriptsDialog.h"
|
||||
#include "EngineSettingsManager.h"
|
||||
|
||||
#include "AzAssetBrowser/AzAssetBrowserWindow.h"
|
||||
#include "AssetEditor/AssetEditorWindow.h"
|
||||
@@ -695,8 +694,6 @@ void MainWindow::InitActions()
|
||||
am->AddAction(ID_TOOLBAR_WIDGET_REDO, QString());
|
||||
am->AddAction(ID_TOOLBAR_WIDGET_SNAP_ANGLE, QString());
|
||||
am->AddAction(ID_TOOLBAR_WIDGET_SNAP_GRID, QString());
|
||||
am->AddAction(ID_TOOLBAR_WIDGET_ENVIRONMENT_MODE, QString());
|
||||
am->AddAction(ID_TOOLBAR_WIDGET_DEBUG_MODE, QString());
|
||||
am->AddAction(ID_TOOLBAR_WIDGET_SPACER_RIGHT, QString());
|
||||
|
||||
// File actions
|
||||
@@ -1253,44 +1250,6 @@ QToolButton* MainWindow::CreateUndoRedoButton(int command)
|
||||
return button;
|
||||
}
|
||||
|
||||
QToolButton* MainWindow::CreateEnvironmentModeButton()
|
||||
{
|
||||
QToolButton* environmentModeButton = new QToolButton(this);
|
||||
environmentModeButton->setAutoRaise(true);
|
||||
environmentModeButton->setPopupMode(QToolButton::InstantPopup);
|
||||
environmentModeButton->setIcon(Style::icon("Environment"));
|
||||
environmentModeButton->setStatusTip(tr("Select from a variety of environment mode options"));
|
||||
environmentModeButton->setToolTip(tr("Environment modes"));
|
||||
|
||||
CVarMenu* environmentModeMenu = new CVarMenu(this);
|
||||
connect(environmentModeMenu, &QMenu::aboutToShow, [this, environmentModeMenu]()
|
||||
{
|
||||
InitEnvironmentModeMenu(environmentModeMenu);
|
||||
});
|
||||
environmentModeButton->setMenu(environmentModeMenu);
|
||||
|
||||
return environmentModeButton;
|
||||
}
|
||||
|
||||
QToolButton* MainWindow::CreateDebugModeButton()
|
||||
{
|
||||
QToolButton* debugModeButton = new QToolButton(this);
|
||||
debugModeButton->setAutoRaise(true);
|
||||
debugModeButton->setPopupMode(QToolButton::InstantPopup);
|
||||
debugModeButton->setIcon(Style::icon("Debugging"));
|
||||
debugModeButton->setStatusTip(tr("Select from a variety of debug/view mode options"));
|
||||
debugModeButton->setToolTip(tr("Debug modes"));
|
||||
|
||||
CVarMenu* debugModeMenu = new CVarMenu(this);
|
||||
connect(debugModeMenu, &QMenu::aboutToShow, [this, debugModeMenu]()
|
||||
{
|
||||
InitDebugModeMenu(debugModeMenu);
|
||||
});
|
||||
debugModeButton->setMenu(debugModeMenu);
|
||||
|
||||
return debugModeButton;
|
||||
}
|
||||
|
||||
QWidget* MainWindow::CreateSpacerRightWidget()
|
||||
{
|
||||
QWidget* spacer = new QWidget(this);
|
||||
@@ -1299,93 +1258,6 @@ QWidget* MainWindow::CreateSpacerRightWidget()
|
||||
return spacer;
|
||||
}
|
||||
|
||||
void MainWindow::InitEnvironmentModeMenu(CVarMenu* environmentModeMenu)
|
||||
{
|
||||
environmentModeMenu->clear();
|
||||
environmentModeMenu->AddCVarToggleItem({ "e_Fog", tr("Hide Global Fog"), 0, 1 });
|
||||
environmentModeMenu->AddCVarToggleItem({ "r_FogVolumes", tr("Hide Fog Volumes"), 0, 1 });
|
||||
environmentModeMenu->AddCVarToggleItem({ "e_Clouds", tr("Hide Clouds"), 0, 1 });
|
||||
environmentModeMenu->AddCVarToggleItem({ "e_Wind", tr("Hide Wind"), 0, 1 });
|
||||
environmentModeMenu->AddSeparator();
|
||||
environmentModeMenu->AddCVarToggleItem({ "e_Sun", tr("Hide Sun"), 0, 1 });
|
||||
environmentModeMenu->AddCVarToggleItem({ "e_Skybox", tr("Hide Skybox"), 0, 1 });
|
||||
environmentModeMenu->AddCVarToggleItem({ "r_SSReflections", tr("Hide Screen Space Reflection"), 0, 1 });
|
||||
environmentModeMenu->AddCVarToggleItem({ "e_Shadows", tr("Hide Shadows"), 0, 1 });
|
||||
environmentModeMenu->AddCVarToggleItem({ "r_TransparentPasses", tr("Hide Transparent Objects"), 0, 1 });
|
||||
environmentModeMenu->AddCVarToggleItem({ "r_ssdo", tr("Hide Screen Space Directional Occlusion"), 0, 1 });
|
||||
environmentModeMenu->AddCVarToggleItem({ "e_DynamicLights", tr("Hide All Dynamic Lights"), 0, 1 });
|
||||
environmentModeMenu->AddSeparator();
|
||||
environmentModeMenu->AddCVarToggleItem({ "e_Entities", tr("Hide Entities"), 0, 1 });
|
||||
environmentModeMenu->AddSeparator();
|
||||
environmentModeMenu->AddCVarToggleItem({ "e_Vegetation", tr("Hide Vegetation"), 0, 1 });
|
||||
environmentModeMenu->AddCVarToggleItem({ "e_Terrain", tr("Hide Terrain"), 0, 1 });
|
||||
environmentModeMenu->AddSeparator();
|
||||
environmentModeMenu->AddCVarToggleItem({ "e_Particles", tr("Hide Particles"), 0, 1 });
|
||||
environmentModeMenu->AddCVarToggleItem({ "e_Flares", tr("Hide Flares"), 0, 1 });
|
||||
environmentModeMenu->AddCVarToggleItem({ "e_Decals", tr("Hide Decals"), 0, 1 });
|
||||
environmentModeMenu->AddSeparator();
|
||||
environmentModeMenu->AddCVarToggleItem({ "e_WaterOcean", tr("Hide Ocean Water (for legacy)"), 0, 1 });
|
||||
environmentModeMenu->AddCVarToggleItem({ "e_WaterVolumes", tr("Hide Water Volumes"), 0, 1 });
|
||||
environmentModeMenu->AddSeparator();
|
||||
environmentModeMenu->AddCVarToggleItem({ "e_BBoxes", tr("Hide BBoxes"), 0, 1 });
|
||||
environmentModeMenu->AddSeparator();
|
||||
environmentModeMenu->AddResetCVarsItem();
|
||||
}
|
||||
|
||||
void MainWindow::InitDebugModeMenu(CVarMenu* debugModeMenu)
|
||||
{
|
||||
debugModeMenu->clear();
|
||||
debugModeMenu->AddCVarValuesItem("r_DebugGBuffer", tr("GBuffers"),
|
||||
{
|
||||
{tr("Full Shading Mode (Default)"), 0},
|
||||
{tr("Normal Visualization"), 1},
|
||||
{tr("Smoothness"), 2},
|
||||
{tr("Reflectance"), 3},
|
||||
{tr("Albedo"), 4},
|
||||
{tr("Lighting Model"), 5},
|
||||
{tr("Translucency"), 6},
|
||||
{tr("Sun Self Shadowing"), 7},
|
||||
{tr("Subsurface Scattering"), 8},
|
||||
{tr("Specular Validation Overlay"), 9}
|
||||
}, 0);
|
||||
debugModeMenu->AddSeparator();
|
||||
debugModeMenu->AddCVarValuesItem("r_Stats", tr("Profiling"),
|
||||
{
|
||||
{tr("Frame Timing"), 1},
|
||||
{tr("Object Timing"), 3},
|
||||
{tr("Instance Draw Calls"), 6},
|
||||
}, 0);
|
||||
debugModeMenu->AddSeparator();
|
||||
debugModeMenu->AddUniqueCVarsItem(tr("Wireframe"),
|
||||
{
|
||||
{"r_wireframe", tr("Wireframe Rendering Mode"), 1, 0},
|
||||
{"r_showlines", tr("Wireframe Overlay"), 1, 0}
|
||||
}),
|
||||
debugModeMenu->AddCVarValuesItem("e_debugdraw", tr("Art Info"),
|
||||
{
|
||||
{tr("Texture Memory Usage"), 4},
|
||||
{tr("Renderable Material Count"), 5},
|
||||
{tr("LOD Vertex Count"), 22}
|
||||
}, 0);
|
||||
|
||||
debugModeMenu->AddSeparator();
|
||||
debugModeMenu->AddCVarValuesItem("e_defaultmaterial", tr("Default Material on all Objects"),
|
||||
{
|
||||
{tr("Gray Material with Normal Maps"), 1},
|
||||
}, 0);
|
||||
|
||||
debugModeMenu->AddCVarValuesItem("r_DeferredShadingTiledDebugAlbedo", tr("Debug Visualization of Deferred Lighting"),
|
||||
{
|
||||
{tr("White Albedo"), 1},
|
||||
}, 0);
|
||||
|
||||
debugModeMenu->AddCVarToggleItem({ "r_ShowTangents", tr("Show Tangents"), 1, 0 });
|
||||
debugModeMenu->AddCVarToggleItem({ "p_draw_helpers", tr("Show Collision Shapes (Proxy)"), 1, 0 });
|
||||
|
||||
debugModeMenu->AddSeparator();
|
||||
debugModeMenu->AddResetCVarsItem();
|
||||
}
|
||||
|
||||
UndoRedoToolButton::UndoRedoToolButton(QWidget* parent)
|
||||
: QToolButton(parent)
|
||||
{
|
||||
@@ -2068,12 +1940,6 @@ void MainWindow::ConnectivityStateChanged(const AzToolsFramework::SourceControlS
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CRY_ENABLE_RC_HELPER)
|
||||
CEngineSettingsManager settingsManager;
|
||||
settingsManager.SetModuleSpecificBoolEntry("RC_EnableSourceControl", connected);
|
||||
settingsManager.StoreData();
|
||||
#endif
|
||||
|
||||
gSettings.enableSourceControl = connected;
|
||||
gSettings.SaveEnableSourceControlFlag(false);
|
||||
}
|
||||
@@ -2150,12 +2016,6 @@ QWidget* MainWindow::CreateToolbarWidget(int actionId)
|
||||
case ID_TOOLBAR_WIDGET_SNAP_ANGLE:
|
||||
w = CreateSnapToAngleWidget();
|
||||
break;
|
||||
case ID_TOOLBAR_WIDGET_ENVIRONMENT_MODE:
|
||||
w = CreateEnvironmentModeButton();
|
||||
break;
|
||||
case ID_TOOLBAR_WIDGET_DEBUG_MODE:
|
||||
w = CreateDebugModeButton();
|
||||
break;
|
||||
case ID_TOOLBAR_WIDGET_SPACER_RIGHT:
|
||||
w = CreateSpacerRightWidget();
|
||||
break;
|
||||
|
||||
@@ -208,11 +208,6 @@ private:
|
||||
|
||||
QToolButton* CreateUndoRedoButton(int command);
|
||||
|
||||
QToolButton* CreateEnvironmentModeButton();
|
||||
QToolButton* CreateDebugModeButton();
|
||||
void InitEnvironmentModeMenu(CVarMenu* environmentModeMenu);
|
||||
void InitDebugModeMenu(CVarMenu* debugModeMenu);
|
||||
|
||||
private Q_SLOTS:
|
||||
void ShowKeyboardCustomization();
|
||||
void ExportKeyboardShortcuts();
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
|
||||
class CEntityObject;
|
||||
class QMenu;
|
||||
class IOpticsElementBase;
|
||||
|
||||
/*!
|
||||
* CEntityEventTarget is an Entity event target and type.
|
||||
|
||||
@@ -72,16 +72,6 @@ public:
|
||||
return "";
|
||||
}
|
||||
|
||||
Serialization::TypeID ResourceContextType(const char* typeName) const override
|
||||
{
|
||||
TTypeMap::const_iterator it = m_typeMap.find(typeName);
|
||||
if (it != m_typeMap.end())
|
||||
{
|
||||
return it->second->contextType;
|
||||
}
|
||||
return Serialization::TypeID();
|
||||
}
|
||||
|
||||
void RegisterResourceSelector(const SStaticResourceSelectorEntry* entry) override
|
||||
{
|
||||
m_typeMap[entry->typeName] = entry;
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#pragma once
|
||||
#ifndef CRYINCLUDE_EDITOR_SERIALIZATION_H
|
||||
#define CRYINCLUDE_EDITOR_SERIALIZATION_H
|
||||
|
||||
#include <Serialization/STL.h>
|
||||
#include <Serialization/SmartPtr.h>
|
||||
#include <Serialization/ClassFactory.h>
|
||||
#include <Serialization/IArchive.h>
|
||||
#include <Serialization/Enum.h>
|
||||
|
||||
using Serialization::IArchive;
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_SERIALIZATION_H
|
||||
@@ -1,283 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "VariableIArchive.h"
|
||||
|
||||
// Editor
|
||||
#include "Serialization/Decorators/Resources.h"
|
||||
#include "Serialization/Decorators/Range.h"
|
||||
|
||||
|
||||
using Serialization::CVariableIArchive;
|
||||
|
||||
namespace VarUtil
|
||||
{
|
||||
_smart_ptr< IVariable > FindChildVariable(const _smart_ptr< IVariable >& pParent, const int childIndexOverride, const char* const name)
|
||||
{
|
||||
if (0 <= childIndexOverride)
|
||||
{
|
||||
return pParent->GetVariable(childIndexOverride);
|
||||
}
|
||||
else
|
||||
{
|
||||
const bool shouldSearchRecursively = false;
|
||||
return pParent->FindVariable(name, shouldSearchRecursively);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template< typename T, typename TOut >
|
||||
bool ReadChildVariableAs(const _smart_ptr< IVariable >& pParent, const int childIndexOverride, const char* const name, TOut& valueOut)
|
||||
{
|
||||
_smart_ptr< IVariable > pVariable = FindChildVariable(pParent, childIndexOverride, name);
|
||||
if (pVariable)
|
||||
{
|
||||
T tmp;
|
||||
pVariable->Get(tmp);
|
||||
valueOut = static_cast< TOut >(tmp);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
template< typename T >
|
||||
bool ReadChildVariable(const _smart_ptr< IVariable >& pParent, const int childIndexOverride, const char* const name, T& valueOut)
|
||||
{
|
||||
return ReadChildVariableAs< T >(pParent, childIndexOverride, name, valueOut);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
CVariableIArchive::CVariableIArchive(const _smart_ptr< IVariable >& pVariable)
|
||||
: IArchive(IArchive::INPUT | IArchive::EDIT | IArchive::NO_EMPTY_NAMES)
|
||||
, m_pVariable(pVariable)
|
||||
, m_childIndexOverride(-1)
|
||||
{
|
||||
CRY_ASSERT(m_pVariable);
|
||||
|
||||
m_structHandlers[ TypeID::get < Serialization::IResourceSelector > ().name() ] = &CVariableIArchive::SerializeResourceSelector;
|
||||
m_structHandlers[ TypeID::get < Serialization::RangeDecorator < float >> ().name() ] = &CVariableIArchive::SerializeRangeFloat;
|
||||
m_structHandlers[ TypeID::get < Serialization::RangeDecorator < int >> ().name() ] = &CVariableIArchive::SerializeRangeInt;
|
||||
m_structHandlers[ TypeID::get < Serialization::RangeDecorator < unsigned int >> ().name() ] = &CVariableIArchive::SerializeRangeUInt;
|
||||
m_structHandlers[ TypeID::get < StringListStaticValue > ().name() ] = &CVariableIArchive::SerializeStringListStaticValue;
|
||||
}
|
||||
|
||||
|
||||
CVariableIArchive::~CVariableIArchive()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool CVariableIArchive::operator()(bool& value, const char* name, [[maybe_unused]] const char* label)
|
||||
{
|
||||
return VarUtil::ReadChildVariableAs< bool >(m_pVariable, m_childIndexOverride, name, value);
|
||||
}
|
||||
|
||||
|
||||
bool CVariableIArchive::operator()(Serialization::IString& value, const char* name, [[maybe_unused]] const char* label)
|
||||
{
|
||||
QString stringValue;
|
||||
const bool readSuccess = VarUtil::ReadChildVariableAs< QString >(m_pVariable, m_childIndexOverride, name, stringValue);
|
||||
if (readSuccess)
|
||||
{
|
||||
value.set(stringValue.toUtf8().data());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CVariableIArchive::operator()([[maybe_unused]] Serialization::IWString& value, [[maybe_unused]] const char* name, [[maybe_unused]] const char* label)
|
||||
{
|
||||
CryFatalError("CVariableIArchive::operator() with IWString is not implemented");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CVariableIArchive::operator()(float& value, const char* name, [[maybe_unused]] const char* label)
|
||||
{
|
||||
return VarUtil::ReadChildVariableAs< float >(m_pVariable, m_childIndexOverride, name, value);
|
||||
}
|
||||
|
||||
|
||||
bool CVariableIArchive::operator()(double& value, const char* name, [[maybe_unused]] const char* label)
|
||||
{
|
||||
return VarUtil::ReadChildVariableAs< float >(m_pVariable, m_childIndexOverride, name, value);
|
||||
}
|
||||
|
||||
|
||||
bool CVariableIArchive::operator()(int16& value, const char* name, [[maybe_unused]] const char* label)
|
||||
{
|
||||
return VarUtil::ReadChildVariableAs< int >(m_pVariable, m_childIndexOverride, name, value);
|
||||
}
|
||||
|
||||
|
||||
bool CVariableIArchive::operator()(uint16& value, const char* name, [[maybe_unused]] const char* label)
|
||||
{
|
||||
return VarUtil::ReadChildVariableAs< int >(m_pVariable, m_childIndexOverride, name, value);
|
||||
}
|
||||
|
||||
|
||||
bool CVariableIArchive::operator()(int32& value, const char* name, [[maybe_unused]] const char* label)
|
||||
{
|
||||
return VarUtil::ReadChildVariableAs< int >(m_pVariable, m_childIndexOverride, name, value);
|
||||
}
|
||||
|
||||
|
||||
bool CVariableIArchive::operator()(uint32& value, const char* name, [[maybe_unused]] const char* label)
|
||||
{
|
||||
return VarUtil::ReadChildVariableAs< int >(m_pVariable, m_childIndexOverride, name, value);
|
||||
}
|
||||
|
||||
|
||||
bool CVariableIArchive::operator()(int64& value, const char* name, [[maybe_unused]] const char* label)
|
||||
{
|
||||
return VarUtil::ReadChildVariableAs< int >(m_pVariable, m_childIndexOverride, name, value);
|
||||
}
|
||||
|
||||
|
||||
bool CVariableIArchive::operator()(uint64& value, const char* name, [[maybe_unused]] const char* label)
|
||||
{
|
||||
return VarUtil::ReadChildVariableAs< int >(m_pVariable, m_childIndexOverride, name, value);
|
||||
}
|
||||
|
||||
|
||||
bool CVariableIArchive::operator()(int8& value, const char* name, [[maybe_unused]] const char* label)
|
||||
{
|
||||
return VarUtil::ReadChildVariableAs< int >(m_pVariable, m_childIndexOverride, name, value);
|
||||
}
|
||||
|
||||
|
||||
bool CVariableIArchive::operator()(uint8& value, const char* name, [[maybe_unused]] const char* label)
|
||||
{
|
||||
return VarUtil::ReadChildVariableAs< int >(m_pVariable, m_childIndexOverride, name, value);
|
||||
}
|
||||
|
||||
|
||||
bool CVariableIArchive::operator()(char& value, const char* name, [[maybe_unused]] const char* label)
|
||||
{
|
||||
return VarUtil::ReadChildVariableAs< int >(m_pVariable, m_childIndexOverride, name, value);
|
||||
}
|
||||
|
||||
|
||||
bool CVariableIArchive::operator()(const Serialization::SStruct& ser, const char* name, const char* label)
|
||||
{
|
||||
const char* const typeName = ser.type().name();
|
||||
HandlersMap::const_iterator it = m_structHandlers.find(typeName);
|
||||
const bool handlerFound = (it != m_structHandlers.end());
|
||||
if (handlerFound)
|
||||
{
|
||||
StructHandlerFunctionPtr pHandler = it->second;
|
||||
return (this->*pHandler)(ser, name, label);
|
||||
}
|
||||
|
||||
return SerializeStruct(ser, name, label);
|
||||
}
|
||||
|
||||
|
||||
bool CVariableIArchive::operator()(Serialization::IContainer& ser, const char* name, [[maybe_unused]] const char* label)
|
||||
{
|
||||
_smart_ptr< IVariable > pChild = VarUtil::FindChildVariable(m_pVariable, m_childIndexOverride, name);
|
||||
if (pChild)
|
||||
{
|
||||
const int elementCount = pChild->GetNumVariables();
|
||||
ser.resize(elementCount);
|
||||
|
||||
if (0 < elementCount)
|
||||
{
|
||||
CVariableIArchive childArchive(pChild);
|
||||
childArchive.SetFilter(GetFilter());
|
||||
childArchive.SetInnerContext(GetInnerContext());
|
||||
|
||||
for (int i = 0; i < elementCount; ++i)
|
||||
{
|
||||
childArchive.m_childIndexOverride = i;
|
||||
|
||||
ser(childArchive, "", "");
|
||||
ser.next();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CVariableIArchive::SerializeStruct(const Serialization::SStruct& ser, const char* name, [[maybe_unused]] const char* label)
|
||||
{
|
||||
_smart_ptr< IVariable > pChild = VarUtil::FindChildVariable(m_pVariable, m_childIndexOverride, name);
|
||||
if (pChild)
|
||||
{
|
||||
CVariableIArchive childArchive(pChild);
|
||||
childArchive.SetFilter(GetFilter());
|
||||
childArchive.SetInnerContext(GetInnerContext());
|
||||
|
||||
ser(childArchive);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CVariableIArchive::SerializeResourceSelector(const Serialization::SStruct& ser, const char* name, [[maybe_unused]] const char* label)
|
||||
{
|
||||
Serialization::IResourceSelector* pSelector = reinterpret_cast< Serialization::IResourceSelector* >(ser.pointer());
|
||||
|
||||
QString stringValue;
|
||||
const bool readSuccess = VarUtil::ReadChildVariableAs< QString >(m_pVariable, m_childIndexOverride, name, stringValue);
|
||||
if (readSuccess)
|
||||
{
|
||||
pSelector->SetValue(stringValue.toUtf8().data());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CVariableIArchive::SerializeStringListStaticValue(const Serialization::SStruct& ser, const char* name, [[maybe_unused]] const char* label)
|
||||
{
|
||||
StringListStaticValue* const pStringListStaticValue = reinterpret_cast< StringListStaticValue* >(ser.pointer());
|
||||
|
||||
_smart_ptr< IVariable > pChild = VarUtil::FindChildVariable(m_pVariable, m_childIndexOverride, name);
|
||||
if (pChild)
|
||||
{
|
||||
int index = -1;
|
||||
pChild->Get(index);
|
||||
*pStringListStaticValue = index;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CVariableIArchive::SerializeRangeFloat(const Serialization::SStruct& ser, const char* name, [[maybe_unused]] const char* label)
|
||||
{
|
||||
const Serialization::RangeDecorator< float >* const pRange = reinterpret_cast< Serialization::RangeDecorator< float >* >(ser.pointer());
|
||||
return VarUtil::ReadChildVariableAs< float >(m_pVariable, m_childIndexOverride, name, *pRange->value);
|
||||
}
|
||||
|
||||
|
||||
bool CVariableIArchive::SerializeRangeInt(const Serialization::SStruct& ser, const char* name, [[maybe_unused]] const char* label)
|
||||
{
|
||||
const Serialization::RangeDecorator< int >* const pRange = reinterpret_cast< Serialization::RangeDecorator< int >* >(ser.pointer());
|
||||
return VarUtil::ReadChildVariableAs< int >(m_pVariable, m_childIndexOverride, name, *pRange->value);
|
||||
}
|
||||
|
||||
bool CVariableIArchive::SerializeRangeUInt(const Serialization::SStruct& ser, const char* name, [[maybe_unused]] const char* label)
|
||||
{
|
||||
const Serialization::RangeDecorator< unsigned int >* const pRange = reinterpret_cast< Serialization::RangeDecorator< unsigned int >* >(ser.pointer());
|
||||
return VarUtil::ReadChildVariableAs< int >(m_pVariable, m_childIndexOverride, name, *pRange->value);
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Util/Variable.h"
|
||||
#include "Serialization.h"
|
||||
|
||||
namespace Serialization
|
||||
{
|
||||
class CVariableIArchive
|
||||
: public IArchive
|
||||
{
|
||||
public:
|
||||
CVariableIArchive(const _smart_ptr< IVariable >& pVariable);
|
||||
virtual ~CVariableIArchive();
|
||||
|
||||
// IArchive
|
||||
virtual bool operator()(bool& value, const char* name = "", const char* label = 0) override;
|
||||
virtual bool operator()(IString& value, const char* name = "", const char* label = 0) override;
|
||||
virtual bool operator()(IWString& value, const char* name = "", const char* label = 0) override;
|
||||
virtual bool operator()(float& value, const char* name = "", const char* label = 0) override;
|
||||
virtual bool operator()(double& value, const char* name = "", const char* label = 0) override;
|
||||
virtual bool operator()(int16& value, const char* name = "", const char* label = 0) override;
|
||||
virtual bool operator()(uint16& value, const char* name = "", const char* label = 0) override;
|
||||
virtual bool operator()(int32& value, const char* name = "", const char* label = 0) override;
|
||||
virtual bool operator()(uint32& value, const char* name = "", const char* label = 0) override;
|
||||
virtual bool operator()(int64& value, const char* name = "", const char* label = 0) override;
|
||||
virtual bool operator()(uint64& value, const char* name = "", const char* label = 0) override;
|
||||
|
||||
virtual bool operator()(int8& value, const char* name = "", const char* label = 0) override;
|
||||
virtual bool operator()(uint8& value, const char* name = "", const char* label = 0) override;
|
||||
virtual bool operator()(char& value, const char* name = "", const char* label = 0);
|
||||
|
||||
virtual bool operator()(const SStruct& ser, const char* name = "", const char* label = 0) override;
|
||||
virtual bool operator()(IContainer& ser, const char* name = "", const char* label = 0) override;
|
||||
//virtual bool operator()( IPointer& ptr, const char* name = "", const char* label = 0 ) override;
|
||||
// ~IArchive
|
||||
|
||||
using IArchive::operator();
|
||||
|
||||
private:
|
||||
bool SerializeResourceSelector(const SStruct& ser, const char* name, const char* label);
|
||||
|
||||
bool SerializeStruct(const SStruct& ser, const char* name, const char* label);
|
||||
|
||||
bool SerializeStringListStaticValue(const SStruct& ser, const char* name, const char* label);
|
||||
|
||||
bool SerializeRangeFloat(const SStruct& ser, const char* name, const char* label);
|
||||
bool SerializeRangeInt(const SStruct& ser, const char* name, const char* label);
|
||||
bool SerializeRangeUInt(const SStruct& ser, const char* name, const char* label);
|
||||
|
||||
private:
|
||||
_smart_ptr< IVariable > m_pVariable;
|
||||
int m_childIndexOverride;
|
||||
|
||||
typedef bool ( CVariableIArchive::* StructHandlerFunctionPtr )(const SStruct&, const char*, const char*);
|
||||
typedef std::map< string, StructHandlerFunctionPtr > HandlersMap;
|
||||
HandlersMap m_structHandlers; // TODO: have only one of these.
|
||||
};
|
||||
}
|
||||
@@ -1,416 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "VariableOArchive.h"
|
||||
|
||||
// Editor
|
||||
#include "Serialization/Decorators/Resources.h"
|
||||
#include "Serialization/Decorators/Range.h"
|
||||
|
||||
|
||||
using Serialization::CVariableOArchive;
|
||||
|
||||
namespace VarUtil
|
||||
{
|
||||
template< typename T >
|
||||
_smart_ptr< IVariable > AddChildVariable(const _smart_ptr< IVariable >& pVariableArray, const T& value, const char* const name, const char* label)
|
||||
{
|
||||
CRY_ASSERT(pVariableArray);
|
||||
|
||||
_smart_ptr< IVariable > pVariable = new CVariable< T >();
|
||||
pVariable->SetName(name);
|
||||
pVariable->SetHumanName(label);
|
||||
pVariable->Set(value);
|
||||
|
||||
pVariableArray->AddVariable(pVariable);
|
||||
|
||||
return pVariable;
|
||||
}
|
||||
|
||||
template< typename TMin, typename TMax >
|
||||
void SetLimits(const _smart_ptr< IVariable >& pVariable, const TMin minValue, const TMax maxValue)
|
||||
{
|
||||
pVariable->SetLimits(static_cast< float >(minValue), static_cast< float >(maxValue));
|
||||
}
|
||||
}
|
||||
|
||||
CVariableOArchive::CVariableOArchive()
|
||||
: IArchive(IArchive::OUTPUT | IArchive::EDIT | IArchive::NO_EMPTY_NAMES)
|
||||
, m_pVariable(new CVariableArray())
|
||||
{
|
||||
m_resourceHandlers[ "Animation" ] = &CVariableOArchive::SerializeAnimationName;
|
||||
m_resourceHandlers[ "Sound" ] = &CVariableOArchive::SerializeSoundName;
|
||||
m_resourceHandlers[ "Model" ] = &CVariableOArchive::SerializeObjectFilename;
|
||||
|
||||
m_structHandlers[ TypeID::get < Serialization::IResourceSelector > ().name() ] = &CVariableOArchive::SerializeIResourceSelector;
|
||||
m_structHandlers[ TypeID::get < Serialization::RangeDecorator < float >> ().name() ] = &CVariableOArchive::SerializeRangeFloat;
|
||||
m_structHandlers[ TypeID::get < Serialization::RangeDecorator < int >> ().name() ] = &CVariableOArchive::SerializeRangeInt;
|
||||
m_structHandlers[ TypeID::get < Serialization::RangeDecorator < unsigned int >> ().name() ] = &CVariableOArchive::SerializeRangeUInt;
|
||||
m_structHandlers[ TypeID::get < StringListStaticValue > ().name() ] = &CVariableOArchive::SerializeStringListStaticValue;
|
||||
}
|
||||
|
||||
|
||||
CVariableOArchive::~CVariableOArchive()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
_smart_ptr< IVariable > CVariableOArchive::GetIVariable() const
|
||||
{
|
||||
return m_pVariable;
|
||||
}
|
||||
|
||||
|
||||
CVarBlockPtr CVariableOArchive::GetVarBlock() const
|
||||
{
|
||||
CVarBlockPtr pVarBlock = new CVarBlock();
|
||||
pVarBlock->AddVariable(m_pVariable);
|
||||
return pVarBlock;
|
||||
}
|
||||
|
||||
|
||||
bool CVariableOArchive::operator()(bool& value, const char* name, const char* label)
|
||||
{
|
||||
VarUtil::AddChildVariable< bool >(m_pVariable, value, name, label);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CVariableOArchive::operator()(Serialization::IString& value, const char* name, const char* label)
|
||||
{
|
||||
const QString valueString = value.get();
|
||||
VarUtil::AddChildVariable< QString >(m_pVariable, valueString, name, label);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CVariableOArchive::operator()([[maybe_unused]] Serialization::IWString& value, [[maybe_unused]] const char* name, [[maybe_unused]] const char* label)
|
||||
{
|
||||
CryFatalError("CVarBlockOArchive::operator() with IWString is not implemented");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CVariableOArchive::operator()(float& value, const char* name, const char* label)
|
||||
{
|
||||
VarUtil::AddChildVariable< float >(m_pVariable, value, name, label);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CVariableOArchive::operator()(double& value, const char* name, const char* label)
|
||||
{
|
||||
VarUtil::AddChildVariable< float >(m_pVariable, value, name, label);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CVariableOArchive::operator()(int16& value, const char* name, const char* label)
|
||||
{
|
||||
_smart_ptr< IVariable > pVariable = VarUtil::AddChildVariable< int >(m_pVariable, value, name, label);
|
||||
VarUtil::SetLimits(pVariable, SHRT_MIN, SHRT_MAX);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CVariableOArchive::operator()(uint16& value, const char* name, const char* label)
|
||||
{
|
||||
_smart_ptr< IVariable > pVariable = VarUtil::AddChildVariable< int >(m_pVariable, value, name, label);
|
||||
VarUtil::SetLimits(pVariable, 0, USHRT_MAX);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CVariableOArchive::operator()(int32& value, const char* name, const char* label)
|
||||
{
|
||||
_smart_ptr< IVariable > pVariable = VarUtil::AddChildVariable< int >(m_pVariable, value, name, label);
|
||||
VarUtil::SetLimits(pVariable, INT_MIN, INT_MAX);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CVariableOArchive::operator()(uint32& value, const char* name, const char* label)
|
||||
{
|
||||
_smart_ptr< IVariable > pVariable = VarUtil::AddChildVariable< int >(m_pVariable, value, name, label);
|
||||
VarUtil::SetLimits(pVariable, 0, INT_MAX);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CVariableOArchive::operator()(int64& value, const char* name, const char* label)
|
||||
{
|
||||
_smart_ptr< IVariable > pVariable = VarUtil::AddChildVariable< int >(m_pVariable, value, name, label);
|
||||
VarUtil::SetLimits(pVariable, INT_MIN, INT_MAX);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CVariableOArchive::operator()(uint64& value, const char* name, const char* label)
|
||||
{
|
||||
_smart_ptr< IVariable > pVariable = VarUtil::AddChildVariable< int >(m_pVariable, value, name, label);
|
||||
VarUtil::SetLimits(pVariable, 0, INT_MAX);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CVariableOArchive::operator()(int8& value, const char* name, const char* label)
|
||||
{
|
||||
_smart_ptr< IVariable > pVariable = VarUtil::AddChildVariable< int >(m_pVariable, value, name, label);
|
||||
VarUtil::SetLimits(pVariable, SCHAR_MIN, SCHAR_MAX);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CVariableOArchive::operator()(uint8& value, const char* name, const char* label)
|
||||
{
|
||||
_smart_ptr< IVariable > pVariable = VarUtil::AddChildVariable< int >(m_pVariable, value, name, label);
|
||||
VarUtil::SetLimits(pVariable, 0, UCHAR_MAX);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CVariableOArchive::operator()(char& value, const char* name, const char* label)
|
||||
{
|
||||
_smart_ptr< IVariable > pVariable = VarUtil::AddChildVariable< int >(m_pVariable, value, name, label);
|
||||
VarUtil::SetLimits(pVariable, CHAR_MIN, CHAR_MAX);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CVariableOArchive::operator()(const Serialization::SStruct& ser, const char* name, const char* label)
|
||||
{
|
||||
const char* const typeName = ser.type().name();
|
||||
HandlersMap::const_iterator it = m_structHandlers.find(typeName);
|
||||
const bool handlerFound = (it != m_structHandlers.end());
|
||||
if (handlerFound)
|
||||
{
|
||||
StructHandlerFunctionPtr pHandler = it->second;
|
||||
return (this->*pHandler)(ser, name, label);
|
||||
}
|
||||
|
||||
return SerializeStruct(ser, name, label);
|
||||
}
|
||||
|
||||
static const char* gVec4Names[] = { "X", "Y", "Z", "W" };
|
||||
static const char* gEmptyNames[] = { "" };
|
||||
|
||||
bool CVariableOArchive::operator()(Serialization::IContainer& ser, const char* name, const char* label)
|
||||
{
|
||||
CVariableOArchive childArchive;
|
||||
childArchive.SetFilter(GetFilter());
|
||||
childArchive.SetInnerContext(GetInnerContext());
|
||||
|
||||
_smart_ptr< IVariable > pChildVariable = childArchive.GetIVariable();
|
||||
pChildVariable->SetName(name);
|
||||
pChildVariable->SetHumanName(label);
|
||||
|
||||
m_pVariable->AddVariable(pChildVariable);
|
||||
|
||||
const size_t containerSize = ser.size();
|
||||
|
||||
const char** nameArray = gEmptyNames;
|
||||
size_t nameArraySize = 1;
|
||||
if (containerSize >= 2 && containerSize <= 4)
|
||||
{
|
||||
nameArray = gVec4Names;
|
||||
nameArraySize = containerSize;
|
||||
}
|
||||
|
||||
size_t index = 0;
|
||||
if (0 < containerSize)
|
||||
{
|
||||
do
|
||||
{
|
||||
ser(childArchive, nameArray[index % nameArraySize], nameArray[index % nameArraySize]);
|
||||
++index;
|
||||
} while (ser.next());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CVariableOArchive::SerializeStruct(const Serialization::SStruct& ser, const char* name, const char* label)
|
||||
{
|
||||
CVariableOArchive childArchive;
|
||||
childArchive.SetFilter(GetFilter());
|
||||
childArchive.SetInnerContext(GetInnerContext());
|
||||
|
||||
_smart_ptr< IVariable > pChildVariable = childArchive.GetIVariable();
|
||||
pChildVariable->SetName(name);
|
||||
pChildVariable->SetHumanName(label);
|
||||
|
||||
m_pVariable->AddVariable(pChildVariable);
|
||||
|
||||
const bool serializeSuccess = ser(childArchive);
|
||||
|
||||
return serializeSuccess;
|
||||
}
|
||||
|
||||
|
||||
bool CVariableOArchive::SerializeAnimationName(const Serialization::IResourceSelector* pSelector, const char* name, const char* label)
|
||||
{
|
||||
const QString valueString = pSelector->GetValue();
|
||||
_smart_ptr< IVariable > pVariable = VarUtil::AddChildVariable< QString >(m_pVariable, valueString, name, label);
|
||||
pVariable->SetDataType(IVariable::DT_ANIMATION);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CVariableOArchive::SerializeSoundName(const Serialization::IResourceSelector* pSelector, const char* name, const char* label)
|
||||
{
|
||||
const QString valueString = pSelector->GetValue();
|
||||
_smart_ptr< IVariable > pVariable = VarUtil::AddChildVariable< QString >(m_pVariable, valueString, name, label);
|
||||
pVariable->SetDataType(IVariable::DT_AUDIO_TRIGGER);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CVariableOArchive::CreateChildEnumVariable(const QStringList& enumValues, const QString& value, const char* name, const char* label)
|
||||
{
|
||||
if (enumValues.empty())
|
||||
{
|
||||
VarUtil::AddChildVariable< QString >(m_pVariable, value, name, label);
|
||||
}
|
||||
else
|
||||
{
|
||||
_smart_ptr< CVariableEnum< QString > > pVariable = new CVariableEnum< QString >();
|
||||
pVariable->SetName(name);
|
||||
pVariable->SetHumanName(label);
|
||||
|
||||
pVariable->AddEnumItem("", "");
|
||||
|
||||
const size_t enumValuesCount = enumValues.size();
|
||||
for (size_t i = 0; i < enumValuesCount; ++i)
|
||||
{
|
||||
pVariable->AddEnumItem(enumValues[ i ], enumValues[ i ]);
|
||||
}
|
||||
|
||||
pVariable->Set(value);
|
||||
|
||||
m_pVariable->AddVariable(pVariable);
|
||||
}
|
||||
}
|
||||
|
||||
bool CVariableOArchive::SerializeObjectFilename(const Serialization::IResourceSelector* pSelector, const char* name, const char* label)
|
||||
{
|
||||
const QString valueString = pSelector->GetValue();
|
||||
_smart_ptr< IVariable > pVariable = VarUtil::AddChildVariable< QString >(m_pVariable, valueString, name, label);
|
||||
pVariable->SetDataType(IVariable::DT_OBJECT);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CVariableOArchive::SerializeStringListStaticValue(const Serialization::SStruct& ser, const char* name, const char* label)
|
||||
{
|
||||
const StringListStaticValue* const pStringListStaticValue = reinterpret_cast< StringListStaticValue* >(ser.pointer());
|
||||
const StringListStatic& stringListStatic = pStringListStaticValue->stringList();
|
||||
const int index = pStringListStaticValue->index();
|
||||
|
||||
_smart_ptr< CVariableEnum< int > > pVariable = new CVariableEnum< int >();
|
||||
pVariable->SetName(name);
|
||||
pVariable->SetHumanName(label);
|
||||
|
||||
const size_t stringListStaticSize = stringListStatic.size();
|
||||
for (size_t i = 0; i < stringListStaticSize; ++i)
|
||||
{
|
||||
pVariable->AddEnumItem(stringListStatic[ i ], static_cast< int >(i));
|
||||
}
|
||||
|
||||
if (0 <= index)
|
||||
{
|
||||
CRY_ASSERT(index < stringListStaticSize);
|
||||
pVariable->Set(static_cast< int >(index));
|
||||
}
|
||||
|
||||
m_pVariable->AddVariable(pVariable);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CVariableOArchive::SerializeIResourceSelector(const Serialization::SStruct& ser, const char* name, const char* label)
|
||||
{
|
||||
const Serialization::IResourceSelector* pSelector = reinterpret_cast< Serialization::IResourceSelector* >(ser.pointer());
|
||||
|
||||
ResourceHandlersMap::iterator it = m_resourceHandlers.find(pSelector->resourceType);
|
||||
if (it != m_resourceHandlers.end())
|
||||
{
|
||||
return (this->*(it->second))(pSelector, name, label);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static void SetLimits(IVariable* pVariable, const Serialization::RangeDecorator<T>* pRange, float stepValue)
|
||||
{
|
||||
if (pRange->softMin != std::numeric_limits<T>::lowest() || pRange->softMax != std::numeric_limits<T>::max())
|
||||
{
|
||||
float minimal = (float)pRange->softMin;
|
||||
float maximal = (float)pRange->softMax;
|
||||
bool hardMin = false;
|
||||
bool hardMax = false;
|
||||
if (pRange->hardMin != std::numeric_limits<T>::lowest())
|
||||
{
|
||||
minimal = pRange->hardMin;
|
||||
hardMin = true;
|
||||
}
|
||||
if (pRange->hardMax != std::numeric_limits<T>::max())
|
||||
{
|
||||
maximal = pRange->hardMax;
|
||||
hardMax = true;
|
||||
}
|
||||
pVariable->SetLimits(minimal, maximal, stepValue, hardMin, hardMax);
|
||||
}
|
||||
else
|
||||
{
|
||||
float minimal = 0.0f;
|
||||
float maximal = 0.0f;
|
||||
float oldStep = 0.0f;
|
||||
bool hardMin = false;
|
||||
bool hardMax = false;
|
||||
pVariable->GetLimits(minimal, maximal, oldStep, hardMin, hardMax);
|
||||
pVariable->SetLimits(minimal, maximal, stepValue, hardMin, hardMax);
|
||||
}
|
||||
}
|
||||
|
||||
bool CVariableOArchive::SerializeRangeFloat(const Serialization::SStruct& ser, const char* name, const char* label)
|
||||
{
|
||||
const Serialization::RangeDecorator< float >* const pRange = reinterpret_cast< Serialization::RangeDecorator< float >* >(ser.pointer());
|
||||
|
||||
_smart_ptr< IVariable > pVariable = VarUtil::AddChildVariable< float >(m_pVariable, *pRange->value, name, label);
|
||||
|
||||
SetLimits(pVariable.get(), pRange, 0.01f);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CVariableOArchive::SerializeRangeInt(const Serialization::SStruct& ser, const char* name, const char* label)
|
||||
{
|
||||
const Serialization::RangeDecorator< int >* const pRange = reinterpret_cast< Serialization::RangeDecorator< int >* >(ser.pointer());
|
||||
|
||||
_smart_ptr< IVariable > pVariable = VarUtil::AddChildVariable< int >(m_pVariable, *pRange->value, name, label);
|
||||
SetLimits(pVariable.get(), pRange, 1.0f);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CVariableOArchive::SerializeRangeUInt(const Serialization::SStruct& ser, const char* name, const char* label)
|
||||
{
|
||||
const Serialization::RangeDecorator< unsigned int >* const pRange = reinterpret_cast< Serialization::RangeDecorator< unsigned int >* >(ser.pointer());
|
||||
|
||||
_smart_ptr< IVariable > pVariable = VarUtil::AddChildVariable< int >(m_pVariable, *pRange->value, name, label);
|
||||
SetLimits(pVariable, pRange, 1.0f);
|
||||
return true;
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Util/Variable.h"
|
||||
#include "Serialization.h"
|
||||
|
||||
|
||||
namespace Serialization
|
||||
{
|
||||
struct IResourceSelector;
|
||||
|
||||
class CVariableOArchive
|
||||
: public IArchive
|
||||
{
|
||||
public:
|
||||
CVariableOArchive();
|
||||
virtual ~CVariableOArchive();
|
||||
|
||||
_smart_ptr< IVariable > GetIVariable() const;
|
||||
CVarBlockPtr GetVarBlock() const;
|
||||
|
||||
// IArchive
|
||||
virtual bool operator()(bool& value, const char* name = "", const char* label = 0) override;
|
||||
virtual bool operator()(IString& value, const char* name = "", const char* label = 0) override;
|
||||
virtual bool operator()(IWString& value, const char* name = "", const char* label = 0) override;
|
||||
virtual bool operator()(float& value, const char* name = "", const char* label = 0) override;
|
||||
virtual bool operator()(double& value, const char* name = "", const char* label = 0) override;
|
||||
virtual bool operator()(int16& value, const char* name = "", const char* label = 0) override;
|
||||
virtual bool operator()(uint16& value, const char* name = "", const char* label = 0) override;
|
||||
virtual bool operator()(int32& value, const char* name = "", const char* label = 0) override;
|
||||
virtual bool operator()(uint32& value, const char* name = "", const char* label = 0) override;
|
||||
virtual bool operator()(int64& value, const char* name = "", const char* label = 0) override;
|
||||
virtual bool operator()(uint64& value, const char* name = "", const char* label = 0) override;
|
||||
|
||||
virtual bool operator()(int8& value, const char* name = "", const char* label = 0) override;
|
||||
virtual bool operator()(uint8& value, const char* name = "", const char* label = 0) override;
|
||||
virtual bool operator()(char& value, const char* name = "", const char* label = 0);
|
||||
|
||||
virtual bool operator()(const SStruct& ser, const char* name = "", const char* label = 0) override;
|
||||
virtual bool operator()(IContainer& ser, const char* name = "", const char* label = 0) override;
|
||||
//virtual bool operator()( IPointer& ptr, const char* name = "", const char* label = 0 ) override;
|
||||
// ~IArchive
|
||||
|
||||
using IArchive::operator();
|
||||
|
||||
private:
|
||||
bool SerializeStruct(const SStruct& ser, const char* name, const char* label);
|
||||
bool SerializeStringListStaticValue(const SStruct& ser, const char* name, const char* label);
|
||||
bool SerializeRangeFloat(const SStruct& ser, const char* name, const char* label);
|
||||
bool SerializeRangeInt(const SStruct& ser, const char* name, const char* label);
|
||||
bool SerializeRangeUInt(const SStruct& ser, const char* name, const char* label);
|
||||
bool SerializeIResourceSelector(const SStruct& ser, const char* name, const char* label);
|
||||
|
||||
bool SerializeAnimationName(const IResourceSelector* pSelector, const char* name, const char* label);
|
||||
bool SerializeSoundName(const IResourceSelector* pSelector, const char* name, const char* label);
|
||||
bool SerializeObjectFilename(const IResourceSelector* pSelector, const char* name, const char* label);
|
||||
|
||||
void CreateChildEnumVariable(const QStringList& enumValues, const QString& value, const char* name, const char* label);
|
||||
|
||||
private:
|
||||
_smart_ptr< IVariable > m_pVariable;
|
||||
|
||||
typedef bool ( CVariableOArchive::* StructHandlerFunctionPtr )(const SStruct&, const char*, const char*);
|
||||
typedef std::map< string, StructHandlerFunctionPtr > HandlersMap;
|
||||
HandlersMap m_structHandlers; // TODO: have only one of these.
|
||||
|
||||
typedef bool ( CVariableOArchive::* ResourceHandlerFunctionPtr )(const IResourceSelector*, const char*, const char*);
|
||||
typedef std::map< string, ResourceHandlerFunctionPtr > ResourceHandlersMap;
|
||||
ResourceHandlersMap m_resourceHandlers;
|
||||
};
|
||||
}
|
||||
@@ -1,177 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "SettingsBlock.h"
|
||||
|
||||
// CryCommon
|
||||
#include <CryCommon/Serialization/ITextInputArchive.h>
|
||||
#include <CryCommon/Serialization/ITextOutputArchive.h>
|
||||
|
||||
// Editor
|
||||
#include "Serialization.h"
|
||||
|
||||
using std::vector;
|
||||
|
||||
SProjectSettingsBlock* SProjectSettingsBlock::s_pLastBlock;
|
||||
|
||||
SProjectSettingsBlock::SProjectSettingsBlock(const char* name, const char* label)
|
||||
: m_name(name)
|
||||
, m_label(label)
|
||||
{
|
||||
m_pPrevious = s_pLastBlock;
|
||||
s_pLastBlock = this;
|
||||
}
|
||||
|
||||
|
||||
struct SAllSettingsSerializer
|
||||
{
|
||||
void Serialize(Serialization::IArchive& ar)
|
||||
{
|
||||
SProjectSettingsBlock* pCurrent = SProjectSettingsBlock::s_pLastBlock;
|
||||
while (pCurrent != 0)
|
||||
{
|
||||
ar(*pCurrent, pCurrent->GetName(), pCurrent->GetLabel());
|
||||
pCurrent = pCurrent->m_pPrevious;
|
||||
}
|
||||
}
|
||||
} static gAllSettingsSerializer;
|
||||
|
||||
void SProjectSettingsBlock::GetAllSettingsSerializer(Serialization::SStruct* pSerializer)
|
||||
{
|
||||
*pSerializer = Serialization::SStruct(gAllSettingsSerializer);
|
||||
}
|
||||
|
||||
SProjectSettingsBlock* SProjectSettingsBlock::Find(const char* blockName)
|
||||
{
|
||||
SProjectSettingsBlock* pCurrent = SProjectSettingsBlock::s_pLastBlock;
|
||||
while (pCurrent != 0)
|
||||
{
|
||||
if (_stricmp(pCurrent->GetName(), blockName) == 0)
|
||||
{
|
||||
return pCurrent;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool ReadFileContent(vector<char>* pBuffer, const char* filename)
|
||||
{
|
||||
AZ::IO::HandleType fileHandle = gEnv->pCryPak->FOpen(filename, "rb");
|
||||
if (fileHandle == AZ::IO::InvalidHandle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t size = gEnv->pCryPak->FGetSize(fileHandle);
|
||||
pBuffer->resize(size);
|
||||
|
||||
bool result = true;
|
||||
if (gEnv->pCryPak->FRead(&(*pBuffer)[0], size, fileHandle) != size)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
gEnv->pCryPak->FClose(fileHandle);
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool SaveFileContent(const char* filename, const char* pBuffer, size_t length)
|
||||
{
|
||||
string fullpath = Path::GamePathToFullPath(filename).toUtf8().data();
|
||||
|
||||
AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle;
|
||||
if (!gEnv->pFileIO->Open(fullpath.c_str(), AZ::IO::GetOpenModeFromStringMode("wb"), fileHandle))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
if (!gEnv->pFileIO->Write(fileHandle, pBuffer, length))
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
|
||||
gEnv->pFileIO->Close(fileHandle);
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool SaveFileContentIfDiffers(const char* filename, const char* pBuffer, size_t length)
|
||||
{
|
||||
vector<char> content;
|
||||
ReadFileContent(&content, filename);
|
||||
|
||||
bool needToWrite = true;
|
||||
if (!content.empty() && content.size() == length)
|
||||
{
|
||||
needToWrite = memcmp(&content[0], pBuffer, length) != 0;
|
||||
}
|
||||
|
||||
if (needToWrite)
|
||||
{
|
||||
return SaveFileContent(filename, pBuffer, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool SProjectSettingsBlock::Load()
|
||||
{
|
||||
const char* filename = GetFilename();
|
||||
|
||||
vector<char> content;
|
||||
if (!ReadFileContent(&content, filename))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto pArchive(Serialization::CreateTextInputArchive());
|
||||
if (!pArchive)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pArchive->AttachMemory(&content[0], content.size()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Serialization::SStruct serializer;
|
||||
GetAllSettingsSerializer(&serializer);
|
||||
serializer(*pArchive);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SProjectSettingsBlock::Save()
|
||||
{
|
||||
const char* filename = GetFilename();
|
||||
auto pArchive(Serialization::CreateTextOutputArchive());
|
||||
if (!pArchive)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Serialization::SStruct serializer;
|
||||
GetAllSettingsSerializer(&serializer);
|
||||
serializer(*pArchive);
|
||||
|
||||
return SaveFileContentIfDiffers(filename, pArchive->GetBuffer(), pArchive->GetBufferLength());
|
||||
}
|
||||
|
||||
const char* SProjectSettingsBlock::GetFilename()
|
||||
{
|
||||
return "SandboxSettings.json";
|
||||
}
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#pragma once
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Following utility can be used to add blocks of per-project settings.
|
||||
// Example:
|
||||
//
|
||||
// MyComponent.cpp:
|
||||
//
|
||||
// struct SProjectSettingsMy : SProjectSettingsBlock
|
||||
// {
|
||||
// bool bMyOption;
|
||||
//
|
||||
// SProjectSettingsMy()
|
||||
// : SProjectSettingsBlock("my", "My")
|
||||
// , bMyOption(false)
|
||||
// {}
|
||||
//
|
||||
// void Serialize(Serialization::IArchive& ar)
|
||||
// {
|
||||
// ar(bMyOption, "myOption", "My Option");
|
||||
// }
|
||||
//
|
||||
// } static gMySettings;
|
||||
//
|
||||
//
|
||||
// Now gMySettings will be loaded and saved automatically and available for
|
||||
// editing through:
|
||||
//
|
||||
// GetIEditor()->OpenProjectSettings("my");
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
#ifndef CRYINCLUDE_EDITOR_SETTINGSBLOCK_H
|
||||
#define CRYINCLUDE_EDITOR_SETTINGSBLOCK_H
|
||||
|
||||
namespace Serialization
|
||||
{
|
||||
class IArchive;
|
||||
struct SStruct;
|
||||
};
|
||||
|
||||
struct SProjectSettingsBlock
|
||||
{
|
||||
SProjectSettingsBlock(const char* name, const char* label);
|
||||
|
||||
virtual void Serialize(Serialization::IArchive& ar) = 0;
|
||||
|
||||
const char* GetName() const{ return m_name; }
|
||||
const char* GetLabel() const{ return m_label; }
|
||||
|
||||
static void GetAllSettingsSerializer(Serialization::SStruct* serializer);
|
||||
static SProjectSettingsBlock* Find(const char* name);
|
||||
static bool Load();
|
||||
static bool Save();
|
||||
static const char* GetFilename();
|
||||
private:
|
||||
const char* m_name;
|
||||
const char* m_label;
|
||||
SProjectSettingsBlock* m_pPrevious;
|
||||
static SProjectSettingsBlock* s_pLastBlock;
|
||||
friend struct SAllSettingsSerializer;
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_SETTINGSBLOCK_H
|
||||
@@ -595,10 +595,6 @@ AmazonToolbar ToolbarManager::GetEditModeToolbar() const
|
||||
t.AddAction(ID_TOOLBAR_WIDGET_SNAP_GRID, ORIGINAL_TOOLBAR_VERSION);
|
||||
t.AddAction(ID_TOOLBAR_WIDGET_SNAP_ANGLE, ORIGINAL_TOOLBAR_VERSION);
|
||||
|
||||
t.AddAction(ID_TOOLBAR_SEPARATOR, ORIGINAL_TOOLBAR_VERSION);
|
||||
t.AddAction(ID_TOOLBAR_WIDGET_ENVIRONMENT_MODE, ORIGINAL_TOOLBAR_VERSION);
|
||||
t.AddAction(ID_TOOLBAR_WIDGET_DEBUG_MODE, ORIGINAL_TOOLBAR_VERSION);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,38 +27,3 @@ void CUsedResources::Add(const char* pResourceFileName)
|
||||
files.insert(pResourceFileName);
|
||||
}
|
||||
}
|
||||
|
||||
void CUsedResources::Validate(IErrorReport* pReport)
|
||||
{
|
||||
auto pPak = gEnv->pCryPak;
|
||||
|
||||
for (TResourceFiles::iterator it = files.begin(); it != files.end(); ++it)
|
||||
{
|
||||
const QString& filename = *it;
|
||||
|
||||
bool fileExists = pPak->IsFileExist(filename.toUtf8().data());
|
||||
|
||||
if (!fileExists)
|
||||
{
|
||||
for (int i = 0; !fileExists && i < IResourceCompilerHelper::GetNumEngineImageFormats(); ++i)
|
||||
{
|
||||
fileExists = gEnv->pCryPak->IsFileExist(PathUtil::ReplaceExtension(filename.toUtf8().data(), IResourceCompilerHelper::GetEngineImageFormat(i, true)).c_str());
|
||||
}
|
||||
for (int i = 0; !fileExists && i < IResourceCompilerHelper::GetNumSourceImageFormats(); ++i)
|
||||
{
|
||||
fileExists = gEnv->pCryPak->IsFileExist(PathUtil::ReplaceExtension(filename.toUtf8().data(), IResourceCompilerHelper::GetSourceImageFormat(i, true)).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!fileExists)
|
||||
{
|
||||
CErrorRecord err;
|
||||
|
||||
err.error = QObject::tr("Resource File %1 not found,").arg(filename);
|
||||
err.severity = CErrorRecord::ESEVERITY_ERROR;
|
||||
err.flags |= CErrorRecord::FLAG_NOFILE;
|
||||
pReport->ReportError(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,8 +36,6 @@ public:
|
||||
|
||||
CUsedResources();
|
||||
void Add(const char* pResourceFileName);
|
||||
//! validate gathered resources, reports warning if resource is not found
|
||||
void Validate(struct IErrorReport* pReport);
|
||||
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
TResourceFiles files;
|
||||
|
||||
@@ -21,206 +21,228 @@
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
static const auto ManipulatorPriority = AzFramework::ViewportControllerPriority::High;
|
||||
static const auto InteractionPriority = AzFramework::ViewportControllerPriority::Low;
|
||||
static const auto ManipulatorPriority = AzFramework::ViewportControllerPriority::Highest;
|
||||
static const auto InteractionPriority = AzFramework::ViewportControllerPriority::High;
|
||||
|
||||
namespace SandboxEditor
|
||||
{
|
||||
|
||||
ViewportManipulatorControllerInstance::ViewportManipulatorControllerInstance(AzFramework::ViewportId viewport, ViewportManipulatorController* controller)
|
||||
: AzFramework::MultiViewportControllerInstanceInterface<ViewportManipulatorController>(viewport, controller)
|
||||
{
|
||||
}
|
||||
|
||||
AzToolsFramework::ViewportInteraction::MouseButton ViewportManipulatorControllerInstance::GetMouseButton(
|
||||
const AzFramework::InputChannel& inputChannel)
|
||||
{
|
||||
using AzToolsFramework::ViewportInteraction::MouseButton;
|
||||
using InputButton = AzFramework::InputDeviceMouse::Button;
|
||||
const auto& id = inputChannel.GetInputChannelId();
|
||||
if (id == InputButton::Left)
|
||||
ViewportManipulatorControllerInstance::ViewportManipulatorControllerInstance(
|
||||
AzFramework::ViewportId viewport, ViewportManipulatorController* controller)
|
||||
: AzFramework::MultiViewportControllerInstanceInterface<ViewportManipulatorController>(viewport, controller)
|
||||
{
|
||||
return MouseButton::Left;
|
||||
}
|
||||
if (id == InputButton::Middle)
|
||||
{
|
||||
return MouseButton::Middle;
|
||||
}
|
||||
if (id == InputButton::Right)
|
||||
{
|
||||
return MouseButton::Right;
|
||||
}
|
||||
return MouseButton::None;
|
||||
}
|
||||
|
||||
bool ViewportManipulatorControllerInstance::IsMouseMove(const AzFramework::InputChannel& inputChannel)
|
||||
{
|
||||
return inputChannel.GetInputChannelId() == AzFramework::InputDeviceMouse::SystemCursorPosition;
|
||||
}
|
||||
|
||||
AzToolsFramework::ViewportInteraction::KeyboardModifier ViewportManipulatorControllerInstance::GetKeyboardModifier(
|
||||
const AzFramework::InputChannel& inputChannel)
|
||||
{
|
||||
using AzToolsFramework::ViewportInteraction::KeyboardModifier;
|
||||
using Key = AzFramework::InputDeviceKeyboard::Key;
|
||||
const auto& id = inputChannel.GetInputChannelId();
|
||||
if (id == Key::ModifierAltL || id == Key::ModifierAltR)
|
||||
{
|
||||
return KeyboardModifier::Alt;
|
||||
}
|
||||
if (id == Key::ModifierCtrlL || id == Key::ModifierCtrlR)
|
||||
{
|
||||
return KeyboardModifier::Ctrl;
|
||||
}
|
||||
if (id == Key::ModifierShiftL || id == Key::ModifierShiftR)
|
||||
{
|
||||
return KeyboardModifier::Shift;
|
||||
}
|
||||
return KeyboardModifier::None;
|
||||
}
|
||||
|
||||
bool ViewportManipulatorControllerInstance::HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event)
|
||||
{
|
||||
// We only care about manipulator and viewport interaction events
|
||||
if (event.m_priority != ManipulatorPriority && event.m_priority != InteractionPriority)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
using InteractionBus = AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus;
|
||||
using namespace AzToolsFramework::ViewportInteraction;
|
||||
using AzFramework::InputChannel;
|
||||
|
||||
bool interactionHandled = false;
|
||||
AZStd::optional<MouseButton> overrideButton;
|
||||
AZStd::optional<MouseEvent> eventType;
|
||||
|
||||
// Because we receive events multiple times at separate priorities for manipulator events and
|
||||
// viewport interaction events, we want to avoid updating our "last tick state" until we're on our last event,
|
||||
// which currently is the low priority Interaction processor.
|
||||
const bool finishedProcessingEvents = event.m_priority == InteractionPriority;
|
||||
|
||||
if (IsMouseMove(event.m_inputChannel))
|
||||
AzToolsFramework::ViewportInteraction::MouseButton ViewportManipulatorControllerInstance::GetMouseButton(
|
||||
const AzFramework::InputChannel& inputChannel)
|
||||
{
|
||||
// Cache the ray trace results when doing manipulator interaction checks, no need to recalculate after
|
||||
if (event.m_priority == ManipulatorPriority)
|
||||
using AzToolsFramework::ViewportInteraction::MouseButton;
|
||||
using InputButton = AzFramework::InputDeviceMouse::Button;
|
||||
const auto& id = inputChannel.GetInputChannelId();
|
||||
if (id == InputButton::Left)
|
||||
{
|
||||
AzFramework::ScreenPoint screenPosition = AzFramework::ScreenPoint(0, 0);
|
||||
ViewportMouseCursorRequestBus::EventResult(
|
||||
screenPosition, GetViewportId(), &ViewportMouseCursorRequestBus::Events::ViewportCursorScreenPosition);
|
||||
|
||||
m_state.m_mousePick.m_screenCoordinates = screenPosition;
|
||||
AZStd::optional<ProjectedViewportRay> ray;
|
||||
ViewportInteractionRequestBus::EventResult(
|
||||
ray, GetViewportId(), &ViewportInteractionRequestBus::Events::ViewportScreenToWorldRay, screenPosition);
|
||||
|
||||
if (ray.has_value())
|
||||
{
|
||||
m_state.m_mousePick.m_rayOrigin = ray.value().origin;
|
||||
m_state.m_mousePick.m_rayDirection = ray.value().direction;
|
||||
}
|
||||
return MouseButton::Left;
|
||||
}
|
||||
eventType = MouseEvent::Move;
|
||||
}
|
||||
else if (auto mouseButton = GetMouseButton(event.m_inputChannel); mouseButton != MouseButton::None)
|
||||
{
|
||||
const AZ::u32 mouseButtonValue = static_cast<AZ::u32>(mouseButton);
|
||||
overrideButton = mouseButton;
|
||||
if (event.m_inputChannel.GetState() == InputChannel::State::Began)
|
||||
if (id == InputButton::Middle)
|
||||
{
|
||||
m_state.m_mouseButtons.m_mouseButtons |= mouseButtonValue;
|
||||
if (IsDoubleClick(mouseButton))
|
||||
return MouseButton::Middle;
|
||||
}
|
||||
if (id == InputButton::Right)
|
||||
{
|
||||
return MouseButton::Right;
|
||||
}
|
||||
return MouseButton::None;
|
||||
}
|
||||
|
||||
bool ViewportManipulatorControllerInstance::IsMouseMove(const AzFramework::InputChannel& inputChannel)
|
||||
{
|
||||
return inputChannel.GetInputChannelId() == AzFramework::InputDeviceMouse::SystemCursorPosition;
|
||||
}
|
||||
|
||||
AzToolsFramework::ViewportInteraction::KeyboardModifier ViewportManipulatorControllerInstance::GetKeyboardModifier(
|
||||
const AzFramework::InputChannel& inputChannel)
|
||||
{
|
||||
using AzToolsFramework::ViewportInteraction::KeyboardModifier;
|
||||
using Key = AzFramework::InputDeviceKeyboard::Key;
|
||||
const auto& id = inputChannel.GetInputChannelId();
|
||||
if (id == Key::ModifierAltL || id == Key::ModifierAltR)
|
||||
{
|
||||
return KeyboardModifier::Alt;
|
||||
}
|
||||
if (id == Key::ModifierCtrlL || id == Key::ModifierCtrlR)
|
||||
{
|
||||
return KeyboardModifier::Ctrl;
|
||||
}
|
||||
if (id == Key::ModifierShiftL || id == Key::ModifierShiftR)
|
||||
{
|
||||
return KeyboardModifier::Shift;
|
||||
}
|
||||
return KeyboardModifier::None;
|
||||
}
|
||||
|
||||
bool ViewportManipulatorControllerInstance::HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event)
|
||||
{
|
||||
// We only care about manipulator and viewport interaction events
|
||||
if (event.m_priority != ManipulatorPriority && event.m_priority != InteractionPriority)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
using InteractionBus = AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus;
|
||||
using namespace AzToolsFramework::ViewportInteraction;
|
||||
using AzFramework::InputChannel;
|
||||
|
||||
bool interactionHandled = false;
|
||||
float wheelDelta = 0.0f;
|
||||
AZStd::optional<MouseButton> overrideButton;
|
||||
AZStd::optional<MouseEvent> eventType;
|
||||
|
||||
// Because we receive events multiple times at separate priorities for manipulator events and
|
||||
// viewport interaction events, we want to avoid updating our "last tick state" until we're on our last event,
|
||||
// which currently is the low priority Interaction processor.
|
||||
const bool finishedProcessingEvents = event.m_priority == InteractionPriority;
|
||||
|
||||
const auto state = event.m_inputChannel.GetState();
|
||||
if (IsMouseMove(event.m_inputChannel))
|
||||
{
|
||||
// Cache the ray trace results when doing manipulator interaction checks, no need to recalculate after
|
||||
if (event.m_priority == ManipulatorPriority)
|
||||
{
|
||||
// Only remove the double click flag once we're done processing both Manipulator and Interaction events
|
||||
if (event.m_priority == InteractionPriority)
|
||||
AzFramework::ScreenPoint screenPosition = AzFramework::ScreenPoint(0, 0);
|
||||
ViewportMouseCursorRequestBus::EventResult(
|
||||
screenPosition, GetViewportId(), &ViewportMouseCursorRequestBus::Events::ViewportCursorScreenPosition);
|
||||
|
||||
m_mouseInteraction.m_mousePick.m_screenCoordinates = screenPosition;
|
||||
AZStd::optional<ProjectedViewportRay> ray;
|
||||
ViewportInteractionRequestBus::EventResult(
|
||||
ray, GetViewportId(), &ViewportInteractionRequestBus::Events::ViewportScreenToWorldRay, screenPosition);
|
||||
|
||||
if (ray.has_value())
|
||||
{
|
||||
m_pendingDoubleClicks.erase(mouseButton);
|
||||
m_mouseInteraction.m_mousePick.m_rayOrigin = ray.value().origin;
|
||||
m_mouseInteraction.m_mousePick.m_rayDirection = ray.value().direction;
|
||||
}
|
||||
eventType = MouseEvent::DoubleClick;
|
||||
}
|
||||
else
|
||||
eventType = MouseEvent::Move;
|
||||
}
|
||||
else if (auto mouseButton = GetMouseButton(event.m_inputChannel); mouseButton != MouseButton::None)
|
||||
{
|
||||
const AZ::u32 mouseButtonValue = static_cast<AZ::u32>(mouseButton);
|
||||
overrideButton = mouseButton;
|
||||
if (state == InputChannel::State::Began)
|
||||
{
|
||||
// Only insert the double click timing once we're done processing events, to avoid a false IsDoubleClick positive
|
||||
if (finishedProcessingEvents)
|
||||
m_mouseInteraction.m_mouseButtons.m_mouseButtons |= mouseButtonValue;
|
||||
if (IsDoubleClick(mouseButton))
|
||||
{
|
||||
m_pendingDoubleClicks[mouseButton] = m_curTime;
|
||||
// Only remove the double click flag once we're done processing both Manipulator and Interaction events
|
||||
if (event.m_priority == InteractionPriority)
|
||||
{
|
||||
m_pendingDoubleClicks.erase(mouseButton);
|
||||
}
|
||||
eventType = MouseEvent::DoubleClick;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only insert the double click timing once we're done processing events, to avoid a false IsDoubleClick positive
|
||||
if (finishedProcessingEvents)
|
||||
{
|
||||
m_pendingDoubleClicks[mouseButton] = m_curTime;
|
||||
}
|
||||
eventType = MouseEvent::Down;
|
||||
}
|
||||
eventType = MouseEvent::Down;
|
||||
}
|
||||
}
|
||||
else if (event.m_inputChannel.GetState() == InputChannel::State::Ended)
|
||||
{
|
||||
// If we've actually logged a mouse down event, forward a mouse up event.
|
||||
// This prevents corner cases like the context menu thinking it should be opened even though no one clicked in this viewport,
|
||||
// due to RenderViewportWidget ensuring all controllers get InputChannel::State::Ended events.
|
||||
if (m_state.m_mouseButtons.m_mouseButtons & mouseButtonValue)
|
||||
else if (state == InputChannel::State::Ended)
|
||||
{
|
||||
// Erase the button from our state if we're done processing events.
|
||||
if (event.m_priority == InteractionPriority)
|
||||
// If we've actually logged a mouse down event, forward a mouse up event.
|
||||
// This prevents corner cases like the context menu thinking it should be opened even though no one clicked in this viewport,
|
||||
// due to RenderViewportWidget ensuring all controllers get InputChannel::State::Ended events.
|
||||
if (m_mouseInteraction.m_mouseButtons.m_mouseButtons & mouseButtonValue)
|
||||
{
|
||||
m_state.m_mouseButtons.m_mouseButtons &= ~mouseButtonValue;
|
||||
// Erase the button from our state if we're done processing events.
|
||||
if (event.m_priority == InteractionPriority)
|
||||
{
|
||||
m_mouseInteraction.m_mouseButtons.m_mouseButtons &= ~mouseButtonValue;
|
||||
}
|
||||
eventType = MouseEvent::Up;
|
||||
}
|
||||
eventType = MouseEvent::Up;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (auto keyboardModifier = GetKeyboardModifier(event.m_inputChannel); keyboardModifier != KeyboardModifier::None)
|
||||
{
|
||||
if (event.m_inputChannel.GetState() == InputChannel::State::Began || event.m_inputChannel.GetState() == InputChannel::State::Updated)
|
||||
else if (auto keyboardModifier = GetKeyboardModifier(event.m_inputChannel); keyboardModifier != KeyboardModifier::None)
|
||||
{
|
||||
m_state.m_keyboardModifiers.m_keyModifiers |= static_cast<AZ::u32>(keyboardModifier);
|
||||
if (state == InputChannel::State::Began || state == InputChannel::State::Updated)
|
||||
{
|
||||
m_mouseInteraction.m_keyboardModifiers.m_keyModifiers |= static_cast<AZ::u32>(keyboardModifier);
|
||||
}
|
||||
else if (state == InputChannel::State::Ended)
|
||||
{
|
||||
m_mouseInteraction.m_keyboardModifiers.m_keyModifiers &= ~static_cast<AZ::u32>(keyboardModifier);
|
||||
}
|
||||
}
|
||||
else if (event.m_inputChannel.GetState() == InputChannel::State::Ended)
|
||||
else if (event.m_inputChannel.GetInputChannelId() == AzFramework::InputDeviceMouse::Movement::Z)
|
||||
{
|
||||
m_state.m_keyboardModifiers.m_keyModifiers &= ~static_cast<AZ::u32>(keyboardModifier);
|
||||
if (state == InputChannel::State::Began || state == InputChannel::State::Updated)
|
||||
{
|
||||
eventType = MouseEvent::Wheel;
|
||||
wheelDelta = event.m_inputChannel.GetValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (eventType)
|
||||
{
|
||||
MouseInteraction mouseInteraction = m_state;
|
||||
if (overrideButton)
|
||||
if (eventType)
|
||||
{
|
||||
mouseInteraction.m_mouseButtons.m_mouseButtons = static_cast<AZ::u32>(overrideButton.value());
|
||||
MouseInteraction mouseInteraction = m_mouseInteraction;
|
||||
if (overrideButton)
|
||||
{
|
||||
mouseInteraction.m_mouseButtons.m_mouseButtons = static_cast<AZ::u32>(overrideButton.value());
|
||||
}
|
||||
|
||||
mouseInteraction.m_interactionId.m_viewportId = GetViewportId();
|
||||
|
||||
// Depending on priority, we dispatch to either the manipulator or viewport interaction event
|
||||
const auto& targetInteractionEvent = event.m_priority == ManipulatorPriority
|
||||
? &InteractionBus::Events::InternalHandleMouseManipulatorInteraction
|
||||
: &InteractionBus::Events::InternalHandleMouseViewportInteraction;
|
||||
|
||||
const auto mouseInteractionEvent = [mouseInteraction, event = eventType.value(), wheelDelta] {
|
||||
switch (event)
|
||||
{
|
||||
case MouseEvent::Up:
|
||||
case MouseEvent::Down:
|
||||
case MouseEvent::Move:
|
||||
case MouseEvent::DoubleClick:
|
||||
return MouseInteractionEvent(AZStd::move(mouseInteraction), event);
|
||||
case MouseEvent::Wheel:
|
||||
return MouseInteractionEvent(AZStd::move(mouseInteraction), wheelDelta);
|
||||
}
|
||||
|
||||
AZ_Assert(false, "Unhandled MouseEvent");
|
||||
return MouseInteractionEvent(MouseInteraction{}, MouseEvent::Up);
|
||||
}();
|
||||
|
||||
InteractionBus::EventResult(
|
||||
interactionHandled, AzToolsFramework::GetEntityContextId(), targetInteractionEvent, mouseInteractionEvent);
|
||||
}
|
||||
mouseInteraction.m_interactionId.m_viewportId = GetViewportId();
|
||||
|
||||
// Depending on priority, we dispatch to either the manipulator or viewport interaction event
|
||||
const auto& targetInteractionEvent =
|
||||
event.m_priority == ManipulatorPriority
|
||||
? &InteractionBus::Events::InternalHandleMouseManipulatorInteraction
|
||||
: &InteractionBus::Events::InternalHandleMouseViewportInteraction;
|
||||
|
||||
InteractionBus::EventResult(
|
||||
interactionHandled,
|
||||
AzToolsFramework::GetEntityContextId(),
|
||||
targetInteractionEvent,
|
||||
MouseInteractionEvent(AZStd::move(mouseInteraction), eventType.value()));
|
||||
return interactionHandled;
|
||||
}
|
||||
|
||||
return interactionHandled;
|
||||
}
|
||||
|
||||
void ViewportManipulatorControllerInstance::ResetInputChannels()
|
||||
{
|
||||
m_pendingDoubleClicks.clear();
|
||||
m_state = AzToolsFramework::ViewportInteraction::MouseInteraction();
|
||||
}
|
||||
|
||||
void ViewportManipulatorControllerInstance::UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event)
|
||||
{
|
||||
m_curTime = event.m_time;
|
||||
}
|
||||
|
||||
bool ViewportManipulatorControllerInstance::IsDoubleClick(AzToolsFramework::ViewportInteraction::MouseButton button) const
|
||||
{
|
||||
auto clickIt = m_pendingDoubleClicks.find(button);
|
||||
if (clickIt == m_pendingDoubleClicks.end())
|
||||
void ViewportManipulatorControllerInstance::ResetInputChannels()
|
||||
{
|
||||
return false;
|
||||
m_pendingDoubleClicks.clear();
|
||||
m_mouseInteraction = AzToolsFramework::ViewportInteraction::MouseInteraction();
|
||||
}
|
||||
const double doubleClickThresholdMilliseconds = qApp->doubleClickInterval();
|
||||
return (m_curTime.GetMilliseconds() - clickIt->second.GetMilliseconds()) < doubleClickThresholdMilliseconds;
|
||||
}
|
||||
|
||||
void ViewportManipulatorControllerInstance::UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event)
|
||||
{
|
||||
m_curTime = event.m_time;
|
||||
}
|
||||
|
||||
bool ViewportManipulatorControllerInstance::IsDoubleClick(AzToolsFramework::ViewportInteraction::MouseButton button) const
|
||||
{
|
||||
auto clickIt = m_pendingDoubleClicks.find(button);
|
||||
if (clickIt == m_pendingDoubleClicks.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const double doubleClickThresholdMilliseconds = qApp->doubleClickInterval();
|
||||
return (m_curTime.GetMilliseconds() - clickIt->second.GetMilliseconds()) < doubleClickThresholdMilliseconds;
|
||||
}
|
||||
} //namespace SandboxEditor
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace SandboxEditor
|
||||
static bool IsMouseMove(const AzFramework::InputChannel& inputChannel);
|
||||
static AzToolsFramework::ViewportInteraction::KeyboardModifier GetKeyboardModifier(const AzFramework::InputChannel& inputChannel);
|
||||
|
||||
AzToolsFramework::ViewportInteraction::MouseInteraction m_state;
|
||||
AzToolsFramework::ViewportInteraction::MouseInteraction m_mouseInteraction;
|
||||
AZStd::unordered_map<AzToolsFramework::ViewportInteraction::MouseButton, AZ::ScriptTimePoint> m_pendingDoubleClicks;
|
||||
AZ::ScriptTimePoint m_curTime;
|
||||
};
|
||||
|
||||
@@ -280,8 +280,6 @@ set(FILES
|
||||
Include/IAnimationCompressionManager.h
|
||||
Include/IAssetItem.h
|
||||
Include/IAssetItemDatabase.h
|
||||
Include/IBackgroundScheduleManager.h
|
||||
Include/IBackgroundTaskManager.h
|
||||
Include/ICommandManager.h
|
||||
Include/IConsoleConnectivity.h
|
||||
Include/IDataBaseItem.h
|
||||
@@ -343,10 +341,6 @@ set(FILES
|
||||
AssetEditor/AssetEditorWindow.cpp
|
||||
AssetEditor/AssetEditorWindow.h
|
||||
AssetEditor/AssetEditorWindow.ui
|
||||
BackgroundTaskManager.cpp
|
||||
BackgroundScheduleManager.cpp
|
||||
BackgroundTaskManager.h
|
||||
BackgroundScheduleManager.h
|
||||
Commands/CommandManager.cpp
|
||||
Commands/CommandManager.h
|
||||
Controls/BitmapToolTip.cpp
|
||||
@@ -357,8 +351,6 @@ set(FILES
|
||||
Controls/ConsoleSCB.h
|
||||
Controls/ConsoleSCB.ui
|
||||
Controls/ConsoleSCB.qrc
|
||||
Controls/CurveEditorCtrl.cpp
|
||||
Controls/CurveEditorCtrl.h
|
||||
Controls/FolderTreeCtrl.cpp
|
||||
Controls/FolderTreeCtrl.h
|
||||
Controls/HotTrackingTreeCtrl.cpp
|
||||
@@ -575,11 +567,6 @@ set(FILES
|
||||
QtUI/WaitCursor.cpp
|
||||
RenderHelpers/AxisHelper.cpp
|
||||
RenderHelpers/AxisHelper.h
|
||||
Serialization.h
|
||||
Serialization/VariableOArchive.cpp
|
||||
Serialization/VariableOArchive.h
|
||||
Serialization/VariableIArchive.cpp
|
||||
Serialization/VariableIArchive.h
|
||||
CustomizeKeyboardDialog.h
|
||||
CustomizeKeyboardDialog.cpp
|
||||
CustomizeKeyboardDialog.ui
|
||||
@@ -738,8 +725,6 @@ set(FILES
|
||||
TrackView/TrackViewEventNode.h
|
||||
ConfigGroup.cpp
|
||||
ConfigGroup.h
|
||||
SettingsBlock.cpp
|
||||
SettingsBlock.h
|
||||
Util/AffineParts.h
|
||||
Util/AutoLogTime.cpp
|
||||
Util/AutoLogTime.h
|
||||
|
||||
Reference in New Issue
Block a user