Merge remote-tracking branch 'upstream/main' into DisableAtomShim
commit
40a35b4e45
@ -1,588 +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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "QRollupCtrl.h"
|
||||
|
||||
// Qt
|
||||
#include <QMenu>
|
||||
#include <QStylePainter>
|
||||
#include <QVBoxLayout>
|
||||
#include <QSettings>
|
||||
#include <QToolButton>
|
||||
#include <QStyleOptionToolButton>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class QRollupCtrlButton
|
||||
: public QToolButton
|
||||
{
|
||||
public:
|
||||
QRollupCtrlButton(QWidget* parent);
|
||||
|
||||
inline void setSelected(bool b) { selected = b; update(); }
|
||||
inline bool isSelected() const { return selected; }
|
||||
|
||||
QSize sizeHint() const override;
|
||||
QSize minimumSizeHint() const override;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent*) override;
|
||||
|
||||
private:
|
||||
bool selected;
|
||||
};
|
||||
|
||||
QRollupCtrlButton::QRollupCtrlButton(QWidget* parent)
|
||||
: QToolButton(parent)
|
||||
, selected(true)
|
||||
{
|
||||
setBackgroundRole(QPalette::Window);
|
||||
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
|
||||
setFocusPolicy(Qt::NoFocus);
|
||||
|
||||
setStyleSheet("* {margin: 2px 5px 2px 5px; border: 1px solid #CBA457;}");
|
||||
}
|
||||
|
||||
QSize QRollupCtrlButton::sizeHint() const
|
||||
{
|
||||
QSize iconSize(8, 8);
|
||||
if (!icon().isNull())
|
||||
{
|
||||
int icone = style()->pixelMetric(QStyle::PM_SmallIconSize);
|
||||
iconSize += QSize(icone + 2, icone);
|
||||
}
|
||||
QSize textSize = fontMetrics().size(Qt::TextShowMnemonic, text()) + QSize(0, 8);
|
||||
|
||||
QSize total(iconSize.width() + textSize.width(), qMax(iconSize.height(), textSize.height()));
|
||||
return total.expandedTo(QApplication::globalStrut());
|
||||
}
|
||||
|
||||
QSize QRollupCtrlButton::minimumSizeHint() const
|
||||
{
|
||||
if (icon().isNull())
|
||||
{
|
||||
return QSize();
|
||||
}
|
||||
int icone = style()->pixelMetric(QStyle::PM_SmallIconSize);
|
||||
return QSize(icone + 8, icone + 8);
|
||||
}
|
||||
|
||||
void QRollupCtrlButton::paintEvent(QPaintEvent*)
|
||||
{
|
||||
QStylePainter p(this);
|
||||
// draw the background manually, not to clash with UI 2.0 style shets
|
||||
// the numbers here are taken from the stylesheet in the constructor
|
||||
p.fillRect(QRect(5, 1, width() - 10, height() - 3), QColor(52, 52, 52));
|
||||
|
||||
{
|
||||
QStyleOptionToolButton opt;
|
||||
initStyleOption(&opt);
|
||||
if (isSelected())
|
||||
{
|
||||
if (opt.state & QStyle::State_MouseOver)
|
||||
{
|
||||
opt.state |= QStyle::State_Sunken;
|
||||
}
|
||||
opt.state |= QStyle::State_MouseOver;
|
||||
}
|
||||
p.drawComplexControl(QStyle::CC_ToolButton, opt);
|
||||
}
|
||||
|
||||
{
|
||||
p.setPen(QPen(QColor(132, 128, 125)));
|
||||
|
||||
int top = height() / 2 - 2;
|
||||
p.drawLine(2, top, 4, top);
|
||||
p.drawLine(width() - 5, top, width() - 3, top);
|
||||
|
||||
int bottom = !isSelected() ? top + 4 : height();
|
||||
p.drawLine(2, bottom, 2, top);
|
||||
p.drawLine(width() - 3, bottom, width() - 3, top);
|
||||
|
||||
if (!isSelected())
|
||||
{
|
||||
p.drawLine(2, bottom, 4, bottom);
|
||||
p.drawLine(width() - 5, bottom, width() - 3, bottom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
QRollupCtrl::Page* QRollupCtrl::page(QWidget* widget) const
|
||||
{
|
||||
if (!widget)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (PageList::ConstIterator i = m_pageList.constBegin(); i != m_pageList.constEnd(); ++i)
|
||||
{
|
||||
if ((*i).widget == widget)
|
||||
{
|
||||
return (Page*)&(*i);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
QRollupCtrl::Page* QRollupCtrl::page(int index)
|
||||
{
|
||||
if (index >= 0 && index < m_pageList.size())
|
||||
{
|
||||
return &m_pageList[index];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const QRollupCtrl::Page* QRollupCtrl::page(int index) const
|
||||
{
|
||||
if (index >= 0 && index < m_pageList.size())
|
||||
{
|
||||
return &m_pageList.at(index);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void QRollupCtrl::Page::setText(const QString& text) { button->setText(text); }
|
||||
inline void QRollupCtrl::Page::setIcon(const QIcon& is) { button->setIcon(is); }
|
||||
inline void QRollupCtrl::Page::setToolTip(const QString& tip) { button->setToolTip(tip); }
|
||||
inline QString QRollupCtrl::Page::text() const { return button->text(); }
|
||||
inline QIcon QRollupCtrl::Page::icon() const { return button->icon(); }
|
||||
inline QString QRollupCtrl::Page::toolTip() const { return button->toolTip(); }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
QRollupCtrl::QRollupCtrl(QWidget* parent)
|
||||
: QScrollArea(parent)
|
||||
, m_layout(0)
|
||||
{
|
||||
m_body = new QWidget(this);
|
||||
m_body->setBackgroundRole(QPalette::Button);
|
||||
setWidgetResizable(true);
|
||||
setAlignment(Qt::AlignLeft | Qt::AlignTop);
|
||||
setWidget(m_body);
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||
relayout();
|
||||
}
|
||||
|
||||
QRollupCtrl::~QRollupCtrl()
|
||||
{
|
||||
foreach(const QRollupCtrl::Page & c, m_pageList)
|
||||
disconnect(c.widget, &QObject::destroyed, this, &QRollupCtrl::_q_widgetDestroyed);
|
||||
}
|
||||
|
||||
void QRollupCtrl::readSettings(const QString& qSettingsGroup)
|
||||
{
|
||||
QSettings settings;
|
||||
settings.beginGroup(qSettingsGroup);
|
||||
|
||||
int i = 0;
|
||||
foreach(const QRollupCtrl::Page & c, m_pageList) {
|
||||
QString qObjectName = c.widget->objectName();
|
||||
|
||||
bool bHidden = settings.value(qObjectName, true).toBool();
|
||||
setIndexVisible(i++, !bHidden);
|
||||
}
|
||||
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
void QRollupCtrl::writeSettings(const QString& qSettingsGroup)
|
||||
{
|
||||
QSettings settings;
|
||||
settings.beginGroup(qSettingsGroup);
|
||||
|
||||
for (int i = 0; i < count(); i++)
|
||||
{
|
||||
QString qObjectName;
|
||||
bool bHidden = isPageHidden(i, qObjectName);
|
||||
|
||||
settings.setValue(qObjectName, bHidden);
|
||||
}
|
||||
}
|
||||
|
||||
void QRollupCtrl::updateTabs()
|
||||
{
|
||||
for (auto i = m_pageList.constBegin(); i != m_pageList.constEnd(); ++i)
|
||||
{
|
||||
QRollupCtrlButton* tB = (*i).button;
|
||||
QWidget* tW = (*i).sv;
|
||||
tB->setSelected(tW->isVisible());
|
||||
tB->update();
|
||||
}
|
||||
}
|
||||
|
||||
int QRollupCtrl::insertItem(int index, QWidget* widget, const QIcon& icon, const QString& text)
|
||||
{
|
||||
if (!widget)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto it = std::find_if(m_pageList.cbegin(), m_pageList.cend(), [widget](const Page& page) { return page.widget == widget; });
|
||||
if (it != m_pageList.cend())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
connect(widget, &QObject::destroyed, this, &QRollupCtrl::_q_widgetDestroyed);
|
||||
|
||||
QRollupCtrl::Page c;
|
||||
c.widget = widget;
|
||||
c.button = new QRollupCtrlButton(m_body);
|
||||
c.button->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(c.button, &QRollupCtrlButton::clicked, this, &QRollupCtrl::_q_buttonClicked);
|
||||
connect(c.button, &QRollupCtrlButton::customContextMenuRequested, this, &QRollupCtrl::_q_custumButtonMenu);
|
||||
|
||||
c.sv = new QFrame(m_body);
|
||||
c.sv->setObjectName("rollupPaneFrame");
|
||||
// c.sv->setFixedHeight(qMax(widget->sizeHint().height(), widget->size().height()));
|
||||
QVBoxLayout* layout = new QVBoxLayout;
|
||||
layout->setMargin(3);
|
||||
layout->addWidget(widget);
|
||||
c.sv->setLayout(layout);
|
||||
c.sv->setStyleSheet("QFrame#rollupPaneFrame {margin: 0px 2px 2px 2px; border: 1px solid #84807D; border-top:0px;}");
|
||||
c.sv->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
c.sv->show();
|
||||
|
||||
c.setText(text);
|
||||
c.setIcon(icon);
|
||||
|
||||
const int numPages = m_pageList.count();
|
||||
if (index < 0 || index >= numPages)
|
||||
{
|
||||
m_pageList.append(c);
|
||||
index = numPages - 1;
|
||||
m_layout->insertWidget(m_layout->count() - 1, c.button);
|
||||
m_layout->insertWidget(m_layout->count() - 1, c.sv);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pageList.insert(index, c);
|
||||
relayout();
|
||||
}
|
||||
|
||||
c.button->show();
|
||||
|
||||
updateTabs();
|
||||
itemInserted(index);
|
||||
return index;
|
||||
}
|
||||
|
||||
void QRollupCtrl::_q_buttonClicked()
|
||||
{
|
||||
QObject* tb = sender();
|
||||
QWidget* item = 0;
|
||||
for (auto i = m_pageList.constBegin(); i != m_pageList.constEnd(); ++i)
|
||||
{
|
||||
if ((*i).button == tb)
|
||||
{
|
||||
item = (*i).widget;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (item)
|
||||
{
|
||||
setIndexVisible(indexOf(item), !item->isVisible());
|
||||
}
|
||||
}
|
||||
|
||||
int QRollupCtrl::count() const
|
||||
{
|
||||
return m_pageList.count();
|
||||
}
|
||||
|
||||
bool QRollupCtrl::isPageHidden(int index, QString& qObjectName) const
|
||||
{
|
||||
if (index < 0 || index >= m_pageList.size())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
const QRollupCtrl::Page& c = m_pageList.at(index);
|
||||
qObjectName = c.widget->objectName();
|
||||
return c.sv->isHidden();
|
||||
}
|
||||
|
||||
void QRollupCtrl::setIndexVisible(int index, bool visible)
|
||||
{
|
||||
QRollupCtrl::Page* c = page(index);
|
||||
if (!c)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (c->sv->isHidden() && visible)
|
||||
{
|
||||
c->sv->show();
|
||||
}
|
||||
else if (c->sv->isVisible() && !visible)
|
||||
{
|
||||
c->sv->hide();
|
||||
}
|
||||
updateTabs();
|
||||
}
|
||||
|
||||
void QRollupCtrl::setWidgetVisible(QWidget* widget, bool visible)
|
||||
{
|
||||
setIndexVisible(indexOf(widget), visible);
|
||||
}
|
||||
|
||||
void QRollupCtrl::relayout()
|
||||
{
|
||||
delete m_layout;
|
||||
m_layout = new QVBoxLayout(m_body);
|
||||
m_layout->setMargin(3);
|
||||
m_layout->setSpacing(0);
|
||||
for (QRollupCtrl::PageList::ConstIterator i = m_pageList.constBegin(); i != m_pageList.constEnd(); ++i)
|
||||
{
|
||||
m_layout->addWidget((*i).button);
|
||||
m_layout->addWidget((*i).sv);
|
||||
}
|
||||
m_layout->addStretch();
|
||||
updateTabs();
|
||||
}
|
||||
|
||||
void QRollupCtrl::_q_widgetDestroyed(QObject* object)
|
||||
{
|
||||
// no verification - vtbl corrupted already
|
||||
QWidget* p = (QWidget*)object;
|
||||
|
||||
QRollupCtrl::Page* c = page(p);
|
||||
if (!p || !c)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_layout->removeWidget(c->sv);
|
||||
m_layout->removeWidget(c->button);
|
||||
c->sv->deleteLater(); // page might still be a child of sv
|
||||
delete c->button;
|
||||
|
||||
m_pageList.removeOne(*c);
|
||||
}
|
||||
|
||||
void QRollupCtrl::_q_custumButtonMenu([[maybe_unused]] const QPoint& pos)
|
||||
{
|
||||
QMenu menu;
|
||||
menu.addAction("Expand All")->setData(-1);
|
||||
menu.addAction("Collapse All")->setData(-2);
|
||||
menu.addSeparator();
|
||||
for (int i = 0; i < m_pageList.size(); ++i)
|
||||
{
|
||||
QRollupCtrl::Page* c = page(i);
|
||||
QAction* action = menu.addAction(c->button->text());
|
||||
action->setCheckable(true);
|
||||
action->setChecked(c->sv->isVisible());
|
||||
action->setData(i);
|
||||
}
|
||||
|
||||
QAction* action = menu.exec(QCursor::pos());
|
||||
if (!action)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int res = action->data().toInt();
|
||||
switch (res)
|
||||
{
|
||||
case -1: // fall through
|
||||
case -2:
|
||||
expandAllPages(res == -1);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
QRollupCtrl::Page* c = page(res);
|
||||
if (c)
|
||||
{
|
||||
setIndexVisible(res, !c->sv->isVisible());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void QRollupCtrl::expandAllPages(bool v)
|
||||
{
|
||||
for (int i = 0; i < m_pageList.size(); i++)
|
||||
{
|
||||
setIndexVisible(i, v);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void QRollupCtrl::clear()
|
||||
{
|
||||
while (!m_pageList.isEmpty())
|
||||
{
|
||||
removeItem(0);
|
||||
}
|
||||
}
|
||||
|
||||
void QRollupCtrl::removeItem(QWidget* widget)
|
||||
{
|
||||
auto it = std::find_if(m_pageList.cbegin(), m_pageList.cend(), [widget](const Page& page) { return page.widget == widget; });
|
||||
if (it != m_pageList.cend())
|
||||
{
|
||||
removeItem(it - m_pageList.cbegin());
|
||||
}
|
||||
}
|
||||
|
||||
void QRollupCtrl::removeItem(int index)
|
||||
{
|
||||
if (QWidget* w = widget(index))
|
||||
{
|
||||
disconnect(w, &QObject::destroyed, this, &QRollupCtrl::_q_widgetDestroyed);
|
||||
w->setParent(this);
|
||||
// destroy internal data
|
||||
_q_widgetDestroyed(w);
|
||||
itemRemoved(index);
|
||||
}
|
||||
}
|
||||
|
||||
QWidget* QRollupCtrl::widget(int index) const
|
||||
{
|
||||
if (index < 0 || index >= (int) m_pageList.size())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return m_pageList.at(index).widget;
|
||||
}
|
||||
|
||||
int QRollupCtrl::indexOf(QWidget* widget) const
|
||||
{
|
||||
QRollupCtrl::Page* c = page(widget);
|
||||
return c ? m_pageList.indexOf(*c) : -1;
|
||||
}
|
||||
|
||||
void QRollupCtrl::setItemEnabled(int index, bool enabled)
|
||||
{
|
||||
QRollupCtrl::Page* c = page(index);
|
||||
if (!c)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
c->button->setEnabled(enabled);
|
||||
if (!enabled)
|
||||
{
|
||||
int curIndexUp = index;
|
||||
int curIndexDown = curIndexUp;
|
||||
const int count = m_pageList.count();
|
||||
while (curIndexUp > 0 || curIndexDown < count - 1)
|
||||
{
|
||||
if (curIndexDown < count - 1)
|
||||
{
|
||||
if (page(++curIndexDown)->button->isEnabled())
|
||||
{
|
||||
index = curIndexDown;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (curIndexUp > 0)
|
||||
{
|
||||
if (page(--curIndexUp)->button->isEnabled())
|
||||
{
|
||||
index = curIndexUp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QRollupCtrl::setItemText(int index, const QString& text)
|
||||
{
|
||||
QRollupCtrl::Page* c = page(index);
|
||||
if (c)
|
||||
{
|
||||
c->setText(text);
|
||||
}
|
||||
}
|
||||
|
||||
void QRollupCtrl::setItemIcon(int index, const QIcon& icon)
|
||||
{
|
||||
QRollupCtrl::Page* c = page(index);
|
||||
if (c)
|
||||
{
|
||||
c->setIcon(icon);
|
||||
}
|
||||
}
|
||||
|
||||
void QRollupCtrl::setItemToolTip(int index, const QString& toolTip)
|
||||
{
|
||||
QRollupCtrl::Page* c = page(index);
|
||||
if (c)
|
||||
{
|
||||
c->setToolTip(toolTip);
|
||||
}
|
||||
}
|
||||
|
||||
bool QRollupCtrl::isItemEnabled(int index) const
|
||||
{
|
||||
const QRollupCtrl::Page* c = page(index);
|
||||
return c && c->button->isEnabled();
|
||||
}
|
||||
|
||||
QString QRollupCtrl::itemText(int index) const
|
||||
{
|
||||
const QRollupCtrl::Page* c = page(index);
|
||||
return (c ? c->text() : QString());
|
||||
}
|
||||
|
||||
QIcon QRollupCtrl::itemIcon(int index) const
|
||||
{
|
||||
const QRollupCtrl::Page* c = page(index);
|
||||
return (c ? c->icon() : QIcon());
|
||||
}
|
||||
|
||||
QString QRollupCtrl::itemToolTip(int index) const
|
||||
{
|
||||
const QRollupCtrl::Page* c = page(index);
|
||||
return (c ? c->toolTip() : QString());
|
||||
}
|
||||
|
||||
void QRollupCtrl::changeEvent(QEvent* ev)
|
||||
{
|
||||
if (ev->type() == QEvent::StyleChange)
|
||||
{
|
||||
updateTabs();
|
||||
}
|
||||
QFrame::changeEvent(ev);
|
||||
}
|
||||
|
||||
void QRollupCtrl::showEvent(QShowEvent* ev)
|
||||
{
|
||||
if (isVisible())
|
||||
{
|
||||
updateTabs();
|
||||
}
|
||||
IEditor* pEditor = GetIEditor();
|
||||
pEditor->SetEditMode(EEditMode::eEditModeSelect);
|
||||
QFrame::showEvent(ev);
|
||||
}
|
||||
|
||||
void QRollupCtrl::itemInserted(int index)
|
||||
{
|
||||
Q_UNUSED(index)
|
||||
}
|
||||
|
||||
void QRollupCtrl::itemRemoved(int index)
|
||||
{
|
||||
Q_UNUSED(index)
|
||||
}
|
||||
|
||||
|
||||
#include <Controls/moc_QRollupCtrl.cpp>
|
||||
@ -1,126 +0,0 @@
|
||||
#ifndef CRYINCLUDE_EDITOR_CONTROLS_QROLLUPCTRL_H
|
||||
#define CRYINCLUDE_EDITOR_CONTROLS_QROLLUPCTRL_H
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <QFrame>
|
||||
#include <QScrollArea>
|
||||
#include <QIcon>
|
||||
#endif
|
||||
|
||||
class QVBoxLayout;
|
||||
class QRollupCtrlButton;
|
||||
|
||||
class QRollupCtrl
|
||||
: public QScrollArea
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int count READ count)
|
||||
|
||||
public:
|
||||
explicit QRollupCtrl(QWidget* parent = 0);
|
||||
~QRollupCtrl();
|
||||
|
||||
int addItem(QWidget* widget, const QString& text);
|
||||
int addItem(QWidget* widget, const QIcon& icon, const QString& text);
|
||||
int insertItem(int index, QWidget* widget, const QString& text);
|
||||
int insertItem(int index, QWidget* widget, const QIcon& icon, const QString& text);
|
||||
|
||||
void clear();
|
||||
void removeItem(QWidget* widget);
|
||||
void removeItem(int index);
|
||||
|
||||
void setItemEnabled(int index, bool enabled);
|
||||
bool isItemEnabled(int index) const;
|
||||
|
||||
void setItemText(int index, const QString& text);
|
||||
QString itemText(int index) const;
|
||||
|
||||
void setItemIcon(int index, const QIcon& icon);
|
||||
QIcon itemIcon(int index) const;
|
||||
|
||||
void setItemToolTip(int index, const QString& toolTip);
|
||||
QString itemToolTip(int index) const;
|
||||
|
||||
QWidget* widget(int index) const;
|
||||
int indexOf(QWidget* widget) const;
|
||||
int count() const;
|
||||
|
||||
void readSettings (const QString& qSettingsGroup);
|
||||
void writeSettings(const QString& qSettingsGroup);
|
||||
|
||||
public slots:
|
||||
void setIndexVisible(int index, bool visible);
|
||||
void setWidgetVisible(QWidget* widget, bool visible);
|
||||
void expandAllPages(bool v);
|
||||
|
||||
protected:
|
||||
virtual void itemInserted(int index);
|
||||
virtual void itemRemoved(int index);
|
||||
void changeEvent(QEvent*) override;
|
||||
void showEvent(QShowEvent*) override;
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(QRollupCtrl)
|
||||
|
||||
struct Page
|
||||
{
|
||||
QRollupCtrlButton* button;
|
||||
QFrame* sv;
|
||||
QWidget* widget;
|
||||
|
||||
void setText(const QString& text);
|
||||
void setIcon(const QIcon& is);
|
||||
void setToolTip(const QString& tip);
|
||||
QString text() const;
|
||||
QIcon icon() const;
|
||||
QString toolTip() const;
|
||||
|
||||
inline bool operator==(const Page& other) const
|
||||
{
|
||||
return widget == other.widget;
|
||||
}
|
||||
};
|
||||
typedef QList<Page> PageList;
|
||||
|
||||
Page* page(QWidget* widget) const;
|
||||
const Page* page(int index) const;
|
||||
Page* page(int index);
|
||||
|
||||
void updateTabs();
|
||||
void relayout();
|
||||
bool isPageHidden(int index, QString& qObjectName) const;
|
||||
|
||||
QWidget* m_body;
|
||||
PageList m_pageList;
|
||||
QVBoxLayout* m_layout;
|
||||
|
||||
private slots:
|
||||
void _q_buttonClicked();
|
||||
void _q_widgetDestroyed(QObject*);
|
||||
void _q_custumButtonMenu(const QPoint&);
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline int QRollupCtrl::addItem(QWidget* item, const QString& text)
|
||||
{ return insertItem(-1, item, QIcon(), text); }
|
||||
inline int QRollupCtrl::addItem(QWidget* item, const QIcon& iconSet, const QString& text)
|
||||
{ return insertItem(-1, item, iconSet, text); }
|
||||
inline int QRollupCtrl::insertItem(int index, QWidget* item, const QString& text)
|
||||
{ return insertItem(index, item, QIcon(), text); }
|
||||
|
||||
#endif
|
||||
@ -1,171 +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.
|
||||
|
||||
// Description : implementation file
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
// Editor
|
||||
#include "CryEditDoc.h"
|
||||
#include "EditTool.h"
|
||||
#include "ToolButton.h"
|
||||
|
||||
|
||||
QEditorToolButton::QEditorToolButton(QWidget* parent /* = nullptr */)
|
||||
: QPushButton(parent)
|
||||
, m_styleSheet(styleSheet())
|
||||
, m_toolClass(nullptr)
|
||||
, m_toolCreated(nullptr)
|
||||
, m_needDocument(true)
|
||||
{
|
||||
setSizePolicy({ QSizePolicy::Expanding, QSizePolicy::Fixed });
|
||||
connect(this, &QAbstractButton::clicked, this, &QEditorToolButton::OnClicked);
|
||||
GetIEditor()->RegisterNotifyListener(this);
|
||||
}
|
||||
|
||||
QEditorToolButton::~QEditorToolButton()
|
||||
{
|
||||
GetIEditor()->UnregisterNotifyListener(this);
|
||||
}
|
||||
|
||||
void QEditorToolButton::SetToolName(const QString& editToolName, const QString& userDataKey, void* userData)
|
||||
{
|
||||
IClassDesc* klass = GetIEditor()->GetClassFactory()->FindClass(editToolName.toUtf8().data());
|
||||
if (!klass)
|
||||
{
|
||||
Warning(QStringLiteral("Editor Tool %1 not registered.").arg(editToolName).toUtf8().data());
|
||||
return;
|
||||
}
|
||||
if (klass->SystemClassID() != ESYSTEM_CLASS_EDITTOOL)
|
||||
{
|
||||
Warning(QStringLiteral("Class name %1 is not a valid Edit Tool class.").arg(editToolName).toUtf8().data());
|
||||
return;
|
||||
}
|
||||
|
||||
QScopedPointer<QObject> o(klass->CreateQObject());
|
||||
if (!qobject_cast<CEditTool*>(o.data()))
|
||||
{
|
||||
Warning(QStringLiteral("Class name %1 is not a valid Edit Tool class.").arg(editToolName).toUtf8().data());
|
||||
return;
|
||||
}
|
||||
SetToolClass(o->metaObject(), userDataKey, userData);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void QEditorToolButton::SetToolClass(const QMetaObject* toolClass, const QString& userDataKey, void* userData)
|
||||
{
|
||||
m_toolClass = toolClass;
|
||||
|
||||
m_userData = userData;
|
||||
if (!userDataKey.isEmpty())
|
||||
{
|
||||
m_userDataKey = userDataKey;
|
||||
}
|
||||
}
|
||||
|
||||
void QEditorToolButton::OnEditorNotifyEvent(EEditorNotifyEvent event)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case eNotify_OnBeginNewScene:
|
||||
case eNotify_OnBeginLoad:
|
||||
case eNotify_OnBeginSceneOpen:
|
||||
{
|
||||
if (m_needDocument)
|
||||
{
|
||||
setEnabled(false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case eNotify_OnEndNewScene:
|
||||
case eNotify_OnEndLoad:
|
||||
case eNotify_OnEndSceneOpen:
|
||||
{
|
||||
if (m_needDocument)
|
||||
{
|
||||
setEnabled(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case eNotify_OnEditToolChange:
|
||||
{
|
||||
CEditTool* tool = GetIEditor()->GetEditTool();
|
||||
|
||||
if (!tool || tool != m_toolCreated || tool->metaObject() != m_toolClass)
|
||||
{
|
||||
m_toolCreated = nullptr;
|
||||
SetSelected(false);
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void QEditorToolButton::OnClicked()
|
||||
{
|
||||
if (!m_toolClass)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_needDocument && !GetIEditor()->GetDocument()->IsDocumentReady())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CEditTool* tool = GetIEditor()->GetEditTool();
|
||||
if (tool && tool->IsMoveToObjectModeAfterEnd() && tool->metaObject() == m_toolClass && tool == m_toolCreated)
|
||||
{
|
||||
GetIEditor()->SetEditTool(nullptr);
|
||||
SetSelected(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
CEditTool* newTool = qobject_cast<CEditTool*>(m_toolClass->newInstance());
|
||||
if (!newTool)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_toolCreated = newTool;
|
||||
|
||||
SetSelected(true);
|
||||
|
||||
if (m_userData)
|
||||
{
|
||||
newTool->SetUserData(m_userDataKey.toUtf8().data(), (void*)m_userData);
|
||||
}
|
||||
|
||||
update();
|
||||
|
||||
// Must be last function, can delete this.
|
||||
GetIEditor()->SetEditTool(newTool);
|
||||
}
|
||||
}
|
||||
|
||||
void QEditorToolButton::SetSelected(bool selected)
|
||||
{
|
||||
if (selected)
|
||||
{
|
||||
setStyleSheet(QStringLiteral("QPushButton { background-color: palette(highlight); color: palette(highlighted-text); }"));
|
||||
}
|
||||
else
|
||||
{
|
||||
setStyleSheet(m_styleSheet);
|
||||
}
|
||||
}
|
||||
|
||||
#include <Controls/moc_ToolButton.cpp>
|
||||
@ -1,60 +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_TOOLBUTTON_H
|
||||
#define CRYINCLUDE_EDITOR_CONTROLS_TOOLBUTTON_H
|
||||
#pragma once
|
||||
|
||||
// ToolButton.h : header file
|
||||
//
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/PlatformDef.h>
|
||||
#include <QPushButton>
|
||||
#endif
|
||||
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_BASECLASS_WARNING
|
||||
class SANDBOX_API QEditorToolButton
|
||||
: public QPushButton
|
||||
, public IEditorNotifyListener
|
||||
{
|
||||
AZ_POP_DISABLE_DLL_EXPORT_BASECLASS_WARNING
|
||||
Q_OBJECT
|
||||
// Construction
|
||||
public:
|
||||
QEditorToolButton(QWidget* parent = nullptr);
|
||||
virtual ~QEditorToolButton();
|
||||
|
||||
void SetToolClass(const QMetaObject* toolClass, const QString& userDataKey = 0, void* userData = nullptr);
|
||||
void SetToolName(const QString& editToolName, const QString& userDataKey = 0, void* userData = nullptr);
|
||||
// Set if this tool button relies on a loaded level / ready document. By default every tool button only works if a level is loaded.
|
||||
// However some tools are also used without a loaded level (e.g. UI Emulator)
|
||||
void SetNeedDocument(bool needDocument) { m_needDocument = needDocument; }
|
||||
|
||||
void SetSelected(bool selected);
|
||||
void OnEditorNotifyEvent(EEditorNotifyEvent event) override;
|
||||
protected:
|
||||
void OnClicked();
|
||||
|
||||
const QString m_styleSheet;
|
||||
|
||||
//! Tool associated with this button.
|
||||
const QMetaObject* m_toolClass;
|
||||
CEditTool* m_toolCreated;
|
||||
QString m_userDataKey;
|
||||
void* m_userData;
|
||||
bool m_needDocument;
|
||||
};
|
||||
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_CONTROLS_TOOLBUTTON_H
|
||||
@ -1,123 +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 "ButtonsPanel.h"
|
||||
|
||||
// Qt
|
||||
#include <QGridLayout>
|
||||
|
||||
// Editor
|
||||
#include "Controls/ToolButton.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CButtonsPanel dialog
|
||||
CButtonsPanel::CButtonsPanel(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
}
|
||||
|
||||
CButtonsPanel::~CButtonsPanel()
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CButtonsPanel::AddButton(const SButtonInfo& button)
|
||||
{
|
||||
SButton b;
|
||||
b.info = button;
|
||||
m_buttons.push_back(b);
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CButtonsPanel::AddButton(const QString& name, const QString& toolClass)
|
||||
{
|
||||
SButtonInfo bi;
|
||||
bi.name = name;
|
||||
bi.toolClassName = toolClass;
|
||||
AddButton(bi);
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CButtonsPanel::AddButton(const QString& name, const QMetaObject* pToolClass)
|
||||
{
|
||||
SButtonInfo bi;
|
||||
bi.name = name;
|
||||
bi.pToolClass = pToolClass;
|
||||
AddButton(bi);
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CButtonsPanel::ClearButtons()
|
||||
{
|
||||
auto buttons = layout()->findChildren<QEditorToolButton*>();
|
||||
foreach(auto button, buttons)
|
||||
{
|
||||
layout()->removeWidget(button);
|
||||
delete button;
|
||||
}
|
||||
m_buttons.clear();
|
||||
}
|
||||
|
||||
void CButtonsPanel::UncheckAll()
|
||||
{
|
||||
for (auto& button : m_buttons)
|
||||
{
|
||||
button.pButton->SetSelected(false);
|
||||
}
|
||||
}
|
||||
|
||||
void CButtonsPanel::OnInitDialog()
|
||||
{
|
||||
auto layout = new QGridLayout(this);
|
||||
setLayout(layout);
|
||||
|
||||
layout->setMargin(4);
|
||||
layout->setHorizontalSpacing(4);
|
||||
layout->setVerticalSpacing(1);
|
||||
|
||||
// Create Buttons.
|
||||
int index = 0;
|
||||
for (auto& button : m_buttons)
|
||||
{
|
||||
button.pButton = new QEditorToolButton(this);
|
||||
button.pButton->setObjectName(button.info.name);
|
||||
button.pButton->setText(button.info.name);
|
||||
button.pButton->SetNeedDocument(button.info.bNeedDocument);
|
||||
button.pButton->setToolTip(button.info.toolTip);
|
||||
|
||||
if (button.info.pToolClass)
|
||||
{
|
||||
button.pButton->SetToolClass(button.info.pToolClass, button.info.toolUserDataKey, (void*)button.info.toolUserData.c_str());
|
||||
}
|
||||
else if (!button.info.toolClassName.isEmpty())
|
||||
{
|
||||
button.pButton->SetToolName(button.info.toolClassName, button.info.toolUserDataKey, (void*)button.info.toolUserData.c_str());
|
||||
}
|
||||
|
||||
layout->addWidget(button.pButton, index / 2, index % 2);
|
||||
connect(button.pButton, &QEditorToolButton::clicked, this, [&]() { OnButtonPressed(button.info); });
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
void CButtonsPanel::EnableButton(const QString& buttonName, bool enable)
|
||||
{
|
||||
for (auto& button : m_buttons)
|
||||
{
|
||||
if (button.pButton->objectName() == buttonName)
|
||||
{
|
||||
button.pButton->setEnabled(enable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include <Dialogs/moc_ButtonsPanel.cpp>
|
||||
@ -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.
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_DIALOGS_BUTTONSPANEL_H
|
||||
#define CRYINCLUDE_EDITOR_DIALOGS_BUTTONSPANEL_H
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <QWidget>
|
||||
#endif
|
||||
|
||||
class QEditorToolButton;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Panel with custom auto arranged buttons
|
||||
class CButtonsPanel
|
||||
: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
struct SButtonInfo
|
||||
{
|
||||
QString name;
|
||||
QString toolClassName;
|
||||
QString toolUserDataKey;
|
||||
std::string toolUserData;
|
||||
QString toolTip;
|
||||
bool bNeedDocument;
|
||||
const QMetaObject* pToolClass;
|
||||
|
||||
SButtonInfo()
|
||||
: pToolClass(nullptr)
|
||||
, bNeedDocument(true) {};
|
||||
};
|
||||
|
||||
CButtonsPanel(QWidget* parent);
|
||||
virtual ~CButtonsPanel();
|
||||
|
||||
virtual void AddButton(const SButtonInfo& button);
|
||||
virtual void AddButton(const QString& name, const QString& toolClass);
|
||||
virtual void AddButton(const QString& name, const QMetaObject* pToolClass);
|
||||
virtual void EnableButton(const QString& buttonName, bool disable);
|
||||
virtual void ClearButtons();
|
||||
|
||||
virtual void OnButtonPressed([[maybe_unused]] const SButtonInfo& button) {};
|
||||
virtual void UncheckAll();
|
||||
|
||||
protected:
|
||||
void ReleaseGuiButtons();
|
||||
|
||||
virtual void OnInitDialog();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
struct SButton
|
||||
{
|
||||
SButtonInfo info;
|
||||
QEditorToolButton* pButton;
|
||||
SButton()
|
||||
: pButton(nullptr) {};
|
||||
};
|
||||
|
||||
std::vector<SButton> m_buttons;
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_DIALOGS_BUTTONSPANEL_H
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,134 +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.
|
||||
|
||||
// Description : Object edit mode describe viewport input behavior when operating on objects.
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_EDITMODE_OBJECTMODE_H
|
||||
#define CRYINCLUDE_EDITOR_EDITMODE_OBJECTMODE_H
|
||||
#pragma once
|
||||
|
||||
// {87109FED-BDB5-4874-936D-338400079F58}
|
||||
DEFINE_GUID(OBJECT_MODE_GUID, 0x87109fed, 0xbdb5, 0x4874, 0x93, 0x6d, 0x33, 0x84, 0x0, 0x7, 0x9f, 0x58);
|
||||
|
||||
#include "EditTool.h"
|
||||
|
||||
class CBaseObject;
|
||||
class CDeepSelection;
|
||||
/*!
|
||||
* CObjectMode is an abstract base class for All Editing Tools supported by Editor.
|
||||
* Edit tools handle specific editing modes in viewports.
|
||||
*/
|
||||
class SANDBOX_API CObjectMode
|
||||
: public CEditTool
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_INVOKABLE CObjectMode(QObject* parent = nullptr);
|
||||
virtual ~CObjectMode();
|
||||
|
||||
static const GUID& GetClassID() { return OBJECT_MODE_GUID; }
|
||||
|
||||
// Registration function.
|
||||
static void RegisterTool(CRegistrationContext& rc);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// CEditTool implementation.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
virtual void BeginEditParams([[maybe_unused]] IEditor* ie, [[maybe_unused]] int flags) {};
|
||||
virtual void EndEditParams();
|
||||
virtual void Display(struct DisplayContext& dc);
|
||||
virtual void DisplaySelectionPreview(struct DisplayContext& dc);
|
||||
virtual void DrawSelectionPreview(struct DisplayContext& dc, CBaseObject* drawObject);
|
||||
void DisplayExtraLightInfo(struct DisplayContext& dc);
|
||||
|
||||
virtual bool MouseCallback(CViewport* view, EMouseEvent event, QPoint& point, int flags);
|
||||
virtual bool OnKeyDown(CViewport* view, uint32 nChar, uint32 nRepCnt, uint32 nFlags);
|
||||
virtual bool OnKeyUp(CViewport* view, uint32 nChar, uint32 nRepCnt, uint32 nFlags);
|
||||
virtual bool OnSetCursor([[maybe_unused]] CViewport* vp) { return false; };
|
||||
|
||||
virtual void OnManipulatorDrag(CViewport* view, ITransformManipulator* pManipulator, QPoint& p0, QPoint& p1, const Vec3& value) override;
|
||||
|
||||
bool IsUpdateUIPanel() override { return true; }
|
||||
|
||||
protected:
|
||||
enum ECommandMode
|
||||
{
|
||||
NothingMode = 0,
|
||||
ScrollZoomMode,
|
||||
SelectMode,
|
||||
MoveMode,
|
||||
RotateMode,
|
||||
ScaleMode,
|
||||
ScrollMode,
|
||||
ZoomMode,
|
||||
};
|
||||
|
||||
virtual bool OnLButtonDown(CViewport* view, int nFlags, const QPoint& point);
|
||||
virtual bool OnLButtonDblClk(CViewport* view, int nFlags, const QPoint& point);
|
||||
virtual bool OnLButtonUp(CViewport* view, int nFlags, const QPoint& point);
|
||||
virtual bool OnRButtonDown(CViewport* view, int nFlags, const QPoint& point);
|
||||
virtual bool OnRButtonUp(CViewport* view, int nFlags, const QPoint& point);
|
||||
virtual bool OnMButtonDown(CViewport* view, int nFlags, const QPoint& point);
|
||||
virtual bool OnMouseMove(CViewport* view, int nFlags, const QPoint& point);
|
||||
virtual bool OnMouseLeave(CViewport* view);
|
||||
|
||||
void SetCommandMode(ECommandMode mode) { m_commandMode = mode; }
|
||||
ECommandMode GetCommandMode() const { return m_commandMode; }
|
||||
|
||||
//! Ctrl-Click in move mode to move selected objects to given pos.
|
||||
void MoveSelectionToPos(CViewport* view, Vec3& pos, bool align, const QPoint& point);
|
||||
void SetObjectCursor(CViewport* view, CBaseObject* hitObj, bool bChangeNow = false);
|
||||
|
||||
virtual void DeleteThis() { delete this; };
|
||||
|
||||
void UpdateStatusText();
|
||||
void AwakeObjectAtPoint(CViewport* view, const QPoint& point);
|
||||
|
||||
void HideMoveByFaceNormGizmo();
|
||||
void HandleMoveByFaceNormal(HitContext& hitInfo);
|
||||
void UpdateMoveByFaceNormGizmo(CBaseObject* pHitObject);
|
||||
|
||||
protected:
|
||||
|
||||
bool m_openContext;
|
||||
|
||||
private:
|
||||
void CheckDeepSelection(HitContext& hitContext, CViewport* view);
|
||||
Vec3& GetScale(const CViewport* view, const QPoint& point, Vec3& OutScale);
|
||||
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
QPoint m_cMouseDownPos;
|
||||
bool m_bDragThresholdExceeded;
|
||||
ECommandMode m_commandMode;
|
||||
|
||||
GUID m_MouseOverObject;
|
||||
typedef std::vector<GUID> TGuidContainer;
|
||||
TGuidContainer m_PreviewGUIDs;
|
||||
|
||||
_smart_ptr<CDeepSelection> m_pDeepSelection;
|
||||
|
||||
bool m_bMoveByFaceNormManipShown;
|
||||
CBaseObject* m_pHitObject;
|
||||
|
||||
bool m_bTransformChanged;
|
||||
|
||||
QPoint m_prevMousePos = QPoint(0, 0);
|
||||
|
||||
Vec3 m_lastValidMoveVector = Vec3(0, 0, 0);
|
||||
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_EDITMODE_OBJECTMODE_H
|
||||
@ -1,430 +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"
|
||||
|
||||
#if defined(AZ_PLATFORM_WINDOWS)
|
||||
#include <InitGuid.h>
|
||||
#endif
|
||||
|
||||
#include "VertexSnappingModeTool.h"
|
||||
|
||||
// Editor
|
||||
#include "Settings.h"
|
||||
#include "Viewport.h"
|
||||
#include "SurfaceInfoPicker.h"
|
||||
#include "Material/Material.h"
|
||||
#include "Util/KDTree.h"
|
||||
|
||||
|
||||
// {3e008046-9269-41d7-82e2-07ffd7254c10}
|
||||
DEFINE_GUID(VERTEXSNAPPING_MODE_GUID, 0x3e008046, 0x9269, 0x41d7, 0x82, 0xe2, 0x07, 0xff, 0xd7, 0x25, 0x4c, 0x10);
|
||||
|
||||
bool FindNearestVertex(CBaseObject* pObject, CKDTree* pTree, const Vec3& vWorldRaySrc, const Vec3& vWorldRayDir, Vec3& outPos, Vec3& vOutHitPosOnCube)
|
||||
{
|
||||
Matrix34 worldInvTM = pObject->GetWorldTM().GetInverted();
|
||||
Vec3 vRaySrc = worldInvTM.TransformPoint(vWorldRaySrc);
|
||||
Vec3 vRayDir = worldInvTM.TransformVector(vWorldRayDir);
|
||||
Vec3 vLocalCameraPos = worldInvTM.TransformPoint(gEnv->pRenderer->GetCamera().GetPosition());
|
||||
Vec3 vPos;
|
||||
Vec3 vHitPosOnCube;
|
||||
|
||||
if (pTree)
|
||||
{
|
||||
if (pTree->FindNearestVertex(vRaySrc, vRayDir, gSettings.vertexSnappingSettings.vertexCubeSize, vLocalCameraPos, vPos, vHitPosOnCube))
|
||||
{
|
||||
outPos = pObject->GetWorldTM().TransformPoint(vPos);
|
||||
vOutHitPosOnCube = pObject->GetWorldTM().TransformPoint(vHitPosOnCube);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// for objects without verts, the pivot is the nearest vertex
|
||||
// return true if the ray hits the bounding box
|
||||
outPos = pObject->GetWorldPos();
|
||||
|
||||
AABB bbox;
|
||||
pObject->GetBoundBox(bbox);
|
||||
if (bbox.IsContainPoint(vWorldRaySrc))
|
||||
{
|
||||
// if ray starts inside bounding box, reject cases where pivot is behind the ray
|
||||
float hitDistAlongRay = vWorldRayDir.Dot(outPos - vWorldRaySrc);
|
||||
if (hitDistAlongRay >= 0.f)
|
||||
{
|
||||
vHitPosOnCube = vWorldRaySrc + (vWorldRayDir * hitDistAlongRay);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (Intersect::Ray_AABB(vWorldRaySrc, vWorldRayDir, bbox, vOutHitPosOnCube))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
CVertexSnappingModeTool::CVertexSnappingModeTool()
|
||||
{
|
||||
m_modeStatus = eVSS_SelectFirstVertex;
|
||||
m_bHit = false;
|
||||
}
|
||||
|
||||
CVertexSnappingModeTool::~CVertexSnappingModeTool()
|
||||
{
|
||||
std::map<CBaseObjectPtr, CKDTree*>::iterator ii = m_ObjectKdTreeMap.begin();
|
||||
for (; ii != m_ObjectKdTreeMap.end(); ++ii)
|
||||
{
|
||||
delete ii->second;
|
||||
}
|
||||
}
|
||||
|
||||
const GUID& CVertexSnappingModeTool::GetClassID()
|
||||
{
|
||||
return VERTEXSNAPPING_MODE_GUID;
|
||||
}
|
||||
|
||||
void CVertexSnappingModeTool::RegisterTool(CRegistrationContext& rc)
|
||||
{
|
||||
rc.pClassFactory->RegisterClass(new CQtViewClass<CVertexSnappingModeTool>("EditTool.VertexSnappingMode", "Select", ESYSTEM_CLASS_EDITTOOL));
|
||||
}
|
||||
|
||||
bool CVertexSnappingModeTool::MouseCallback(CViewport* view, EMouseEvent event, QPoint& point, int flags)
|
||||
{
|
||||
CBaseObjectPtr pExcludedObject = NULL;
|
||||
if (m_modeStatus == eVSS_MoveSelectVertexToAnotherVertex)
|
||||
{
|
||||
pExcludedObject = m_SelectionInfo.m_pObject;
|
||||
}
|
||||
|
||||
m_bHit = HitTest(view, point, pExcludedObject, m_vHitVertex, m_pHitObject, m_Objects);
|
||||
|
||||
if (event == eMouseLDown && m_bHit && m_pHitObject && m_modeStatus == eVSS_SelectFirstVertex)
|
||||
{
|
||||
m_modeStatus = eVSS_MoveSelectVertexToAnotherVertex;
|
||||
m_SelectionInfo.m_pObject = m_pHitObject;
|
||||
m_SelectionInfo.m_vPos = m_vHitVertex;
|
||||
|
||||
GetIEditor()->BeginUndo();
|
||||
m_pHitObject->StoreUndo("Vertex Snapping", true);
|
||||
|
||||
view->SetCapture();
|
||||
}
|
||||
|
||||
if (m_modeStatus == eVSS_MoveSelectVertexToAnotherVertex)
|
||||
{
|
||||
if (event == eMouseLUp)
|
||||
{
|
||||
m_modeStatus = eVSS_SelectFirstVertex;
|
||||
|
||||
GetIEditor()->AcceptUndo("Vertex Snapping");
|
||||
view->ReleaseMouse();
|
||||
}
|
||||
else if ((flags & MK_LBUTTON) && event == eMouseMove)
|
||||
{
|
||||
Vec3 vOffset = m_SelectionInfo.m_pObject->GetWorldPos() - m_SelectionInfo.m_vPos;
|
||||
m_SelectionInfo.m_pObject->SetWorldPos(m_vHitVertex + vOffset);
|
||||
m_SelectionInfo.m_vPos = m_SelectionInfo.m_pObject->GetWorldPos() - vOffset;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CVertexSnappingModeTool::HitTest(CViewport* view, const QPoint& point, CBaseObject* pExcludedObj, Vec3& outHitPos, CBaseObjectPtr& pOutHitObject, std::vector<CBaseObjectPtr>& outObjects)
|
||||
{
|
||||
if (gSettings.vertexSnappingSettings.bRenderPenetratedBoundBox)
|
||||
{
|
||||
m_DebugBoxes.clear();
|
||||
}
|
||||
|
||||
pOutHitObject = NULL;
|
||||
outObjects.clear();
|
||||
|
||||
//
|
||||
// Collect valid objects that mouse is over
|
||||
//
|
||||
|
||||
CSurfaceInfoPicker picker;
|
||||
CSurfaceInfoPicker::CExcludedObjects excludedObjects;
|
||||
if (pExcludedObj)
|
||||
{
|
||||
excludedObjects.Add(pExcludedObj);
|
||||
}
|
||||
|
||||
int nPickFlag = CSurfaceInfoPicker::ePOG_Entity;
|
||||
|
||||
std::vector<CBaseObjectPtr> penetratedObjects;
|
||||
if (!picker.PickByAABB(point, nPickFlag, view, &excludedObjects, &penetratedObjects))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0, iCount(penetratedObjects.size()); i < iCount; ++i)
|
||||
{
|
||||
CMaterial* pMaterial = penetratedObjects[i]->GetMaterial();
|
||||
if (pMaterial)
|
||||
{
|
||||
QString matName = pMaterial->GetName();
|
||||
if (!QString::compare(matName, "Objects/sky/forest_sky_dome", Qt::CaseInsensitive))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
outObjects.push_back(penetratedObjects[i]);
|
||||
}
|
||||
|
||||
//
|
||||
// Find the best vertex.
|
||||
//
|
||||
|
||||
Vec3 vWorldRaySrc, vWorldRayDir;
|
||||
view->ViewToWorldRay(point, vWorldRaySrc, vWorldRayDir);
|
||||
|
||||
std::vector<CBaseObjectPtr>::iterator ii = outObjects.begin();
|
||||
float fNearestDist = 3e10f;
|
||||
Vec3 vNearestPos;
|
||||
CBaseObjectPtr pNearestObject = NULL;
|
||||
for (ii = outObjects.begin(); ii != outObjects.end(); ++ii)
|
||||
{
|
||||
if (gSettings.vertexSnappingSettings.bRenderPenetratedBoundBox)
|
||||
{
|
||||
// add to debug boxes: the penetrated nodes of each object's kd-tree
|
||||
if (auto pTree = GetKDTree(*ii))
|
||||
{
|
||||
Matrix34 invWorldTM = (*ii)->GetWorldTM().GetInverted();
|
||||
int nIndex = m_DebugBoxes.size();
|
||||
|
||||
Vec3 vLocalRaySrc = invWorldTM.TransformPoint(vWorldRaySrc);
|
||||
Vec3 vLocalRayDir = invWorldTM.TransformVector(vWorldRayDir);
|
||||
pTree->GetPenetratedBoxes(vLocalRaySrc, vLocalRayDir, m_DebugBoxes);
|
||||
for (int i = nIndex; i < m_DebugBoxes.size(); ++i)
|
||||
{
|
||||
m_DebugBoxes[i].SetTransformedAABB((*ii)->GetWorldTM(), m_DebugBoxes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// find the nearest vertex on this object
|
||||
Vec3 vPos, vHitPosOnCube;
|
||||
if (FindNearestVertex(*ii, GetKDTree(*ii), vWorldRaySrc, vWorldRayDir, vPos, vHitPosOnCube))
|
||||
{
|
||||
// is this the best so far?
|
||||
float fDistance = vHitPosOnCube.GetDistance(vWorldRaySrc);
|
||||
if (fDistance < fNearestDist)
|
||||
{
|
||||
fNearestDist = fDistance;
|
||||
vNearestPos = vPos;
|
||||
pNearestObject = *ii;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fNearestDist < 3e10f)
|
||||
{
|
||||
outHitPos = vNearestPos;
|
||||
pOutHitObject = pNearestObject;
|
||||
}
|
||||
|
||||
// if the mouse is over the object's pivot, use that instead of a vertex
|
||||
if (pOutHitObject)
|
||||
{
|
||||
Vec3 vPivotPos = pOutHitObject->GetWorldPos();
|
||||
Vec3 vPivotBox = GetCubeSize(view, pOutHitObject->GetWorldPos());
|
||||
AABB pivotAABB(vPivotPos - vPivotBox, vPivotPos + vPivotBox);
|
||||
Vec3 vPosOnPivotCube;
|
||||
if (Intersect::Ray_AABB(vWorldRaySrc, vWorldRayDir, pivotAABB, vPosOnPivotCube))
|
||||
{
|
||||
outHitPos = vPivotPos;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return pOutHitObject && pOutHitObject == pNearestObject;
|
||||
}
|
||||
|
||||
Vec3 CVertexSnappingModeTool::GetCubeSize(IDisplayViewport* pView, const Vec3& pos) const
|
||||
{
|
||||
if (!pView)
|
||||
{
|
||||
return Vec3(0, 0, 0);
|
||||
}
|
||||
float fScreenFactor = pView->GetScreenScaleFactor(pos);
|
||||
return gSettings.vertexSnappingSettings.vertexCubeSize * Vec3(fScreenFactor, fScreenFactor, fScreenFactor);
|
||||
}
|
||||
|
||||
void CVertexSnappingModeTool::Display(struct DisplayContext& dc)
|
||||
{
|
||||
const ColorB SnappedColor(0xFF00FF00);
|
||||
const ColorB PivotColor(0xFF2020FF);
|
||||
const ColorB VertexColor(0xFFFFAAAA);
|
||||
|
||||
// draw all objects under mouse
|
||||
dc.SetColor(VertexColor);
|
||||
for (int i = 0, iCount(m_Objects.size()); i < iCount; ++i)
|
||||
{
|
||||
AABB worldAABB;
|
||||
m_Objects[i]->GetBoundBox(worldAABB);
|
||||
if (!dc.view->IsBoundsVisible(worldAABB))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto pStatObj = m_Objects[i]->GetIStatObj())
|
||||
{
|
||||
DrawVertexCubes(dc, m_Objects[i]->GetWorldTM(), pStatObj);
|
||||
}
|
||||
else
|
||||
{
|
||||
dc.DrawWireBox(worldAABB.min, worldAABB.max);
|
||||
}
|
||||
}
|
||||
|
||||
// draw object being moved
|
||||
if (m_modeStatus == eVSS_MoveSelectVertexToAnotherVertex && m_SelectionInfo.m_pObject)
|
||||
{
|
||||
dc.SetColor(QColor(0xaa, 0xaa, 0xaa));
|
||||
if (auto pStatObj = m_SelectionInfo.m_pObject->GetIStatObj())
|
||||
{
|
||||
DrawVertexCubes(dc, m_SelectionInfo.m_pObject->GetWorldTM(), pStatObj);
|
||||
}
|
||||
else
|
||||
{
|
||||
AABB bounds;
|
||||
m_SelectionInfo.m_pObject->GetBoundBox(bounds);
|
||||
dc.DrawWireBox(bounds.min, bounds.max);
|
||||
}
|
||||
}
|
||||
|
||||
// draw pivot of hit object
|
||||
if (m_pHitObject && (!m_bHit || m_bHit && !m_pHitObject->GetWorldPos().IsEquivalent(m_vHitVertex, 0.001f)))
|
||||
{
|
||||
dc.SetColor(PivotColor);
|
||||
dc.DepthTestOff();
|
||||
|
||||
Vec3 vBoxSize = GetCubeSize(dc.view, m_pHitObject->GetWorldPos()) * 1.2f;
|
||||
AABB vertexBox(m_pHitObject->GetWorldPos() - vBoxSize, m_pHitObject->GetWorldPos() + vBoxSize);
|
||||
dc.DrawBall((vertexBox.min + vertexBox.max) * 0.5f, (vertexBox.max.x - vertexBox.min.x) * 0.5f);
|
||||
|
||||
dc.DepthTestOn();
|
||||
}
|
||||
|
||||
// draw the vertex (or pivot) that's being hit
|
||||
if (m_bHit)
|
||||
{
|
||||
dc.DepthTestOff();
|
||||
dc.SetColor(SnappedColor);
|
||||
Vec3 vBoxSize = GetCubeSize(dc.view, m_vHitVertex);
|
||||
if (m_vHitVertex.IsEquivalent(m_pHitObject->GetWorldPos(), 0.001f))
|
||||
{
|
||||
dc.DrawBall(m_vHitVertex, vBoxSize.x * 1.2f);
|
||||
}
|
||||
else
|
||||
{
|
||||
dc.DrawSolidBox(m_vHitVertex - vBoxSize, m_vHitVertex + vBoxSize);
|
||||
}
|
||||
dc.DepthTestOn();
|
||||
}
|
||||
|
||||
// draw wireframe of hit object
|
||||
if (m_pHitObject && m_pHitObject->GetIStatObj())
|
||||
{
|
||||
SGeometryDebugDrawInfo dd;
|
||||
dd.tm = m_pHitObject->GetWorldTM();
|
||||
dd.color = ColorB(250, 0, 250, 30);
|
||||
dd.lineColor = ColorB(255, 255, 0, 160);
|
||||
dd.bExtrude = true;
|
||||
m_pHitObject->GetIStatObj()->DebugDraw(dd);
|
||||
}
|
||||
|
||||
// draw debug boxes
|
||||
if (gSettings.vertexSnappingSettings.bRenderPenetratedBoundBox)
|
||||
{
|
||||
ColorB boxColor(40, 40, 40);
|
||||
for (int i = 0, iCount(m_DebugBoxes.size()); i < iCount; ++i)
|
||||
{
|
||||
dc.SetColor(boxColor);
|
||||
boxColor += ColorB(25, 25, 25);
|
||||
dc.DrawWireBox(m_DebugBoxes[i].min, m_DebugBoxes[i].max);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CVertexSnappingModeTool::DrawVertexCubes(DisplayContext& dc, const Matrix34& tm, IStatObj* pStatObj)
|
||||
{
|
||||
if (!pStatObj)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IIndexedMesh* pIndexedMesh = pStatObj->GetIndexedMesh();
|
||||
if (pIndexedMesh)
|
||||
{
|
||||
IIndexedMesh::SMeshDescription md;
|
||||
pIndexedMesh->GetMeshDescription(md);
|
||||
for (int k = 0; k < md.m_nVertCount; ++k)
|
||||
{
|
||||
Vec3 vPos(0, 0, 0);
|
||||
if (md.m_pVerts)
|
||||
{
|
||||
vPos = md.m_pVerts[k];
|
||||
}
|
||||
else if (md.m_pVertsF16)
|
||||
{
|
||||
vPos = md.m_pVertsF16[k].ToVec3();
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
vPos = tm.TransformPoint(vPos);
|
||||
Vec3 vBoxSize = GetCubeSize(dc.view, vPos);
|
||||
if (!m_bHit || !m_vHitVertex.IsEquivalent(vPos, 0.001f))
|
||||
{
|
||||
dc.DrawSolidBox(vPos - vBoxSize, vPos + vBoxSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0, iSubStatObjNum(pStatObj->GetSubObjectCount()); i < iSubStatObjNum; ++i)
|
||||
{
|
||||
IStatObj::SSubObject* pSubObj = pStatObj->GetSubObject(i);
|
||||
if (pSubObj)
|
||||
{
|
||||
DrawVertexCubes(dc, tm * pSubObj->localTM, pSubObj->pStatObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CKDTree* CVertexSnappingModeTool::GetKDTree(CBaseObject* pObject)
|
||||
{
|
||||
auto existingTree = m_ObjectKdTreeMap.find(pObject);
|
||||
if (existingTree != m_ObjectKdTreeMap.end())
|
||||
{
|
||||
return existingTree->second;
|
||||
}
|
||||
|
||||
// Don't build a kd-tree for objects without verts
|
||||
CKDTree* pTree = nullptr;
|
||||
if (auto pStatObj = pObject->GetIStatObj())
|
||||
{
|
||||
pTree = new CKDTree();
|
||||
pTree->Build(pObject->GetIStatObj());
|
||||
}
|
||||
|
||||
m_ObjectKdTreeMap[pObject] = pTree;
|
||||
return pTree;
|
||||
}
|
||||
|
||||
#include <EditMode/moc_VertexSnappingModeTool.cpp>
|
||||
@ -1,91 +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_EDITMODE_VERTEXSNAPPINGMODETOOL_H
|
||||
#define CRYINCLUDE_EDITOR_EDITMODE_VERTEXSNAPPINGMODETOOL_H
|
||||
#pragma once
|
||||
|
||||
#include "EditTool.h"
|
||||
#include "Objects/BaseObject.h"
|
||||
|
||||
class CKDTree;
|
||||
struct IDisplayViewport;
|
||||
|
||||
class CVertexSnappingModeTool
|
||||
: public CEditTool
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_INVOKABLE CVertexSnappingModeTool();
|
||||
~CVertexSnappingModeTool();
|
||||
|
||||
static const GUID& GetClassID();
|
||||
|
||||
static void RegisterTool(CRegistrationContext& rc);
|
||||
|
||||
void Display(DisplayContext& dc);
|
||||
bool MouseCallback(CViewport* view, EMouseEvent event, QPoint& point, int flags);
|
||||
|
||||
protected:
|
||||
|
||||
void DrawVertexCubes(DisplayContext& dc, const Matrix34& tm, IStatObj* pStatObj);
|
||||
void DeleteThis(){ delete this; }
|
||||
Vec3 GetCubeSize(IDisplayViewport* pView, const Vec3& pos) const;
|
||||
|
||||
private:
|
||||
|
||||
using CEditTool::HitTest;
|
||||
bool HitTest(CViewport* view, const QPoint& point, CBaseObject* pExcludedObj, Vec3& outHitPos, CBaseObjectPtr& pOutHitObject, std::vector<CBaseObjectPtr>& outObjects);
|
||||
CKDTree* GetKDTree(CBaseObject* pObject);
|
||||
|
||||
enum EVertexSnappingStatus
|
||||
{
|
||||
eVSS_SelectFirstVertex,
|
||||
eVSS_MoveSelectVertexToAnotherVertex
|
||||
};
|
||||
EVertexSnappingStatus m_modeStatus;
|
||||
|
||||
struct SSelectionInfo
|
||||
{
|
||||
SSelectionInfo()
|
||||
{
|
||||
m_pObject = NULL;
|
||||
m_vPos = Vec3(0, 0, 0);
|
||||
}
|
||||
CBaseObjectPtr m_pObject;
|
||||
Vec3 m_vPos;
|
||||
};
|
||||
|
||||
/// Info on object being moved (when in eVSS_MoveSelectVertexToAnotherVertex mode).
|
||||
SSelectionInfo m_SelectionInfo;
|
||||
|
||||
/// Objects that mouse is over
|
||||
std::vector<CBaseObjectPtr> m_Objects;
|
||||
|
||||
/// Position of vertex that mouse is hitting.
|
||||
/// Invalid when m_bHit is false.
|
||||
Vec3 m_vHitVertex;
|
||||
|
||||
/// Whether the mouse hit test succeeded
|
||||
bool m_bHit;
|
||||
|
||||
/// Object that mouse is hitting
|
||||
CBaseObjectPtr m_pHitObject;
|
||||
|
||||
/// Boxes to render for debug drawing
|
||||
std::vector<AABB> m_DebugBoxes;
|
||||
|
||||
/// For each object, a tree containing its vertices.
|
||||
std::map<CBaseObjectPtr, CKDTree*> m_ObjectKdTreeMap;
|
||||
};
|
||||
#endif // CRYINCLUDE_EDITOR_EDITMODE_VERTEXSNAPPINGMODETOOL_H
|
||||
@ -1,89 +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 "EditTool.h"
|
||||
|
||||
// Editor
|
||||
#include "Include/IObjectManager.h"
|
||||
#include "Objects/SelectionGroup.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Class description.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CEditTool_ClassDesc
|
||||
: public CRefCountClassDesc
|
||||
{
|
||||
virtual ESystemClassID SystemClassID() { return ESYSTEM_CLASS_EDITTOOL; }
|
||||
virtual REFGUID ClassID()
|
||||
{
|
||||
// {0A43AB8E-B1AE-44aa-93B1-229F73D58CA4}
|
||||
static const GUID guid = {
|
||||
0xa43ab8e, 0xb1ae, 0x44aa, { 0x93, 0xb1, 0x22, 0x9f, 0x73, 0xd5, 0x8c, 0xa4 }
|
||||
};
|
||||
return guid;
|
||||
}
|
||||
virtual QString ClassName() { return "EditTool.Default"; };
|
||||
virtual QString Category() { return "EditTool"; };
|
||||
};
|
||||
CEditTool_ClassDesc g_stdClassDesc;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CEditTool::CEditTool(QObject* parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
m_pClassDesc = &g_stdClassDesc;
|
||||
m_nRefCount = 0;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CEditTool::SetParentTool(CEditTool* pTool)
|
||||
{
|
||||
m_pParentTool = pTool;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CEditTool* CEditTool::GetParentTool()
|
||||
{
|
||||
return m_pParentTool;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CEditTool::Abort()
|
||||
{
|
||||
if (m_pParentTool)
|
||||
{
|
||||
GetIEditor()->SetEditTool(m_pParentTool);
|
||||
}
|
||||
else
|
||||
{
|
||||
GetIEditor()->SetEditTool(0);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CEditTool::GetAffectedObjects(DynArray<CBaseObject*>& outAffectedObjects)
|
||||
{
|
||||
CSelectionGroup* pSelection = GetIEditor()->GetObjectManager()->GetSelection();
|
||||
if (pSelection == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (int i = 0, iCount(pSelection->GetCount()); i < iCount; ++i)
|
||||
{
|
||||
outAffectedObjects.push_back(pSelection->GetObject(i));
|
||||
}
|
||||
}
|
||||
|
||||
#include <moc_EditTool.cpp>
|
||||
@ -1,175 +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_EDITTOOL_H
|
||||
#define CRYINCLUDE_EDITOR_EDITTOOL_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include "QtViewPaneManager.h"
|
||||
#endif
|
||||
|
||||
class CViewport;
|
||||
struct IClassDesc;
|
||||
struct ITransformManipulator;
|
||||
struct HitContext;
|
||||
|
||||
enum EEditToolType
|
||||
{
|
||||
EDIT_TOOL_TYPE_PRIMARY,
|
||||
EDIT_TOOL_TYPE_SECONDARY,
|
||||
};
|
||||
|
||||
/*!
|
||||
* CEditTool is an abstract base class for All Editing Tools supported by Editor.
|
||||
* Edit tools handle specific editing modes in viewports.
|
||||
*/
|
||||
class SANDBOX_API CEditTool
|
||||
: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CEditTool(QObject* parent = nullptr);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// For reference counting.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void AddRef() { m_nRefCount++; };
|
||||
void Release()
|
||||
{
|
||||
AZ_Assert(m_nRefCount > 0, "Negative ref count");
|
||||
if (--m_nRefCount == 0)
|
||||
{
|
||||
DeleteThis();
|
||||
}
|
||||
};
|
||||
|
||||
//! Returns class description for this tool.
|
||||
IClassDesc* GetClassDesc() const { return m_pClassDesc; }
|
||||
|
||||
virtual void SetParentTool(CEditTool* pTool);
|
||||
virtual CEditTool* GetParentTool();
|
||||
|
||||
virtual EEditToolType GetType() { return EDIT_TOOL_TYPE_PRIMARY; }
|
||||
virtual EOperationMode GetMode() { return eOperationModeNone; }
|
||||
|
||||
// Abort tool.
|
||||
virtual void Abort();
|
||||
|
||||
// Accept tool.
|
||||
virtual void Accept([[maybe_unused]] bool resetPosition = false) {}
|
||||
|
||||
//! Status text displayed when this tool is active.
|
||||
void SetStatusText(const QString& text) { m_statusText = text; };
|
||||
QString GetStatusText() { return m_statusText; };
|
||||
|
||||
// Description:
|
||||
// Activates tool.
|
||||
// Arguments:
|
||||
// pPreviousTool - Previously active edit tool.
|
||||
// Return:
|
||||
// True if the tool can be activated,
|
||||
virtual bool Activate([[maybe_unused]] CEditTool* pPreviousTool) { return true; };
|
||||
|
||||
//! Used to pass user defined data to edit tool from ToolButton.
|
||||
virtual void SetUserData([[maybe_unused]] const char* key, [[maybe_unused]] void* userData) {};
|
||||
|
||||
//! Called when user starts using this tool.
|
||||
//! Flags is comnination of ObjectEditFlags flags.
|
||||
virtual void BeginEditParams([[maybe_unused]] IEditor* ie, [[maybe_unused]] int flags) {};
|
||||
//! Called when user ends using this tool.
|
||||
virtual void EndEditParams() {};
|
||||
|
||||
// Called each frame to display tool for given viewport.
|
||||
virtual void Display(struct DisplayContext& dc) = 0;
|
||||
|
||||
//! Mouse callback sent from viewport.
|
||||
//! Returns true if event processed by callback, and all other processing for this event should abort.
|
||||
//! Return false if event was not processed by callback, and other processing for this event should occur.
|
||||
//! @param view Viewport that sent this callback.
|
||||
//! @param event Indicate what kind of event occured in viewport.
|
||||
//! @param point 2D coordinate in viewport where event occured.
|
||||
//! @param flags Additional flags (MK_LBUTTON,etc..) or from (MouseEventFlags) specified by viewport when calling callback.
|
||||
virtual bool MouseCallback(CViewport* view, EMouseEvent event, QPoint& point, int flags) = 0;
|
||||
|
||||
//! Called when key in viewport is pressed while using this tool.
|
||||
//! Returns true if event processed by callback, and all other processing for this event should abort.
|
||||
//! Returns false if event was not processed by callback, and other processing for this event should occur.
|
||||
//! @param view Viewport where key was pressed.
|
||||
//! @param nChar Specifies the virtual key code of the given key. For a list of standard virtual key codes, see Winuser.h
|
||||
//! @param nRepCnt Specifies the repeat count, that is, the number of times the keystroke is repeated as a result of the user holding down the key.
|
||||
//! @param nFlags Specifies the scan code, key-transition code, previous key state, and context code, (see WM_KEYDOWN)
|
||||
virtual bool OnKeyDown([[maybe_unused]] CViewport* view, [[maybe_unused]] uint32 nChar, [[maybe_unused]] uint32 nRepCnt, [[maybe_unused]] uint32 nFlags) { return false; };
|
||||
|
||||
//! Called when key in viewport is released while using this tool.
|
||||
//! Returns true if event processed by callback, and all other processing for this event should abort.
|
||||
//! Returns false if event was not processed by callback, and other processing for this event should occur.
|
||||
//! @param view Viewport where key was pressed.
|
||||
//! @param nChar Specifies the virtual key code of the given key. For a list of standard virtual key codes, see Winuser.h
|
||||
//! @param nRepCnt Specifies the repeat count, that is, the number of times the keystroke is repeated as a result of the user holding down the key.
|
||||
//! @param nFlags Specifies the scan code, key-transition code, previous key state, and context code, (see WM_KEYDOWN)
|
||||
virtual bool OnKeyUp([[maybe_unused]] CViewport* view, [[maybe_unused]] uint32 nChar, [[maybe_unused]] uint32 nRepCnt, [[maybe_unused]] uint32 nFlags) { return false; };
|
||||
|
||||
//! Called when mouse is moved and give oportunity to tool to set it own cursor.
|
||||
//! @return true if cursor changed. or false otherwise.
|
||||
virtual bool OnSetCursor([[maybe_unused]] CViewport* vp) { return false; };
|
||||
|
||||
// Return objects affected by this edit tool. The returned objects usually will be the selected objects.
|
||||
virtual void GetAffectedObjects(DynArray<CBaseObject*>& outAffectedObjects);
|
||||
|
||||
// Called in response to the dragging of the manipulator in the view.
|
||||
// Allow edit tool to handle manipulator dragging the way it wants.
|
||||
virtual void OnManipulatorDrag([[maybe_unused]] CViewport* view, [[maybe_unused]] ITransformManipulator* pManipulator, [[maybe_unused]] QPoint& p0, [[maybe_unused]] QPoint& p1, [[maybe_unused]] const Vec3& value) {}
|
||||
|
||||
virtual void OnManipulatorDrag(CViewport* view, ITransformManipulator* pManipulator, const Vec3& value)
|
||||
{
|
||||
// Overload with less boiler-plate
|
||||
QPoint p0, p1;
|
||||
OnManipulatorDrag(view, pManipulator, p0, p1, value);
|
||||
}
|
||||
|
||||
// Called in response to mouse event of the manipulator in the view
|
||||
virtual void OnManipulatorMouseEvent([[maybe_unused]] CViewport* view, [[maybe_unused]] ITransformManipulator* pManipulator, [[maybe_unused]] EMouseEvent event, [[maybe_unused]] QPoint& point, [[maybe_unused]] int flags, [[maybe_unused]] bool bHitGizmo = false) {}
|
||||
|
||||
virtual bool IsNeedMoveTool() { return false; }
|
||||
virtual bool IsNeedSpecificBehaviorForSpaceAcce() { return false; }
|
||||
virtual bool IsNeedToSkipPivotBoxForObjects() { return false; }
|
||||
virtual bool IsDisplayGrid() { return true; }
|
||||
virtual bool IsUpdateUIPanel() { return false; }
|
||||
virtual bool IsMoveToObjectModeAfterEnd() { return true; }
|
||||
virtual bool IsCircleTypeRotateGizmo() { return false; }
|
||||
|
||||
// Draws object specific helpers for this tool
|
||||
virtual void DrawObjectHelpers([[maybe_unused]] CBaseObject* pObject, [[maybe_unused]] DisplayContext& dc) {}
|
||||
|
||||
// Hit test against edit tool
|
||||
virtual bool HitTest([[maybe_unused]] CBaseObject* pObject, [[maybe_unused]] HitContext& hc) { return false; }
|
||||
|
||||
protected:
|
||||
virtual ~CEditTool() {};
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Delete edit tool.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
virtual void DeleteThis() = 0;
|
||||
|
||||
protected:
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
_smart_ptr<CEditTool> m_pParentTool; // Pointer to parent edit tool.
|
||||
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
QString m_statusText;
|
||||
IClassDesc* m_pClassDesc;
|
||||
int m_nRefCount;
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_EDITTOOL_H
|
||||
@ -1,170 +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 "MaterialPickTool.h"
|
||||
|
||||
// Editor
|
||||
#include "MaterialManager.h"
|
||||
#include "SurfaceInfoPicker.h"
|
||||
#include "Viewport.h"
|
||||
|
||||
|
||||
#define RENDER_MESH_TEST_DISTANCE 0.2f
|
||||
|
||||
static IClassDesc * s_ToolClass = NULL;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CMaterialPickTool::CMaterialPickTool()
|
||||
{
|
||||
m_pClassDesc = s_ToolClass;
|
||||
m_statusText = tr("Left Click To Pick Material");
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CMaterialPickTool::~CMaterialPickTool()
|
||||
{
|
||||
SetMaterial(0);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CMaterialPickTool::MouseCallback(CViewport* view, EMouseEvent event, QPoint& point, int flags)
|
||||
{
|
||||
if (event == eMouseLDown)
|
||||
{
|
||||
if (m_pMaterial)
|
||||
{
|
||||
CMaterial* pMtl = GetIEditor()->GetMaterialManager()->FromIMaterial(m_pMaterial);
|
||||
if (pMtl)
|
||||
{
|
||||
GetIEditor()->GetMaterialManager()->SetHighlightedMaterial(0);
|
||||
GetIEditor()->OpenMaterialLibrary(pMtl);
|
||||
Abort();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (event == eMouseMove)
|
||||
{
|
||||
return OnMouseMove(view, flags, point);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CMaterialPickTool::Display(DisplayContext& dc)
|
||||
{
|
||||
QPoint mousePoint = QCursor::pos();
|
||||
|
||||
dc.view->ScreenToClient(mousePoint);
|
||||
|
||||
Vec3 wp = dc.view->ViewToWorld(mousePoint);
|
||||
|
||||
if (m_pMaterial)
|
||||
{
|
||||
float color[4] = {1, 1, 1, 1};
|
||||
dc.renderer->Draw2dLabel(mousePoint.x() + 12, mousePoint.y ()+ 8, 1.2f, color, false, "%s", m_displayString.toUtf8().data());
|
||||
}
|
||||
|
||||
float fScreenScale = dc.view->GetScreenScaleFactor(m_HitInfo.vHitPos) * 0.06f;
|
||||
|
||||
dc.DepthTestOff();
|
||||
dc.SetColor(ColorB(0, 0, 255, 255));
|
||||
if (!m_HitInfo.vHitNormal.IsZero())
|
||||
{
|
||||
dc.DrawLine(m_HitInfo.vHitPos, m_HitInfo.vHitPos + m_HitInfo.vHitNormal * fScreenScale);
|
||||
|
||||
Vec3 raySrc, rayDir;
|
||||
dc.view->ViewToWorldRay(mousePoint, raySrc, rayDir);
|
||||
|
||||
Matrix34 tm;
|
||||
|
||||
Vec3 zAxis = m_HitInfo.vHitNormal;
|
||||
Vec3 xAxis = rayDir.Cross(zAxis);
|
||||
if (!xAxis.IsZero())
|
||||
{
|
||||
xAxis.Normalize();
|
||||
Vec3 yAxis = xAxis.Cross(zAxis).GetNormalized();
|
||||
tm.SetFromVectors(xAxis, yAxis, zAxis, m_HitInfo.vHitPos);
|
||||
|
||||
dc.PushMatrix(tm);
|
||||
dc.DrawCircle(Vec3(0, 0, 0), 0.5f * fScreenScale);
|
||||
dc.PopMatrix();
|
||||
}
|
||||
}
|
||||
dc.DepthTestOn();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CMaterialPickTool::OnMouseMove(CViewport* view, [[maybe_unused]] UINT nFlags, const QPoint& point)
|
||||
{
|
||||
view->SetCurrentCursor(STD_CURSOR_HIT, "");
|
||||
|
||||
_smart_ptr<IMaterial> pNearestMaterial(NULL);
|
||||
|
||||
m_Mouse2DPosition = point;
|
||||
|
||||
CSurfaceInfoPicker surfacePicker;
|
||||
int nPickObjectGroupFlag = CSurfaceInfoPicker::ePOG_All;
|
||||
if (surfacePicker.Pick(point, pNearestMaterial, m_HitInfo, NULL, nPickObjectGroupFlag))
|
||||
{
|
||||
SetMaterial(pNearestMaterial);
|
||||
return true;
|
||||
}
|
||||
|
||||
SetMaterial(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
const GUID& CMaterialPickTool::GetClassID()
|
||||
{
|
||||
// {FD20F6F2-7B87-4349-A5D4-7533538E357F}
|
||||
static const GUID guid = {
|
||||
0xfd20f6f2, 0x7b87, 0x4349, { 0xa5, 0xd4, 0x75, 0x33, 0x53, 0x8e, 0x35, 0x7f }
|
||||
};
|
||||
return guid;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CMaterialPickTool::RegisterTool(CRegistrationContext& rc)
|
||||
{
|
||||
rc.pClassFactory->RegisterClass(s_ToolClass = new CQtViewClass<CMaterialPickTool>("EditTool.PickMaterial", "Material", ESYSTEM_CLASS_EDITTOOL));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CMaterialPickTool::SetMaterial(_smart_ptr<IMaterial> pMaterial)
|
||||
{
|
||||
if (pMaterial == m_pMaterial)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_pMaterial = pMaterial;
|
||||
CMaterial* pCMaterial = GetIEditor()->GetMaterialManager()->FromIMaterial(m_pMaterial);
|
||||
GetIEditor()->GetMaterialManager()->SetHighlightedMaterial(pCMaterial);
|
||||
|
||||
m_displayString = "";
|
||||
if (pMaterial)
|
||||
{
|
||||
QString sfType;
|
||||
sfType = QStringLiteral("%1 : %2").arg(pMaterial->GetSurfaceType()->GetId()).arg(pMaterial->GetSurfaceType()->GetName());
|
||||
|
||||
m_displayString = "\n";
|
||||
m_displayString += pMaterial->GetName();
|
||||
m_displayString += "\n";
|
||||
m_displayString += sfType;
|
||||
}
|
||||
}
|
||||
|
||||
#include <Material/moc_MaterialPickTool.cpp>
|
||||
@ -1,57 +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.
|
||||
|
||||
// Description : Definition of PickObjectTool, tool used to pick objects.
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_MATERIAL_MATERIALPICKTOOL_H
|
||||
#define CRYINCLUDE_EDITOR_MATERIAL_MATERIALPICKTOOL_H
|
||||
#pragma once
|
||||
|
||||
#include "EditTool.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CMaterialPickTool
|
||||
: public CEditTool
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_INVOKABLE CMaterialPickTool();
|
||||
|
||||
static const GUID& GetClassID();
|
||||
|
||||
static void RegisterTool(CRegistrationContext& rc);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// CEditTool implementation
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
virtual bool MouseCallback(CViewport* view, EMouseEvent event, QPoint& point, int flags);
|
||||
virtual void Display(DisplayContext& dc);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
protected:
|
||||
|
||||
bool OnMouseMove(CViewport* view, UINT nFlags, const QPoint& point);
|
||||
void SetMaterial(_smart_ptr<IMaterial> pMaterial);
|
||||
|
||||
virtual ~CMaterialPickTool();
|
||||
// Delete itself.
|
||||
void DeleteThis() { delete this; };
|
||||
|
||||
_smart_ptr<IMaterial> m_pMaterial;
|
||||
QString m_displayString;
|
||||
QPoint m_Mouse2DPosition;
|
||||
SRayHitInfo m_HitInfo;
|
||||
};
|
||||
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_MATERIAL_MATERIALPICKTOOL_H
|
||||
@ -1,37 +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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "NullEditTool.h"
|
||||
|
||||
|
||||
NullEditTool::NullEditTool() {}
|
||||
|
||||
const GUID& NullEditTool::GetClassID()
|
||||
{
|
||||
// {65AFF87A-34E0-479B-B062-94B1B867B13D}
|
||||
static const GUID guid =
|
||||
{
|
||||
0x65AFF87A, 0x34E0, 0x479B,{ 0xB0, 0x62, 0x94, 0xB1, 0xB8, 0x67, 0xB1, 0x3D }
|
||||
};
|
||||
|
||||
return guid;
|
||||
}
|
||||
|
||||
void NullEditTool::RegisterTool(CRegistrationContext& rc)
|
||||
{
|
||||
rc.pClassFactory->RegisterClass(
|
||||
new CQtViewClass<NullEditTool>("EditTool.NullEditTool", "Select", ESYSTEM_CLASS_EDITTOOL));
|
||||
}
|
||||
|
||||
#include <moc_NullEditTool.cpp>
|
||||
@ -1,39 +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.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include "EditTool.h"
|
||||
#endif
|
||||
|
||||
/// An EditTool that does nothing - it provides the Null-Object pattern.
|
||||
class SANDBOX_API NullEditTool
|
||||
: public CEditTool
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_INVOKABLE NullEditTool();
|
||||
virtual ~NullEditTool() = default;
|
||||
|
||||
static const GUID& GetClassID();
|
||||
static void RegisterTool(CRegistrationContext& rc);
|
||||
|
||||
// CEditTool
|
||||
void BeginEditParams([[maybe_unused]] IEditor* ie, [[maybe_unused]] int flags) override {}
|
||||
void EndEditParams() override {}
|
||||
void Display([[maybe_unused]] DisplayContext& dc) override {}
|
||||
bool MouseCallback([[maybe_unused]] CViewport* view, [[maybe_unused]] EMouseEvent event, [[maybe_unused]] QPoint& point, [[maybe_unused]] int flags) override { return false; }
|
||||
bool OnKeyDown([[maybe_unused]] CViewport* view, [[maybe_unused]] uint32 nChar, [[maybe_unused]] uint32 nRepCnt, [[maybe_unused]] uint32 nFlags) override { return false; }
|
||||
bool OnKeyUp([[maybe_unused]] CViewport* view, [[maybe_unused]] uint32 nChar, [[maybe_unused]] uint32 nRepCnt, [[maybe_unused]] uint32 nFlags) override { return true; }
|
||||
void DeleteThis() override { delete this; }
|
||||
};
|
||||
@ -1,336 +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 "ObjectCloneTool.h"
|
||||
|
||||
// Editor
|
||||
#include "MainWindow.h"
|
||||
#include "Viewport.h"
|
||||
#include "ViewManager.h"
|
||||
#include "Include/IObjectManager.h"
|
||||
#include "Objects/SelectionGroup.h"
|
||||
#include "Settings.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Class description.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CObjectCloneTool_ClassDesc
|
||||
: public CRefCountClassDesc
|
||||
{
|
||||
virtual ESystemClassID SystemClassID() { return ESYSTEM_CLASS_EDITTOOL; }
|
||||
virtual REFGUID ClassID()
|
||||
{
|
||||
// {6A73E865-71DF-4ED0-ABA2-457E66119B35}
|
||||
static const GUID guid = {
|
||||
0x6a73e865, 0x71df, 0x4ed0,{ 0xab, 0xa2, 0x45, 0x7e, 0x66, 0x11, 0x9b, 0x35 }
|
||||
};
|
||||
return guid;
|
||||
}
|
||||
virtual QString ClassName() { return "EditTool.Clone"; };
|
||||
virtual QString Category() { return "EditTool"; };
|
||||
};
|
||||
CObjectCloneTool_ClassDesc g_cloneClassDesc;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CObjectCloneTool::CObjectCloneTool()
|
||||
: m_currentUndoBatch(nullptr)
|
||||
{
|
||||
m_pClassDesc = &g_cloneClassDesc;
|
||||
m_bSetConstrPlane = true;
|
||||
|
||||
GetIEditor()->SuperBeginUndo();
|
||||
|
||||
GetIEditor()->BeginUndo();
|
||||
m_selection = nullptr;
|
||||
if (!GetIEditor()->GetSelection()->IsEmpty())
|
||||
{
|
||||
QWaitCursor wait;
|
||||
CloneSelection();
|
||||
m_selection = GetIEditor()->GetSelection();
|
||||
m_origin = m_selection->GetCenter();
|
||||
}
|
||||
GetIEditor()->AcceptUndo("Clone");
|
||||
GetIEditor()->BeginUndo();
|
||||
|
||||
if (!gSettings.deepSelectionSettings.bStickDuplicate)
|
||||
{
|
||||
SetStatusText("Clone object at the same location");
|
||||
}
|
||||
else
|
||||
{
|
||||
SetStatusText("Left click to clone object");
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CObjectCloneTool::~CObjectCloneTool()
|
||||
{
|
||||
EndUndoBatch();
|
||||
|
||||
if (GetIEditor()->IsUndoRecording())
|
||||
{
|
||||
GetIEditor()->SuperCancelUndo();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CObjectCloneTool::CloneSelection()
|
||||
{
|
||||
// Allow component application to intercept cloning behavior.
|
||||
// This is to allow support for "smart" cloning of prefabs, and other contextual features.
|
||||
AZ_Assert(!m_currentUndoBatch, "CloneSelection undo batch already created.");
|
||||
EBUS_EVENT_RESULT(m_currentUndoBatch, AzToolsFramework::ToolsApplicationRequests::Bus, BeginUndoBatch, "Clone Selection");
|
||||
bool handled = false;
|
||||
EBUS_EVENT(AzToolsFramework::EditorRequests::Bus, CloneSelection, handled);
|
||||
if (handled)
|
||||
{
|
||||
GetIEditor()->GetObjectManager()->CheckAndFixSelection();
|
||||
return;
|
||||
}
|
||||
|
||||
// This is the legacy case. We're not cloning AZ entities, so abandon the AZ undo batch.
|
||||
EndUndoBatch();
|
||||
|
||||
CSelectionGroup selObjects;
|
||||
CSelectionGroup sel;
|
||||
|
||||
CSelectionGroup* currSelection = GetIEditor()->GetSelection();
|
||||
|
||||
currSelection->Clone(selObjects);
|
||||
|
||||
GetIEditor()->ClearSelection();
|
||||
for (int i = 0; i < selObjects.GetCount(); i++)
|
||||
{
|
||||
if (selObjects.GetObject(i))
|
||||
{
|
||||
GetIEditor()->SelectObject(selObjects.GetObject(i));
|
||||
}
|
||||
}
|
||||
MainWindow::instance()->setFocus();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CObjectCloneTool::SetConstrPlane(CViewport* view, [[maybe_unused]] const QPoint& point)
|
||||
{
|
||||
Matrix34 originTM;
|
||||
originTM.SetIdentity();
|
||||
CSelectionGroup* selection = GetIEditor()->GetSelection();
|
||||
if (selection->GetCount() == 1)
|
||||
{
|
||||
originTM = selection->GetObject(0)->GetWorldTM();
|
||||
}
|
||||
else if (selection->GetCount() > 1)
|
||||
{
|
||||
originTM = selection->GetObject(0)->GetWorldTM();
|
||||
Vec3 center = view->SnapToGrid(originTM.GetTranslation());
|
||||
originTM.SetTranslation(center);
|
||||
}
|
||||
view->SetConstructionMatrix(COORDS_LOCAL, originTM);
|
||||
}
|
||||
|
||||
//static Vec3 gP1,gP2;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CObjectCloneTool::Display([[maybe_unused]] DisplayContext& dc)
|
||||
{
|
||||
//dc.SetColor( 1,1,0,1 );
|
||||
//dc.DrawBall( gP1,1.1f );
|
||||
//dc.DrawBall( gP2,1.1f );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CObjectCloneTool::MouseCallback(CViewport* view, EMouseEvent event, QPoint& point, int flags)
|
||||
{
|
||||
if (m_selection)
|
||||
{
|
||||
// Set construction plane origin to selection origin.
|
||||
if (m_bSetConstrPlane)
|
||||
{
|
||||
SetConstrPlane(view, point);
|
||||
m_bSetConstrPlane = false;
|
||||
}
|
||||
|
||||
if (event == eMouseLDown)
|
||||
{
|
||||
// Accept group.
|
||||
Accept();
|
||||
GetIEditor()->GetSelection()->FinishChanges();
|
||||
return true;
|
||||
}
|
||||
if (event == eMouseMove)
|
||||
{
|
||||
// Move selection.
|
||||
CSelectionGroup* selection = GetIEditor()->GetSelection();
|
||||
if (selection != m_selection)
|
||||
{
|
||||
Abort();
|
||||
}
|
||||
else if (!selection->IsEmpty())
|
||||
{
|
||||
GetIEditor()->RestoreUndo();
|
||||
|
||||
Vec3 v;
|
||||
bool followTerrain = false;
|
||||
|
||||
CSelectionGroup* pSelection = GetIEditor()->GetSelection();
|
||||
Vec3 selectionCenter = view->SnapToGrid(pSelection->GetCenter());
|
||||
|
||||
int axis = GetIEditor()->GetAxisConstrains();
|
||||
if (axis == AXIS_TERRAIN)
|
||||
{
|
||||
bool hitTerrain;
|
||||
v = view->ViewToWorld(point, &hitTerrain) - selectionCenter;
|
||||
if (axis == AXIS_TERRAIN)
|
||||
{
|
||||
v = view->SnapToGrid(v);
|
||||
if (hitTerrain)
|
||||
{
|
||||
followTerrain = true;
|
||||
v.z = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Vec3 p1 = selectionCenter;
|
||||
Vec3 p2 = view->MapViewToCP(point);
|
||||
if (p2.IsZero())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
v = view->GetCPVector(p1, p2);
|
||||
// Snap v offset to grid if its enabled.
|
||||
view->SnapToGrid(v);
|
||||
}
|
||||
|
||||
CSelectionGroup::EMoveSelectionFlag selectionFlag = CSelectionGroup::eMS_None;
|
||||
if (followTerrain)
|
||||
{
|
||||
selectionFlag = CSelectionGroup::eMS_FollowTerrain;
|
||||
}
|
||||
|
||||
// Disable undo recording for these move commands as the only operation we need
|
||||
// to undo is the creation of the new object. Undo commands are queued so it's
|
||||
// possible that the object creation could be undone before attempting to undo
|
||||
// these move operations causing undesired behavior.
|
||||
bool wasRecording = CUndo::IsRecording();
|
||||
if (wasRecording)
|
||||
{
|
||||
GetIEditor()->SuspendUndo();
|
||||
}
|
||||
|
||||
GetIEditor()->GetSelection()->Move(v, selectionFlag, GetIEditor()->GetReferenceCoordSys(), point);
|
||||
|
||||
if (wasRecording)
|
||||
{
|
||||
GetIEditor()->ResumeUndo();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (event == eMouseWheel)
|
||||
{
|
||||
CSelectionGroup* selection = GetIEditor()->GetSelection();
|
||||
if (selection != m_selection)
|
||||
{
|
||||
Abort();
|
||||
}
|
||||
else if (!selection->IsEmpty())
|
||||
{
|
||||
double angle = 1;
|
||||
|
||||
if (view->GetViewManager()->GetGrid()->IsAngleSnapEnabled())
|
||||
{
|
||||
angle = view->GetViewManager()->GetGrid()->GetAngleSnap();
|
||||
}
|
||||
|
||||
for (int i = 0; i < selection->GetCount(); ++i)
|
||||
{
|
||||
CBaseObject* pObj = selection->GetFilteredObject(i);
|
||||
Quat rot = pObj->GetRotation();
|
||||
rot.SetRotationXYZ(Ang3(0, 0, rot.GetRotZ() + DEG2RAD(flags > 0 ? angle * (-1) : angle)));
|
||||
pObj->SetRotation(rot);
|
||||
}
|
||||
GetIEditor()->AcceptUndo("Rotate Selection");
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CObjectCloneTool::Abort()
|
||||
{
|
||||
EndUndoBatch();
|
||||
|
||||
// Abort
|
||||
GetIEditor()->SetEditTool(0);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CObjectCloneTool::Accept(bool resetPosition)
|
||||
{
|
||||
// Close the az undo batch so it can add the appropriate objects to the cry undo stack
|
||||
EndUndoBatch();
|
||||
|
||||
if (resetPosition)
|
||||
{
|
||||
GetIEditor()->GetSelection()->MoveTo(m_origin, CSelectionGroup::eMS_None, GetIEditor()->GetReferenceCoordSys());
|
||||
}
|
||||
|
||||
if (GetIEditor()->IsUndoRecording())
|
||||
{
|
||||
GetIEditor()->SuperAcceptUndo("Clone");
|
||||
}
|
||||
|
||||
GetIEditor()->SetEditTool(0);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CObjectCloneTool::EndUndoBatch()
|
||||
{
|
||||
if (m_currentUndoBatch)
|
||||
{
|
||||
AzToolsFramework::UndoSystem::URSequencePoint* undoBatch = nullptr;
|
||||
EBUS_EVENT_RESULT(undoBatch, AzToolsFramework::ToolsApplicationRequests::Bus, GetCurrentUndoBatch);
|
||||
AZ_Error("ObjectCloneTool", undoBatch == m_currentUndoBatch, "Undo batch is not in sync.");
|
||||
if (undoBatch == m_currentUndoBatch)
|
||||
{
|
||||
EBUS_EVENT(AzToolsFramework::ToolsApplicationRequests::Bus, EndUndoBatch);
|
||||
}
|
||||
m_currentUndoBatch = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CObjectCloneTool::BeginEditParams([[maybe_unused]] IEditor* ie, [[maybe_unused]] int flags)
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CObjectCloneTool::EndEditParams()
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CObjectCloneTool::OnKeyDown([[maybe_unused]] CViewport* view, uint32 nChar, [[maybe_unused]] uint32 nRepCnt, [[maybe_unused]] uint32 nFlags)
|
||||
{
|
||||
if (nChar == VK_ESCAPE)
|
||||
{
|
||||
Abort();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#include <moc_ObjectCloneTool.cpp>
|
||||
@ -1,81 +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.
|
||||
|
||||
// Description : Definition of ObjectCloneTool, edit tool for cloning of objects..
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_OBJECTCLONETOOL_H
|
||||
#define CRYINCLUDE_EDITOR_OBJECTCLONETOOL_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "EditTool.h"
|
||||
|
||||
class CBaseObject;
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace UndoSystem
|
||||
{
|
||||
class URSequencePoint;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* CObjectCloneTool, When created duplicate current selection, and manages cloned selection.
|
||||
*
|
||||
*/
|
||||
|
||||
class CObjectCloneTool
|
||||
: public CEditTool
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_INVOKABLE CObjectCloneTool();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Ovverides from CEditTool
|
||||
bool MouseCallback(CViewport* view, EMouseEvent event, QPoint& point, int flags);
|
||||
|
||||
virtual void BeginEditParams(IEditor* ie, int flags);
|
||||
virtual void EndEditParams();
|
||||
|
||||
virtual void Display(DisplayContext& dc);
|
||||
virtual bool OnKeyDown(CViewport* view, uint32 nChar, uint32 nRepCnt, uint32 nFlags);
|
||||
virtual bool OnKeyUp([[maybe_unused]] CViewport* view, [[maybe_unused]] uint32 nChar, [[maybe_unused]] uint32 nRepCnt, [[maybe_unused]] uint32 nFlags) { return false; };
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Accept(bool resetPosition = false);
|
||||
void Abort();
|
||||
|
||||
protected:
|
||||
virtual ~CObjectCloneTool();
|
||||
// Delete itself.
|
||||
void DeleteThis() { delete this; };
|
||||
|
||||
private:
|
||||
void CloneSelection();
|
||||
void SetConstrPlane(CViewport* view, const QPoint& point);
|
||||
|
||||
CSelectionGroup* m_selection;
|
||||
Vec3 m_origin;
|
||||
bool m_bSetConstrPlane;
|
||||
//bool m_bSetCapture;
|
||||
|
||||
void EndUndoBatch();
|
||||
|
||||
AzToolsFramework::UndoSystem::URSequencePoint* m_currentUndoBatch;
|
||||
};
|
||||
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_OBJECTCLONETOOL_H
|
||||
File diff suppressed because it is too large
Load Diff
@ -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.
|
||||
*
|
||||
*/
|
||||
#ifndef CRYINCLUDE_EDITOR_ROTATETOOL_H
|
||||
#define CRYINCLUDE_EDITOR_ROTATETOOL_H
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include "EditTool.h"
|
||||
#include "IObjectManager.h"
|
||||
#include "EditMode/ObjectMode.h"
|
||||
#include "Objects/BaseObject.h" // for CBaseObject::EventListener
|
||||
#include "Objects/DisplayContext.h"
|
||||
#include "Include/HitContext.h"
|
||||
#endif
|
||||
|
||||
//! Provides rendering utilities to support CRotateTool
|
||||
namespace RotationDrawHelper
|
||||
{
|
||||
//! Circle drawing and hit testing functionality over arbitrary axes
|
||||
class Axis
|
||||
{
|
||||
public:
|
||||
|
||||
//! \param defaultColor Color used to draw the camera aligned portion of the axis.
|
||||
//! \param highlightColor Color used to draw the circle when it is in focus.
|
||||
Axis(const ColorF& defaultColor = Col_White, const ColorF& highlightColor = Col_Yellow);
|
||||
|
||||
//! Draws an axis aligned circle.
|
||||
//! \param dc DisplayContext to use for rendering.
|
||||
//! \param position World space position used as the center of the circle.
|
||||
//! \param axis The axis by which to align the circle.
|
||||
//! \param angleRadians The angle towards which the circle will be highlighted.
|
||||
//! \param radius The radius of the circle.
|
||||
//! \param highlighted If true it will draw the circle in the specified highlightColor.
|
||||
void Draw(DisplayContext& dc, const Vec3& position, const Vec3& axis, float angleRadians, float angleStepRadians, float radius, bool highlighted, CBaseObject* object, float screenScale);
|
||||
|
||||
//! Calculates a hit testing mesh (invisible) used for intersection testing.
|
||||
//! \param object The object selected if hit testing return true.
|
||||
//! \param hc The HitContext in which the hit object is set if an intersection is true.
|
||||
//! \param radius The radius for the axis' circle.
|
||||
//! \param angleStepRadians The angle for the step used to calculate the circle, a smaller angle results in a higher quality circle.
|
||||
//! \param axis The axis by which to align the intersection geometry.
|
||||
//! \param screenScale This is an internal parameter used to deduce the view distance ratio in order to scale the tool.
|
||||
bool HitTest(CBaseObject* object, HitContext& hc, float radius, float angleStepRadians, const Vec3& axis, float screenScale);
|
||||
|
||||
//! Draws the generated hit testing geometry, good for diagnostics and debugging.
|
||||
//! \param dc DisplayContext to use for rendering.
|
||||
//! \param hc The HitContext that contains the view direction raycast.
|
||||
//! \param position World space position used as the center of the circle.
|
||||
//! \param radius The radius for the axis' circle.
|
||||
//! \param angleStepRadians The angle for the step used to calculate the circle, a smaller angle results in a higher quality circle.
|
||||
//! \param axis The axis by which to align the intersection geometry.
|
||||
//! \param screenScale This is an internal parameter used to deduce the view distance ratio in order to scale the tool.
|
||||
void DebugDrawHitTestSurface(DisplayContext& dc, HitContext& hc, const Vec3& position, float radius, float angleStepRadians, const Vec3& axis, float screenScale);
|
||||
|
||||
protected:
|
||||
|
||||
enum States
|
||||
{
|
||||
StateDefault,
|
||||
StateHighlight,
|
||||
StateCount
|
||||
};
|
||||
|
||||
ColorF m_colors[StateCount];
|
||||
|
||||
//! Defines the width of the generated hit testing geometry.
|
||||
float m_hitTestWidth = 0.4f;
|
||||
|
||||
//! Contains the vertices that make up the ring for the intersection testing geometry.
|
||||
//! \remark Only contains the center positions, quads are generated by calculating the four vertices offset by m_hitTestWidth.
|
||||
std::vector<Vec3> m_vertices;
|
||||
|
||||
//! Generates the world space geometry necessary to perform hit testing.
|
||||
//! \param hc The HitContext data.
|
||||
//! \param position The world space position around which the geometry will be centered.
|
||||
//! \param radius The radius of the ring.
|
||||
//! \param angleStepRadians The angle for the step used to calculate the circle, a smaller angle results in a higher quality circle.
|
||||
//! \param axis The axis to which the geometry will be aligned to.
|
||||
//! \param screenScale This is an internal parameter used to deduce the view distance ratio in order to scale the tool.
|
||||
void GenerateHitTestGeometry(HitContext& hc, const Vec3& position, float radius, float angleStepRadians, const Vec3& axis, float screenScale);
|
||||
|
||||
//! Performs intersection testing between a ray and both sides of a quad
|
||||
//! \param ray The ray to test (in world space)
|
||||
//! \param quad An array of four Vec3 points in world space.
|
||||
//! \param[out] contact The intersection position in world space at which the intersection occurred.
|
||||
bool IntersectRayWithQuad(const Ray&ray, Vec3 quad[4], Vec3 & contact);
|
||||
};
|
||||
|
||||
//! Provides the means to set and restore DisplayContext settings within a given scope.
|
||||
class DisplayContextScope
|
||||
{
|
||||
public:
|
||||
DisplayContextScope(DisplayContext& dc)
|
||||
: m_dc(dc)
|
||||
{
|
||||
m_dc.DepthTestOff();
|
||||
m_dc.CullOff();
|
||||
}
|
||||
|
||||
~DisplayContextScope()
|
||||
{
|
||||
m_dc.DepthTestOn();
|
||||
m_dc.CullOn();
|
||||
}
|
||||
|
||||
DisplayContext& m_dc;
|
||||
};
|
||||
|
||||
//! Helper function that draws the representation of the inner angle of a rotation.
|
||||
namespace AngleDecorator
|
||||
{
|
||||
//! \param dc
|
||||
//! \param position World space position of the center of the decorator.
|
||||
//! \param axisToAlign Axis to which the decorator will be aligned to.
|
||||
//! \param startAngleRadians The starting angle from which the rotation will be performed.
|
||||
//! \param sweepAngleRadians An angle that represents the sweep of the rotation arc.
|
||||
//! \param angleStepRadians The angle for the step used to calculate the circle, a smaller angle results in a higher quality circle.
|
||||
//! \param radius The radius of the decorator.
|
||||
//! \param screenScale This is an internal parameter used to deduce the view distance ratio in order to scale the tool.
|
||||
void Draw(DisplayContext& dc, const Vec3& position, const Vec3& axisToAlign, float startAngleRadians, float sweepAngleRadians, float stepAngleRadians, float radius, float screenScale);
|
||||
}
|
||||
}
|
||||
|
||||
//! Provides rotation manipulation controls.
|
||||
class SANDBOX_API CRotateTool
|
||||
: public CObjectMode
|
||||
, public IObjectSelectCallback
|
||||
, public CBaseObject::EventListener
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_INVOKABLE CRotateTool(CBaseObject* pObject = nullptr, QWidget* parent = nullptr);
|
||||
virtual ~CRotateTool();
|
||||
|
||||
static const GUID& GetClassID();
|
||||
|
||||
// Registration function.
|
||||
static void RegisterTool(CRegistrationContext& rc);
|
||||
|
||||
void Display(DisplayContext& dc) override;
|
||||
void DrawObjectHelpers([[maybe_unused]] CBaseObject* pObject, [[maybe_unused]] DisplayContext& dc) override {}
|
||||
bool HitTest(CBaseObject* pObject, HitContext& hc) override;
|
||||
void DeleteThis() override;
|
||||
bool OnLButtonDown(CViewport* view, int nFlags, const QPoint& point) override;
|
||||
bool OnLButtonUp(CViewport* view, int nFlags, const QPoint& point) override;
|
||||
bool OnMouseMove(CViewport* view, int nFlags, const QPoint& point) override;
|
||||
|
||||
protected:
|
||||
|
||||
//! Utility to calculate the view distance ratio used to scale the tool.
|
||||
float GetScreenScale(IDisplayViewport* view, CCamera* camera = nullptr);
|
||||
|
||||
enum Axis
|
||||
{
|
||||
AxisNone,
|
||||
AxisX, //! X axis visualization and hit testing
|
||||
AxisY, //! Y axis visualization and hit testing
|
||||
AxisZ, //! Z axis visualization and hit testing
|
||||
AxisView, //! View direction axis, used to rotate along the vector from the camera to the object.
|
||||
AxisCount
|
||||
};
|
||||
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
//! Axis visualization and hit testing
|
||||
RotationDrawHelper::Axis m_axes[Axis::AxisCount];
|
||||
|
||||
//! We record the starting angle when we begin to drag an object
|
||||
float m_initialViewAxisAngleRadians;
|
||||
|
||||
//! The angle from the object's (or selection's) center to the mouse cursor.
|
||||
float m_angleToCursor;
|
||||
|
||||
//! Specified which axis is currently selected.
|
||||
Axis m_highlightAxis;
|
||||
|
||||
//! True when we are using the view direction rotation axis.
|
||||
bool m_viewAxisRotation;
|
||||
|
||||
//! True when the mouse has been pressed, becomes false on release.
|
||||
bool m_draggingMouse;
|
||||
|
||||
//! The last mouse position on screen when rotating.
|
||||
QPoint m_lastPosition;
|
||||
|
||||
//! Cumulative rotation angle in degrees.
|
||||
Ang3 m_rotationAngles;
|
||||
|
||||
//! The selected object.
|
||||
CBaseObject* m_object;
|
||||
|
||||
//! True if there has been a change in rotation that affects the object.
|
||||
bool m_bTransformChanged;
|
||||
|
||||
//! Sum of the total rotation angles.
|
||||
float m_totalRotationAngle;
|
||||
|
||||
//! Radius used to draw the XYZ axes
|
||||
float m_basisAxisRadius;
|
||||
|
||||
//! Radius used to draw the view direction axis
|
||||
float m_viewAxisRadius;
|
||||
|
||||
//! Rotation step controls the quality of the axes, a smaller angle represents a higher number of vertices.
|
||||
float m_arcRotationStepRadians;
|
||||
|
||||
//! Thickness of for the axis line rendering.
|
||||
float m_lineThickness = 4.f;
|
||||
|
||||
//! Draws angle decorator for the current rotation axis.
|
||||
void DrawAngleDecorator(DisplayContext& dc);
|
||||
|
||||
//! Useful for debugging and visualizing hit testing
|
||||
void DrawHitTestGeometry(DisplayContext& dc, HitContext& hc);
|
||||
|
||||
//! Diagnostic tool to examine view direction angle (follows mouse cursor)
|
||||
void DrawViewDirectionAngleTracking(DisplayContext& dc, HitContext& hc);
|
||||
|
||||
//! Callback registered to receive Selection callbacks to set m_object
|
||||
bool OnSelectObject(CBaseObject* object) override;
|
||||
|
||||
//! Callback to check that an object can be selected
|
||||
bool CanSelectObject(CBaseObject* object) override;
|
||||
|
||||
//! Callback installed on the object, used to determine destruction or deselection.
|
||||
void OnObjectEvent(CBaseObject* object, int event) override;
|
||||
|
||||
//! Handle key down events.
|
||||
bool OnKeyDown(CViewport* view, uint32 nChar, uint32 nRepCnt, uint32 nFlags) override;
|
||||
|
||||
//! Retrieves the object's transformation according to the specified reference coordinate system.
|
||||
Matrix34 GetTransform(RefCoordSys referenceCoordinateSystem, IDisplayViewport* view);
|
||||
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
|
||||
//! Calculate orientation of 3 points on screen, return 1.0f if clockwise, -1.0f if counter-clockwise
|
||||
float CalculateOrientation(const QPoint& p1, const QPoint& p2, const QPoint& p3);
|
||||
|
||||
private:
|
||||
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
HitContext m_hc; //!< HACK: Cache the hitcontext given that it's values may differ depending on the viewport they are coming from.
|
||||
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
};
|
||||
|
||||
//! Singleton that holds all the configuration cvars for the different features and debug options
|
||||
//! used by the CRotationControl
|
||||
class RotationControlConfiguration
|
||||
{
|
||||
public:
|
||||
|
||||
static RotationControlConfiguration& Get()
|
||||
{
|
||||
static RotationControlConfiguration instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
//! If enabled it will draw the inner rotation decorator.
|
||||
DeclareConstIntCVar(RotationControl_DrawDecorators, 0);
|
||||
|
||||
//! If enabled the hit testing geometry is rendered.
|
||||
DeclareConstIntCVar(RotationControl_DebugHitTesting, 0);
|
||||
|
||||
//! If enabled a sphere will be drawn to represent the view axis angle to the mouse cursor.
|
||||
DeclareConstIntCVar(RotationControl_AngleTracking, 0);
|
||||
|
||||
private:
|
||||
|
||||
RotationControlConfiguration();
|
||||
RotationControlConfiguration(const RotationControlConfiguration&) = delete;
|
||||
RotationControlConfiguration& operator = (const RotationControlConfiguration&) = delete;
|
||||
~RotationControlConfiguration() {}
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_ROTATETOOL_H
|
||||
@ -1,151 +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 "VoxelAligningTool.h"
|
||||
|
||||
// Editor
|
||||
#include "SurfaceInfoPicker.h"
|
||||
#include "Objects/SelectionGroup.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CVoxelAligningTool::CVoxelAligningTool()
|
||||
{
|
||||
m_curObj = 0;
|
||||
m_PreviewMode = ePM_Idle;
|
||||
|
||||
CSelectionGroup* sel = GetIEditor()->GetSelection();
|
||||
if (!sel->IsEmpty())
|
||||
{
|
||||
m_curObj = sel->GetObject(0);
|
||||
m_CurObjTMBeforePreviewMode = m_curObj->GetWorldTM();
|
||||
m_q = m_curObj->GetRotation();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CVoxelAligningTool::~CVoxelAligningTool()
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CVoxelAligningTool::Display([[maybe_unused]] DisplayContext& dc)
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CVoxelAligningTool::MouseCallback([[maybe_unused]] CViewport* view, EMouseEvent event, QPoint& point, int flags)
|
||||
{
|
||||
// Get contrl key status.
|
||||
bool bCtrlClick = (flags & MK_CONTROL);
|
||||
bool bShiftClick = (flags & MK_SHIFT);
|
||||
bool bOnlyCtrlClick = bCtrlClick && !bShiftClick;
|
||||
|
||||
CSelectionGroup* sel = GetIEditor()->GetSelection();
|
||||
if (sel->IsEmpty() || m_curObj != sel->GetObject(0))
|
||||
{
|
||||
GetIEditor()->SetEditTool(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event == eMouseMove)
|
||||
{
|
||||
if (m_PreviewMode == ePM_Idle)
|
||||
{
|
||||
if (bOnlyCtrlClick)
|
||||
{
|
||||
if (m_curObj)
|
||||
{
|
||||
m_CurObjTMBeforePreviewMode = m_curObj->GetWorldTM();
|
||||
}
|
||||
m_PreviewMode = ePM_Previewing;
|
||||
GetIEditor()->BeginUndo();
|
||||
}
|
||||
}
|
||||
else if (!bOnlyCtrlClick)
|
||||
{
|
||||
if (m_curObj)
|
||||
{
|
||||
m_curObj->SetWorldTM(m_CurObjTMBeforePreviewMode);
|
||||
//m_curObj->SetRotation(m_extraRot);
|
||||
}
|
||||
m_PreviewMode = ePM_Idle;
|
||||
GetIEditor()->CancelUndo();
|
||||
}
|
||||
|
||||
if (m_PreviewMode == ePM_Previewing && bOnlyCtrlClick)
|
||||
{ // Preview align to normal
|
||||
ApplyPickedTM2CurObj(point);
|
||||
}
|
||||
}
|
||||
|
||||
if (event == eMouseLDown && m_PreviewMode == ePM_Previewing)
|
||||
{
|
||||
m_CurObjTMBeforePreviewMode = m_curObj->GetWorldTM();
|
||||
GetIEditor()->AcceptUndo("Surface Normal Aligning");
|
||||
GetIEditor()->SetEditTool(NULL);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CVoxelAligningTool::ApplyPickedTM2CurObj(const QPoint& point, [[maybe_unused]] bool bPickOnlyTerrain)
|
||||
{
|
||||
int nPickFlag = CSurfaceInfoPicker::ePOG_All;
|
||||
SRayHitInfo hitInfo;
|
||||
CSurfaceInfoPicker::CExcludedObjects excludeObjects;
|
||||
if (m_curObj)
|
||||
{
|
||||
excludeObjects.Add(m_curObj);
|
||||
}
|
||||
CSurfaceInfoPicker surfacePicker;
|
||||
if (surfacePicker.Pick(point, hitInfo, &excludeObjects, nPickFlag))
|
||||
{
|
||||
m_curObj->SetPos(hitInfo.vHitPos, eObjectUpdateFlags_UserInput);
|
||||
ApplyRotation(hitInfo.vHitNormal);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CVoxelAligningTool::ApplyRotation(Vec3& normal)
|
||||
{
|
||||
Vec3 zaxis = m_q * Vec3(0, 0, 1);
|
||||
zaxis.Normalize();
|
||||
Quat nq;
|
||||
nq.SetRotationV0V1(zaxis, normal);
|
||||
m_curObj->SetRotation(nq * m_q, eObjectUpdateFlags_UserInput);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CVoxelAligningTool::BeginEditParams([[maybe_unused]] IEditor* ie, [[maybe_unused]] int flags)
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CVoxelAligningTool::EndEditParams()
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CVoxelAligningTool::OnKeyDown([[maybe_unused]] CViewport* view, uint32 nChar, [[maybe_unused]] uint32 nRepCnt, [[maybe_unused]] uint32 nFlags)
|
||||
{
|
||||
if (nChar == VK_ESCAPE)
|
||||
{
|
||||
GetIEditor()->SetEditTool(0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#include <moc_VoxelAligningTool.cpp>
|
||||
@ -1,75 +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.
|
||||
|
||||
// Description : Definition of VoxelAligningTool, edit tool for cloning of objects..
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_VOXELALIGNINGTOOL_H
|
||||
#define CRYINCLUDE_EDITOR_VOXELALIGNINGTOOL_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include "EditTool.h"
|
||||
#endif
|
||||
|
||||
class CBaseObject;
|
||||
|
||||
/*!
|
||||
* CVoxelAligningTool, When created duplicate current selection, and manages cloned selection.
|
||||
*
|
||||
*/
|
||||
|
||||
class CVoxelAligningTool
|
||||
: public CEditTool
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_INVOKABLE CVoxelAligningTool();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Ovverides from CEditTool
|
||||
bool MouseCallback(CViewport* view, EMouseEvent event, QPoint& point, int flags);
|
||||
|
||||
virtual void BeginEditParams(IEditor* ie, int flags);
|
||||
virtual void EndEditParams();
|
||||
|
||||
virtual void Display(DisplayContext& dc);
|
||||
virtual bool OnKeyDown(CViewport* view, uint32 nChar, uint32 nRepCnt, uint32 nFlags);
|
||||
virtual bool OnKeyUp([[maybe_unused]] CViewport* view, [[maybe_unused]] uint32 nChar, [[maybe_unused]] uint32 nRepCnt, [[maybe_unused]] uint32 nFlags) { return false; };
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
protected:
|
||||
virtual ~CVoxelAligningTool();
|
||||
// Delete itself.
|
||||
void DeleteThis() { delete this; };
|
||||
|
||||
void ApplyPickedTM2CurObj(const QPoint& point, bool bPickOnlyTerrain = false);
|
||||
void ApplyRotation(Vec3& normal);
|
||||
|
||||
private:
|
||||
|
||||
CBaseObject* m_curObj;
|
||||
Quat m_q;
|
||||
|
||||
enum EPreviewMode
|
||||
{
|
||||
ePM_Idle,
|
||||
ePM_Previewing,
|
||||
};
|
||||
EPreviewMode m_PreviewMode;
|
||||
Matrix34 m_CurObjTMBeforePreviewMode;
|
||||
};
|
||||
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_VOXELALIGNINGTOOL_H
|
||||
@ -1,12 +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.
|
||||
#
|
||||
|
||||
add_subdirectory(CrySCompileServer)
|
||||
@ -1,63 +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.
|
||||
#
|
||||
|
||||
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME})
|
||||
ly_get_list_relative_pal_filename(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common)
|
||||
ly_get_pal_tool_dirs(pal_tool_dirs ${CMAKE_CURRENT_LIST_DIR}/Platform)
|
||||
ly_get_pal_tool_dirs(pal_tool_core_server_dirs ${CMAKE_CURRENT_LIST_DIR}/Core/Server/Platform)
|
||||
|
||||
include(${pal_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
|
||||
|
||||
if(NOT PAL_TRAIT_BUILD_CRYSCOMPILESERVER_SUPPORTED OR NOT PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(platform_tools_files)
|
||||
foreach(enabled_platform ${LY_PAL_TOOLS_ENABLED})
|
||||
string(TOLOWER ${enabled_platform} enabled_platform_lowercase)
|
||||
ly_get_list_relative_pal_filename(pal_tool_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${enabled_platform})
|
||||
list(APPEND platform_tools_files ${pal_tool_dir}/pal_tools_${enabled_platform_lowercase}.cmake)
|
||||
endforeach()
|
||||
|
||||
ly_add_target(
|
||||
NAME CrySCompileServer EXECUTABLE
|
||||
NAMESPACE Legacy
|
||||
FILES_CMAKE
|
||||
cryscompileserver_files.cmake
|
||||
PLATFORM_INCLUDE_FILES
|
||||
Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake
|
||||
${platform_tools_files}
|
||||
${common_dir}/${PAL_TRAIT_COMPILER_ID}/cryscompileserver_${PAL_TRAIT_COMPILER_ID_LOWERCASE}.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
PUBLIC
|
||||
.
|
||||
External
|
||||
PRIVATE
|
||||
${pal_tool_dirs}
|
||||
${pal_tool_core_server_dirs}
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
3rdParty::zlib
|
||||
AZ::AzCore
|
||||
AZ::AzFramework
|
||||
)
|
||||
ly_add_source_properties(
|
||||
SOURCES
|
||||
Core/Server/CrySimpleJobCompile.cpp
|
||||
CrySCompileServer.cpp
|
||||
PROPERTY COMPILE_DEFINITIONS
|
||||
VALUES ${LY_PAL_TOOLS_DEFINES}
|
||||
)
|
||||
ly_add_source_properties(
|
||||
SOURCES Core/Server/CrySimpleServer.cpp
|
||||
PROPERTY COMPILE_DEFINITIONS
|
||||
VALUES ${LY_PAL_TOOLS_DEFINES}
|
||||
)
|
||||
@ -1,39 +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_CRYSCOMPILESERVER_CORE_COMMON_H
|
||||
#define CRYINCLUDE_CRYSCOMPILESERVER_CORE_COMMON_H
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/PlatformDef.h>
|
||||
#include <AzCore/PlatformIncl.h>
|
||||
|
||||
#if defined(AZ_PLATFORM_WINDOWS)
|
||||
# if !defined(_WIN32_WINNT)
|
||||
# define _WIN32_WINNT 0x0501
|
||||
# endif
|
||||
|
||||
// Windows platform requires either a long or an unsigned long/uint64 for the
|
||||
// Interlock instructions.
|
||||
typedef long AtomicCountType;
|
||||
|
||||
#else
|
||||
|
||||
// Linux/Mac platforms don't support a long for the atomic types, only int32 or
|
||||
// int64 (no unsigned support).
|
||||
typedef int32_t AtomicCountType;
|
||||
|
||||
#endif
|
||||
|
||||
#endif // CRYINCLUDE_CRYSCOMPILESERVER_CORE_COMMON_H
|
||||
@ -1,73 +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 "StdTypes.hpp"
|
||||
#include "Error.hpp"
|
||||
#include <tinyxml/tinyxml.h>
|
||||
#include "Server/CrySimpleErrorLog.hpp"
|
||||
#include "Server/CrySimpleJob.hpp"
|
||||
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/Debug/Trace.h>
|
||||
#include <time.h>
|
||||
|
||||
ICryError::ICryError(EErrorType t)
|
||||
: m_eType(t)
|
||||
, m_numDupes(0)
|
||||
{
|
||||
}
|
||||
|
||||
void logmessage(const char* text, ...)
|
||||
{
|
||||
va_list arg;
|
||||
va_start(arg, text);
|
||||
|
||||
char szBuffer[256];
|
||||
char* error = szBuffer;
|
||||
int bufferlen = sizeof(szBuffer) - 1;
|
||||
memset(szBuffer, 0, sizeof(szBuffer));
|
||||
|
||||
long req = CCrySimpleJob::GlobalRequestNumber();
|
||||
|
||||
int ret = azsnprintf(error, bufferlen, "%8ld | ", req);
|
||||
|
||||
if (ret <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
error += ret;
|
||||
bufferlen -= ret;
|
||||
|
||||
time_t ltime;
|
||||
time(<ime);
|
||||
tm today;
|
||||
#if defined(AZ_PLATFORM_WINDOWS)
|
||||
localtime_s(&today, <ime);
|
||||
#else
|
||||
localtime_r(<ime, &today);
|
||||
#endif
|
||||
ret = (int)strftime(error, bufferlen, "%d/%m %H:%M:%S | ", &today);
|
||||
|
||||
if (ret <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
error += ret;
|
||||
bufferlen -= ret;
|
||||
|
||||
vsnprintf(error, bufferlen, text, arg);
|
||||
|
||||
AZ_TracePrintf(0, szBuffer);
|
||||
|
||||
va_end(arg);
|
||||
}
|
||||
@ -1,95 +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 __DXPSERROR__
|
||||
#define __DXPSERROR__
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include "STLHelper.hpp"
|
||||
|
||||
// printf wrapper to format things nicely
|
||||
void logmessage(const char* text, ...);
|
||||
|
||||
class ICryError
|
||||
{
|
||||
public:
|
||||
enum EErrorType
|
||||
{
|
||||
SIMPLE_ERROR = 0,
|
||||
COMPILE_ERROR,
|
||||
};
|
||||
|
||||
enum EOutputFormatType
|
||||
{
|
||||
OUTPUT_EMAIL = 0,
|
||||
OUTPUT_TTY,
|
||||
OUTPUT_HASH,
|
||||
};
|
||||
|
||||
ICryError(EErrorType t);
|
||||
virtual ~ICryError() {};
|
||||
|
||||
EErrorType GetType() const { return m_eType; }
|
||||
|
||||
tdHash Hash() const { return CSTLHelper::Hash(GetErrorName() + GetErrorDetails(OUTPUT_HASH)); };
|
||||
|
||||
virtual bool Compare(const ICryError* err) const
|
||||
{
|
||||
if (GetType() != err->GetType())
|
||||
{
|
||||
return GetType() < err->GetType();
|
||||
}
|
||||
return Hash() < err->Hash();
|
||||
};
|
||||
virtual bool CanMerge([[maybe_unused]] const ICryError* err) const { return true; }
|
||||
|
||||
virtual void AddDuplicate([[maybe_unused]] ICryError* err) { m_numDupes++; }
|
||||
uint32_t NumDuplicates() const { return m_numDupes; }
|
||||
|
||||
virtual void SetUniqueID([[maybe_unused]] int uniqueID) {}
|
||||
|
||||
virtual bool HasFile() const { return false; };
|
||||
|
||||
virtual void AddCCs([[maybe_unused]] std::set<std::string>& ccs) const {}
|
||||
|
||||
virtual std::string GetErrorName() const = 0;
|
||||
virtual std::string GetErrorDetails(EOutputFormatType outputType) const = 0;
|
||||
virtual std::string GetFilename() const { return "NoFile"; }
|
||||
virtual std::string GetFileContents() const { return ""; }
|
||||
private:
|
||||
EErrorType m_eType;
|
||||
uint32_t m_numDupes;
|
||||
};
|
||||
|
||||
class CSimpleError
|
||||
: public ICryError
|
||||
{
|
||||
public:
|
||||
CSimpleError(const std::string& in_text)
|
||||
: ICryError(SIMPLE_ERROR)
|
||||
, m_text(in_text) {}
|
||||
virtual ~CSimpleError() {}
|
||||
|
||||
virtual std::string GetErrorName() const { return m_text; };
|
||||
virtual std::string GetErrorDetails([[maybe_unused]] EOutputFormatType outputType) const { return m_text; };
|
||||
private:
|
||||
std::string m_text;
|
||||
};
|
||||
|
||||
|
||||
#define CrySimple_ERROR(X) throw new CSimpleError(X)
|
||||
#define CrySimple_SECURE_START try{
|
||||
#define CrySimple_SECURE_END }catch (const ICryError* err) {printf(err->GetErrorName().c_str()); delete err; }
|
||||
|
||||
#endif
|
||||
@ -1,334 +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 __CSCMD5__
|
||||
#define __CSCMD5__
|
||||
|
||||
/*
|
||||
* This code implements the MD5 message-digest algorithm.
|
||||
* The algorithm is due to Ron Rivest. This code was
|
||||
* written by Colin Plumb in 1993, no copyright is claimed.
|
||||
* This code is in the public domain; do with it what you wish.
|
||||
*
|
||||
* Equivalent code is available from RSA Data Security, Inc.
|
||||
* This code has been tested against that, and is equivalent,
|
||||
* except that you don't need to include two pages of legalese
|
||||
* with every copy.
|
||||
*
|
||||
* To compute the message digest of a chunk of bytes, declare an
|
||||
* MD5Context structure, pass it to MD5Init, call MD5Update as
|
||||
* needed on buffers full of bytes, and then call MD5Final, which
|
||||
* will fill a supplied 16-byte array with the digest.
|
||||
*/
|
||||
|
||||
/* This code was modified in 1997 by Jim Kingdon of Cyclic Software to
|
||||
not require an integer type which is exactly 32 bits. This work
|
||||
draws on the changes for the same purpose by Tatu Ylonen
|
||||
<ylo@cs.hut.fi> as part of SSH, but since I didn't actually use
|
||||
that code, there is no copyright issue. I hereby disclaim
|
||||
copyright in any changes I have made; this code remains in the
|
||||
public domain. */
|
||||
|
||||
/* Note regarding cvs_* namespace: this avoids potential conflicts
|
||||
with libraries such as some versions of Kerberos. No particular
|
||||
need to worry about whether the system supplies an MD5 library, as
|
||||
this file is only about 3k of object code. */
|
||||
|
||||
|
||||
struct cvs_MD5Context
|
||||
{
|
||||
uint32_t buf[4];
|
||||
uint32_t bits[2];
|
||||
unsigned char in[64];
|
||||
};
|
||||
|
||||
void cvs_MD5Init(struct cvs_MD5Context* context);
|
||||
void cvs_MD5Update(struct cvs_MD5Context* context, unsigned char const* buf, unsigned len);
|
||||
void cvs_MD5Final(unsigned char digest[16], struct cvs_MD5Context* context);
|
||||
void cvs_MD5Transform(uint32_t buf[4], const unsigned char in[64]);
|
||||
|
||||
/* Little-endian byte-swapping routines. Note that these do not
|
||||
depend on the size of datatypes such as uint32_t, nor do they require
|
||||
us to detect the endianness of the machine we are running on. It
|
||||
is possible they should be macros for speed, but I would be
|
||||
surprised if they were a performance bottleneck for MD5. */
|
||||
|
||||
uint32_t getu32 (const unsigned char* addr)
|
||||
{
|
||||
return (((((unsigned long)addr[3] << 8) | addr[2]) << 8) | addr[1]) << 8 | addr[0];
|
||||
}
|
||||
|
||||
void putu32(uint32_t data, unsigned char* addr)
|
||||
{
|
||||
addr[0] = (unsigned char)data;
|
||||
addr[1] = (unsigned char)(data >> 8);
|
||||
addr[2] = (unsigned char)(data >> 16);
|
||||
addr[3] = (unsigned char)(data >> 24);
|
||||
}
|
||||
|
||||
/*
|
||||
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
|
||||
* initialization constants.
|
||||
*/
|
||||
void cvs_MD5Init(cvs_MD5Context& rCtx)
|
||||
{
|
||||
rCtx.buf[0] = 0x67452301;
|
||||
rCtx.buf[1] = 0xefcdab89;
|
||||
rCtx.buf[2] = 0x98badcfe;
|
||||
rCtx.buf[3] = 0x10325476;
|
||||
rCtx.bits[0] = 0;
|
||||
rCtx.bits[1] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update context to reflect the concatenation of another buffer full
|
||||
* of bytes.
|
||||
*/
|
||||
void cvs_MD5Update(cvs_MD5Context& rCtx, unsigned char const* buf, uint32_t len)
|
||||
{
|
||||
uint32_t t;
|
||||
|
||||
/* Update bitcount */
|
||||
|
||||
t = rCtx.bits[0];
|
||||
if ((rCtx.bits[0] = (t + ((uint32_t)len << 3)) & 0xffffffff) < t)
|
||||
{
|
||||
rCtx.bits[1]++; /* Carry from low to high */
|
||||
}
|
||||
rCtx.bits[1] += len >> 29;
|
||||
|
||||
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
|
||||
|
||||
/* Handle any leading odd-sized chunks */
|
||||
|
||||
if (t)
|
||||
{
|
||||
unsigned char* p = rCtx.in + t;
|
||||
|
||||
t = 64 - t;
|
||||
if (len < t)
|
||||
{
|
||||
memcpy(p, buf, len);
|
||||
return;
|
||||
}
|
||||
memcpy(p, buf, t);
|
||||
cvs_MD5Transform (rCtx.buf, rCtx.in);
|
||||
buf += t;
|
||||
len -= t;
|
||||
}
|
||||
|
||||
/* Process data in 64-byte chunks */
|
||||
|
||||
while (len >= 64)
|
||||
{
|
||||
memcpy(rCtx.in, buf, 64);
|
||||
cvs_MD5Transform (rCtx.buf, rCtx.in);
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
/* Handle any remaining bytes of data. */
|
||||
|
||||
memcpy(rCtx.in, buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Final wrapup - pad to 64-byte boundary with the bit pattern
|
||||
* 1 0* (64-bit count of bits processed, MSB-first)
|
||||
*/
|
||||
void cvs_MD5Final(unsigned char digest[16], cvs_MD5Context& rCtx)
|
||||
{
|
||||
unsigned count;
|
||||
uint8_t* p;
|
||||
|
||||
/* Compute number of bytes mod 64 */
|
||||
count = (rCtx.bits[0] >> 3) & 0x3F;
|
||||
|
||||
/* Set the first char of padding to 0x80. This is safe since there is
|
||||
always at least one byte free */
|
||||
p = rCtx.in + count;
|
||||
*p++ = 0x80;
|
||||
|
||||
/* Bytes of padding needed to make 64 bytes */
|
||||
count = 64 - 1 - count;
|
||||
|
||||
/* Pad out to 56 mod 64 */
|
||||
if (count < 8)
|
||||
{
|
||||
/* Two lots of padding: Pad the first block to 64 bytes */
|
||||
memset(p, 0, count);
|
||||
cvs_MD5Transform (rCtx.buf, rCtx.in);
|
||||
|
||||
/* Now fill the next block with 56 bytes */
|
||||
memset(rCtx.in, 0, 56);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Pad block to 56 bytes */
|
||||
memset(p, 0, count - 8);
|
||||
}
|
||||
|
||||
/* Append length in bits and transform */
|
||||
putu32(rCtx.bits[0], rCtx.in + 56);
|
||||
putu32(rCtx.bits[1], rCtx.in + 60);
|
||||
|
||||
cvs_MD5Transform (rCtx.buf, rCtx.in);
|
||||
putu32(rCtx.buf[0], digest);
|
||||
putu32(rCtx.buf[1], digest + 4);
|
||||
putu32(rCtx.buf[2], digest + 8);
|
||||
putu32(rCtx.buf[3], digest + 12);
|
||||
//memset(&rCtx,0,sizeof(rCtx)); // In case it's sensitive
|
||||
}
|
||||
|
||||
|
||||
/* The four core functions - F1 is optimized somewhat */
|
||||
|
||||
/* #define F1(x, y, z) (x & y | ~x & z) */
|
||||
#define F1(x, y, z) (z ^ (x & (y ^ z)))
|
||||
#define F2(x, y, z) F1(z, x, y)
|
||||
#define F3(x, y, z) (x ^ y ^ z)
|
||||
#define F4(x, y, z) (y ^ (x | ~z))
|
||||
|
||||
/* This is the central step in the MD5 algorithm. */
|
||||
#define MD5STEP(f, w, x, y, z, data, s) \
|
||||
(w += f(x, y, z) + data, w &= 0xffffffff, w = w << s | w >> (32 - s), w += x)
|
||||
|
||||
/*
|
||||
* The core of the MD5 algorithm, this alters an existing MD5 hash to
|
||||
* reflect the addition of 16 longwords of new data. MD5Update blocks
|
||||
* the data and converts bytes into longwords for this routine.
|
||||
*/
|
||||
void cvs_MD5Transform(uint32_t buf[4], const unsigned char inraw[64])
|
||||
{
|
||||
uint32_t a, b, c, d;
|
||||
uint32_t in[16];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; ++i)
|
||||
{
|
||||
in[i] = getu32 (inraw + 4 * i);
|
||||
}
|
||||
|
||||
a = buf[0];
|
||||
b = buf[1];
|
||||
c = buf[2];
|
||||
d = buf[3];
|
||||
|
||||
MD5STEP(F1, a, b, c, d, in[ 0] + 0xd76aa478, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 1] + 0xe8c7b756, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[ 2] + 0x242070db, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[ 3] + 0xc1bdceee, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[ 4] + 0xf57c0faf, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 5] + 0x4787c62a, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[ 6] + 0xa8304613, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[ 7] + 0xfd469501, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[ 8] + 0x698098d8, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 9] + 0x8b44f7af, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
|
||||
|
||||
MD5STEP(F2, a, b, c, d, in[ 1] + 0xf61e2562, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[ 6] + 0xc040b340, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 0] + 0xe9b6c7aa, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[ 5] + 0xd62f105d, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 4] + 0xe7d3fbc8, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[ 9] + 0x21e1cde6, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[ 3] + 0xf4d50d87, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 8] + 0x455a14ed, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[ 2] + 0xfcefa3f8, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[ 7] + 0x676f02d9, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
|
||||
|
||||
MD5STEP(F3, a, b, c, d, in[ 5] + 0xfffa3942, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 8] + 0x8771f681, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[ 1] + 0xa4beea44, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 4] + 0x4bdecfa9, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[ 7] + 0xf6bb4b60, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 0] + 0xeaa127fa, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[ 3] + 0xd4ef3085, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[ 6] + 0x04881d05, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[ 9] + 0xd9d4d039, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[ 2] + 0xc4ac5665, 23);
|
||||
|
||||
MD5STEP(F4, a, b, c, d, in[ 0] + 0xf4292244, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[ 7] + 0x432aff97, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[ 5] + 0xfc93a039, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[ 3] + 0x8f0ccc92, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[ 1] + 0x85845dd1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[ 8] + 0x6fa87e4f, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[ 6] + 0xa3014314, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[ 4] + 0xf7537e82, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[ 2] + 0x2ad7d2bb, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[ 9] + 0xeb86d391, 21);
|
||||
|
||||
buf[0] += a;
|
||||
buf[1] += b;
|
||||
buf[2] += c;
|
||||
buf[3] += d;
|
||||
}
|
||||
|
||||
/*
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
struct cvs_MD5Context context;
|
||||
unsigned char checksum[16];
|
||||
int i;
|
||||
int j;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
fprintf (stderr, "usage: %s string-to-hash\n", argv[0]);
|
||||
exit (1);
|
||||
}
|
||||
for (j = 1; j < argc; ++j)
|
||||
{
|
||||
printf ("MD5 (\"%s\") = ", argv[j]);
|
||||
cvs_MD5Init (&context);
|
||||
cvs_MD5Update (&context, argv[j], strlen (argv[j]));
|
||||
cvs_MD5Final (checksum, &context);
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
printf ("%02x", (unsigned int) checksum[i]);
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,420 +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 "Mailer.h"
|
||||
#include "WindowsAPIImplementation.h"
|
||||
|
||||
#include <AzCore/PlatformDef.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if defined(AZ_PLATFORM_MAC)
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#elif defined(AZ_PLATFORM_WINDOWS)
|
||||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
|
||||
#pragma comment(lib,"ws2_32.lib")
|
||||
|
||||
|
||||
namespace // helpers
|
||||
{
|
||||
static const char cb64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
|
||||
void Base64EncodeBlock(const unsigned char* in, unsigned char* out)
|
||||
{
|
||||
out[0] = cb64[in[0] >> 2];
|
||||
out[1] = cb64[((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4)];
|
||||
out[2] = cb64[((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6)];
|
||||
out[3] = cb64[in[2] & 0x3f];
|
||||
}
|
||||
|
||||
|
||||
void Base64EncodeBlock(const unsigned char* in, unsigned char* out, int len)
|
||||
{
|
||||
out[0] = cb64[in[0] >> 2];
|
||||
out[1] = cb64[((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4)];
|
||||
out[2] = (unsigned char) (len > 1 ? cb64[((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6)] : '=');
|
||||
out[3] = (unsigned char) (len > 2 ? cb64[in[2] & 0x3f] : '=');
|
||||
}
|
||||
|
||||
|
||||
void Base64Encode(const unsigned char* pSrc, const size_t srcLen, unsigned char* pDst, [[maybe_unused]] const size_t dstLen)
|
||||
{
|
||||
assert(dstLen >= 4 * ((srcLen + 2) / 3));
|
||||
|
||||
size_t len = srcLen;
|
||||
for (; len > 2; len -= 3, pSrc += 3, pDst += 4)
|
||||
{
|
||||
Base64EncodeBlock(pSrc, pDst);
|
||||
}
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
unsigned char in[3];
|
||||
in[0] = pSrc[0];
|
||||
in[1] = len > 1 ? pSrc[1] : 0;
|
||||
in[2] = 0;
|
||||
Base64EncodeBlock(in, pDst, (int) len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string Base64EncodeString(const std::string& in)
|
||||
{
|
||||
const size_t srcLen = in.size();
|
||||
const size_t dstLen = 4 * ((srcLen + 2) / 3);
|
||||
std::string out(dstLen, 0);
|
||||
|
||||
Base64Encode((const unsigned char*) in.c_str(), srcLen, (unsigned char*) out.c_str(), dstLen);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
const char* ExtractFileName(const char* filepath)
|
||||
{
|
||||
for (const char* p = filepath + strlen(filepath) - 1; p >= filepath; --p)
|
||||
{
|
||||
if (*p == '\\' || *p == '/')
|
||||
{
|
||||
return p + 1;
|
||||
}
|
||||
}
|
||||
return filepath;
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::atomic_long CSMTPMailer::ms_OpenSockets = {0};
|
||||
|
||||
CSMTPMailer::CSMTPMailer(const tstr& username, const tstr& password, const tstr& server, int port)
|
||||
: m_server(server)
|
||||
, m_username(username)
|
||||
, m_password(password)
|
||||
, m_port(port)
|
||||
, m_winSockAvail(false)
|
||||
, m_response()
|
||||
{
|
||||
#if defined(AZ_PLATFORM_WINDOWS)
|
||||
WSADATA wd;
|
||||
m_winSockAvail = WSAStartup(MAKEWORD(1, 1), &wd) == 0;
|
||||
if (!m_winSockAvail)
|
||||
{
|
||||
m_response += "Error: Unable to initialize WinSock 1.1\n";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
CSMTPMailer::~CSMTPMailer()
|
||||
{
|
||||
#if defined(AZ_PLATFORM_WINDOWS)
|
||||
if (m_winSockAvail)
|
||||
{
|
||||
WSACleanup();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void CSMTPMailer::ReceiveLine(SOCKET connection)
|
||||
{
|
||||
char buf[1025];
|
||||
int ret = recv(connection, buf, sizeof(buf) - 1, 0);
|
||||
if (ret == SOCKET_ERROR)
|
||||
{
|
||||
ret = azsnprintf(buf, sizeof(buf), "Error: WinSock error %d during recv()\n", WSAGetLastError());
|
||||
if (ret == sizeof(buf) || ret < 0)
|
||||
{
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buf[ret] = 0;
|
||||
}
|
||||
m_response += buf;
|
||||
}
|
||||
|
||||
|
||||
void CSMTPMailer::SendLine(SOCKET connection, const char* format, ...) const
|
||||
{
|
||||
char buf[2049];
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int len = azvsnprintf(buf, sizeof(buf), format, args);
|
||||
if (len == sizeof(buf) || len < 0)
|
||||
{
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
len = sizeof(buf) - 1;
|
||||
}
|
||||
va_end(args);
|
||||
send(connection, buf, len, 0);
|
||||
}
|
||||
|
||||
|
||||
void CSMTPMailer::SendRaw(SOCKET connection, const char* data, size_t dataLen) const
|
||||
{
|
||||
send(connection, data, (int) dataLen, 0);
|
||||
}
|
||||
|
||||
|
||||
void CSMTPMailer::SendFile(SOCKET connection, const tattachment& filepath, const char* boundary) const
|
||||
{
|
||||
AZ::IO::SystemFile inputFile;
|
||||
const bool wasSuccessful = inputFile.Open(filepath.second.c_str(), AZ::IO::SystemFile::SF_OPEN_READ_ONLY);
|
||||
if (wasSuccessful)
|
||||
{
|
||||
SendLine(connection, "--%s\r\n", boundary);
|
||||
SendLine(connection, "Content-Type: application/octet-stream\r\n");
|
||||
SendLine(connection, "Content-Transfer-Encoding: base64\r\n");
|
||||
SendLine(connection, "Content-Disposition: attachment; filename=\"%s\"\r\n", filepath.first.c_str());
|
||||
SendLine(connection, "\r\n");
|
||||
|
||||
AZ::IO::SystemFile::SizeType fileSize = inputFile.Length();
|
||||
while (fileSize)
|
||||
{
|
||||
const int DEF_BLOCK_SIZE = 128; // 72
|
||||
char in[3 * DEF_BLOCK_SIZE];
|
||||
size_t blockSize = fileSize > sizeof(in) ? sizeof(in) : fileSize;
|
||||
inputFile.Read(blockSize, in);
|
||||
|
||||
char out[4 * DEF_BLOCK_SIZE];
|
||||
Base64Encode((unsigned char*) in, blockSize, (unsigned char*) out, sizeof(out));
|
||||
SendRaw(connection, out, 4 * ((blockSize + 2) / 3));
|
||||
|
||||
SendLine(connection, "\r\n"); // seems to get sent faster if you split up the data lines
|
||||
|
||||
fileSize -= blockSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SOCKET CSMTPMailer::Open(const char* host, unsigned short port, sockaddr_in& serverAddress)
|
||||
{
|
||||
SOCKET connection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (connection == INVALID_SOCKET)
|
||||
{
|
||||
m_response += "Error: Failed to create socket\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct addrinfo* addressInfo{};
|
||||
char portBuffer[16];
|
||||
struct addrinfo hints{};
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
azsnprintf(portBuffer, AZStd::size(portBuffer), "%hu", port);
|
||||
int addrInfoReturnCode = getaddrinfo(host, portBuffer, &hints, &addressInfo);
|
||||
if(addrInfoReturnCode != 0)
|
||||
{
|
||||
char buf[1025];
|
||||
int ret = azsnprintf(buf, sizeof(buf), "Error: Host %s not found\n", host);
|
||||
if (ret == sizeof(buf) || ret < 0)
|
||||
{
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
}
|
||||
m_response += buf;
|
||||
closesocket(connection);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (addressInfo)
|
||||
{
|
||||
++ms_OpenSockets;
|
||||
|
||||
serverAddress = *reinterpret_cast<sockaddr_in*>(addressInfo->ai_addr);
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
|
||||
void CSMTPMailer::AddReceivers(SOCKET connection, const tstrcol& receivers)
|
||||
{
|
||||
for (tstrcol::const_iterator it = receivers.begin(), itEnd = receivers.end(); it != itEnd; ++it)
|
||||
{
|
||||
if (!(*it).empty())
|
||||
{
|
||||
SendLine(connection, "rcpt to: %s\r\n", (*it).c_str());
|
||||
ReceiveLine(connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CSMTPMailer::AssignReceivers(SOCKET connection, const char* receiverTag, const tstrcol& receivers)
|
||||
{
|
||||
tstrcol::const_iterator it = receivers.begin();
|
||||
tstrcol::const_iterator itEnd = receivers.end();
|
||||
|
||||
while (it != itEnd && (*it).empty())
|
||||
{
|
||||
++it;
|
||||
}
|
||||
|
||||
if (it != itEnd)
|
||||
{
|
||||
tstr out(receiverTag);
|
||||
out += *it;
|
||||
++it;
|
||||
for (; it != itEnd; ++it)
|
||||
{
|
||||
if (!(*it).empty())
|
||||
{
|
||||
out += "; ";
|
||||
out += *it;
|
||||
}
|
||||
}
|
||||
out += "\r\n";
|
||||
SendLine(connection, out.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CSMTPMailer::SendAttachments(SOCKET connection, const tattachlist& attachments, const char* boundary)
|
||||
{
|
||||
for (tattachlist::const_iterator it = attachments.begin(), itEnd = attachments.end(); it != itEnd; ++it)
|
||||
{
|
||||
if (!(*it).first.empty() && !(*it).second.empty())
|
||||
{
|
||||
SendFile(connection, *it, boundary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CSMTPMailer::IsEmpty(const tstrcol& col) const
|
||||
{
|
||||
if (!col.empty())
|
||||
{
|
||||
for (tstrcol::const_iterator it = col.begin(), itEnd = col.end(); it != itEnd; ++it)
|
||||
{
|
||||
if (!(*it).empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CSMTPMailer::Send(const tstr& from, const tstrcol& to, const tstrcol& cc, const tstrcol& bcc, const tstr& subject, const tstr& body, const tattachlist& attachments)
|
||||
{
|
||||
if (!m_winSockAvail)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (from.empty() || IsEmpty(to))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
sockaddr_in serverAddress;
|
||||
SOCKET connection = Open(m_server.c_str(), m_port, serverAddress); // SMTP telnet (usually port 25)
|
||||
if (connection == INVALID_SOCKET)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (connect(connection, (sockaddr*) &serverAddress, sizeof(serverAddress)) != SOCKET_ERROR)
|
||||
{
|
||||
ReceiveLine(connection);
|
||||
|
||||
SendLine(connection, "helo localhost\r\n");
|
||||
ReceiveLine(connection);
|
||||
|
||||
if (!m_username.empty() && !m_password.empty())
|
||||
{
|
||||
SendLine(connection, "auth login\r\n"); // most servers should implement this (todo: otherwise fall back to PLAIN or CRAM-MD5 (requiring EHLO))
|
||||
ReceiveLine(connection);
|
||||
SendLine(connection, "%s\r\n", Base64EncodeString(m_username).c_str());
|
||||
ReceiveLine(connection);
|
||||
SendLine(connection, "%s\r\n", Base64EncodeString(m_password).c_str());
|
||||
ReceiveLine(connection);
|
||||
}
|
||||
|
||||
SendLine(connection, "mail from: %s\r\n", from.c_str());
|
||||
ReceiveLine(connection);
|
||||
|
||||
AddReceivers(connection, to);
|
||||
AddReceivers(connection, cc);
|
||||
AddReceivers(connection, bcc);
|
||||
|
||||
SendLine(connection, "data\r\n");
|
||||
ReceiveLine(connection);
|
||||
|
||||
SendLine(connection, "From: %s\r\n", from.c_str());
|
||||
AssignReceivers(connection, "To: ", to);
|
||||
AssignReceivers(connection, "Cc: ", cc);
|
||||
AssignReceivers(connection, "Bcc: ", bcc);
|
||||
|
||||
SendLine(connection, "Subject: %s\r\n", subject.c_str());
|
||||
|
||||
static const char boundary[] = "------a95ed0b485e4a9b0fd4ff93f50ad06ca"; // beware, boundary should not clash with text content of message body!
|
||||
|
||||
SendLine(connection, "MIME-Version: 1.0\r\n");
|
||||
SendLine(connection, "Content-Type: multipart/mixed; boundary=\"%s\"\r\n", boundary);
|
||||
SendLine(connection, "\r\n");
|
||||
SendLine(connection, "This is a multi-part message in MIME format.\r\n");
|
||||
|
||||
SendLine(connection, "--%s\r\n", boundary);
|
||||
SendLine(connection, "Content-Type: text/plain; charset=iso-8859-1; format=flowed\r\n"); // the used charset should support the commonly used special characters of western languages
|
||||
SendLine(connection, "Content-Transfer-Encoding: 7bit\r\n");
|
||||
SendLine(connection, "\r\n");
|
||||
SendRaw(connection, body.c_str(), body.size());
|
||||
SendLine(connection, "\r\n");
|
||||
|
||||
SendAttachments(connection, attachments, boundary);
|
||||
|
||||
SendLine(connection, "--%s--\r\n", boundary);
|
||||
|
||||
SendLine(connection, "\r\n.\r\n");
|
||||
ReceiveLine(connection);
|
||||
|
||||
SendLine(connection, "quit\r\n");
|
||||
ReceiveLine(connection);
|
||||
}
|
||||
else
|
||||
{
|
||||
char buf[1025];
|
||||
int ret = azsnprintf(buf, sizeof(buf), "Error: Failed to connect to %s:%d\n", m_server.c_str(), m_port);
|
||||
if (ret == sizeof(buf) || ret < 0)
|
||||
{
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
}
|
||||
m_response += buf;
|
||||
return false;
|
||||
}
|
||||
|
||||
closesocket(connection);
|
||||
--ms_OpenSockets;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const char* CSMTPMailer::GetResponse() const
|
||||
{
|
||||
return m_response.c_str();
|
||||
}
|
||||
@ -1,72 +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_CRYSCOMPILESERVER_CORE_MAILER_H
|
||||
#define CRYINCLUDE_CRYSCOMPILESERVER_CORE_MAILER_H
|
||||
#pragma once
|
||||
|
||||
#include "Common.h"
|
||||
#include "Server/CrySimpleSock.hpp"
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <AzCore/std/parallel/atomic.h>
|
||||
|
||||
class CSMTPMailer
|
||||
{
|
||||
public:
|
||||
typedef std::string tstr;
|
||||
typedef std::set<tstr> tstrcol;
|
||||
typedef std::pair<std::string, std::string> tattachment;
|
||||
typedef std::list<tattachment> tattachlist;
|
||||
|
||||
static const int DEFAULT_PORT = 25;
|
||||
static AZStd::atomic_long ms_OpenSockets;
|
||||
|
||||
public:
|
||||
CSMTPMailer(const tstr& username, const tstr& password, const tstr& server, int port = DEFAULT_PORT);
|
||||
~CSMTPMailer();
|
||||
|
||||
bool Send(const tstr& from, const tstrcol& to, const tstrcol& cc, const tstrcol& bcc, const tstr& subject, const tstr& body, const tattachlist& attachments);
|
||||
const char* GetResponse() const;
|
||||
|
||||
static long GetOpenSockets() { return ms_OpenSockets; }
|
||||
|
||||
private:
|
||||
void ReceiveLine(SOCKET connection);
|
||||
void SendLine(SOCKET connection, const char* format, ...) const;
|
||||
void SendRaw(SOCKET connection, const char* data, size_t dataLen) const;
|
||||
void SendFile(SOCKET connection, const tattachment& file, const char* boundary) const;
|
||||
|
||||
SOCKET Open(const char* host, unsigned short port, sockaddr_in& serverAddress);
|
||||
|
||||
void AddReceivers(SOCKET connection, const tstrcol& receivers);
|
||||
void AssignReceivers(SOCKET connection, const char* receiverTag, const tstrcol& receivers);
|
||||
void SendAttachments(SOCKET connection, const tattachlist& attachments, const char* boundary);
|
||||
|
||||
bool IsEmpty(const tstrcol& col) const;
|
||||
|
||||
private:
|
||||
|
||||
std::unique_ptr<CCrySimpleSock> m_socket;
|
||||
tstr m_server;
|
||||
tstr m_username;
|
||||
tstr m_password;
|
||||
int m_port;
|
||||
|
||||
bool m_winSockAvail;
|
||||
tstr m_response;
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_CRYSCOMPILESERVER_CORE_MAILER_H
|
||||
@ -1,343 +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 "StdTypes.hpp"
|
||||
#include "Error.hpp"
|
||||
#include "STLHelper.hpp"
|
||||
|
||||
#include <AzCore/PlatformDef.h>
|
||||
#include <AzCore/PlatformIncl.h>
|
||||
#include <AzCore/Debug/Trace.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/Casting/lossy_cast.h>
|
||||
|
||||
#if defined(AZ_PLATFORM_WINDOWS)
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#include "MD5.hpp"
|
||||
#include <assert.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <cstdio>
|
||||
|
||||
void CSTLHelper::Log(const std::string& rLog)
|
||||
{
|
||||
const std::string Output = rLog + "\n";
|
||||
logmessage(Output.c_str());
|
||||
}
|
||||
|
||||
void CSTLHelper::Tokenize(tdEntryVec& rRet, const std::string& Tokens, const std::string& Separator)
|
||||
{
|
||||
rRet.clear();
|
||||
std::string::size_type Pt;
|
||||
std::string::size_type Start = 0;
|
||||
std::string::size_type SSize = Separator.size();
|
||||
|
||||
while ((Pt = Tokens.find(Separator, Start)) != std::string::npos)
|
||||
{
|
||||
std::string SubStr = Tokens.substr(Start, Pt - Start);
|
||||
rRet.push_back(SubStr);
|
||||
Start = Pt + SSize;
|
||||
}
|
||||
|
||||
rRet.push_back(Tokens.substr(Start));
|
||||
}
|
||||
|
||||
|
||||
void CSTLHelper::Replace(std::string& rRet, const std::string& rSrc, const std::string& rToReplace, const std::string& rReplacement)
|
||||
{
|
||||
std::vector<uint8_t> Out;
|
||||
std::vector<uint8_t> In(rSrc.c_str(), rSrc.c_str() + rSrc.size() + 1);
|
||||
Replace(Out, In, rToReplace, rReplacement);
|
||||
rRet = std::string(reinterpret_cast<char*>(&Out[0]));
|
||||
}
|
||||
|
||||
void CSTLHelper::Replace(std::vector<uint8_t>& rRet, const std::vector<uint8_t>& rTokenSrc, const std::string& rToReplace, const std::string& rReplacement)
|
||||
{
|
||||
rRet.clear();
|
||||
size_t SSize = rToReplace.size();
|
||||
for (size_t a = 0, Size = rTokenSrc.size(); a < Size; a++)
|
||||
{
|
||||
if (a + SSize < Size && strncmp((const char*)&rTokenSrc[a], rToReplace.c_str(), SSize) == 0)
|
||||
{
|
||||
for (size_t b = 0, RSize = rReplacement.size(); b < RSize; b++)
|
||||
{
|
||||
rRet.push_back(rReplacement.c_str()[b]);
|
||||
}
|
||||
a += SSize - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
rRet.push_back(rTokenSrc[a]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tdToken CSTLHelper::SplitToken(const std::string& rToken, const std::string& rSeparator)
|
||||
{
|
||||
#undef min
|
||||
using namespace std;
|
||||
string Token;
|
||||
Remove(Token, rToken, ' ');
|
||||
|
||||
string::size_type Pt = Token.find(rSeparator);
|
||||
return tdToken(Token.substr(0, Pt), Token.substr(std::min(Pt + 1, Token.size())));
|
||||
}
|
||||
|
||||
void CSTLHelper::Splitizer(tdTokenList& rTokenList, const tdEntryVec& rFilter, const std::string& rSeparator)
|
||||
{
|
||||
rTokenList.clear();
|
||||
for (size_t a = 0, Size = rFilter.size(); a < Size; a++)
|
||||
{
|
||||
rTokenList.push_back(SplitToken(rFilter[a], rSeparator));
|
||||
}
|
||||
}
|
||||
|
||||
void CSTLHelper::Trim(std::string& rStr, const std::string& charsToTrim)
|
||||
{
|
||||
std::string::size_type Pt1 = rStr.find_first_not_of(charsToTrim);
|
||||
if (Pt1 == std::string::npos)
|
||||
{
|
||||
// At this point the string could be empty or it could only contain 'charsToTrim' characters.
|
||||
// In case it's the later then trim should be applied by leaving the string empty.
|
||||
rStr = "";
|
||||
return;
|
||||
}
|
||||
|
||||
std::string::size_type Pt2 = rStr.find_last_not_of(charsToTrim) + 1;
|
||||
|
||||
Pt2 = Pt2 - Pt1;
|
||||
rStr = rStr.substr(Pt1, Pt2);
|
||||
}
|
||||
|
||||
void CSTLHelper::Remove(std::string& rTokenDst, const std::string& rTokenSrc, const char C)
|
||||
{
|
||||
using namespace std;
|
||||
AZ_PUSH_DISABLE_WARNING(4996, "-Wdeprecated-declarations")
|
||||
remove_copy_if(rTokenSrc.begin(), rTokenSrc.end(), back_inserter(rTokenDst), [C](char token) { return token == C; });
|
||||
AZ_POP_DISABLE_WARNING
|
||||
}
|
||||
|
||||
|
||||
bool CSTLHelper::ToFile(const std::string& rFileName, const std::vector<uint8_t>& rOut)
|
||||
{
|
||||
if (rOut.size() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::IO::SystemFile outputFile;
|
||||
const bool wasSuccessful = outputFile.Open(rFileName.c_str(), AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY | AZ::IO::SystemFile::SF_OPEN_CREATE);
|
||||
|
||||
if (wasSuccessful == false)
|
||||
{
|
||||
AZ_Error("ShaderCompiler", wasSuccessful, "CSTLHelper::ToFile Could not create file: %s", rFileName.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
outputFile.Write(&rOut[0], rOut.size());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSTLHelper::FromFile(const std::string& rFileName, std::vector<uint8_t>& rIn)
|
||||
{
|
||||
AZ::IO::SystemFile inputFile;
|
||||
bool wasSuccess = inputFile.Open(rFileName.c_str(), AZ::IO::SystemFile::SF_OPEN_READ_WRITE);
|
||||
if (!wasSuccess)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::IO::SystemFile::SizeType fileSize = inputFile.Length();
|
||||
if (fileSize <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
rIn.resize(fileSize);
|
||||
AZ::IO::SystemFile::SizeType actualReadAmount = inputFile.Read(fileSize, &rIn[0]);
|
||||
|
||||
return actualReadAmount == fileSize;
|
||||
}
|
||||
|
||||
bool CSTLHelper::ToFileCompressed(const std::string& rFileName, const std::vector<uint8_t>& rOut)
|
||||
{
|
||||
std::vector<uint8_t> buf;
|
||||
|
||||
unsigned long sourceLen = (unsigned long)rOut.size();
|
||||
unsigned long destLen = compressBound(sourceLen) + 16;
|
||||
|
||||
buf.resize(destLen);
|
||||
compress(buf.data(), &destLen, &rOut[0], sourceLen);
|
||||
|
||||
if (destLen > 0)
|
||||
{
|
||||
AZ::IO::SystemFile outputFile;
|
||||
const bool wasSuccessful = outputFile.Open(rFileName.c_str(), AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY | AZ::IO::SystemFile::SF_OPEN_CREATE);
|
||||
AZ_Error("ShaderCompiler", wasSuccessful, "Could not create compressed file: %s", rFileName.c_str());
|
||||
|
||||
if (wasSuccessful == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::IO::SystemFile::SizeType bytesWritten = outputFile.Write(&sourceLen, sizeof(sourceLen));
|
||||
AZ_Error("ShaderCompiler", bytesWritten == sizeof(sourceLen), "Could not save out size of compressed data to %s", rFileName.c_str());
|
||||
|
||||
if (bytesWritten != sizeof(sourceLen))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bytesWritten = outputFile.Write(buf.data(), destLen);
|
||||
AZ_Error("ShaderCompiler", bytesWritten == destLen, "Could not save out compressed data to %s", rFileName.c_str());
|
||||
|
||||
if (bytesWritten != destLen)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CSTLHelper::FromFileCompressed(const std::string& rFileName, std::vector<uint8_t>& rIn)
|
||||
{
|
||||
std::vector<uint8_t> buf;
|
||||
AZ::IO::SystemFile inputFile;
|
||||
const bool wasSuccessful = inputFile.Open(rFileName.c_str(), AZ::IO::SystemFile::SF_OPEN_READ_ONLY);
|
||||
AZ_Error("ShaderCompiler", wasSuccessful, "Could not read: ", rFileName.c_str());
|
||||
|
||||
if (!wasSuccessful)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::IO::SystemFile::SizeType FileLen = inputFile.Length();
|
||||
AZ_Error("ShaderCompiler", FileLen > 0, "Error getting file-size of ", rFileName.c_str());
|
||||
|
||||
if (FileLen <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned long uncompressedLen = 0;
|
||||
// Possible, expected, loss of data from u64 to u32. Zlib supports only unsigned long
|
||||
unsigned long sourceLen = azlossy_caster((FileLen - 4));
|
||||
|
||||
buf.resize(sourceLen);
|
||||
|
||||
AZ::IO::SystemFile::SizeType bytesReadIn = inputFile.Read(sizeof(uncompressedLen), &uncompressedLen);
|
||||
AZ_Warning("ShaderCompiler", bytesReadIn == sizeof(uncompressedLen), "Expected to read in %d but read in %d from file %s", sizeof(uncompressedLen), bytesReadIn, rFileName.c_str());
|
||||
|
||||
bytesReadIn = inputFile.Read(buf.size(), buf.data());
|
||||
AZ_Warning("ShaderCompiler", bytesReadIn == buf.size(), "Expected to read in %d but read in %d from file %s", buf.size(), bytesReadIn, rFileName.c_str());
|
||||
|
||||
unsigned long nUncompressedBytes = uncompressedLen;
|
||||
rIn.resize(uncompressedLen);
|
||||
int nRes = uncompress(rIn.data(), &nUncompressedBytes, buf.data(), sourceLen);
|
||||
|
||||
return nRes == Z_OK && nUncompressedBytes == uncompressedLen;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CSTLHelper::AppendToFile(const std::string& rFileName, const std::vector<uint8_t>& rOut)
|
||||
{
|
||||
AZ::IO::SystemFile outputFile;
|
||||
int openMode = AZ::IO::SystemFile::SF_OPEN_APPEND;
|
||||
if (!AZ::IO::SystemFile::Exists(rFileName.c_str()))
|
||||
{
|
||||
openMode = AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY;
|
||||
}
|
||||
const bool wasSuccessful = outputFile.Open(rFileName.c_str(), openMode);
|
||||
AZ_Error("ShaderCompiler", wasSuccessful, "Could not open file for appending: %s", rFileName.c_str());
|
||||
if (wasSuccessful == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
[[maybe_unused]] AZ::IO::SystemFile::SizeType bytesWritten = outputFile.Write(rOut.data(), rOut.size());
|
||||
AZ_Warning("ShaderCompiler", bytesWritten == rOut.size(), "Did not write out all the data to the file: %s", rFileName.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
tdHash CSTLHelper::Hash(const uint8_t* pData, const size_t Size)
|
||||
{
|
||||
tdHash CheckSum;
|
||||
cvs_MD5Context MD5Context;
|
||||
cvs_MD5Init(MD5Context);
|
||||
cvs_MD5Update(MD5Context, pData, static_cast<uint32_t>(Size));
|
||||
cvs_MD5Final(CheckSum.hash, MD5Context);
|
||||
return CheckSum;
|
||||
}
|
||||
|
||||
static char C2A[17] = "0123456789ABCDEF";
|
||||
|
||||
std::string CSTLHelper::Hash2String(const tdHash& rHash)
|
||||
{
|
||||
std::string Ret;
|
||||
for (size_t a = 0, Size = std::min<size_t>(sizeof(rHash.hash), 16u); a < Size; a++)
|
||||
{
|
||||
const uint8_t C1 = rHash[a] & 0xf;
|
||||
const uint8_t C2 = rHash[a] >> 4;
|
||||
Ret += C2A[C1];
|
||||
Ret += C2A[C2];
|
||||
}
|
||||
return Ret;
|
||||
}
|
||||
|
||||
tdHash CSTLHelper::String2Hash(const std::string& rStr)
|
||||
{
|
||||
assert(rStr.size() == 32);
|
||||
tdHash Ret;
|
||||
for (size_t a = 0, Size = std::min<size_t>(rStr.size(), 32u); a < Size; a += 2)
|
||||
{
|
||||
const uint8_t C1 = rStr.c_str()[a];
|
||||
const uint8_t C2 = rStr.c_str()[a + 1];
|
||||
Ret[a >> 1] = C1 - (C1 >= '0' && C1 <= '9' ? '0' : 'A' - 10);
|
||||
Ret[a >> 1] |= (C2 - (C2 >= '0' && C2 <= '9' ? '0' : 'A' - 10)) << 4;
|
||||
}
|
||||
return Ret;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CSTLHelper::Compress(const std::vector<uint8_t>& rIn, std::vector<uint8_t>& rOut)
|
||||
{
|
||||
unsigned long destLen, sourceLen = (unsigned long)rIn.size();
|
||||
destLen = compressBound(sourceLen) + 16;
|
||||
rOut.resize(destLen + 4);
|
||||
compress(&rOut[4], &destLen, &rIn[0], sourceLen);
|
||||
rOut.resize(destLen + 4);
|
||||
*(uint32_t*)(&rOut[0]) = sourceLen;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSTLHelper::Uncompress(const std::vector<uint8_t>& rIn, std::vector<uint8_t>& rOut)
|
||||
{
|
||||
unsigned long sourceLen = (unsigned long)rIn.size() - 4;
|
||||
unsigned long nUncompressed = *(uint32_t*)(&rIn[0]);
|
||||
unsigned long nUncompressedBytes = nUncompressed;
|
||||
rOut.resize(nUncompressed);
|
||||
int nRes = uncompress(&rOut[0], &nUncompressedBytes, &rIn[4], sourceLen);
|
||||
return nRes == Z_OK && nUncompressed == nUncompressedBytes;
|
||||
}
|
||||
@ -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 __STLHELPER__
|
||||
#define __STLHELPER__
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
typedef std::vector<std::string> tdEntryVec;
|
||||
typedef std::pair<std::string, std::string> tdToken;
|
||||
typedef std::vector<tdToken> tdTokenList;
|
||||
typedef std::vector<uint8_t> tdDataVector;
|
||||
//typedef std::vector<uint8_t> tdHash;
|
||||
|
||||
struct tdHash
|
||||
{
|
||||
uint8_t hash[16];
|
||||
|
||||
inline bool operator<(const tdHash& other) const { return memcmp(hash, other.hash, sizeof(hash)) < 0; }
|
||||
inline bool operator>(const tdHash& other) const { return memcmp(hash, other.hash, sizeof(hash)) > 0; }
|
||||
inline bool operator==(const tdHash& other) const { return memcmp(hash, other.hash, sizeof(hash)) == 0; }
|
||||
inline uint8_t& operator[](size_t nIndex) { return hash[nIndex]; }
|
||||
inline const uint8_t& operator[](size_t nIndex) const { return hash[nIndex]; }
|
||||
};
|
||||
|
||||
class CSTLHelper
|
||||
{
|
||||
static tdHash Hash(const uint8_t* pData, const size_t Size);
|
||||
public:
|
||||
static void Tokenize(tdEntryVec& rRet, const std::string& Tokens, const std::string& Separator);
|
||||
static tdToken SplitToken(const std::string& rToken, const std::string& rSeparator);
|
||||
static void Splitizer(tdTokenList& rTokenList, const tdEntryVec& rFilter, const std::string& rSeparator);
|
||||
static void Trim(std::string& rStr, const std::string& charsToTrim);
|
||||
static void Remove(std::string& rTokenDst, const std::string& rTokenSrc, const char C);
|
||||
static void Replace(std::vector<uint8_t>& rRet, const std::vector<uint8_t>& rTokenSrc, const std::string& rToReplace, const std::string& rReplacement);
|
||||
static void Replace(std::string& rRet, const std::string& rSrc, const std::string& rToReplace, const std::string& rReplacement);
|
||||
|
||||
|
||||
static bool ToFile(const std::string& rFileName, const std::vector<uint8_t>& rOut);
|
||||
static bool FromFile(const std::string& rFileName, std::vector<uint8_t>& rIn);
|
||||
|
||||
static bool AppendToFile(const std::string& rFileName, const std::vector<uint8_t>& rOut);
|
||||
|
||||
static bool ToFileCompressed(const std::string& rFileName, const std::vector<uint8_t>& rOut);
|
||||
static bool FromFileCompressed(const std::string& rFileName, std::vector<uint8_t>& rIn);
|
||||
|
||||
static bool Compress(const std::vector<uint8_t>& rIn, std::vector<uint8_t>& rOut);
|
||||
static bool Uncompress(const std::vector<uint8_t>& rIn, std::vector<uint8_t>& rOut);
|
||||
|
||||
|
||||
static void EndianSwizzleU64(uint64_t& S)
|
||||
{
|
||||
uint8_t* pT = reinterpret_cast<uint8_t*>(&S);
|
||||
uint8_t T;
|
||||
T = pT[0];
|
||||
pT[0] = pT[7];
|
||||
pT[7] = T;
|
||||
T = pT[1];
|
||||
pT[1] = pT[6];
|
||||
pT[6] = T;
|
||||
T = pT[2];
|
||||
pT[2] = pT[5];
|
||||
pT[5] = T;
|
||||
T = pT[3];
|
||||
pT[3] = pT[4];
|
||||
pT[4] = T;
|
||||
}
|
||||
static void EndianSwizzleU32(uint32_t& S)
|
||||
{
|
||||
uint8_t* pT = reinterpret_cast<uint8_t*>(&S);
|
||||
uint8_t T;
|
||||
T = pT[0];
|
||||
pT[0] = pT[3];
|
||||
pT[3] = T;
|
||||
T = pT[1];
|
||||
pT[1] = pT[2];
|
||||
pT[2] = T;
|
||||
}
|
||||
static void EndianSwizzleU16(uint16_t& S)
|
||||
{
|
||||
uint8_t* pT = reinterpret_cast<uint8_t*>(&S);
|
||||
uint8_t T;
|
||||
T = pT[0];
|
||||
pT[0] = pT[1];
|
||||
pT[1] = T;
|
||||
}
|
||||
|
||||
|
||||
static void Log(const std::string& rLog);
|
||||
|
||||
static tdHash Hash(const std::string& rStr) { return Hash(reinterpret_cast<const uint8_t*>(rStr.c_str()), rStr.size()); }
|
||||
static tdHash Hash(const std::vector<uint8_t>& rData) { return Hash(&rData[0], rData.size()); }
|
||||
static tdHash Hash(const std::vector<uint8_t>& rData, size_t Size) { return Hash(&rData[0], Size); }
|
||||
|
||||
static std::string Hash2String(const tdHash& rHash);
|
||||
static tdHash String2Hash(const std::string& rStr);
|
||||
};
|
||||
|
||||
#define CRYSIMPLE_LOG(X) CSTLHelper::Log(X)
|
||||
#endif
|
||||
|
||||
@ -1,311 +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 "CrySimpleCache.hpp"
|
||||
#include "CrySimpleServer.hpp"
|
||||
|
||||
#include <Core/StdTypes.hpp>
|
||||
#include <Core/Error.hpp>
|
||||
#include <Core/STLHelper.hpp>
|
||||
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/std/time.h>
|
||||
#include <AzCore/std/algorithm.h>
|
||||
|
||||
enum EFileEntryHeaderFlags
|
||||
{
|
||||
EFEHF_NONE = (0 << 0),
|
||||
EFEHF_REFERENCE = (1 << 0),
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct SFileEntryHeader
|
||||
{
|
||||
char signature[4]; // entry signature.
|
||||
uint32_t dataSize; // Size of entry data.
|
||||
uint32_t flags; // Flags
|
||||
uint8_t hash[16]; // Hash code for the data.
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
static const int MAX_DATA_SIZE = 1024 * 1024;
|
||||
|
||||
CCrySimpleCache& CCrySimpleCache::Instance()
|
||||
{
|
||||
static CCrySimpleCache g_Cache;
|
||||
return g_Cache;
|
||||
}
|
||||
|
||||
void CCrySimpleCache::Init()
|
||||
{
|
||||
CCrySimpleMutexAutoLock Lock(m_Mutex);
|
||||
m_CachingEnabled = false;
|
||||
m_Hit = 0;
|
||||
m_Miss = 0;
|
||||
}
|
||||
|
||||
std::string CCrySimpleCache::CreateFileName(const tdHash& rHash) const
|
||||
{
|
||||
AZStd::string Name;
|
||||
Name = CSTLHelper::Hash2String(rHash).c_str();
|
||||
char Tmp[4] = "012";
|
||||
Tmp[0] = Name.c_str()[0];
|
||||
Tmp[1] = Name.c_str()[1];
|
||||
Tmp[2] = Name.c_str()[2];
|
||||
|
||||
AZ::IO::Path resultFileName = SEnviropment::Instance().m_CachePath / Tmp / Name;
|
||||
return std::string{ resultFileName.c_str(), resultFileName.Native().size() };
|
||||
}
|
||||
|
||||
|
||||
bool CCrySimpleCache::Find(const tdHash& rHash, tdDataVector& rData)
|
||||
{
|
||||
if (!m_CachingEnabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CCrySimpleMutexAutoLock Lock(m_Mutex);
|
||||
tdEntries::iterator it = m_Entries.find(rHash);
|
||||
if (it != m_Entries.end())
|
||||
{
|
||||
tdData::iterator dataIt = m_Data.find(it->second);
|
||||
if (dataIt == m_Data.end())
|
||||
{
|
||||
m_Miss++;
|
||||
return false;
|
||||
}
|
||||
m_Hit++;
|
||||
rData = dataIt->second;
|
||||
return true;
|
||||
}
|
||||
m_Miss++;
|
||||
return false;
|
||||
}
|
||||
|
||||
void CCrySimpleCache::Add(const tdHash& rHash, const tdDataVector& rData)
|
||||
{
|
||||
if (!m_CachingEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (rData.size() > 0)
|
||||
{
|
||||
SFileEntryHeader hdr;
|
||||
memcpy(hdr.signature, "SHDR", 4);
|
||||
hdr.dataSize = (uint32_t)rData.size();
|
||||
hdr.flags = EFEHF_NONE;
|
||||
memcpy(hdr.hash, &rHash, sizeof(hdr.hash));
|
||||
const uint8_t* pData = &rData[0];
|
||||
|
||||
tdHash DataHash = CSTLHelper::Hash(rData);
|
||||
{
|
||||
CCrySimpleMutexAutoLock Lock(m_Mutex);
|
||||
m_Entries[rHash] = DataHash;
|
||||
if (m_Data.find(DataHash) == m_Data.end())
|
||||
{
|
||||
m_Data[DataHash] = rData;
|
||||
}
|
||||
else
|
||||
{
|
||||
hdr.flags |= EFEHF_REFERENCE;
|
||||
hdr.dataSize = sizeof(tdHash);
|
||||
pData = reinterpret_cast<const uint8_t*>(&DataHash);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
tdDataVector buf;
|
||||
buf.resize(sizeof(hdr) + hdr.dataSize);
|
||||
memcpy(&buf[0], &hdr, sizeof(hdr));
|
||||
memcpy(&buf[sizeof(hdr)], pData, hdr.dataSize);
|
||||
|
||||
tdDataVector* pPendingCacheEntry = new tdDataVector(buf);
|
||||
{
|
||||
CCrySimpleMutexAutoLock LockFile(m_FileMutex);
|
||||
m_PendingCacheEntries.push_back(pPendingCacheEntry);
|
||||
if (m_PendingCacheEntries.size() > 10000)
|
||||
{
|
||||
printf("Warning: Too many pending entries not saved to disk!!!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CCrySimpleCache::LoadCacheFile(const std::string& filename)
|
||||
{
|
||||
AZ::u64 startTimeInMillis = AZStd::GetTimeUTCMilliSecond();
|
||||
|
||||
printf("Loading shader cache from %s\n", filename.c_str());
|
||||
|
||||
tdDataVector rData;
|
||||
|
||||
tdHash hash;
|
||||
|
||||
bool bLoadedOK = true;
|
||||
|
||||
uint32_t Loaded = 0;
|
||||
uint32_t num = 0;
|
||||
|
||||
uint64_t nFilePos = 0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
AZ::IO::SystemFile cacheFile;
|
||||
const bool wasSuccessful = cacheFile.Open(filename.c_str(), AZ::IO::SystemFile::SF_OPEN_READ_ONLY);
|
||||
if (!wasSuccessful)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::IO::SystemFile::SizeType fileSize = cacheFile.Length();
|
||||
|
||||
uint64_t SizeAdded = 0;
|
||||
uint64_t SizeAddedCount = 0;
|
||||
uint64_t SizeSaved = 0;
|
||||
uint64_t SizeSavedCount = 0;
|
||||
|
||||
while (nFilePos < fileSize)
|
||||
{
|
||||
SFileEntryHeader hdr;
|
||||
AZ::IO::SystemFile::SizeType bytesReadIn = cacheFile.Read(sizeof(hdr), &hdr);
|
||||
if (bytesReadIn != sizeof(hdr))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (memcmp(hdr.signature, "SHDR", 4) != 0)
|
||||
{
|
||||
// Bad Entry!
|
||||
bLoadedOK = false;
|
||||
printf("\nSkipping Invalid cache entry %d\n at file position: %llu because signature is bad", num, nFilePos);
|
||||
break;
|
||||
}
|
||||
|
||||
if (hdr.dataSize > MAX_DATA_SIZE || hdr.dataSize == 0)
|
||||
{
|
||||
// Too big entry, probably invalid.
|
||||
bLoadedOK = false;
|
||||
printf("\nSkipping Invalid cache entry %d\n at file position: %llu because data size is too big", num, nFilePos);
|
||||
break;
|
||||
}
|
||||
|
||||
rData.resize(hdr.dataSize);
|
||||
bytesReadIn = cacheFile.Read(hdr.dataSize, rData.data());
|
||||
if (bytesReadIn != hdr.dataSize)
|
||||
{
|
||||
break;
|
||||
}
|
||||
memcpy(&hash, hdr.hash, sizeof(hdr.hash));
|
||||
|
||||
if (hdr.flags & EFEHF_REFERENCE)
|
||||
{
|
||||
if (hdr.dataSize != sizeof(tdHash))
|
||||
{
|
||||
// Too big entry, probably invalid.
|
||||
bLoadedOK = false;
|
||||
printf("\nSkipping Invalid cache entry %d\n at file position: %llu, was flagged as cache reference but size was %d", num, nFilePos, hdr.dataSize);
|
||||
break;
|
||||
}
|
||||
|
||||
bool bSkip = false;
|
||||
|
||||
tdHash DataHash = *reinterpret_cast<tdHash*>(&rData[0]);
|
||||
tdData::iterator it = m_Data.find(DataHash);
|
||||
if (it == m_Data.end())
|
||||
{
|
||||
// Too big entry, probably invalid.
|
||||
bSkip = true; // don't abort reading whole file just yet - skip only this entry
|
||||
printf("\nSkipping Invalid cache entry %d\n at file position: %llu, data-hash references to not existing data ", num, nFilePos);
|
||||
}
|
||||
|
||||
if (!bSkip)
|
||||
{
|
||||
m_Entries[hash] = DataHash;
|
||||
SizeSaved += it->second.size();
|
||||
SizeSavedCount++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tdHash DataHash = CSTLHelper::Hash(rData);
|
||||
m_Entries[hash] = DataHash;
|
||||
if (m_Data.find(DataHash) == m_Data.end())
|
||||
{
|
||||
SizeAdded += rData.size();
|
||||
m_Data[DataHash] = rData;
|
||||
SizeAddedCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
SizeSaved += rData.size();
|
||||
SizeSavedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (num % 1000 == 0)
|
||||
{
|
||||
AZ::u64 endTimeInMillis = AZStd::GetTimeUTCMilliSecond();
|
||||
|
||||
Loaded = static_cast<uint32_t>(nFilePos * 100 / fileSize);
|
||||
printf("\rLoad:%3u%% %6uk t=%llus Compress: (Count)%llu%% %lluk:%lluk (MB)%llu%% %lluMB:%lluMB", Loaded, num / 1000u, (endTimeInMillis - startTimeInMillis),
|
||||
SizeAddedCount / AZStd::GetMax((SizeAddedCount + SizeSavedCount) / 100ull, 1ull),
|
||||
SizeAddedCount / 1000, SizeSavedCount / 1000,
|
||||
SizeAdded / AZStd::GetMax((SizeAdded + SizeSaved) / 100ull, 1ull),
|
||||
SizeAdded / (MAX_DATA_SIZE), SizeSaved / (MAX_DATA_SIZE));
|
||||
}
|
||||
|
||||
num++;
|
||||
nFilePos += hdr.dataSize + sizeof(SFileEntryHeader);
|
||||
}
|
||||
|
||||
printf("\n%d shaders loaded from cache\n", num);
|
||||
|
||||
return bLoadedOK;
|
||||
}
|
||||
|
||||
void CCrySimpleCache::Finalize()
|
||||
{
|
||||
m_CachingEnabled = true;
|
||||
printf("\n caching enabled\n");
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CCrySimpleCache::ThreadFunc_SavePendingCacheEntries()
|
||||
{
|
||||
// Check pending entries and save them to disk.
|
||||
bool bListEmpty = false;
|
||||
do
|
||||
{
|
||||
tdDataVector* pPendingCacheEntry = 0;
|
||||
|
||||
{
|
||||
CCrySimpleMutexAutoLock LockFile(m_FileMutex);
|
||||
if (!m_PendingCacheEntries.empty())
|
||||
{
|
||||
pPendingCacheEntry = m_PendingCacheEntries.front();
|
||||
m_PendingCacheEntries.pop_front();
|
||||
}
|
||||
//CSTLHelper::AppendToFile( SEnviropment::Instance().m_CachePath+"Cache.dat",buf );
|
||||
bListEmpty = m_PendingCacheEntries.empty();
|
||||
}
|
||||
|
||||
if (pPendingCacheEntry)
|
||||
{
|
||||
AZ::IO::Path cacheDatPath = SEnviropment::Instance().m_CachePath / "Cache.dat";
|
||||
CSTLHelper::AppendToFile(std::string{ cacheDatPath.c_str(), cacheDatPath.Native().size() }, *pPendingCacheEntry);
|
||||
delete pPendingCacheEntry;
|
||||
}
|
||||
} while (!bListEmpty);
|
||||
}
|
||||
@ -1,68 +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 __CRYSIMPLECACHE__
|
||||
#define __CRYSIMPLECACHE__
|
||||
|
||||
#include "CrySimpleMutex.hpp"
|
||||
|
||||
#include <Core/STLHelper.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
/*class CCrySimpleCacheEntry
|
||||
{
|
||||
tdCache
|
||||
public:
|
||||
protected:
|
||||
private:
|
||||
};*/
|
||||
|
||||
typedef std::map<tdHash, tdHash> tdEntries;
|
||||
typedef std::map<tdHash, tdDataVector> tdData;
|
||||
|
||||
class CCrySimpleCache
|
||||
{
|
||||
volatile bool m_CachingEnabled;
|
||||
int m_Hit;
|
||||
int m_Miss;
|
||||
tdEntries m_Entries;
|
||||
tdData m_Data;
|
||||
CCrySimpleMutex m_Mutex;
|
||||
CCrySimpleMutex m_FileMutex;
|
||||
|
||||
std::list<tdDataVector*> m_PendingCacheEntries;
|
||||
std::string CreateFileName(const tdHash& rHash) const;
|
||||
|
||||
public:
|
||||
void Init();
|
||||
bool Find(const tdHash& rHash, tdDataVector& rData);
|
||||
void Add(const tdHash& rHash, const tdDataVector& rData);
|
||||
|
||||
bool LoadCacheFile(const std::string& filename);
|
||||
void Finalize();
|
||||
|
||||
void ThreadFunc_SavePendingCacheEntries();
|
||||
|
||||
static CCrySimpleCache& Instance();
|
||||
|
||||
|
||||
std::list<tdDataVector*>& PendingCacheEntries(){return m_PendingCacheEntries; }
|
||||
int Hit() const{return m_Hit; }
|
||||
int Miss() const{return m_Miss; }
|
||||
int EntryCount() const{return static_cast<int>(m_Entries.size()); }
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,274 +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 "CrySimpleErrorLog.hpp"
|
||||
#include "CrySimpleServer.hpp"
|
||||
#include "CrySimpleJob.hpp"
|
||||
|
||||
#include <Core/Common.h>
|
||||
#include <Core/StdTypes.hpp>
|
||||
#include <Core/Error.hpp>
|
||||
#include <Core/STLHelper.hpp>
|
||||
#include <Core/Mailer.h>
|
||||
#include <tinyxml/tinyxml.h>
|
||||
|
||||
#include <AzCore/std/time.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <process.h>
|
||||
#include <direct.h>
|
||||
#endif
|
||||
#ifdef UNIX
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
static unsigned int volatile g_bSendingMail = false;
|
||||
static unsigned int volatile g_nMailNum = 0;
|
||||
|
||||
CCrySimpleErrorLog& CCrySimpleErrorLog::Instance()
|
||||
{
|
||||
static CCrySimpleErrorLog g_Cache;
|
||||
return g_Cache;
|
||||
}
|
||||
|
||||
CCrySimpleErrorLog::CCrySimpleErrorLog()
|
||||
{
|
||||
m_lastErrorTime = 0;
|
||||
}
|
||||
|
||||
void CCrySimpleErrorLog::Init()
|
||||
{
|
||||
}
|
||||
|
||||
bool CCrySimpleErrorLog::Add(ICryError* err)
|
||||
{
|
||||
CCrySimpleMutexAutoLock Lock(m_LogMutex);
|
||||
|
||||
if (m_Log.size() > 150)
|
||||
{
|
||||
// too many, just throw this error away
|
||||
return false; // no ownership of this error
|
||||
}
|
||||
|
||||
m_Log.push_back(err);
|
||||
|
||||
m_lastErrorTime = AZStd::GetTimeUTCMilliSecond();
|
||||
|
||||
return true; // take ownership of this error
|
||||
}
|
||||
|
||||
inline bool CmpError(ICryError* a, ICryError* b)
|
||||
{
|
||||
return a->Compare(b);
|
||||
}
|
||||
|
||||
void CCrySimpleErrorLog::SendMail()
|
||||
{
|
||||
CSMTPMailer::tstrcol Rcpt;
|
||||
|
||||
std::string mailBody;
|
||||
|
||||
tdEntryVec RcptVec;
|
||||
CSTLHelper::Tokenize(RcptVec, SEnviropment::Instance().m_FailEMail, ";");
|
||||
|
||||
for (size_t i = 0; i < RcptVec.size(); i++)
|
||||
{
|
||||
Rcpt.insert(RcptVec[i]);
|
||||
}
|
||||
|
||||
tdErrorList tempLog;
|
||||
{
|
||||
CCrySimpleMutexAutoLock Lock(m_LogMutex);
|
||||
m_Log.swap(tempLog);
|
||||
}
|
||||
#if defined(_MSC_VER)
|
||||
{
|
||||
char compName[256];
|
||||
DWORD size = ARRAYSIZE(compName);
|
||||
|
||||
typedef BOOL (WINAPI * FP_GetComputerNameExA)(COMPUTER_NAME_FORMAT, LPSTR, LPDWORD);
|
||||
FP_GetComputerNameExA pGetComputerNameExA = (FP_GetComputerNameExA) GetProcAddress(LoadLibrary("kernel32.dll"), "GetComputerNameExA");
|
||||
|
||||
if (pGetComputerNameExA)
|
||||
{
|
||||
pGetComputerNameExA(ComputerNamePhysicalDnsFullyQualified, compName, &size);
|
||||
}
|
||||
else
|
||||
{
|
||||
GetComputerName(compName, &size);
|
||||
}
|
||||
|
||||
mailBody += std::string("Report sent from ") + compName + "...\n\n";
|
||||
}
|
||||
#endif
|
||||
{
|
||||
bool dedupe = SEnviropment::Instance().m_DedupeErrors;
|
||||
|
||||
std::vector<ICryError*> errors;
|
||||
|
||||
if (!dedupe)
|
||||
{
|
||||
for (tdErrorList::const_iterator it = tempLog.begin(); it != tempLog.end(); ++it)
|
||||
{
|
||||
errors.push_back(*it);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::map<tdHash, ICryError*> uniqErrors;
|
||||
for (tdErrorList::const_iterator it = tempLog.begin(); it != tempLog.end(); ++it)
|
||||
{
|
||||
ICryError* err = *it;
|
||||
|
||||
tdHash hash = err->Hash();
|
||||
|
||||
std::map<tdHash, ICryError*>::iterator uniq = uniqErrors.find(hash);
|
||||
if (uniq != uniqErrors.end())
|
||||
{
|
||||
uniq->second->AddDuplicate(err);
|
||||
delete err;
|
||||
}
|
||||
else
|
||||
{
|
||||
uniqErrors[hash] = err;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::map<tdHash, ICryError*>::iterator it = uniqErrors.begin(); it != uniqErrors.end(); ++it)
|
||||
{
|
||||
errors.push_back(it->second);
|
||||
}
|
||||
}
|
||||
|
||||
std::string body = mailBody;
|
||||
CSMTPMailer::tstrcol cc;
|
||||
CSMTPMailer::tattachlist Attachment;
|
||||
|
||||
std::sort(errors.begin(), errors.end(), CmpError);
|
||||
|
||||
int a = 0;
|
||||
for (uint32_t i = 0; i < errors.size(); i++)
|
||||
{
|
||||
ICryError* err = errors[i];
|
||||
|
||||
err->SetUniqueID(a + 1);
|
||||
|
||||
// doesn't have to be related to any job/error,
|
||||
// we just use it to differentiate "1-IlluminationPS.txt" from "1-IlluminationPS.txt"
|
||||
long req = CCrySimpleJob::GlobalRequestNumber();
|
||||
|
||||
if (err->HasFile())
|
||||
{
|
||||
char Filename[1024];
|
||||
azsprintf(Filename, "%d-req%ld-%s", a + 1, req, err->GetFilename().c_str());
|
||||
|
||||
char DispFilename[1024];
|
||||
azsprintf(DispFilename, "%d-%s", a + 1, err->GetFilename().c_str());
|
||||
|
||||
std::string sErrorFile = (SEnviropment::Instance().m_ErrorPath / Filename).c_str();
|
||||
|
||||
std::vector<uint8_t> bytes;
|
||||
std::string text = err->GetFileContents();
|
||||
bytes.resize(text.size() + 1);
|
||||
std::copy(text.begin(), text.end(), bytes.begin());
|
||||
while (bytes.size() && bytes[bytes.size() - 1] == 0)
|
||||
{
|
||||
bytes.pop_back();
|
||||
}
|
||||
|
||||
CrySimple_SECURE_START
|
||||
|
||||
CSTLHelper::ToFile(sErrorFile, bytes);
|
||||
|
||||
Attachment.push_back(CSMTPMailer::tattachment(DispFilename, sErrorFile));
|
||||
|
||||
CrySimple_SECURE_END
|
||||
}
|
||||
|
||||
body += std::string("=============================================================\n");
|
||||
body += err->GetErrorDetails(ICryError::OUTPUT_EMAIL) + "\n";
|
||||
|
||||
err->AddCCs(cc);
|
||||
a++;
|
||||
|
||||
if (i == errors.size() - 1 || !err->CanMerge(errors[i + 1]))
|
||||
{
|
||||
CSMTPMailer::tstrcol bcc;
|
||||
|
||||
CSMTPMailer mail("", "", SEnviropment::Instance().m_MailServer);
|
||||
mail.Send(SEnviropment::Instance().m_FailEMail, Rcpt, cc, bcc, err->GetErrorName(), body, Attachment);
|
||||
|
||||
a = 0;
|
||||
body = mailBody;
|
||||
cc.clear();
|
||||
|
||||
for (CSMTPMailer::tattachlist::iterator attach = Attachment.begin(); attach != Attachment.end(); ++attach)
|
||||
{
|
||||
AZ::IO::SystemFile::Delete(attach->second.c_str());
|
||||
}
|
||||
|
||||
Attachment.clear();
|
||||
}
|
||||
|
||||
delete err;
|
||||
}
|
||||
}
|
||||
|
||||
g_bSendingMail = false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CCrySimpleErrorLog::Tick()
|
||||
{
|
||||
if (SEnviropment::Instance().m_MailInterval == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AZ::u64 lastError = 0;
|
||||
bool forceFlush = false;
|
||||
|
||||
{
|
||||
CCrySimpleMutexAutoLock Lock(m_LogMutex);
|
||||
|
||||
if (m_Log.size() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// log has gotten pretty big, force a flush to avoid losing any errors
|
||||
if (m_Log.size() > 100)
|
||||
{
|
||||
forceFlush = true;
|
||||
}
|
||||
|
||||
lastError = m_lastErrorTime;
|
||||
}
|
||||
|
||||
AZ::u64 t = AZStd::GetTimeUTCMilliSecond();
|
||||
if (forceFlush || t < lastError || (t - lastError) > SEnviropment::Instance().m_MailInterval * 1000)
|
||||
{
|
||||
if (!g_bSendingMail)
|
||||
{
|
||||
g_bSendingMail = true;
|
||||
g_nMailNum++;
|
||||
logmessage("Sending Errors Mail %d\n", g_nMailNum);
|
||||
CCrySimpleErrorLog::Instance().SendMail();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,42 +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 __CRYSIMPLEERRORLOG__
|
||||
#define __CRYSIMPLEERRORLOG__
|
||||
|
||||
#include "CrySimpleMutex.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
class ICryError;
|
||||
typedef std::list<ICryError*> tdErrorList;
|
||||
|
||||
class CCrySimpleErrorLog
|
||||
{
|
||||
CCrySimpleMutex m_LogMutex; // protects both below variables
|
||||
tdErrorList m_Log; // error log
|
||||
AZ::u64 m_lastErrorTime; // last time an error came in (we mail out a little after we've stopped receiving errors)
|
||||
|
||||
void Init();
|
||||
void SendMail();
|
||||
CCrySimpleErrorLog();
|
||||
public:
|
||||
|
||||
bool Add(ICryError* err);
|
||||
void Tick();
|
||||
|
||||
static CCrySimpleErrorLog& Instance();
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,228 +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 "CrySimpleHTTP.hpp"
|
||||
#include "CrySimpleSock.hpp"
|
||||
#include "CrySimpleJobCompile.hpp"
|
||||
#include "CrySimpleServer.hpp"
|
||||
#include "CrySimpleCache.hpp"
|
||||
|
||||
#include <Core/StdTypes.hpp>
|
||||
#include <Core/Error.hpp>
|
||||
#include <Core/STLHelper.hpp>
|
||||
#include <tinyxml/tinyxml.h>
|
||||
|
||||
#include <AzCore/Jobs/Job.h>
|
||||
#include <AzCore/std/algorithm.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <memory>
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CHTTPRequest
|
||||
{
|
||||
CCrySimpleSock* m_pSock;
|
||||
public:
|
||||
CHTTPRequest(CCrySimpleSock* pSock)
|
||||
: m_pSock(pSock){}
|
||||
|
||||
~CHTTPRequest(){delete m_pSock; }
|
||||
|
||||
CCrySimpleSock* Socket(){return m_pSock; }
|
||||
};
|
||||
|
||||
#define HTML_HEADER "HTTP/1.1 200 OK\n\
|
||||
Server: Shader compile server %s\n\
|
||||
Content-Length: %zu\n\
|
||||
Content-Language: de (nach RFC 3282 sowie RFC 1766)\n\
|
||||
Content-Type: text/html\n\
|
||||
Connection: close\n\
|
||||
\n\
|
||||
<html><title>shader compile server %s</title><body>"
|
||||
|
||||
#define TABLE_START "<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=2 WIDTH=640>\n\
|
||||
<TR bgcolor=lightgrey><TH align=left>Description</TH><TH WIDTH=5></TH><TH>Value</TH><TH>Max</TH>\n\
|
||||
<TH WIDTH=10> </TH><TH align=center>%</TH></TR>\n"
|
||||
#define TABLE_INFO "<TR><TD>%s</TD><TD> </TD><TD align=left>%s</TD><TD align=center></TD><TD> </TD><TD valign=middle>\n\
|
||||
</TD></TR>\n\
|
||||
</TD></TR>\n"
|
||||
#define TABLE_BAR "<TR><TD>%s</TD><TD> </TD><TD align=center>%d</TD><TD align=center>%d</TD><TD> </TD><TD valign=middle>\n\
|
||||
<TABLE><TR><TD bgcolor=darkred style=\"width: %d;\" ></TD>\n\
|
||||
<TD><FONT SIZE=1>%d%%</FONT></TD></TR>\n\
|
||||
</TABLE></TD></TR>\n\
|
||||
</TD></TR>\n"
|
||||
#define TABLE_END "</TABLE>"
|
||||
|
||||
std::string CreateBar(const std::string& rName, int Value, int Max, int Percentage)
|
||||
{
|
||||
AZStd::string formattedString = AZStd::string::format(TABLE_BAR, rName.c_str(), Value, Max, Percentage, Percentage);
|
||||
return formattedString.c_str();
|
||||
}
|
||||
|
||||
std::string CreateInfoText(const std::string& rName, const std::string& rValue)
|
||||
{
|
||||
AZStd::string formattedString = AZStd::string::format(TABLE_INFO, rName.c_str(), rValue.c_str());
|
||||
return formattedString.c_str();
|
||||
}
|
||||
|
||||
std::string CreateInfoText(const std::string& rName, int Value)
|
||||
{
|
||||
char Text[64];
|
||||
azsprintf(Text, "%d", Value);
|
||||
return CreateInfoText(rName, Text);
|
||||
}
|
||||
|
||||
class HttpProcessRequestJob
|
||||
: public AZ::Job
|
||||
{
|
||||
public:
|
||||
HttpProcessRequestJob(CHTTPRequest* request)
|
||||
: AZ::Job(true, nullptr)
|
||||
, m_request(request) { }
|
||||
|
||||
protected:
|
||||
void Process() override
|
||||
{
|
||||
#if defined(AZ_PLATFORM_WINDOWS)
|
||||
FILETIME IdleTime0, IdleTime1;
|
||||
FILETIME KernelTime0, KernelTime1;
|
||||
FILETIME UserTime0, UserTime1;
|
||||
|
||||
int Ret0 = GetSystemTimes(&IdleTime0, &KernelTime0, &UserTime0);
|
||||
Sleep(100);
|
||||
int Ret1 = GetSystemTimes(&IdleTime1, &KernelTime1, &UserTime1);
|
||||
const int Idle = IdleTime1.dwLowDateTime - IdleTime0.dwLowDateTime;
|
||||
const int Kernel = KernelTime1.dwLowDateTime - KernelTime0.dwLowDateTime;
|
||||
const int User = UserTime1.dwLowDateTime - UserTime0.dwLowDateTime;
|
||||
//const int Idle = IdleTime1.dwHighDateTime-IdleTime0.dwHighDateTime;
|
||||
//const int Kernel = KernelTime1.dwHighDateTime-KernelTime0.dwHighDateTime;
|
||||
//const int User = UserTime1.dwHighDateTime-UserTime0.dwHighDateTime;
|
||||
const int Total = Kernel + User;
|
||||
#else
|
||||
int Ret0 = 0;
|
||||
int Ret1 = 0;
|
||||
int Total = 0;
|
||||
int Idle = 0;
|
||||
#endif
|
||||
|
||||
std::string Ret = TABLE_START;
|
||||
|
||||
Ret += CreateInfoText("<b>Load</b>:", "");
|
||||
if (Ret0 && Ret1 && Total)
|
||||
{
|
||||
Ret += CreateBar("CPU-Usage", Total - Idle, Total, 100 - Idle * 100 / Total);
|
||||
}
|
||||
|
||||
Ret += CreateBar("CompileTasks", CCrySimpleJobCompile::GlobalCompileTasks(),
|
||||
CCrySimpleJobCompile::GlobalCompileTasksMax(),
|
||||
CCrySimpleJobCompile::GlobalCompileTasksMax() ?
|
||||
CCrySimpleJobCompile::GlobalCompileTasks() * 100 /
|
||||
CCrySimpleJobCompile::GlobalCompileTasksMax() : 0);
|
||||
|
||||
|
||||
Ret += CreateInfoText("<b>Setup</b>:", "");
|
||||
Ret += CreateInfoText("Root", SEnviropment::Instance().m_Root.c_str());
|
||||
Ret += CreateInfoText("CompilerPath", SEnviropment::Instance().m_CompilerPath.c_str());
|
||||
Ret += CreateInfoText("CachePath", SEnviropment::Instance().m_CachePath.c_str());
|
||||
Ret += CreateInfoText("TempPath", SEnviropment::Instance().m_TempPath.c_str());
|
||||
Ret += CreateInfoText("ErrorPath", SEnviropment::Instance().m_ErrorPath.c_str());
|
||||
Ret += CreateInfoText("ShaderPath", SEnviropment::Instance().m_ShaderPath.c_str());
|
||||
Ret += CreateInfoText("FailEMail", SEnviropment::Instance().m_FailEMail);
|
||||
Ret += CreateInfoText("MailServer", SEnviropment::Instance().m_MailServer);
|
||||
Ret += CreateInfoText("port", SEnviropment::Instance().m_port);
|
||||
Ret += CreateInfoText("MailInterval", SEnviropment::Instance().m_MailInterval);
|
||||
Ret += CreateInfoText("Caching", SEnviropment::Instance().m_Caching ? "Enabled" : "Disabled");
|
||||
Ret += CreateInfoText("FallbackServer", SEnviropment::Instance().m_FallbackServer == "" ? "None" : SEnviropment::Instance().m_FallbackServer);
|
||||
Ret += CreateInfoText("FallbackTreshold", static_cast<int>(SEnviropment::Instance().m_FallbackTreshold));
|
||||
Ret += CreateInfoText("DumpShaders", static_cast<int>(SEnviropment::Instance().m_DumpShaders));
|
||||
|
||||
Ret += CreateInfoText("<b>Cache</b>:", "");
|
||||
Ret += CreateInfoText("Entries", CCrySimpleCache::Instance().EntryCount());
|
||||
Ret += CreateBar("Hits", CCrySimpleCache::Instance().Hit(),
|
||||
CCrySimpleCache::Instance().Hit() + CCrySimpleCache::Instance().Miss(),
|
||||
CCrySimpleCache::Instance().Hit() * 100 / AZStd::GetMax(1, (CCrySimpleCache::Instance().Hit() + CCrySimpleCache::Instance().Miss())));
|
||||
Ret += CreateInfoText("Pending Entries", static_cast<int>(CCrySimpleCache::Instance().PendingCacheEntries().size()));
|
||||
|
||||
|
||||
|
||||
Ret += TABLE_END;
|
||||
|
||||
Ret += "</Body></hmtl>";
|
||||
char Text[sizeof(HTML_HEADER) + 1024];
|
||||
azsprintf(Text, HTML_HEADER, __DATE__, Ret.size(), __DATE__);
|
||||
Ret = std::string(Text) + Ret;
|
||||
m_request->Socket()->Send(Ret);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<CHTTPRequest> m_request;
|
||||
};
|
||||
|
||||
class HttpServerJob
|
||||
: public AZ::Job
|
||||
{
|
||||
public:
|
||||
HttpServerJob(CCrySimpleHTTP* simpleHttp)
|
||||
: AZ::Job(true, nullptr)
|
||||
, m_simpleHttp(simpleHttp) { }
|
||||
|
||||
protected:
|
||||
void Process()
|
||||
{
|
||||
m_simpleHttp->Run();
|
||||
}
|
||||
private:
|
||||
CCrySimpleHTTP* m_simpleHttp;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CCrySimpleHTTP::CCrySimpleHTTP()
|
||||
: m_pServerSocket(0)
|
||||
{
|
||||
CrySimple_SECURE_START
|
||||
|
||||
Init();
|
||||
|
||||
CrySimple_SECURE_END
|
||||
}
|
||||
|
||||
void CCrySimpleHTTP::Init()
|
||||
{
|
||||
m_pServerSocket = new CCrySimpleSock(61480, SEnviropment::Instance().m_WhitelistAddresses); //http
|
||||
m_pServerSocket->Listen();
|
||||
HttpServerJob* serverJob = new HttpServerJob(this);
|
||||
serverJob->Start();
|
||||
}
|
||||
|
||||
void CCrySimpleHTTP::Run()
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
// New client message, receive new client socket connection.
|
||||
CCrySimpleSock* newClientSocket = m_pServerSocket->Accept();
|
||||
if(!newClientSocket)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// HTTP Request Data for new job
|
||||
CHTTPRequest* pData = new CHTTPRequest(newClientSocket);
|
||||
|
||||
HttpProcessRequestJob* requestJob = new HttpProcessRequestJob(pData);
|
||||
requestJob->Start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,36 +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 __CrySimpleHTTP__
|
||||
#define __CrySimpleHTTP__
|
||||
|
||||
#include <AzCore/std/parallel/atomic.h>
|
||||
#include <Core/Common.h>
|
||||
#include <string>
|
||||
|
||||
extern bool g_Success;
|
||||
|
||||
class CCrySimpleSock;
|
||||
|
||||
class CCrySimpleHTTP
|
||||
{
|
||||
static AZStd::atomic_long ms_ExceptionCount;
|
||||
CCrySimpleSock* m_pServerSocket;
|
||||
void Init();
|
||||
public:
|
||||
CCrySimpleHTTP();
|
||||
|
||||
void Run();
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,211 +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 "CrySimpleJob.hpp"
|
||||
#include "CrySimpleFileGuard.hpp"
|
||||
#include "CrySimpleServer.hpp"
|
||||
|
||||
#include <Core/StdTypes.hpp>
|
||||
#include <Core/Error.hpp>
|
||||
#include <Core/STLHelper.hpp>
|
||||
#include <Core/Common.h>
|
||||
#include <Core/WindowsAPIImplementation.h>
|
||||
#include <tinyxml/tinyxml.h>
|
||||
|
||||
#include <thread>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
|
||||
AZStd::atomic_long CCrySimpleJob::m_GlobalRequestNumber = {0};
|
||||
|
||||
CCrySimpleJob::CCrySimpleJob(uint32_t requestIP)
|
||||
: m_State(ECSJS_NONE)
|
||||
, m_RequestIP(requestIP)
|
||||
{
|
||||
++m_GlobalRequestNumber;
|
||||
}
|
||||
|
||||
CCrySimpleJob::~CCrySimpleJob()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool CCrySimpleJob::ExecuteCommand(const std::string& rCmd, std::string& outError)
|
||||
{
|
||||
const bool showStdOuput = false; // For Debug: Set to true if you want the compiler's standard ouput printed out as well.
|
||||
const bool showStdErrorOuput = SEnviropment::Instance().m_PrintWarnings;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
bool Ret = false;
|
||||
DWORD ExitCode = 0;
|
||||
|
||||
STARTUPINFO StartupInfo;
|
||||
PROCESS_INFORMATION ProcessInfo;
|
||||
memset(&StartupInfo, 0, sizeof(StartupInfo));
|
||||
memset(&ProcessInfo, 0, sizeof(ProcessInfo));
|
||||
StartupInfo.cb = sizeof(StartupInfo);
|
||||
|
||||
|
||||
std::string Path = "";
|
||||
std::string::size_type Pt = rCmd.find_first_of(' ');
|
||||
if (Pt != std::string::npos)
|
||||
{
|
||||
std::string First = std::string(rCmd.c_str(), Pt);
|
||||
std::string::size_type Pt2 = First.find_last_of('/');
|
||||
if (Pt2 != std::string::npos)
|
||||
{
|
||||
Path = std::string(First.c_str(), Pt2);
|
||||
}
|
||||
else
|
||||
{
|
||||
Pt = std::string::npos;
|
||||
}
|
||||
}
|
||||
|
||||
HANDLE hReadErr, hWriteErr;
|
||||
|
||||
{
|
||||
CreatePipe(&hReadErr, &hWriteErr, NULL, 0);
|
||||
SetHandleInformation(hWriteErr, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
|
||||
|
||||
StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
|
||||
StartupInfo.hStdOutput = (showStdOuput) ? GetStdHandle(STD_OUTPUT_HANDLE) : NULL;
|
||||
StartupInfo.hStdError = hWriteErr;
|
||||
StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
|
||||
|
||||
BOOL processCreated = CreateProcess(NULL, (char*)rCmd.c_str(), 0, 0, TRUE, CREATE_DEFAULT_ERROR_MODE, 0, Pt != std::string::npos ? Path.c_str() : 0, &StartupInfo, &ProcessInfo) != false;
|
||||
|
||||
if (!processCreated)
|
||||
{
|
||||
outError = "Couldn't create process - missing compiler for cmd?: '" + rCmd + "'";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string error;
|
||||
|
||||
DWORD waitResult = 0;
|
||||
HANDLE waitHandles[] = { ProcessInfo.hProcess, hReadErr };
|
||||
while (true)
|
||||
{
|
||||
//waitResult = WaitForMultipleObjects(sizeof(waitHandles) / sizeof(waitHandles[0]), waitHandles, FALSE, 1000 );
|
||||
waitResult = WaitForSingleObject(ProcessInfo.hProcess, 1000);
|
||||
if (waitResult == WAIT_FAILED)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
DWORD bytesRead, bytesAvailable;
|
||||
while (PeekNamedPipe(hReadErr, NULL, 0, NULL, &bytesAvailable, NULL) && bytesAvailable)
|
||||
{
|
||||
char buff[4096];
|
||||
ReadFile(hReadErr, buff, sizeof(buff) - 1, &bytesRead, 0);
|
||||
buff[bytesRead] = '\0';
|
||||
error += buff;
|
||||
}
|
||||
CSTLHelper::Trim(error," \t\r\n");
|
||||
|
||||
//if (waitResult == WAIT_OBJECT_0 || waitResult == WAIT_TIMEOUT)
|
||||
//break;
|
||||
|
||||
if (waitResult == WAIT_OBJECT_0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//if (waitResult != WAIT_TIMEOUT)
|
||||
{
|
||||
GetExitCodeProcess(ProcessInfo.hProcess, &ExitCode);
|
||||
if (ExitCode)
|
||||
{
|
||||
Ret = false;
|
||||
outError = error;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (showStdErrorOuput && !error.empty())
|
||||
{
|
||||
AZ_Printf(0, "\n%s\n", error.c_str());
|
||||
}
|
||||
Ret = true;
|
||||
}
|
||||
}
|
||||
/*
|
||||
else
|
||||
{
|
||||
Ret = false;
|
||||
outError = std::string("Timed out executing compiler: ") + rCmd;
|
||||
TerminateProcess(ProcessInfo.hProcess, 1);
|
||||
}
|
||||
*/
|
||||
|
||||
CloseHandle(ProcessInfo.hProcess);
|
||||
CloseHandle(ProcessInfo.hThread);
|
||||
}
|
||||
|
||||
CloseHandle(hReadErr);
|
||||
if (hWriteErr)
|
||||
{
|
||||
CloseHandle(hWriteErr);
|
||||
}
|
||||
}
|
||||
|
||||
return Ret;
|
||||
#endif
|
||||
|
||||
#if defined(AZ_PLATFORM_LINUX) || defined(AZ_PLATFORM_MAC)
|
||||
std::thread::id threadId = std::this_thread::get_id();
|
||||
std::stringstream threadIdStream;
|
||||
threadIdStream << threadId;
|
||||
|
||||
// Multiple threads could execute a command, therefore the temporary file has to be unique per thread.
|
||||
AZ::IO::Path errorTempFilePath = SEnviropment::Instance().m_TempPath / AZStd::string::format("stderr_%s.log", threadIdStream.str().c_str());
|
||||
std::string stdErrorTempFilename{ errorTempFilePath.c_str(), errorTempFilePath.Native().size() };
|
||||
|
||||
CCrySimpleFileGuard FGTmpOutput(stdErrorTempFilename); // Delete file at the end of this function
|
||||
|
||||
std::string systemCmd = rCmd;
|
||||
if(!showStdOuput)
|
||||
{
|
||||
// Standard output redirected to null to disable it
|
||||
systemCmd += " > /dev/null";
|
||||
}
|
||||
// Standard error ouput redirected to the temporary file
|
||||
systemCmd += " 2> \"" + stdErrorTempFilename + "\"";
|
||||
|
||||
int ret = system(systemCmd.c_str());
|
||||
|
||||
// Obtain standard error output
|
||||
std::ifstream fileStream(stdErrorTempFilename.c_str());
|
||||
std::stringstream stdErrorStream;
|
||||
stdErrorStream << fileStream.rdbuf();
|
||||
std::string stdErrorString = stdErrorStream.str();
|
||||
CSTLHelper::Trim(stdErrorString," \t\r\n");
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
outError = stdErrorString;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (showStdErrorOuput && !stdErrorString.empty())
|
||||
{
|
||||
AZ_Printf(0, "\n%s\n", stdErrorString.c_str());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1,74 +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 __CRYSIMPLEJOB__
|
||||
#define __CRYSIMPLEJOB__
|
||||
|
||||
#include <Core/Common.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <AzCore/std/parallel/atomic.h>
|
||||
|
||||
class TiXmlElement;
|
||||
|
||||
enum ECrySimpleJobState
|
||||
{
|
||||
ECSJS_NONE,
|
||||
ECSJS_DONE = 1, //this is checked on client side, don't change!
|
||||
ECSJS_JOBNOTFOUND,
|
||||
ECSJS_CACHEHIT,
|
||||
ECSJS_ERROR,
|
||||
ECSJS_ERROR_COMPILE = 5, //this is checked on client side, don't change!
|
||||
ECSJS_ERROR_COMPRESS,
|
||||
ECSJS_ERROR_FILEIO,
|
||||
ECSJS_ERROR_INVALID_PROFILE,
|
||||
ECSJS_ERROR_INVALID_PROJECT,
|
||||
ECSJS_ERROR_INVALID_PLATFORM,
|
||||
ECSJS_ERROR_INVALID_PROGRAM,
|
||||
ECSJS_ERROR_INVALID_ENTRY,
|
||||
ECSJS_ERROR_INVALID_COMPILEFLAGS,
|
||||
ECSJS_ERROR_INVALID_COMPILER,
|
||||
ECSJS_ERROR_INVALID_LANGUAGE,
|
||||
ECSJS_ERROR_INVALID_SHADERREQUESTLINE,
|
||||
ECSJS_ERROR_INVALID_SHADERLIST,
|
||||
};
|
||||
|
||||
class CCrySimpleJob
|
||||
{
|
||||
ECrySimpleJobState m_State;
|
||||
uint32_t m_RequestIP;
|
||||
static AZStd::atomic_long m_GlobalRequestNumber;
|
||||
|
||||
|
||||
protected:
|
||||
virtual bool ExecuteCommand(const std::string& rCmd, std::string& outError);
|
||||
public:
|
||||
CCrySimpleJob(uint32_t requestIP);
|
||||
virtual ~CCrySimpleJob();
|
||||
|
||||
virtual bool Execute(const TiXmlElement* pElement) = 0;
|
||||
|
||||
void State(ECrySimpleJobState S)
|
||||
{
|
||||
if (m_State < ECSJS_ERROR || S >= ECSJS_ERROR)
|
||||
{
|
||||
m_State = S;
|
||||
}
|
||||
}
|
||||
ECrySimpleJobState State() const { return m_State; }
|
||||
const uint32_t& RequestIP() const { return m_RequestIP; }
|
||||
static long GlobalRequestNumber() { return m_GlobalRequestNumber; }
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,36 +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 "CrySimpleJobCache.hpp"
|
||||
#include "CrySimpleCache.hpp"
|
||||
|
||||
#include <Core/StdTypes.hpp>
|
||||
#include <Core/Error.hpp>
|
||||
#include <Core/STLHelper.hpp>
|
||||
#include <Core/Common.h>
|
||||
#include <tinyxml/tinyxml.h>
|
||||
|
||||
CCrySimpleJobCache::CCrySimpleJobCache(uint32_t requestIP)
|
||||
: CCrySimpleJob(requestIP)
|
||||
{
|
||||
}
|
||||
|
||||
void CCrySimpleJobCache::CheckHashID(std::vector<uint8_t>& rVec, size_t Size)
|
||||
{
|
||||
m_HashID = CSTLHelper::Hash(rVec, Size);
|
||||
if (CCrySimpleCache::Instance().Find(m_HashID, rVec))
|
||||
{
|
||||
State(ECSJS_CACHEHIT);
|
||||
logmessage("\r"); // Just update cache hit number
|
||||
}
|
||||
}
|
||||
@ -1,35 +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 __CRYSIMPLEJOBCACHE__
|
||||
#define __CRYSIMPLEJOBCACHE__
|
||||
|
||||
#include "CrySimpleJob.hpp"
|
||||
#include <Core/STLHelper.hpp>
|
||||
|
||||
class CCrySimpleJobCache
|
||||
: public CCrySimpleJob
|
||||
{
|
||||
tdHash m_HashID;
|
||||
|
||||
protected:
|
||||
|
||||
void CheckHashID(std::vector<uint8_t>& rVec, size_t Size);
|
||||
|
||||
public:
|
||||
CCrySimpleJobCache(uint32_t requestIP);
|
||||
|
||||
tdHash HashID() const{return m_HashID; }
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,969 +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 "CrySimpleSock.hpp"
|
||||
#include "CrySimpleJobCompile.hpp"
|
||||
#include "CrySimpleFileGuard.hpp"
|
||||
#include "CrySimpleServer.hpp"
|
||||
#include "CrySimpleCache.hpp"
|
||||
#include "ShaderList.hpp"
|
||||
|
||||
#include <Core/Error.hpp>
|
||||
#include <Core/STLHelper.hpp>
|
||||
#include <tinyxml/tinyxml.h>
|
||||
#include <Core/StdTypes.hpp>
|
||||
#include <Core/WindowsAPIImplementation.h>
|
||||
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/std/algorithm.h>
|
||||
#include <AzCore/std/sort.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#if defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS)
|
||||
#undef AZ_RESTRICTED_SECTION
|
||||
#define CRYSIMPLEJOBCOMPILE_CPP_SECTION_1 1
|
||||
#endif
|
||||
|
||||
#define MAX_COMPILER_WAIT_TIME (60 * 1000)
|
||||
|
||||
AZStd::atomic_long CCrySimpleJobCompile::m_GlobalCompileTasks = {0};
|
||||
AZStd::atomic_long CCrySimpleJobCompile::m_GlobalCompileTasksMax = {0};
|
||||
volatile int32_t CCrySimpleJobCompile::m_RemoteServerID = 0;
|
||||
volatile int64_t CCrySimpleJobCompile::m_GlobalCompileTime = 0;
|
||||
|
||||
struct STimer
|
||||
{
|
||||
int64_t m_freq;
|
||||
STimer()
|
||||
{
|
||||
QueryPerformanceFrequency((LARGE_INTEGER*)&m_freq);
|
||||
}
|
||||
int64_t GetTime() const
|
||||
{
|
||||
int64_t t;
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&t);
|
||||
return t;
|
||||
}
|
||||
|
||||
double TimeToSeconds(int64_t t)
|
||||
{
|
||||
return ((double)t) / m_freq;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
STimer g_Timer;
|
||||
|
||||
// This function validates executables up to version 21
|
||||
// because it's received within the compilation flags.
|
||||
bool ValidateExecutableStringLegacy(const AZStd::string& executableString)
|
||||
{
|
||||
AZStd::string::size_type endOfCommand = executableString.find(" ");
|
||||
|
||||
// Game always sends some type of options after the command. If we don't
|
||||
// have a space then that implies that there are no options. Reject the
|
||||
// command as someone being malicious
|
||||
if (endOfCommand == AZStd::string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AZStd::string commandString = executableString.substr(0, endOfCommand);
|
||||
|
||||
// The game never sends a parent directory in the compiler flags so lets
|
||||
// reject any commands that have .. in it
|
||||
if (commandString.find("..") != AZStd::string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Though the code later down would fail gracefully reject any absolute paths here
|
||||
if (commandString.find("\\\\") != AZStd::string::npos ||
|
||||
commandString.find(":") != AZStd::string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only allow a subset of executables to be accepted...
|
||||
if (commandString.find("fxc.exe") == AZStd::string::npos &&
|
||||
commandString.find("FXC.exe") == AZStd::string::npos &&
|
||||
commandString.find("HLSLcc.exe") == AZStd::string::npos &&
|
||||
commandString.find("HLSLcc_dedicated.exe") == AZStd::string::npos &&
|
||||
commandString.find("DXProvoShaderCompiler.exe") == AZStd::string::npos &&
|
||||
commandString.find("dxcGL") == AZStd::string::npos &&
|
||||
commandString.find("dxcMetal") == AZStd::string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CCrySimpleJobCompile::CCrySimpleJobCompile(uint32_t requestIP, EProtocolVersion Version, std::vector<uint8_t>* pRVec)
|
||||
: CCrySimpleJobCache(requestIP)
|
||||
, m_Version(Version)
|
||||
, m_pRVec(pRVec)
|
||||
{
|
||||
++m_GlobalCompileTasks;
|
||||
if (m_GlobalCompileTasksMax < m_GlobalCompileTasks)
|
||||
{
|
||||
//Need this cast as the copy assignment operator is implicitly deleted
|
||||
m_GlobalCompileTasksMax = static_cast<long>(m_GlobalCompileTasks);
|
||||
}
|
||||
}
|
||||
|
||||
CCrySimpleJobCompile::~CCrySimpleJobCompile()
|
||||
{
|
||||
--m_GlobalCompileTasks;
|
||||
}
|
||||
|
||||
bool CCrySimpleJobCompile::Execute(const TiXmlElement* pElement)
|
||||
{
|
||||
std::vector<uint8_t>& rVec = *m_pRVec;
|
||||
|
||||
size_t Size = SizeOf(rVec);
|
||||
|
||||
CheckHashID(rVec, Size);
|
||||
|
||||
if (State() == ECSJS_CACHEHIT)
|
||||
{
|
||||
State(ECSJS_DONE);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!SEnviropment::Instance().m_FallbackServer.empty() && m_GlobalCompileTasks > SEnviropment::Instance().m_FallbackTreshold)
|
||||
{
|
||||
tdEntryVec ServerVec;
|
||||
CSTLHelper::Tokenize(ServerVec, SEnviropment::Instance().m_FallbackServer, ";");
|
||||
uint32_t Idx = m_RemoteServerID++;
|
||||
uint32_t Count = (uint32_t)ServerVec.size();
|
||||
std::string Server = ServerVec[Idx % Count];
|
||||
printf(" Remote Compile on %s ...\n", Server.c_str());
|
||||
CCrySimpleSock Sock(Server, SEnviropment::Instance().m_port);
|
||||
if (Sock.Valid())
|
||||
{
|
||||
Sock.Forward(rVec);
|
||||
std::vector<uint8_t> Tmp;
|
||||
if (Sock.Backward(Tmp))
|
||||
{
|
||||
rVec = Tmp;
|
||||
if (Tmp.size() <= 4 || (m_Version == EPV_V002 && Tmp[4] != ECSJS_DONE))
|
||||
{
|
||||
State(ECSJS_ERROR_COMPILE);
|
||||
CrySimple_ERROR("failed to compile request");
|
||||
return false;
|
||||
}
|
||||
State(ECSJS_DONE);
|
||||
//printf("done\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("failed, fallback to local\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("failed, fallback to local\n");
|
||||
}
|
||||
}
|
||||
if (State() == ECSJS_NONE)
|
||||
{
|
||||
if (!Compile(pElement, rVec) || rVec.size() == 0)
|
||||
{
|
||||
State(ECSJS_ERROR_COMPILE);
|
||||
CrySimple_ERROR("failed to compile request");
|
||||
return false;
|
||||
}
|
||||
|
||||
tdDataVector rDataRaw;
|
||||
rDataRaw.swap(rVec);
|
||||
if (!CSTLHelper::Compress(rDataRaw, rVec))
|
||||
{
|
||||
State(ECSJS_ERROR_COMPRESS);
|
||||
CrySimple_ERROR("failed to compress request");
|
||||
return false;
|
||||
}
|
||||
State(ECSJS_DONE);
|
||||
}
|
||||
|
||||
// Cache compiled data
|
||||
const char* pCaching = pElement->Attribute("Caching");
|
||||
if (State() != ECSJS_ERROR && (!pCaching || std::string(pCaching) == "1"))
|
||||
{
|
||||
CCrySimpleCache::Instance().Add(HashID(), rVec);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCrySimpleJobCompile::Compile(const TiXmlElement* pElement, std::vector<uint8_t>& rVec)
|
||||
{
|
||||
AZStd::string platform;
|
||||
AZStd::string compiler;
|
||||
AZStd::string language;
|
||||
AZStd::string shaderPath;
|
||||
|
||||
if (m_Version >= EPV_V0023)
|
||||
{
|
||||
// NOTE: These attributes were alredy validated.
|
||||
platform = pElement->Attribute("Platform");
|
||||
compiler = pElement->Attribute("Compiler");
|
||||
language = pElement->Attribute("Language");
|
||||
|
||||
shaderPath = AZStd::string::format("%s%s-%s-%s/", SEnviropment::Instance().m_ShaderPath.c_str(), platform.c_str(), compiler.c_str(), language.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
// In previous versions Platform attribute is the language
|
||||
platform = "N/A";
|
||||
language = pElement->Attribute("Platform");
|
||||
|
||||
// Map shader language to shader compiler key
|
||||
const AZStd::unordered_map<AZStd::string, AZStd::string> languageToCompilerMap
|
||||
{
|
||||
{
|
||||
"GL4", SEnviropment::m_GLSL_HLSLcc
|
||||
},{
|
||||
"GLES3_0", SEnviropment::m_GLSL_HLSLcc
|
||||
},{
|
||||
"GLES3_1", SEnviropment::m_GLSL_HLSLcc
|
||||
},{
|
||||
"DX11", SEnviropment::m_D3D11_FXC
|
||||
},{
|
||||
"METAL", SEnviropment::m_METAL_HLSLcc
|
||||
},{
|
||||
"ORBIS", SEnviropment::m_Orbis_DXC
|
||||
},{
|
||||
"JASPER", SEnviropment::m_Jasper_FXC
|
||||
}
|
||||
};
|
||||
|
||||
auto foundShaderLanguage = languageToCompilerMap.find(language);
|
||||
if (foundShaderLanguage == languageToCompilerMap.end())
|
||||
{
|
||||
State(ECSJS_ERROR_INVALID_LANGUAGE);
|
||||
CrySimple_ERROR("Trying to compile with invalid shader language");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_Version < EPV_V0022)
|
||||
{
|
||||
compiler = "N/A"; // Compiler exe will be specified inside 'compile flags', this variable won't be used
|
||||
}
|
||||
else
|
||||
{
|
||||
compiler = foundShaderLanguage->second;
|
||||
|
||||
if (!SEnviropment::Instance().IsShaderCompilerValid(compiler))
|
||||
{
|
||||
State(ECSJS_ERROR_INVALID_COMPILER);
|
||||
CrySimple_ERROR("Trying to compile with invalid shader compiler");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
shaderPath = AZStd::string::format("%s%s/", SEnviropment::Instance().m_ShaderPath.c_str(), language.c_str());
|
||||
}
|
||||
|
||||
shaderPath = AZ::IO::PathView(shaderPath).LexicallyNormal().Native();
|
||||
if (!IsPathValid(shaderPath))
|
||||
{
|
||||
State(ECSJS_ERROR);
|
||||
CrySimple_ERROR("Shaders output path is invalid");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create shaders directory
|
||||
AZ::IO::SystemFile::CreateDir( shaderPath.c_str() );
|
||||
|
||||
const char* pProfile = pElement->Attribute("Profile");
|
||||
const char* pProgram = pElement->Attribute("Program");
|
||||
const char* pEntry = pElement->Attribute("Entry");
|
||||
const char* pCompileFlags = pElement->Attribute("CompileFlags");
|
||||
const char* pShaderRequestLine = pElement->Attribute("ShaderRequest");
|
||||
|
||||
if (!pProfile)
|
||||
{
|
||||
State(ECSJS_ERROR_INVALID_PROFILE);
|
||||
CrySimple_ERROR("failed to extract Profile of the request");
|
||||
return false;
|
||||
}
|
||||
if (!pProgram)
|
||||
{
|
||||
State(ECSJS_ERROR_INVALID_PROGRAM);
|
||||
CrySimple_ERROR("failed to extract Program of the request");
|
||||
return false;
|
||||
}
|
||||
if (!pEntry)
|
||||
{
|
||||
State(ECSJS_ERROR_INVALID_ENTRY);
|
||||
CrySimple_ERROR("failed to extract Entry of the request");
|
||||
return false;
|
||||
}
|
||||
if (!pShaderRequestLine)
|
||||
{
|
||||
State(ECSJS_ERROR_INVALID_SHADERREQUESTLINE);
|
||||
CrySimple_ERROR("failed to extract ShaderRequest of the request");
|
||||
return false;
|
||||
}
|
||||
if (!pCompileFlags)
|
||||
{
|
||||
State(ECSJS_ERROR_INVALID_COMPILEFLAGS);
|
||||
CrySimple_ERROR("failed to extract CompileFlags of the request");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate that the shader request line has a set of open/close parens as
|
||||
// the code below this expects at least the open paren to be in the string.
|
||||
// Without the open paren the code below will crash the compiler
|
||||
std::string strippedShaderRequestLine(pShaderRequestLine);
|
||||
const size_t locationOfOpenParen = strippedShaderRequestLine.find("(");
|
||||
const size_t locationOfCloseParen = strippedShaderRequestLine.find(")");
|
||||
if (locationOfOpenParen == std::string::npos ||
|
||||
locationOfCloseParen == std::string::npos || locationOfCloseParen < locationOfOpenParen)
|
||||
{
|
||||
State(ECSJS_ERROR_INVALID_SHADERREQUESTLINE);
|
||||
CrySimple_ERROR("invalid ShaderRequest attribute");
|
||||
return false;
|
||||
}
|
||||
|
||||
static AZStd::atomic_long nTmpCounter = { 0 };
|
||||
++nTmpCounter;
|
||||
|
||||
const auto tmpIndex = AZStd::string::format("%ld", static_cast<long>(nTmpCounter));
|
||||
const AZ::IO::Path TmpIn = SEnviropment::Instance().m_TempPath / (tmpIndex + ".In");
|
||||
const AZ::IO::Path TmpOut = SEnviropment::Instance().m_TempPath / (tmpIndex + ".Out");
|
||||
CCrySimpleFileGuard FGTmpIn(TmpIn.c_str());
|
||||
CCrySimpleFileGuard FGTmpOut(TmpOut.c_str());
|
||||
CSTLHelper::ToFile(TmpIn.c_str(), std::vector<uint8_t>(pProgram, &pProgram[strlen(pProgram)]));
|
||||
|
||||
AZ::IO::Path compilerPath = SEnviropment::Instance().m_CompilerPath;
|
||||
AZStd::string command;
|
||||
if (m_Version >= EPV_V0022)
|
||||
{
|
||||
AZStd::string compilerExecutable;
|
||||
bool validCompiler = SEnviropment::Instance().GetShaderCompilerExecutable(compiler, compilerExecutable);
|
||||
if (!validCompiler)
|
||||
{
|
||||
State(ECSJS_ERROR_INVALID_COMPILER);
|
||||
CrySimple_ERROR("Trying to compile with unknown compiler");
|
||||
return false;
|
||||
}
|
||||
|
||||
AZStd::string commandStringToFormat = (compilerPath / compilerExecutable).Native();
|
||||
|
||||
#if defined(AZ_PLATFORM_LINUX) || defined(AZ_PLATFORM_MAC)
|
||||
// Surrounding compiler path+executable with quotes to support spaces in the path.
|
||||
// NOTE: Executable has a space at the end on purpose, inserting quote before.
|
||||
commandStringToFormat.insert(0, "\"");
|
||||
commandStringToFormat.insert(commandStringToFormat.length()-1, "\"");
|
||||
#endif
|
||||
|
||||
commandStringToFormat.append(pCompileFlags);
|
||||
|
||||
if (strstr(pCompileFlags, "-fxc") != nullptr)
|
||||
{
|
||||
AZStd::string fxcCompilerExecutable;
|
||||
bool validFXCCompiler = SEnviropment::Instance().GetShaderCompilerExecutable(SEnviropment::m_D3D11_FXC, fxcCompilerExecutable);
|
||||
if (!validFXCCompiler)
|
||||
{
|
||||
State(ECSJS_ERROR_INVALID_COMPILER);
|
||||
CrySimple_ERROR("FXC compiler executable cannot be found");
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::IO::Path fxcLocation = compilerPath / fxcCompilerExecutable;
|
||||
|
||||
// Handle an extra string parameter to specify the base directory where the fxc compiler is located
|
||||
command = AZStd::move(AZStd::string::format(commandStringToFormat.c_str(), fxcLocation.c_str(), pEntry, pProfile, TmpOut.c_str(), TmpIn.c_str()));
|
||||
}
|
||||
else
|
||||
{
|
||||
command = AZStd::move(AZStd::string::format(commandStringToFormat.c_str(), pEntry, pProfile, TmpOut.c_str(), TmpIn.c_str()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ValidateExecutableStringLegacy(pCompileFlags))
|
||||
{
|
||||
State(ECSJS_ERROR_INVALID_COMPILEFLAGS);
|
||||
CrySimple_ERROR("CompileFlags failed validation");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strstr(pCompileFlags, "-fxc=\"%s") != nullptr)
|
||||
{
|
||||
// Check that the string after the %s is a valid shader compiler
|
||||
// executable
|
||||
AZStd::string tempString(pCompileFlags);
|
||||
const AZStd::string::size_type fxcOffset = tempString.find("%s") + 2;
|
||||
const AZStd::string::size_type endOfFxcString = tempString.find(" ", fxcOffset);
|
||||
tempString = tempString.substr(fxcOffset, endOfFxcString);
|
||||
if (!ValidateExecutableStringLegacy(tempString))
|
||||
{
|
||||
State(ECSJS_ERROR_INVALID_COMPILEFLAGS);
|
||||
CrySimple_ERROR("CompileFlags failed validation");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle an extra string parameter to specify the base directory where the fxc compiler is located
|
||||
command = AZStd::move(AZStd::string::format(pCompileFlags, compilerPath.c_str(), pEntry, pProfile, TmpOut.c_str(), TmpIn.c_str()));
|
||||
|
||||
// Need to add the string for escaped quotes around the path to the compiler. This is in case the path has spaces.
|
||||
// Adding just quotes (escaped) doesn't work because this cmd line is used to execute another process.
|
||||
AZStd::string insertPattern = "\\\"";
|
||||
|
||||
// Search for the next space until that path exists. Then we assume that's the path to the executable.
|
||||
size_t startPos = command.find(compilerPath.Native());
|
||||
for (size_t pos = command.find(" ", startPos); pos != AZStd::string::npos; pos = command.find(" ", pos + 1))
|
||||
{
|
||||
if (AZ::IO::SystemFile::Exists(command.substr(startPos, pos - startPos).c_str()))
|
||||
{
|
||||
command.insert(pos, insertPattern);
|
||||
command.insert(startPos, insertPattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
command = AZStd::move(AZStd::string::format(pCompileFlags, pEntry, pProfile, TmpOut.c_str(), TmpIn.c_str()));
|
||||
}
|
||||
|
||||
command = compilerPath.Native() + command;
|
||||
}
|
||||
|
||||
AZStd::string hardwareTarget;
|
||||
|
||||
#if defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS)
|
||||
#if defined(TOOLS_SUPPORT_JASPER)
|
||||
#define AZ_RESTRICTED_SECTION CRYSIMPLEJOBCOMPILE_CPP_SECTION_1
|
||||
#include AZ_RESTRICTED_FILE_EXPLICIT(CrySimpleJobCompile_cpp, jasper)
|
||||
#endif
|
||||
#if defined(TOOLS_SUPPORT_PROVO)
|
||||
#define AZ_RESTRICTED_SECTION CRYSIMPLEJOBCOMPILE_CPP_SECTION_1
|
||||
#include AZ_RESTRICTED_FILE_EXPLICIT(CrySimpleJobCompile_cpp, provo)
|
||||
#endif
|
||||
#if defined(TOOLS_SUPPORT_SALEM)
|
||||
#define AZ_RESTRICTED_SECTION CRYSIMPLEJOBCOMPILE_CPP_SECTION_1
|
||||
#include AZ_RESTRICTED_FILE_EXPLICIT(CrySimpleJobCompile_cpp, salem)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int64_t t0 = g_Timer.GetTime();
|
||||
|
||||
std::string outError;
|
||||
|
||||
std::string shaderName;
|
||||
std::stringstream crcStringStream;
|
||||
|
||||
|
||||
// Dump source shader
|
||||
if (SEnviropment::Instance().m_DumpShaders)
|
||||
{
|
||||
unsigned long crc = crc32(0l, Z_NULL, 0);
|
||||
// shader permutations start with '('
|
||||
size_t position = strippedShaderRequestLine.find('(');
|
||||
// split the string into shader name
|
||||
shaderName = strippedShaderRequestLine.substr(0, position);
|
||||
// split the string into permutation
|
||||
std::string permutation = strippedShaderRequestLine.substr(position, strippedShaderRequestLine.length() - position);
|
||||
// replace illegal filename characters with valid ones
|
||||
AZStd::replace(shaderName.begin(), shaderName.end(), '<', '(');
|
||||
AZStd::replace(shaderName.begin(), shaderName.end(), '>', ')');
|
||||
AZStd::replace(shaderName.begin(), shaderName.end(), '/', '_');
|
||||
AZStd::replace(shaderName.begin(), shaderName.end(), '|', '+');
|
||||
AZStd::replace(shaderName.begin(), shaderName.end(), '*', '^');
|
||||
AZStd::replace(shaderName.begin(), shaderName.end(), ':', ';');
|
||||
AZStd::replace(shaderName.begin(), shaderName.end(), '?', '!');
|
||||
AZStd::replace(shaderName.begin(), shaderName.end(), '%', '$');
|
||||
|
||||
crc = crc32(crc, reinterpret_cast<const unsigned char*>(permutation.c_str()), static_cast<unsigned int>(permutation.length()));
|
||||
crcStringStream << crc;
|
||||
const std::string HlslDump = shaderPath.c_str() + shaderName + "_" + crcStringStream.str() + ".hlsl";
|
||||
CSTLHelper::ToFile(HlslDump, std::vector<uint8_t>(pProgram, &pProgram[strlen(pProgram)]));
|
||||
std::ofstream crcFile;
|
||||
|
||||
std::string crcFileName = shaderPath.c_str() + shaderName + "_" + crcStringStream.str() + ".txt";
|
||||
|
||||
crcFile.open(crcFileName, std::ios_base::trunc);
|
||||
|
||||
if (!crcFile.fail())
|
||||
{
|
||||
// store permutation
|
||||
crcFile << permutation;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Error opening file " + crcFileName << std::endl;
|
||||
}
|
||||
|
||||
crcFile.close();
|
||||
}
|
||||
|
||||
if (SEnviropment::Instance().m_PrintCommands)
|
||||
{
|
||||
AZ_Printf(0, "Compiler Command:\n%s\n\n", command.c_str());
|
||||
}
|
||||
|
||||
if (!ExecuteCommand(command.c_str(), outError))
|
||||
{
|
||||
unsigned char* nIP = (unsigned char*) &RequestIP();
|
||||
char sIP[128];
|
||||
azsprintf(sIP, "%d.%d.%d.%d", nIP[0], nIP[1], nIP[2], nIP[3]);
|
||||
|
||||
const char* pProject = pElement->Attribute("Project");
|
||||
const char* pTags = pElement->Attribute("Tags");
|
||||
const char* pEmailCCs = pElement->Attribute("EmailCCs");
|
||||
|
||||
std::string project = pProject ? pProject : "Unk/";
|
||||
std::string ccs = pEmailCCs ? pEmailCCs : "";
|
||||
std::string tags = pTags ? pTags : "";
|
||||
|
||||
std::string filteredError;
|
||||
AZ::IO::Path patchFilePath = TmpIn;
|
||||
patchFilePath.ReplaceFilename(AZ::IO::PathView{ AZStd::string{ TmpIn.Filename().Native() } + ".patched" });
|
||||
CSTLHelper::Replace(filteredError, outError, patchFilePath.c_str(), "%filename%"); // DXPS does its own patching
|
||||
CSTLHelper::Replace(filteredError, filteredError, TmpIn.c_str(), "%filename%");
|
||||
// replace any that don't have the full path
|
||||
CSTLHelper::Replace(filteredError, filteredError, (tmpIndex + ".In.patched").c_str(), "%filename%"); // DXPS does its own patching
|
||||
CSTLHelper::Replace(filteredError, filteredError, (tmpIndex + ".In").c_str(), "%filename%");
|
||||
|
||||
CSTLHelper::Replace(filteredError, filteredError, "\r\n", "\n");
|
||||
|
||||
State(ECSJS_ERROR_COMPILE);
|
||||
throw new CCompilerError(pEntry, filteredError, ccs, sIP, pShaderRequestLine, pProgram, project, platform.c_str(), compiler.c_str(), language.c_str(), tags, pProfile);
|
||||
}
|
||||
|
||||
if (!CSTLHelper::FromFile(TmpOut.c_str(), rVec))
|
||||
{
|
||||
State(ECSJS_ERROR_FILEIO);
|
||||
std::string errorString("Could not read: ");
|
||||
errorString += std::string(TmpOut.c_str(), TmpOut.Native().size());
|
||||
CrySimple_ERROR(errorString.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Dump cross-compiled shader
|
||||
if (SEnviropment::Instance().m_DumpShaders)
|
||||
{
|
||||
AZStd::string fileExtension = language;
|
||||
AZStd::transform(fileExtension.begin(), fileExtension.end(), fileExtension.begin(), tolower);
|
||||
|
||||
std::string shaderDump = shaderPath.c_str() + shaderName + "_" + crcStringStream.str() + "." + fileExtension.c_str();
|
||||
CSTLHelper::ToFile(shaderDump, rVec);
|
||||
}
|
||||
|
||||
|
||||
int64_t t1 = g_Timer.GetTime();
|
||||
int64_t dt = t1 - t0;
|
||||
m_GlobalCompileTime += dt;
|
||||
|
||||
int millis = (int)(g_Timer.TimeToSeconds(dt) * 1000.0);
|
||||
int secondsTotal = (int)g_Timer.TimeToSeconds(m_GlobalCompileTime);
|
||||
logmessage("Compiled [%5dms|%8ds] (%s - %s - %s - %s) %s\n", millis, secondsTotal, platform.c_str(), compiler.c_str(), language.c_str(), pProfile, pEntry);
|
||||
|
||||
if (hardwareTarget.empty())
|
||||
{
|
||||
logmessage("Compiled [%5dms|%8ds] (% 5s %s) %s\n", millis, secondsTotal, platform.c_str(), pProfile, pEntry);
|
||||
}
|
||||
else
|
||||
{
|
||||
logmessage("Compiled [%5dms|%8ds] (% 5s %s) %s %s\n", millis, secondsTotal, platform.c_str(), pProfile, pEntry, hardwareTarget.c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
inline bool SortByLinenum(const std::pair<int, std::string>& f1, const std::pair<int, std::string>& f2)
|
||||
{
|
||||
return f1.first < f2.first;
|
||||
}
|
||||
|
||||
CCompilerError::CCompilerError(const std::string& entry, const std::string& errortext, const std::string& ccs, const std::string& IP,
|
||||
const std::string& requestLine, const std::string& program, const std::string& project,
|
||||
const std::string& platform, const std::string& compiler, const std::string& language, const std::string& tags, const std::string& profile)
|
||||
: ICryError(COMPILE_ERROR)
|
||||
, m_entry(entry)
|
||||
, m_errortext(errortext)
|
||||
, m_IP(IP)
|
||||
, m_program(program)
|
||||
, m_project(project)
|
||||
, m_platform(platform)
|
||||
, m_compiler(compiler)
|
||||
, m_language(language)
|
||||
, m_tags(tags)
|
||||
, m_profile(profile)
|
||||
, m_uniqueID(0)
|
||||
{
|
||||
m_requests.push_back(requestLine);
|
||||
Init();
|
||||
|
||||
CSTLHelper::Tokenize(m_CCs, ccs, ";");
|
||||
}
|
||||
|
||||
void CCompilerError::Init()
|
||||
{
|
||||
while (!m_errortext.empty() && (m_errortext.back() == '\r' || m_errortext.back() == '\n'))
|
||||
{
|
||||
m_errortext.pop_back();
|
||||
}
|
||||
|
||||
if (m_requests[0].size())
|
||||
{
|
||||
m_shader = m_requests[0];
|
||||
size_t offs = m_shader.find('>');
|
||||
if (offs != std::string::npos)
|
||||
{
|
||||
m_shader.erase(0, m_shader.find('>') + 1); // remove <2> version
|
||||
}
|
||||
offs = m_shader.find('@');
|
||||
if (offs != std::string::npos)
|
||||
{
|
||||
m_shader.erase(m_shader.find('@')); // remove everything after @
|
||||
}
|
||||
offs = m_shader.find('/');
|
||||
if (offs != std::string::npos)
|
||||
{
|
||||
m_shader.erase(m_shader.find('/')); // remove everything after / (used on xenon)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// default to entry function
|
||||
m_shader = m_entry;
|
||||
size_t len = m_shader.length();
|
||||
|
||||
// if it ends in ?S then trim those two characters
|
||||
if (m_shader[len - 1] == 'S')
|
||||
{
|
||||
m_shader.pop_back();
|
||||
m_shader.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> lines;
|
||||
CSTLHelper::Tokenize(lines, m_errortext, "\n");
|
||||
|
||||
for (uint32_t i = 0; i < lines.size(); i++)
|
||||
{
|
||||
std::string& line = lines[i];
|
||||
|
||||
if (line.substr(0, 5) == "error")
|
||||
{
|
||||
m_errors.push_back(std::pair<int, std::string>(-1, line));
|
||||
m_hasherrors += line;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.find(": error") == std::string::npos)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.substr(0, 10) != "%filename%")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line[10] != '(')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t c = 11;
|
||||
|
||||
int linenum = 0;
|
||||
{
|
||||
bool ln = true;
|
||||
while (c < line.length() &&
|
||||
((line[c] >= '0' && line[c] <= '9') || line[c] == ',' || line[c] == '-')
|
||||
)
|
||||
{
|
||||
if (line[c] == ',')
|
||||
{
|
||||
ln = false; // reached column, don't save the value - just keep reading to the end
|
||||
}
|
||||
if (ln)
|
||||
{
|
||||
linenum *= 10;
|
||||
linenum += line[c] - '0';
|
||||
}
|
||||
c++;
|
||||
}
|
||||
|
||||
if (c >= line.length())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line[c] != ')')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
c++;
|
||||
}
|
||||
|
||||
while (c < line.length() && (line[c] == ' ' || line[c] == ':'))
|
||||
{
|
||||
c++;
|
||||
}
|
||||
|
||||
if (line.substr(c, 5) != "error")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
m_errors.push_back(std::pair<int, std::string>(linenum, line));
|
||||
m_hasherrors += line.substr(c);
|
||||
}
|
||||
|
||||
AZStd::sort(m_errors.begin(), m_errors.end(), SortByLinenum);
|
||||
}
|
||||
|
||||
std::string CCompilerError::GetErrorLines() const
|
||||
{
|
||||
std::string ret = "";
|
||||
|
||||
for (uint32_t i = 0; i < m_errors.size(); i++)
|
||||
{
|
||||
if (m_errors[i].first < 0)
|
||||
{
|
||||
ret += m_errors[i].second + "\n";
|
||||
}
|
||||
else if (i > 0 && m_errors[i - 1].first < 0)
|
||||
{
|
||||
ret += "\n" + GetContext(m_errors[i].first) + "\n" + m_errors[i].second + "\n\n";
|
||||
}
|
||||
else if (i > 0 && m_errors[i - 1].first == m_errors[i].first)
|
||||
{
|
||||
ret.pop_back(); // pop extra newline
|
||||
ret += m_errors[i].second + "\n\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
ret += GetContext(m_errors[i].first) + "\n" + m_errors[i].second + "\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string CCompilerError::GetContext(int linenum, int context, std::string prefix) const
|
||||
{
|
||||
std::vector<std::string> lines;
|
||||
CSTLHelper::Tokenize(lines, m_program, "\n");
|
||||
|
||||
std::string ret = "";
|
||||
|
||||
linenum--; // line numbers start at one
|
||||
|
||||
char sLineNum[16];
|
||||
|
||||
for (uint32_t i = AZStd::GetMax(0U, (uint32_t)(linenum - context)); i <= AZStd::GetMin((uint32_t)lines.size() - 1U, (uint32_t)(linenum + context)); i++)
|
||||
{
|
||||
azsprintf(sLineNum, "% 3d", i + 1);
|
||||
|
||||
ret += sLineNum;
|
||||
ret += " ";
|
||||
|
||||
if (prefix.size())
|
||||
{
|
||||
if (i == linenum)
|
||||
{
|
||||
ret += "*";
|
||||
}
|
||||
else
|
||||
{
|
||||
ret += " ";
|
||||
}
|
||||
|
||||
ret += prefix;
|
||||
|
||||
ret += " ";
|
||||
}
|
||||
|
||||
ret += lines[i] + "\n";
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CCompilerError::AddDuplicate(ICryError* err)
|
||||
{
|
||||
ICryError::AddDuplicate(err);
|
||||
|
||||
if (err->GetType() == COMPILE_ERROR)
|
||||
{
|
||||
CCompilerError* comperr = (CCompilerError*)err;
|
||||
m_requests.insert(m_requests.end(), comperr->m_requests.begin(), comperr->m_requests.end());
|
||||
}
|
||||
}
|
||||
|
||||
bool CCompilerError::Compare(const ICryError* err) const
|
||||
{
|
||||
if (GetType() != err->GetType())
|
||||
{
|
||||
return GetType() < err->GetType();
|
||||
}
|
||||
|
||||
CCompilerError* e = (CCompilerError*)err;
|
||||
|
||||
if (m_platform != e->m_platform)
|
||||
{
|
||||
return m_platform < e->m_platform;
|
||||
}
|
||||
|
||||
if (m_compiler != e->m_compiler)
|
||||
{
|
||||
return m_compiler < e->m_compiler;
|
||||
}
|
||||
|
||||
if (m_language != e->m_language)
|
||||
{
|
||||
return m_language < e->m_language;
|
||||
}
|
||||
|
||||
if (m_shader != e->m_shader)
|
||||
{
|
||||
return m_shader < e->m_shader;
|
||||
}
|
||||
|
||||
if (m_entry != e->m_entry)
|
||||
{
|
||||
return m_entry < e->m_entry;
|
||||
}
|
||||
|
||||
return Hash() < err->Hash();
|
||||
}
|
||||
|
||||
bool CCompilerError::CanMerge(const ICryError* err) const
|
||||
{
|
||||
if (GetType() != err->GetType()) // don't merge with non compile errors
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CCompilerError* e = (CCompilerError*)err;
|
||||
|
||||
if (m_platform != e->m_platform || m_compiler != e->m_compiler || m_language != e->m_language || m_shader != e->m_shader)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_CCs.size() != e->m_CCs.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t a = 0, S = m_CCs.size(); a < S; a++)
|
||||
{
|
||||
if (m_CCs[a] != e->m_CCs[a])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CCompilerError::AddCCs(std::set<std::string>& ccs) const
|
||||
{
|
||||
for (size_t a = 0, S = m_CCs.size(); a < S; a++)
|
||||
{
|
||||
ccs.insert(m_CCs[a]);
|
||||
}
|
||||
}
|
||||
|
||||
std::string CCompilerError::GetErrorName() const
|
||||
{
|
||||
return std::string("[") + m_tags + "] Shader Compile Errors in " + m_shader + " on " + m_language + " for " + m_platform + " " + m_compiler;
|
||||
}
|
||||
|
||||
std::string CCompilerError::GetErrorDetails(EOutputFormatType outputType) const
|
||||
{
|
||||
std::string errorString("");
|
||||
|
||||
char sUniqueID[16], sNumDuplicates[16];
|
||||
azsprintf(sUniqueID, "%d", m_uniqueID);
|
||||
azsprintf(sNumDuplicates, "%d", NumDuplicates());
|
||||
|
||||
std::string errorOutput;
|
||||
CSTLHelper::Replace(errorOutput, GetErrorLines(), "%filename%", std::string(sUniqueID) + "-" + GetFilename());
|
||||
|
||||
std::string fullOutput;
|
||||
CSTLHelper::Replace(fullOutput, m_errortext, "%filename%", std::string(sUniqueID) + "-" + GetFilename());
|
||||
|
||||
if (outputType == OUTPUT_HASH)
|
||||
{
|
||||
errorString = GetFilename() + m_IP + m_platform + m_compiler + m_language + m_project + m_entry + m_tags + m_profile + m_hasherrors /*+ m_requestline*/;
|
||||
}
|
||||
else if (outputType == OUTPUT_EMAIL)
|
||||
{
|
||||
errorString = std::string("=== Shader compile error in ") + m_entry + " (" + sNumDuplicates + " duplicates)\n\n";
|
||||
|
||||
/////
|
||||
errorString += std::string("* From: ") + m_IP + " on " + m_language + " for " + m_platform + " " + m_compiler + " " + m_project;
|
||||
if (m_tags != "")
|
||||
{
|
||||
errorString += std::string(" (Tags: ") + m_tags + ")";
|
||||
}
|
||||
errorString += "\n";
|
||||
|
||||
/////
|
||||
errorString += std::string("* Target profile: ") + m_profile + "\n";
|
||||
|
||||
/////
|
||||
bool hasrequests = false;
|
||||
for (uint32_t i = 0; i < m_requests.size(); i++)
|
||||
{
|
||||
if (m_requests[i].size())
|
||||
{
|
||||
errorString += std::string("* Shader request line: ") + m_requests[i] + "\n";
|
||||
hasrequests = true;
|
||||
}
|
||||
}
|
||||
|
||||
errorString += "\n";
|
||||
|
||||
if (hasrequests)
|
||||
{
|
||||
errorString += "* Shader source from first listed request\n";
|
||||
}
|
||||
|
||||
errorString += std::string("* Reported error(s) from ") + sUniqueID + "-" + GetFilename() + "\n\n";
|
||||
errorString += errorOutput + "\n\n";
|
||||
|
||||
errorString += std::string("* Full compiler output:\n\n");
|
||||
errorString += fullOutput + "\n";
|
||||
}
|
||||
else if (outputType == OUTPUT_TTY)
|
||||
{
|
||||
errorString = std::string("=== Shader compile error in ") + m_entry + " { " + m_requests[0] + " }\n";
|
||||
// errors only
|
||||
errorString += std::string("* Reported error(s):\n\n");
|
||||
errorString += errorOutput;
|
||||
errorString += m_errortext;
|
||||
}
|
||||
|
||||
return errorString;
|
||||
}
|
||||
@ -1,92 +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 __CRYSIMPLEJOBCOMPILE__
|
||||
#define __CRYSIMPLEJOBCOMPILE__
|
||||
|
||||
#include "CrySimpleJobCache.hpp"
|
||||
#include <Core/Common.h>
|
||||
#include <Core/Error.hpp>
|
||||
|
||||
|
||||
class CCrySimpleJobCompile
|
||||
: public CCrySimpleJobCache
|
||||
{
|
||||
public:
|
||||
CCrySimpleJobCompile(uint32_t requestIP, EProtocolVersion Version, std::vector<uint8_t>* pRVec);
|
||||
virtual ~CCrySimpleJobCompile();
|
||||
|
||||
virtual bool Execute(const TiXmlElement* pElement);
|
||||
|
||||
static long GlobalCompileTasks(){return m_GlobalCompileTasks; }
|
||||
static long GlobalCompileTasksMax(){return m_GlobalCompileTasksMax; }
|
||||
|
||||
private:
|
||||
static AZStd::atomic_long m_GlobalCompileTasks;
|
||||
static AZStd::atomic_long m_GlobalCompileTasksMax;
|
||||
static volatile int32_t m_RemoteServerID;
|
||||
static volatile int64_t m_GlobalCompileTime;
|
||||
|
||||
EProtocolVersion m_Version;
|
||||
std::vector<uint8_t>* m_pRVec;
|
||||
|
||||
virtual size_t SizeOf(std::vector<uint8_t>& rVec) = 0;
|
||||
|
||||
bool Compile(const TiXmlElement* pElement, std::vector<uint8_t>& rVec);
|
||||
};
|
||||
|
||||
class CCompilerError
|
||||
: public ICryError
|
||||
{
|
||||
public:
|
||||
CCompilerError(const std::string& entry, const std::string& errortext, const std::string& ccs, const std::string& IP,
|
||||
const std::string& requestLine, const std::string& program, const std::string& project,
|
||||
const std::string& platform, const std::string& compiler, const std::string& language, const std::string& tags, const std::string& profile);
|
||||
|
||||
virtual ~CCompilerError() {}
|
||||
|
||||
virtual void AddDuplicate(ICryError* err);
|
||||
|
||||
virtual void SetUniqueID(int uniqueID) { m_uniqueID = uniqueID; }
|
||||
|
||||
virtual bool Compare(const ICryError* err) const;
|
||||
virtual bool CanMerge(const ICryError* err) const;
|
||||
|
||||
virtual bool HasFile() const { return true; }
|
||||
|
||||
virtual void AddCCs(std::set<std::string>& ccs) const;
|
||||
|
||||
virtual std::string GetErrorName() const;
|
||||
virtual std::string GetErrorDetails(EOutputFormatType outputType) const;
|
||||
virtual std::string GetFilename() const { return m_entry + ".txt"; }
|
||||
virtual std::string GetFileContents() const { return m_program; }
|
||||
|
||||
std::vector<std::string> m_requests;
|
||||
private:
|
||||
void Init();
|
||||
std::string GetErrorLines() const;
|
||||
std::string GetContext(int linenum, int context = 2, std::string prefix = ">") const;
|
||||
|
||||
std::vector< std::pair<int, std::string> > m_errors;
|
||||
|
||||
tdEntryVec m_CCs;
|
||||
|
||||
std::string m_entry, m_errortext, m_hasherrors, m_IP,
|
||||
m_program, m_project, m_shader,
|
||||
m_platform, m_compiler, m_language, m_tags, m_profile;
|
||||
int m_uniqueID;
|
||||
|
||||
friend CCompilerError;
|
||||
};
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue