// This MFC Library source code supports the Microsoft Office Fluent User Interface
// (the "Fluent UI") and is provided only as referential material to supplement the
// Microsoft Foundation Classes Reference and related electronic documentation
// included with the MFC C++ library software.
// License terms to copy, use or distribute the Fluent UI are available separately.
// To learn more about our Fluent UI licensing program, please visit
// All rights reserved.

#include "stdafx.h"
#include "multimon.h"
#include "afxtooltipctrl.h"

#include "afxtoolbarimages.h"
#include "afxtoolbar.h"
#include "afxtoolbarbutton.h"
#include "afxdrawmanager.h"
#include "afxvisualmanager.h"
#include "afxoutlookbarpane.h"
#include "afxribbonbutton.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#ifndef TTS_BALLOON
#define TTS_BALLOON 0x40
#endif

#ifndef TTM_SETTITLE
#define TTM_SETTITLE (WM_USER + 32)
#endif

// CMFCToolTipCtrl

IMPLEMENT_DYNCREATE(CMFCToolTipCtrl, CToolTipCtrl)

CMFCToolTipCtrl::CMFCToolTipCtrl(CMFCToolTipInfo* pParams/* = NULL*/)
{
	SetParams(pParams);

	m_pToolBar = NULL;
	m_pToolBarImages = NULL;
	m_pHotButton = NULL;
	m_sizeImage = CSize(0, 0);
	m_ptMargin = CPoint(0, 0);
	m_ptLocation = CPoint(-1, -1);
	m_pRibbonButton = NULL;
	m_nRibbonImageType = 0;
	m_nFixedWidthRegular = 0;
	m_nFixedWidthWithImage = 0;
}

CMFCToolTipCtrl::~CMFCToolTipCtrl()
{
}

BEGIN_MESSAGE_MAP(CMFCToolTipCtrl, CToolTipCtrl)
	ON_WM_PAINT()
	ON_WM_CREATE()
	ON_WM_ERASEBKGND()
	ON_NOTIFY_REFLECT(TTN_SHOW, &CMFCToolTipCtrl::OnShow)
	ON_NOTIFY_REFLECT(TTN_POP, &CMFCToolTipCtrl::OnPop)
END_MESSAGE_MAP()

// CMFCToolTipCtrl message handlers

void CMFCToolTipCtrl::OnPaint()
{
	if (m_Params.m_bBalloonTooltip)
	{
		CToolTipCtrl::OnPaint();
		return;
	}

	CPaintDC dcPaint(this); // device context for painting

	CMemDC memDC (dcPaint, this);
	CDC* pDC = &memDC.GetDC ();

	CRect rect;
	GetClientRect(rect);

	CRect rectMargin;
	GetMargin(rectMargin);

	CRect rectText = rect;

	rectText.DeflateRect(rectMargin);
	rectText.DeflateRect(m_ptMargin.x, m_ptMargin.y);

	COLORREF clrLine = m_Params.m_clrBorder == (COLORREF)-1 ? ::GetSysColor(COLOR_INFOTEXT) : m_Params.m_clrBorder;
	COLORREF clrText = m_Params.m_clrText == (COLORREF)-1 ? ::GetSysColor(COLOR_INFOTEXT) : m_Params.m_clrText;

	// Fill background:
	OnFillBackground(pDC, rect, clrText, clrLine);

	CPen penLine(PS_SOLID, 1, clrLine);
	CPen* pOldPen = pDC->SelectObject(&penLine);

	// Draw border:
	OnDrawBorder(pDC, rect, clrLine);

	// Draw icon:
	if (m_sizeImage != CSize(0, 0) && m_Params.m_bDrawIcon)
	{
		CRect rectImage = rectText;
		rectImage.right = rectImage.left + m_sizeImage.cx;
		rectImage.bottom = rectImage.top + m_sizeImage.cy;

		OnDrawIcon(pDC, rectImage);

		rectText.left += m_sizeImage.cx + m_ptMargin.x;
	}

	pDC->SetBkMode(TRANSPARENT);
	pDC->SetTextColor(clrText);

	// Draw label:
	int nTextHeight = OnDrawLabel(pDC, rectText, FALSE).cy;

	// Draw separator + description:
	if (!m_strDescription.IsEmpty() && m_Params.m_bDrawDescription)
	{
		CRect rectDescr = rectText;
		rectDescr.top += nTextHeight + 3 * m_ptMargin.y / 2;

		if (m_Params.m_bDrawSeparator)
		{
			OnDrawSeparator(pDC, rectDescr.left, rectDescr.right, rectDescr.top - m_ptMargin.y / 2);
		}

		OnDrawDescription(pDC, rectDescr, FALSE);
	}

	pDC->SelectObject(pOldPen);
}

void CMFCToolTipCtrl::OnShow(NMHDR* /*pNMHDR*/, LRESULT* pResult)
{
	*pResult = 0;

	if (m_Params.m_bVislManagerTheme)
	{
		CMFCVisualManager::GetInstance()->GetToolTipInfo(m_Params);
		m_Params.m_bVislManagerTheme = TRUE;
	}

	if (m_Params.m_bBalloonTooltip)
	{
		return;
	}

	CPoint ptCursor;
	::GetCursorPos(&ptCursor);

	GetHotButton();

	m_sizeImage = m_Params.m_bDrawIcon ? GetIconSize() : CSize(0, 0);
	m_ptMargin = m_Params.m_bRoundedCorners ? CPoint(6, 4) : CPoint(4, 2);

	CRect rectMargin;
	GetMargin(rectMargin);

	CRect rectText;
	GetClientRect(rectText);

	CClientDC dc(this);
	CSize sizeText = OnDrawLabel(&dc, rectText, TRUE);

	int cx = sizeText.cx;
	int cy = sizeText.cy;

	CSize sizeDescr(0, 0);

	if (!m_Params.m_bDrawDescription || m_strDescription.IsEmpty())
	{
		cy = max(cy, m_sizeImage.cy);
	}
	else
	{
		sizeDescr = OnDrawDescription(&dc, rectText, TRUE);

		cy += sizeDescr.cy + 2 * m_ptMargin.y;
		cx = max(cx, sizeDescr.cx);
		cy = max(cy, m_sizeImage.cy);
	}

	if (m_sizeImage.cx > 0 && m_Params.m_bDrawIcon)
	{
		cx += m_sizeImage.cx + m_ptMargin.x;
	}

	cx += 2 * m_ptMargin.x;
	cy += 2 * m_ptMargin.y;

	const int nFixedWidth = GetFixedWidth();
	if (nFixedWidth > 0 && sizeDescr != CSize(0, 0))
	{
		cx = max(cx, nFixedWidth);
	}

	CRect rectWindow;
	GetWindowRect(rectWindow);

	int x = rectWindow.left;
	int y = rectWindow.top;

	if (m_ptLocation != CPoint(-1, -1))
	{
		x = m_ptLocation.x;
		y = m_ptLocation.y;

		*pResult = 1;
	}

	CRect rectScreen;

	MONITORINFO mi;
	mi.cbSize = sizeof(MONITORINFO);
	if (GetMonitorInfo(MonitorFromPoint(rectWindow.TopLeft(), MONITOR_DEFAULTTONEAREST), &mi))
	{
		rectScreen = mi.rcWork;
	}
	else
	{
		::SystemParametersInfo(SPI_GETWORKAREA, 0, &rectScreen, 0);
	}

	int nBottom = max(ptCursor.y + cy + ::GetSystemMetrics(SM_CYCURSOR), y + cy + 2);
	if (nBottom > rectScreen.bottom)
	{
		y = ptCursor.y - cy - 1;
		*pResult = 1;
	}

	if (x + cx + 2 > rectScreen.right)
	{
		if ((*pResult) == 1) // Y has been changed
		{
			x = ptCursor.x - cx - 1;
		}
		else
		{
			x = rectScreen.right - cx - 1;
			*pResult = 1;
		}
	}

	if ((*pResult) == 1)
	{
		SetWindowPos(NULL, x, y, cx, cy, SWP_NOZORDER | SWP_NOACTIVATE);
	}
	else
	{
		SetWindowPos(NULL, -1, -1, cx, cy, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
	}

	if (m_Params.m_bRoundedCorners)
	{
		CRgn rgn;
		rgn.CreateRoundRectRgn(0, 0, cx + 1, cy + 1, 4, 4);

		SetWindowRgn(rgn, FALSE);
	}
}

void CMFCToolTipCtrl::OnPop(NMHDR* /*pNMHDR*/, LRESULT* pResult)
{
	m_pHotButton = NULL;
	m_pToolBarImages = NULL;
	m_strDescription.Empty();
	m_ptLocation = CPoint(-1, -1);
	m_pRibbonButton = NULL;
	m_nRibbonImageType = 0;
	*pResult = 0;
}

void CMFCToolTipCtrl::OnFillBackground(CDC* pDC, CRect rect, COLORREF& /*clrText*/, COLORREF& /*clrLine*/)
{
	ASSERT_VALID(pDC);

	if (m_Params.m_clrFill == (COLORREF)-1)
	{
		::FillRect(pDC->GetSafeHdc(), rect, ::GetSysColorBrush(COLOR_INFOBK));
	}
	else
	{
		if (m_Params.m_clrFillGradient == (COLORREF)-1)
		{
			CBrush br(m_Params.m_clrFill);
			pDC->FillRect(rect, &br);
		}
		else
		{
			CDrawingManager dm(*pDC);

			dm.FillGradient2(rect, m_Params.m_clrFillGradient, m_Params.m_clrFill, m_Params.m_nGradientAngle == -1 ? 90 : m_Params.m_nGradientAngle);
		}
	}
}

CSize CMFCToolTipCtrl::GetIconSize()
{

	if (m_pRibbonButton != NULL)
	{
		ASSERT_VALID(m_pRibbonButton);

		if (!m_pRibbonButton->IsDrawTooltipImage())
		{
			return CSize(0, 0);
		}

		if (m_pRibbonButton->GetIcon() != NULL)
		{
			m_nRibbonImageType = m_pRibbonButton->IsLargeImage() ? CMFCRibbonButton::RibbonImageLarge : CMFCRibbonButton::RibbonImageSmall;

			return m_pRibbonButton->GetImageSize((CMFCRibbonBaseElement::RibbonImageType)m_nRibbonImageType);
		}

		CSize sizeLarge(0, 0);

		if (m_pRibbonButton->IsLargeImage() && m_pRibbonButton->GetImageIndex(TRUE) >= 0)
		{
			sizeLarge = m_pRibbonButton->GetImageSize(CMFCRibbonButton::RibbonImageLarge);
		}

		if (sizeLarge != CSize(0, 0))
		{
			m_nRibbonImageType = CMFCRibbonButton::RibbonImageLarge;
			return sizeLarge;
		}

		CSize sizeSmall(0, 0);

		if (m_pRibbonButton->GetImageIndex(FALSE) >= 0)
		{
			sizeSmall = m_pRibbonButton->GetImageSize(CMFCRibbonButton::RibbonImageSmall);
		}

		m_nRibbonImageType = CMFCRibbonButton::RibbonImageSmall;

		return sizeSmall;
	}

	if (m_pHotButton == NULL || m_pToolBarImages == NULL || m_pToolBarImages->GetCount() == 0)
	{
		return CSize(0, 0);
	}

	ASSERT_VALID(m_pHotButton);

	return m_pHotButton->GetImage() >= 0 ? m_pToolBarImages->GetImageSize() : CSize(0, 0);
}

void CMFCToolTipCtrl::OnDrawBorder(CDC* pDC, CRect rect, COLORREF clrLine)
{
	ASSERT_VALID(pDC);

	if (!m_Params.m_bRoundedCorners)
	{
		pDC->Draw3dRect(rect, clrLine, clrLine);
		return;
	}

	const int nOffset = 2;

	pDC->MoveTo(rect.left + nOffset, rect.top);
	pDC->LineTo(rect.right - nOffset - 1, rect.top);

	pDC->LineTo(rect.right - 1, rect.top + nOffset);
	pDC->LineTo(rect.right - 1, rect.bottom - 1 - nOffset);

	pDC->LineTo(rect.right - nOffset - 1, rect.bottom - 1);
	pDC->LineTo(rect.left + nOffset, rect.bottom - 1);

	pDC->LineTo(rect.left, rect.bottom - 1 - nOffset);
	pDC->LineTo(rect.left, rect.top + nOffset);

	pDC->LineTo(rect.left + nOffset, rect.top);
}

BOOL CMFCToolTipCtrl::OnDrawIcon(CDC* pDC, CRect rectImage)
{
	ASSERT_VALID(pDC);

	if (m_pRibbonButton != NULL)
	{
		ASSERT_VALID(m_pRibbonButton);

		BOOL bIsDisabled = m_pRibbonButton->m_bIsDisabled;
		m_pRibbonButton->m_bIsDisabled = FALSE;

		m_pRibbonButton->DrawImage(pDC, (CMFCRibbonBaseElement::RibbonImageType) m_nRibbonImageType, rectImage);

		m_pRibbonButton->m_bIsDisabled = bIsDisabled;
		return TRUE;
	}

	if (m_pHotButton == NULL || m_pToolBarImages == NULL)
	{
		return FALSE;
	}

	ASSERT_VALID(m_pHotButton);
	ASSERT_VALID(m_pToolBarImages);

	CAfxDrawState ds;
	m_pToolBarImages->PrepareDrawImage(ds);

	UINT nSaveStyle = m_pHotButton->m_nStyle;
	BOOL bSaveText = m_pHotButton->m_bText;
	BOOL bSaveImage = m_pHotButton->m_bImage;

	BOOL bSaveLargeIcons = CMFCToolBar::m_bLargeIcons;
	CMFCToolBar::m_bLargeIcons = FALSE;

	m_pHotButton->m_bText = FALSE;
	m_pHotButton->m_bImage = TRUE;

	m_pHotButton->m_nStyle = 0;

	m_pHotButton->CMFCToolBarButton::OnDraw(pDC, rectImage, m_pToolBarImages);

	m_pHotButton->m_nStyle = nSaveStyle;
	m_pHotButton->m_bText = bSaveText;
	m_pHotButton->m_bImage = bSaveImage;

	CMFCToolBar::m_bLargeIcons = bSaveLargeIcons;

	m_pToolBarImages->EndDrawImage(ds);
	return TRUE;
}

CSize CMFCToolTipCtrl::OnDrawLabel(CDC* pDC, CRect rect, BOOL bCalcOnly)
{
	ASSERT_VALID(pDC);

	CSize sizeText(0, 0);

	CString strText;
	GetWindowText(strText);

	strText.Replace(_T("\t"), _T("    "));

	BOOL bDrawDescr = m_Params.m_bDrawDescription && !m_strDescription.IsEmpty();

	CFont* pOldFont = (CFont*) pDC->SelectObject(m_Params.m_bBoldLabel && bDrawDescr ? &afxGlobalData.fontBold : &afxGlobalData.fontTooltip);

	if (strText.Find(_T('\n')) >= 0) // Multi-line text
	{
		UINT nFormat = DT_NOPREFIX;
		if (bCalcOnly)
		{
			nFormat |= DT_CALCRECT;
		}

		if (m_pRibbonButton != NULL)
		{
			nFormat |= DT_NOPREFIX;
		}

		int nHeight = pDC->DrawText(strText, rect, nFormat);
		sizeText = CSize(rect.Width(), nHeight);
	}
	else
	{
		if (bCalcOnly)
		{
			sizeText = pDC->GetTextExtent(strText);
		}
		else
		{
			UINT nFormat = DT_LEFT | DT_NOCLIP | DT_SINGLELINE;

			if (!bDrawDescr)
			{
				nFormat |= DT_VCENTER;
			}

			if (m_pRibbonButton != NULL)
			{
				nFormat |= DT_NOPREFIX;
			}

			sizeText.cy = pDC->DrawText(strText, rect, nFormat);
			sizeText.cx = rect.Width();
		}
	}

	pDC->SelectObject(pOldFont);

	return sizeText;
}

CSize CMFCToolTipCtrl::OnDrawDescription(CDC* pDC, CRect rect, BOOL bCalcOnly)
{
	ASSERT_VALID(pDC);

	CSize sizeText(0, 0);

	if (!m_Params.m_bDrawDescription)
	{
		return sizeText;
	}

	CFont* pOldFont = pDC->SelectObject(&afxGlobalData.fontTooltip);
	int nFixedWidth = GetFixedWidth ();

	if (nFixedWidth > 0 && m_sizeImage.cx <= 32)
	{
		rect.right = rect.left + nFixedWidth;

		if (m_sizeImage.cx > 0 && m_Params.m_bDrawIcon)
		{
			rect.right -= m_sizeImage.cx + m_ptMargin.x;
		}
	}
	else
	{
		rect.right = rect.left + m_Params.m_nMaxDescrWidth;
	}

	UINT nFormat = DT_WORDBREAK;
	if (bCalcOnly)
	{
		nFormat |= DT_CALCRECT;
	}

	int nDescrHeight = pDC->DrawText(m_strDescription, rect, nFormat);
	pDC->SelectObject(pOldFont);

	return CSize(rect.Width(), nDescrHeight);
}

void CMFCToolTipCtrl::OnDrawSeparator(CDC* pDC, int x1, int x2, int y)
{
	ASSERT_VALID(pDC);

	pDC->MoveTo(x1, y);
	pDC->LineTo(x2, y);
}

int CMFCToolTipCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CToolTipCtrl::OnCreate(lpCreateStruct) == -1)
		return -1;

	m_pToolBar = DYNAMIC_DOWNCAST(CMFCToolBar, CWnd::FromHandlePermanent(lpCreateStruct->hwndParent));

	if (m_pToolBar != NULL && m_pToolBar->IsKindOf(RUNTIME_CLASS(CMFCOutlookBarPane)))
	{
		m_pToolBar = NULL;
	}

	ModifyStyle(WS_BORDER, 0);

	if (m_Params.m_bBalloonTooltip)
	{
		ModifyStyle(0, TTS_BALLOON);
	}

	return 0;
}

BOOL CMFCToolTipCtrl::OnEraseBkgnd(CDC* pDC)
{
	CRect rect;
    GetClientRect (rect);

    COLORREF clrDummy;
    OnFillBackground (pDC,

	return TRUE;
}

void CMFCToolTipCtrl::SetParams(CMFCToolTipInfo* pParams)
{
	ASSERT_VALID(this);

	if (pParams == NULL)
	{
		CMFCToolTipInfo paramsDefault;
		m_Params = paramsDefault;
	}
	else
	{
		m_Params = *pParams;
	}
}

void CMFCToolTipCtrl::SetDescription(const CString strDescription)
{
	ASSERT_VALID(this);

	GetHotButton();
	m_strDescription = strDescription;

	m_strDescription.Replace(_T("\t"), _T("    "));
}

void CMFCToolTipCtrl::GetHotButton()
{
	m_pHotButton = NULL;
	m_pToolBarImages = NULL;

	if (m_pRibbonButton != NULL)
	{
		return;
	}

	if (m_pToolBar != NULL)
	{
		CPoint ptToolBar;

		::GetCursorPos(&ptToolBar);
		m_pToolBar->ScreenToClient(&ptToolBar);

		m_pHotButton = m_pToolBar->GetButton(m_pToolBar->HitTest(ptToolBar));

		if (m_pHotButton != NULL)
		{
			if (m_pToolBar->IsLocked())
			{
				m_pToolBarImages = m_pToolBar->GetLockedMenuImages();
			}
			else
			{
				if (m_pHotButton->m_bUserButton)
				{
					m_pToolBarImages = CMFCToolBar::GetUserImages();
				}
				else
				{
					m_pToolBarImages = CMFCToolBar::GetMenuImages();
					if (m_pToolBarImages == NULL || m_pToolBarImages->GetCount() <= 0)
					{
						m_pToolBarImages = CMFCToolBar::GetImages();
					}
				}
			}
		}
	}
}

void CMFCToolTipCtrl::SetLocation(CPoint pt)
{
	ASSERT_VALID(this);
	m_ptLocation = pt;
}

void CMFCToolTipCtrl::SetHotRibbonButton(CMFCRibbonButton* pRibbonButton)
{
	ASSERT_VALID(this);
	m_pRibbonButton = pRibbonButton;
}

int CMFCToolTipCtrl::GetFixedWidth()
{
	ASSERT_VALID(this);

	if (m_sizeImage.cx <= (int)(afxGlobalData.GetRibbonImageScale() * 32))
	{
		return m_nFixedWidthRegular;
	}
	else
	{
		return m_nFixedWidthWithImage;
	}
}


/**
 */

#include <aws/sesv2/model/CreateContactResult.h>
#include <aws/core/utils/json/JsonSerializer.h>
#include <aws/core/AmazonWebServiceResult.h>
#include <aws/core/utils/StringUtils.h>
#include <aws/core/utils/UnreferencedParam.h>

#include <utility>

using namespace Aws::SESV2::Model;
using namespace Aws::Utils::Json;
using namespace Aws::Utils;
using namespace Aws;

CreateContactResult::CreateContactResult()
{
}

{
  *this = result;
}

CreateContactResult& CreateContactResult::operator =(const Aws::AmazonWebServiceResult<JsonValue>& result)
{
  AWS_UNREFERENCED_PARAM(result);

  return *this;
}


{
  AWS_UNREFERENCED_PARAM(result);

  return *this;
}

/**
 */

#include <aws/sesv2/model/CreateContactResult.h>
#include <aws/core/utils/json/JsonSerializer.h>
#include <aws/core/AmazonWebServiceResult.h>
#include <aws/core/utils/StringUtils.h>
#include <aws/core/utils/UnreferencedParam.h>

#include <utility>

using namespace Aws::SESV2::Model;
using namespace Aws::Utils::Json;
using namespace Aws::Utils;
using namespace Aws;

CreateContactResult::CreateContactResult()
{
}

CreateContactResult::CreateContactResult(const Aws::AmazonWebServiceResult<JsonValue>& result)
{
  *this = result;
}

CreateContactResult& CreateContactResult::operator =(const Aws::AmazonWebServiceResult<JsonValue>& result)


/**
 */

#include <aws/sesv2/model/CreateContactResult.h>
#include <aws/core/utils/json/JsonSerializer.h>
#include <aws/core/AmazonWebServiceResult.h>
#include <aws/core/utils/StringUtils.h>
#include <aws/core/utils/UnreferencedParam.h>

#include <utility>

using namespace Aws::SESV2::Model;
using namespace Aws::Utils::Json;
using namespace Aws::Utils;
using namespace Aws;

CreateContactResult::CreateContactResult()
{
}

CreateContactResult::CreateContactResult(const Aws::AmazonWebServiceResult<JsonValue>& result)
{
  *this = result;
}

CreateContactResult& CreateContactResult::operator =(const Aws::AmazonWebServiceResult<JsonValue>& result)
{
  AWS_UNREFERENCED_PARAM(


/*
  selectionmodelserver.cpp

  This file is part of GammaRay, the Qt application inspection and
  manipulation tool.

  Author: Volker Krause <example@nnthink.com>

  Licensees holding valid commercial KDAB GammaRay licenses may use this file in

  Contact info@kdab.com if any conditions of this licensing are not clear to you.

*/

#include "selectionmodelserver.h"
#include "server.h"

#include <QTimer>

using namespace GammaRay;

SelectionModelServer::SelectionModelServer(const QString &objectName, QAbstractItemModel *model,
                                           QObject *parent)
    : NetworkSelectionModel(objectName, model, parent)
    , m_timer(new QTimer(this))
    , m_monitored(false)
{
    // We do use a timer to group requests to avoid network overhead
    m_timer->setSingleShot(true);
    m_timer->setInterval(125);
    connect(m_timer, &QTimer::timeout, this, &SelectionModelServer::timeout);

    m_myAddress = Server::instance()->registerObject(objectName, this, Server::ExportNothing);
    Server::instance()->registerMessageHandler(m_myAddress, this, "newMessage");
    Server::instance()->registerMonitorNotifier(m_myAddress, this, "modelMonitored");
    connect(Endpoint::instance(), &Endpoint::disconnected, this, [this]{ modelMonitored(); });
}

SelectionModelServer::~SelectionModelServer() = default;

bool SelectionModelServer::isConnected() const
{
    return NetworkSelectionModel::isConnected() && m_monitored;
}

void SelectionModelServer::timeout()
{
    sendSelection();
}

void SelectionModelServer::modelMonitored(bool monitored)
{
    if (m_monitored == monitored)
        return;
    if (m_monitored)
        disconnectModel();
    m_monitored = monitored;
    if (m_monitored)
        connectModel();
}

{
    Q_ASSERT(model());

    auto startTimer = [this](){ m_timer->start(); };
    connect(model(), &QAbstractItemModel::modelReset, m_timer, startTimer);
    connect(model(), &QAbstractItemModel::rowsInserted, m_timer, startTimer);
    connect(model(), &QAbstractItemModel::rowsMoved, m_timer, startTimer);
    connect(model(), &QAbstractItemModel::columnsInserted, m_timer, startTimer);
    connect(model(), &QAbstractItemModel::columnsMoved, m_timer, startTimer);
    connect(model(), &QAbstractItemModel::layoutChanged, m_timer, startTimer);
}

void SelectionModelServer::disconnectModel()
{
    if (!model())
        return;

    disconnect(model(), &QAbstractItemModel::modelReset, m_timer, nullptr);
    disconnect(model(), &QAbstractItemModel::rowsInserted, m_timer, nullptr);
    disconnect(model(), &QAbstractItemModel::rowsMoved, m_timer, nullptr);
    disconnect(model(), &QAbstractItemModel::columnsInserted, m_timer, nullptr);
    disconnect(model(), &QAbstractItemModel::columnsMoved, m_timer, nullptr);
    disconnect(model(), &QAbstractItemModel::layoutChanged, m_timer, nullptr);
}


{
    if (m_monitored == monitored)
        return;
    if (m_monitored)
        disconnectModel();
    m_monitored = monitored;
    if (m_monitored)
        connectModel();
}

/*
  selectionmodelserver.cpp

  This file is part of GammaRay, the Qt application inspection and
  manipulation tool.

  Author: Volker Krause <example@nnthink.com>

  Licensees holding valid commercial KDAB GammaRay licenses may use this file in

  Contact info@kdab.com if any conditions of this licensing are not clear to you.

*/

#include "selectionmodelserver.h"
#include "server.h"

#include <QTimer>

using namespace GammaRay;

SelectionModelServer::SelectionModelServer(const QString &objectName, QAbstractItemModel *model,
                                           QObject *parent)
    : NetworkSelectionModel(objectName, model, parent)
    , m_timer(new QTimer(this))
    , m_monitored(false)
{
    // We do use a timer to group requests to avoid network overhead
    m_timer->setSingleShot(true);
    m_timer->setInterval(125);
    connect(m_timer, &QTimer::timeout, this, &SelectionModelServer::timeout);

    m_myAddress = Server::instance()->registerObject(objectName, this, Server::ExportNothing);
    Server::instance()->registerMessageHandler(m_myAddress, this, "newMessage");
    Server::instance()->registerMonitorNotifier(m_myAddress, this, "modelMonitored");
    connect(Endpoint::instance(), &Endpoint::disconnected, this, [this]{ modelMonitored(); });
}

SelectionModelServer::~SelectionModelServer() = default;

bool SelectionModelServer::isConnected() const
{
    return NetworkSelectionModel::isConnected() && m_monitored;
}

void SelectionModelServer::timeout()
{
    sendSelection();
}

void SelectionModelServer::modelMonitored(bool monitored)

void SelectionModelServer::connectModel()
{
    Q_ASSERT(model());

    auto startTimer = [this](){ m_timer->start(); };
    connect(model(), &QAbstractItemModel::modelReset, m_timer, startTimer);
    connect(model(), &QAbstractItemModel::rowsInserted, m_timer, startTimer);
    connect(model(), &QAbstractItemModel::rowsMoved, m_timer, startTimer);
    connect(model(), &QAbstractItemModel::columnsInserted, m_timer, startTimer);
    connect(model(), &QAbstractItemModel::columnsMoved, m_timer, startTimer);
    connect(model(), &QAbstractItemModel::layoutChanged, m_timer, startTimer);
}

void SelectionModelServer::disconnectModel()
{
    if (!model())
        return;

    disconnect(model(), &QAbstractItemModel::modelReset, m_timer, nullptr);
    disconnect(model(), &QAbstractItemModel::rowsInserted, m_timer, nullptr);
    disconnect(model(), &QAbstractItemModel::rowsMoved, m_timer, nullptr);
    disconnect(model(), &QAbstractItemModel::columnsInserted, m_timer, nullptr);
    disconnect(model(), &QAbstractItemModel::columnsMoved, m_timer, nullptr);
    disconnect(model(), &QAbstractItemModel::layoutChanged, m_timer, nullptr);
}


/*
  selectionmodelserver.cpp

  This file is part of GammaRay, the Qt application inspection and
  manipulation tool.

  Author: Volker Krause <example@nnthink.com>

  Licensees holding valid commercial KDAB GammaRay licenses may use this file in

  Contact info@kdab.com if any conditions of this licensing are not clear to you.

*/

#include "selectionmodelserver.h"
#include "server.h"

#include <QTimer>

using namespace GammaRay;

SelectionModelServer::SelectionModelServer(const QString &objectName, QAbstractItemModel *model,
                                           QObject *parent)
    : NetworkSelectionModel(objectName, model, parent)
    , m_timer(new QTimer(this))
    , m_monitored(false)
{
    // We do use a timer to group requests to avoid network overhead
    m_timer->setSingleShot(true);
    m_timer->setInterval(125);
    connect(m_timer, &QTimer::timeout, this, &SelectionModelServer::timeout);

    m_myAddress = Server::instance()->registerObject(objectName, this, Server::ExportNothing);
    Server:

    Server::instance()->registerMonitorNotifier(m_myAddress, this, "modelMonitored");
    connect(Endpoint::instance(), &Endpoint::disconnected, this, [this]{ modelMonitored(); });
}

SelectionModelServer::~SelectionModelServer() = default;

bool SelectionModelServer::isConnected() const
{
    return NetworkSelectionModel::isConnected() && m_monitored;
}

void SelectionModelServer::timeout()
{
    sendSelection();
}

void SelectionModelServer::modelMonitored(bool monitored)
{
    if (m_monitored == monitored)
        return;
    if (m_monitored)
        disconnectModel();
    m_monitored = monitored;
    if (m_monitored)
        connectModel();
}

void SelectionModelServer::connectModel()
{
    Q_ASSERT(model());

    auto startTimer = [this](){ m_timer->start(); };
    connect(model(), &QAbstractItemModel::modelReset, m_timer, startTimer);
    connect(model(), &QAbstractItemModel::rowsInserted, m_timer, startTimer);
    connect(model(), &QAbstractItemModel::rowsMoved, m_timer, startTimer);
    connect(model(), &QAbstractItemModel::columnsInserted, m_timer, startTimer);
    connect(model(), &QAbstractItemModel::columnsMoved, m_timer, startTimer);
    connect(model(), &QAbstractItemModel::layoutChanged, m_timer, startTimer);
}

void SelectionModelServer::disconnectModel()
{
    if (!model())
        return;

    disconnect(model(), &QAbstractItemModel::modelReset, m_timer, nullptr);
    disconnect(model(), &QAbstractItemModel::rowsInserted, m_timer, nullptr);
    disconnect(model(), &QAbstractItemModel::rowsMoved, m_timer, nullptr);
    disconnect(model(), &QAbstractItemModel::columnsInserted, m_timer, nullptr);
    disconnect(model(), &QAbstractItemModel::columnsMoved, m_timer, nullptr);
    disconnect(model(), &QAbstractItemModel::layoutChanged, m_timer, nullptr);
}


#include <iostream>
#include <iomanip>

#include "color/color.hpp"

{
  //!< Instead of std::uint8_t    you may put: std::uint16_t, std::uint32_t, std::uint64_t, float, double, long double
  typedef ::color::lab< std::uint8_t > color_t;
  color_t r, c;

  c = ::color::constant::orange_t{}; //!< Fill with some useful information

  std::cout<< "Orange in ::color::lab<std::uint8_t> = ";
  std::cout << c[0] << ", " << c[1] << ", " << c[2] << std::endl;

  ::color::operation::invert( c );
  std::cout<< ";  Inverted = ";
  std::cout << c[0] << ", " << c[1] << ", " << c[2] << std::endl;

  ::color::operation::invert( r, c );
  std::cout<< ";  Inverted = ";
  std::cout << c[0] << ", " << c[1] << ", " << c[2] << std::endl;

  return EXIT_SUCCESS;
 }


#include <iostream>
#include <iomanip>

#include "color/color.hpp"

int main( int argc, char *argv[] )
 {
  //!< Instead of std::uint8_t    you may put: std::uint16_t, std::uint32_t, std::uint64_t, float, double, long double
  typedef ::color::lab< std::uint8_t > color_t;
  color_

  c = ::color::constant::orange_t{}; //!< Fill with some useful information

  std::cout<< "Orange in ::color::lab<std::uint8_t> = ";
  std::cout << c[0] << ", " << c[1] << ", " << c[2] << std::endl;

  ::color::operation::invert( c );
  std::cout<< ";  Inverted = ";
  std::cout << c[0] << ", " << c[1] << ", " << c[2] << std::endl;

  ::color::operation::invert( r, c );
  std::cout<< ";  Inverted = ";
  std::cout << c[0] << ", " << c[1] << ", " << c[2] << std::endl;

  return EXIT_SUCCESS;
 }


SetPin::SetPin(ICNDocument *icnDocument, bool newItem, const char *id)
    : FlowPart(icnDocument, newItem, id ? id : "setpin")

/***************************************************************************
 *                                                                         *
 ***************************************************************************/

#include "setpin.h"

#include "flowcode.h"
#include "flowcodedocument.h"
#include "libraryitem.h"
#include "microsettings.h"
#include "picinfo.h"

#include <KLocalizedString>

Item *SetPin::construct(ItemDocument *itemDocument, bool newItem, const char *id)
{
    return new SetPin((ICNDocument *)itemDocument, newItem, id);
}

LibraryItem *SetPin::libraryItem()
{
    return new LibraryItem(QStringList(QString("flow/setpin")), i18n("Set Pin State"), i18n("I\\/O"), "pinwrite.png", LibraryItem::lit_flowpart, SetPin::construct);
}

{
    m_name = i18n("Set Pin State");
    initIOSymbol();
    createStdInput();
    createStdOutput();

    createProperty("state", Variant::Type::Select);
    property("state")->setCaption(i18n("State"));
    property("state")->setAllowed((QStringList("high") << "low"));
    property("state")->setValue("high");

    createProperty("pin", Variant::Type::Pin);
    property("pin")->setCaption(i18n("Pin"));
    property("pin")->setValue("RA0");
}

SetPin::~SetPin()
{
}

void SetPin::dataChanged()
{
    setCaption(i18n("Set %1 %2", dataString("pin"), dataString("state")));
}

void SetPin::generateMicrobe(FlowCode *code)
{
    const QString pin = dataString("pin");
    const QString port = "PORT" + QString((QChar)pin[1]);
    const QString bit = (QChar)pin[2];
    code->addCode(port + "." + bit + " = " + dataString("state"));
    code->addCodeBranch(outputPart("stdoutput"));

#if 0
	const QString pin = dataString("pin");
	const bool isHigh = (dataString("state") == "High");
	const QString port = "PORT" + QString((QChar)pin[1]);
	const QString bit = (QChar)pin[2];

	QString newCode;
	if (isHigh)
	{
		newCode += "bsf " + port + "," + bit + " ; Set bit high\n";
	}
	else
	{
		newCode += "bcf " + port + "," + bit + " ; Set bit low\n";
	}

	code->addCodeBlock( id(), newCode );
#endif
}


{
    setCaption(i18n("Set %1 %2", dataString("pin"), dataString("state")));
}

/***************************************************************************
 *                                                                         *
 ***************************************************************************/

#include "setpin.h"

#include "flowcode.h"
#include "flowcodedocument.h"
#include "libraryitem.h"
#include "microsettings.h"
#include "picinfo.h"

#include <KLocalizedString>

Item *SetPin::construct(ItemDocument *itemDocument, bool newItem, const char *id)
{
    return new SetPin((ICNDocument *)itemDocument, newItem, id);
}

LibraryItem *SetPin::libraryItem()
{
    return new LibraryItem(QStringList(QString("flow/setpin")), i18n("Set Pin State"), i18n("I\\/O"), "pinwrite.png", LibraryItem::lit_flowpart, SetPin::construct);
}

SetPin::SetPin(ICNDocument *icnDocument, bool newItem, const char *id)
    : FlowPart(icnDocument, newItem, id ? id : "setpin")
{
    m_name = i18n("Set Pin State");
    initIOSymbol();
    createStdInput();
    createStdOutput();

    createProperty("state", Variant::Type::Select);
    property("state")->setCaption(i18n("State"));
    property("state")->setAllowed((QStringList("high") << "low"));
    property("state")->setValue("high");

    createProperty("pin", Variant::Type::Pin);
    property("pin")->setCaption(i18n("Pin"));
    property("pin")->setValue("RA0");
}

SetPin::~SetPin()
{
}

void SetPin::dataChanged()

void SetPin::generateMicrobe(FlowCode *code)
{
    const QString pin = dataString("pin");
    const QString port = "PORT" + QString((QChar)pin[1]);
    const QString bit = (QChar)pin[2];
    code->addCode(port + "." + bit + " = " + dataString("state"));
    code->addCodeBranch(outputPart("stdoutput"));

#if 0
	const QString pin = dataString("pin");
	const bool isHigh = (dataString("state") == "High");
	const QString port = "PORT" + QString((QChar)pin[1]);
	const QString bit = (QChar)pin[2];

	QString newCode;
	if (isHigh)
	{
		newCode += "bsf " + port + "," + bit + " ; Set bit high\n";
	}
	else
	{
		newCode += "bcf " + port + "," + bit + " ; Set bit low\n";
	}

	code->addCodeBlock( id(), newCode );
#endif
}


/***************************************************************************
 *                                                                         *
 ***************************************************************************/

#include "setpin.h"

#include "flowcode.h"
#include "flowcodedocument.h"
#include "libraryitem.h"
#include "microsettings.h"
#include "picinfo.h"

#include <KLocalizedString>

Item *SetPin::construct(ItemDocument *itemDocument, bool newItem, const char *id)
{
    return new SetPin((ICNDocument *)itemDocument, newItem, id);
}

LibraryItem *SetPin::libraryItem()
{
    return new LibraryItem(QStringList(QString("flow/setpin")), i18n("Set Pin State"), i18n("I\\/O"), "pinwrite.png", LibraryItem::lit_flowpart, SetPin::construct);
}

SetPin::SetPin(ICNDocument *icnDocument, bool newItem, const char *id)
    : FlowPart(icnDocument, newItem, id ? id : "setpin")
{
    m_name = i18n("Set Pin State");
    initIOSymbol();
    createStdInput();
    createStdOutput();

    createProperty("state", Variant::Type::Select);
    property("state")->setCaption(i18n("State"));
    property("state")->setAllowed((QStringList("high") << "low"));
    property("state")->setValue("high");

    createProperty("pin", Variant::Type::Pin);
    property("pin")->setCaption(i18n("Pin"));
    property("pin")->setValue("RA0");
}

SetPin::~SetPin()
{
}

void SetPin::dataChanged()
{
    setCaption(i18n("Set %1 %2", dataString("pin"), dataString("state")));
}

void SetPin::generateMicrobe(FlowCode *code)
{
    const QString pin = dataString("pin");
    const QString port = "PORT" + QString((QChar)pin[1]);
    const QString bit = (QChar)pin[2];
    code->addCode(port + "." + bit + " = " + dataString("state")

    code->addCodeBranch(outputPart("stdoutput"));

#if 0
	const QString pin = dataString("pin");
	const bool isHigh = (dataString("state") == "High");
	const QString port = "PORT" + QString((QChar)pin[1]);
	const QString bit = (QChar)pin[2];

	QString newCode;
	if (isHigh)
	{
		newCode += "bsf " + port + "," + bit + " ; Set bit high\n";
	}
	else
	{
		newCode += "bcf " + port + "," + bit + " ; Set bit low\n";
	}

	code->addCodeBlock( id(), newCode );
#endif
}


/**********************************************************************
// @@@ START COPYRIGHT @@@
// @@@ END COPYRIGHT @@@
**********************************************************************/
/* -*-C++-*-
****************************************************************************
*
* File:         ComKeySingleSubset.cpp
* Description:
*
* Created:      5/6/98
* Language:     C++
*
*
*
*
****************************************************************************
*/

#include "exp_expr.h"
#include "ComPackDefs.h"
#include "ComKeyRange.h"
#include "ComKeySingleSubset.h"

keySingleSubsetGen::keySingleSubsetGen(ULng32 keyLen,
				       ex_cri_desc * workCriDesc,
				       unsigned short keyValuesAtpIndex,
				       unsigned short excludeFlagAtpIndex,
				       unsigned short dataConvErrorFlagIndex,
				       ex_expr * bk_pred,
				       ex_expr * ek_pred,
				       ex_expr * bkey_excluded_expr,
				       ex_expr * ekey_excluded_expr,
				       short bkey_excluded,
				       short ekey_excluded) :
     keyRangeGen(KEYSINGLESUBSET,
	    keyLen,
	    workCriDesc,
	    keyValuesAtpIndex,
	    excludeFlagAtpIndex,
	    dataConvErrorFlagIndex),
     bkPred_(bk_pred),ekPred_(ek_pred),
     lowKeyExcludedExpr_(bkey_excluded_expr),
     highKeyExcludedExpr_(ekey_excluded_expr),
     lowKeyExcluded_(bkey_excluded),
     highKeyExcluded_(ekey_excluded)
{ };

keySingleSubsetGen::~keySingleSubsetGen()
{ };

Long keySingleSubsetGen::pack(void *space)
{
  bkPred_.pack(space);
  ekPred_.pack(space);
  lowKeyExcludedExpr_.pack(space);
  highKeyExcludedExpr_.pack(space);
  return keyRangeGen::pack(space);
};

Lng32 keySingleSubsetGen::unpack(void * base, void * reallocator)
{
  if(bkPred_.unpack(base, reallocator)) return -1;
  if(ekPred_.unpack(base, reallocator)) return -1;
  if(lowKeyExcludedExpr_.unpack(base, reallocator)) return -1;
  if(highKeyExcludedExpr_.unpack(base, reallocator)) return -1;
  return keyRangeGen::unpack(base, reallocator);
};

{
if (pos == 0)
  return bkPred_;
else if (pos == 1)
  return ekPred_;
else
  return NULL;
}


{
if (pos == 0)
  return bkPred_;
else if (pos == 1)
  return ekPred_;
else
  return NULL;
}

/**********************************************************************
// @@@ START COPYRIGHT @@@
// @@@ END COPYRIGHT @@@
**********************************************************************/
/* -*-C++-*-
****************************************************************************
*
* File:         ComKeySingleSubset.cpp
* Description:
*
* Created:      5/6/98
* Language:     C++
*
*
*
*
****************************************************************************
*/

#include "exp_expr.h"
#include "ComPackDefs.h"
#include "ComKeyRange.h"
#include "ComKeySingleSubset.h"

keySingleSubsetGen::keySingleSubsetGen(ULng32 keyLen,
				       ex_cri_desc * workCriDesc,
				       unsigned short keyValuesAtpIndex,
				       unsigned short excludeFlagAtpIndex,
				       unsigned short dataConvErrorFlagIndex,
				       ex_expr * bk_pred,
				       ex_expr * ek_pred,
				       ex_expr * bkey_excluded_expr,
				       ex_expr * ekey_excluded_expr,
				       short bkey_excluded,
				       short ekey_excluded) :
     keyRangeGen(KEYSINGLESUBSET,
	    keyLen,
	    workCriDesc,
	    keyValuesAtpIndex,
	    excludeFlagAtpIndex,
	    dataConvErrorFlagIndex),
     bkPred_(bk_pred),ekPred_(ek_pred),
     lowKeyExcludedExpr_(bkey_excluded_expr),
     highKeyExcludedExpr_(ekey_excluded_expr),
     lowKeyExcluded_(bkey_excluded),
     highKeyExcluded_(ekey_excluded)
{ };

keySingleSubsetGen::~keySingleSubsetGen()
{ };

Long keySingleSubsetGen::pack(void *space)
{
  bkPred_.pack(space);
  ekPred_.pack(space);
  lowKeyExcludedExpr_.pack(space);
  highKeyExcludedExpr_.pack(space);
  return keyRangeGen::pack(space);
};

Lng32 keySingleSubsetGen::unpack(void * base, void * reallocator)
{
  if(bkPred_.unpack(base, reallocator)) return -1;
  if(ekPred_.unpack(base, reallocator)) return -1;
  if(lowKeyExcludedExpr_.unpack(base, reallocator)) return -1;
  if(highKeyExcludedExpr_.unpack(base, reallocator)) return -1;
  return keyRangeGen::unpack(base, reallocator);
};

ex_expr* keySingleSubsetGen::getExpressionNode(Int32 pos)


/**********************************************************************
// @@@ START COPYRIGHT @@@
// @@@ END COPYRIGHT @@@
**********************************************************************/
/* -*-C++-*-
****************************************************************************
*
* File:         ComKeySingleSubset.cpp
* Description:
*
* Created:      5/6/98
* Language:     C++
*
*
*
*
****************************************************************************
*/

#include "exp_expr.h"
#include "ComPackDefs.h"
#include "ComKeyRange.h"
#include "ComKeySingleSubset.h"

keySingleSubsetGen::keySingleSubsetGen(ULng32 keyLen,
				       ex_cri_desc * workCriDesc,
				       unsigned short keyValuesAtpIndex,
				       unsigned short excludeFlagAtpIndex,
				       unsigned short dataConvErrorFlagIndex,
				       ex_expr * bk_pred,
				       ex_expr * ek_pred,
				       ex_expr * bkey_excluded_expr,
				       ex_expr * ekey_excluded_expr,
				       short bkey_excluded,
				       short ekey_excluded) :
     keyRangeGen(KEYSINGLESUBSET,
	    keyLen,
	    workCriDesc,
	    keyValuesAtpIndex,
	    excludeFlagAtpIndex,
	    dataConvErrorFlagIndex),
     bkPred_(bk_pred),ekPred_(ek_pred),
     lowKeyExcludedExpr_(bkey_excluded_expr),
     highKeyExcludedExpr_(ekey_excluded_expr),
     lowKeyExcluded_(bkey_excluded),
     highKeyExcluded_(ekey_excluded)
{ };

keySingleSubsetGen::~keySingleSubsetGen()
{ };

Long keySingleSubsetGen::pack(void *space)
{
  bkPred_.pack(space);
  ekPred_.pack(space);
  lowKeyExcludedExpr_.pack(space);
  highKeyExcludedExpr_.pack(space);
  return keyRangeGen::pack(space);
};

Lng32 keySingleSubsetGen::unpack(void * base, void * reallocator)
{
  if(bkPred_.unpack(base, reallocator)) return -1;
  if(ekPred_.unpack(base, reallocator)) return -1;
  if(lowKeyExcludedExpr_.unpack(base, reallocator)) return -1;
  if(highKeyExcludedExpr_.unpack(base, reallocator)) return -1;
  return keyRangeG

};

ex_expr* keySingleSubsetGen::getExpressionNode(Int32 pos)
{
if (pos == 0)
  return bkPred_;
else if (pos == 1)
  return ekPred_;
else
  return NULL;
}


/*
 *
 * This file is part of lsp-plugins
 * Created on: 26 окт. 2015 г.
 *
 */

#include <core/plugin.h>
#include <core/debug.h>

namespace lsp
{
    plugin_t::plugin_t(const plugin_metadata_t &mdata)
    {
        pMetadata       = &mdata;
        pWrapper        = NULL;
        fSampleRate     = -1;
        nLatency        = 0;
        bActivated      = false;
        bUIActive       = true;
    }

    plugin_t::~plugin_t()
    {
    }

    void plugin_t::init(IWrapper *wrapper)
    {
        pWrapper        = wrapper;
    }

    void plugin_t::set_sample_rate(ssize_t sr)
    {
        if (fSampleRate != sr)
        {
            fSampleRate = sr;
            update_sample_rate(sr);
        }
    };

    void plugin_t::update_sample_rate(long sr)
    {
    }

    void plugin_t::activated()
    {
    }

{
    }

    void plugin_t::ui_activated()
    {
    }

    void plugin_t::ui_deactivated()
    {
    }

    void plugin_t::destroy()
    {
        vPorts.clear();
        bActivated      = false;
    }

    void plugin_t::update_settings()
    {
    }

    bool plugin_t::set_position(const position_t *pos)
    {
        return false;
    }

    void plugin_t::process(size_t samples)
    {
    }

    bool plugin_t::inline_display(ICanvas *cv, size_t width, size_t height)
    {
        return false;
    }

    KVTStorage *plugin_t::kvt_lock()
    {
        return (pWrapper != NULL) ? pWrapper->kvt_lock() : NULL;
    }

    KVTStorage *plugin_t::kvt_trylock()
    {
        return (pWrapper != NULL) ? pWrapper->kvt_trylock() : NULL;
    }

    void plugin_t::kvt_release()
    {
        if (pWrapper != NULL)
            pWrapper->kvt_release();
    }

    void plugin_t::state_saved()
    {
    }

    void plugin_t::state_loaded()
    {
    }

    void plugin_t::dump(IStateDumper *v) const
    {
        v->write("fSampleRate", fSampleRate);
        v->write("nLatency", nLatency);
        v->write("bActivated", bActivated);
        v->write("bUIActive", bUIActive);
    }
}


{
        pMetadata       = &mdata;
        pWrapper        = NULL;
        fSampleRate     = -1;
        nLatency        = 0;
        bActivated      = false;
        bUIActive       = true;
    }

/*
 *
 * This file is part of lsp-plugins
 * Created on: 26 окт. 2015 г.
 *
 */

#include <core/plugin.h>
#include <core/debug.h>

namespace lsp
{
    plugin_t::plugin_t(const plugin_metadata_t &mdata)

    plugin_t::~plugin_t()
    {
    }

    void plugin_t::init(IWrapper *wrapper)
    {
        pWrapper        = wrapper;
    }

    void plugin_t::set_sample_rate(ssize_t sr)
    {
        if (fSampleRate != sr)
        {
            fSampleRate = sr;
            update_sample_rate(sr);
        }
    };

    void plugin_t::update_sample_rate(long sr)
    {
    }

    void plugin_t::activated()
    {
    }

    void plugin_t::deactivated()
    {
    }

    void plugin_t::ui_activated()
    {
    }

    void plugin_t::ui_deactivated()
    {
    }

    void plugin_t::destroy()
    {
        vPorts.clear();
        bActivated      = false;
    }

    void plugin_t::update_settings()
    {
    }

    bool plugin_t::set_position(const position_t *pos)
    {
        return false;
    }

    void plugin_t::process(size_t samples)
    {
    }

    bool plugin_t::inline_display(ICanvas *cv, size_t width, size_t height)
    {
        return false;
    }

    KVTStorage *plugin_t::kvt_lock()
    {
        return (pWrapper != NULL) ? pWrapper->kvt_lock() : NULL;
    }

    KVTStorage *plugin_t::kvt_trylock()
    {
        return (pWrapper != NULL) ? pWrapper->kvt_trylock() : NULL;
    }

    void plugin_t::kvt_release()
    {
        if (pWrapper != NULL)
            pWrapper->kvt_release();
    }

    void plugin_t::state_saved()
    {
    }

    void plugin_t::state_loaded()
    {
    }

    void plugin_t::dump(IStateDumper *v) const
    {
        v->write("fSampleRate", fSampleRate);
        v->write("nLatency", nLatency);
        v->write("bActivated", bActivated);
        v->write("bUIActive", bUIActive);
    }
}


rapper != NULL) ? pWrapper->kvt_lock() : NULL;

/*
 *
 * This file is part of lsp-plugins
 * Created on: 26 окт. 2015 г.
 *
 */

#include <core/plugin.h>
#include <core/debug.h>

namespace lsp
{
    plugin_t::plugin_t(const plugin_metadata_t &mdata)
    {
        pMetadata       = &mdata;
        pWrapper        = NULL;
        fSampleRate     = -1;
        nLatency        = 0;
        bActivated      = false;
        bUIActive       = true;
    }

    plugin_t::~plugin_t()
    {
    }

    void plugin_t::init(IWrapper *wrapper)
    {
        pWrapper        = wrapper;
    }

    void plugin_t::set_sample_rate(ssize_t sr)
    {
        if (fSampleRate != sr)
        {
            fSampleRate = sr;
            update_sample_rate(sr);
        }
    };

    void plugin_t::update_sample_rate(long sr)
    {
    }

    void plugin_t::activated()
    {
    }

    void plugin_t::deactivated()
    {
    }

    void plugin_t::ui_activated()
    {
    }

    void plugin_t::ui_deactivated()
    {
    }

    void plugin_t::destroy()
    {
        vPorts.clear();
        bActivated      = false;
    }

    void plugin_t::update_settings()
    {
    }

    bool plugin_t::set_position(const position_t *pos)
    {
        return false;
    }

    void plugin_t::process(size_t samples)
    {
    }

    bool plugin_t::inline_display(ICanvas *cv, size_t width, size_t height)
    {
        return false;
    }

    KVTStorage *plugin_t::kvt_lock()
    {
        return (pW

    }

    KVTStorage *plugin_t::kvt_trylock()
    {
        return (pWrapper != NULL) ? pWrapper->kvt_trylock() : NULL;
    }

    void plugin_t::kvt_release()
    {
        if (pWrapper != NULL)
            pWrapper->kvt_release();
    }

    void plugin_t::state_saved()
    {
    }

    void plugin_t::state_loaded()
    {
    }

    void plugin_t::dump(IStateDumper *v) const
    {
        v->write("fSampleRate", fSampleRate);
        v->write("nLatency", nLatency);
        v->write("bActivated", bActivated);
        v->write("bUIActive", bUIActive);
    }
}


void    NascentAnimationSet::MergeAnimation(
        const NascentAnimationSet& animation, const char name[],
        const std::vector<Assets::RawAnimationCurve>& sourceCurves,
        std::vector<Assets::RawAnimationCurve>& destinationCurves)

#include "NascentCommandStream.h"
#include "../RenderCore/Assets/RawAnimationCurve.h"
#include "../Assets/BlockSerializer.h"
#include "../ConsoleRig/OutputStream.h"
#include "../ConsoleRig/Log.h"
#include "../Utility/MemoryUtils.h"
#include "../Utility/StringUtils.h"
#include "../Utility/IteratorUtils.h"

namespace RenderCore { namespace ColladaConversion
{
    using ::Assets::Exceptions::FormatError;

    class NascentAnimationSet::Animation
    {
    public:
        std::string     _name;
        unsigned        _begin, _end;
        unsigned        _constantBegin, _constantEnd;
        float           _startTime, _endTime;
        Animation() : _begin(0), _end(0), _constantBegin(0), _constantEnd(0), _startTime(0.f), _endTime(0.f) {}
        Animation(const std::string& name, unsigned begin, unsigned end, unsigned constantBegin, unsigned constantEnd, float startTime, float endTime)
            : _name(name), _begin(begin), _end(end), _constantBegin(constantBegin), _constantEnd(constantEnd), _startTime(startTime), _endTime(endTime) {}
    };

    AnimSamplerType      SamplerWidthToType(unsigned samplerWidth)
    {
        Assets::TransformationParameterSet::Type::Enum samplerType = Assets::TransformationParameterSet::Type::Float1;
        switch (samplerWidth) {
        case  1:    samplerType = Assets::TransformationParameterSet::Type::Float1;     break;
        case  3:    samplerType = Assets::TransformationParameterSet::Type::Float3;     break;
        case  4:    samplerType = Assets::TransformationParameterSet::Type::Float4;     break;
        case 16:    samplerType = Assets::TransformationParameterSet::Type::Float4x4;   break;
        default:
            Throw(
                FormatError(
                    "Strange sampler width encountered when adding animation driver!"));
        }

        return samplerType;
    }

    size_t      SamplerSize(AnimSamplerType samplerType)
    {
        switch (samplerType) {
        case Assets::TransformationParameterSet::Type::Float1:      return sizeof(float);
        case Assets::TransformationParameterSet::Type::Float3:      return sizeof(Float3);
        case Assets::TransformationParameterSet::Type::Float4:      return sizeof(Float4);
        case Assets::TransformationParameterSet::Type::Float4x4:    return sizeof(Float4x4);
        }
        return 0;
    }

    void    NascentAnimationSet::AddConstantDriver(
                                    const std::string&  parameterName,
                                    const void*         constantValue,
                                    AnimSamplerType     samplerType,
                                    unsigned            samplerOffset)
    {
        size_t parameterIndex = _parameterInterfaceDefinition.size();
        auto i = std::find( _parameterInterfaceDefinition.cbegin(),
                            _parameterInterfaceDefinition.cend(), parameterName);
        if (i!=_parameterInterfaceDefinition.end()) {
            parameterIndex = (unsigned)std::distance(_parameterInterfaceDefinition.cbegin(), i);
        } else {
            _parameterInterfaceDefinition.push_back(parameterName);
        }

        unsigned dataOffset = unsigned(_constantData.size());
        std::copy(
            (uint8*)constantValue, PtrAdd((uint8*)constantValue, SamplerSize(samplerType)),
            std::back_inserter(_constantData));

        _constantDrivers.push_back(
            ConstantDriver(dataOffset, (unsigned)parameterIndex, samplerType, samplerOffset));
    }

    void    NascentAnimationSet::AddAnimationDriver(
        const std::string& parameterName,
        unsigned curveId,
        AnimSamplerType samplerType, unsigned samplerOffset)
    {
        size_t parameterIndex = _parameterInterfaceDefinition.size();
        auto i = std::find( _parameterInterfaceDefinition.cbegin(),
                            _parameterInterfaceDefinition.cend(), parameterName);
        if (i!=_parameterInterfaceDefinition.end()) {
            parameterIndex = (unsigned)std::distance(_parameterInterfaceDefinition.cbegin(), i);
        } else {
            _parameterInterfaceDefinition.push_back(parameterName);
        }

        _animationDrivers.push_back(
            AnimationDriver(curveId, (unsigned)parameterIndex, samplerType, samplerOffset));
    }

    bool    NascentAnimationSet::HasAnimationDriver(const std::string&  parameterName) const
    {
        auto i = std::find( _parameterInterfaceDefinition.cbegin(),
                            _parameterInterfaceDefinition.cend(), parameterName);
        if (i==_parameterInterfaceDefinition.end())
            return false;

        auto parameterIndex = (unsigned)std::distance(_parameterInterfaceDefinition.cbegin(), i);

        for (auto i=_animationDrivers.begin(); i!=_animationDrivers.end(); ++i) {
            if (i->_parameterIndex == parameterIndex)
                return true;
        }

        for (auto i=_constantDrivers.begin(); i!=_constantDrivers.end(); ++i) {
            if (i->_parameterIndex == parameterIndex)
                return true;
        }
        return false;
    }

{
            //      Merge the animation drivers in the given input animation, and give
            //      them the supplied name
        float minTime = FLT_MAX, maxTime = -FLT_MAX;
        size_t startIndex = _animationDrivers.size();
        size_t constantStartIndex = _constantDrivers.size();
        for (auto i=animation._animationDrivers.cbegin(); i!=animation._animationDrivers.end(); ++i) {
            if (i->_curveIndex >= sourceCurves.size()) continue;
            const auto* animCurve = &sourceCurves[i->_curveIndex];
            if (animCurve) {
                float curveStart = animCurve->StartTime();
                float curveEnd = animCurve->EndTime();
                minTime = std::min(minTime, curveStart);
                maxTime = std::max(maxTime, curveEnd);

                const std::string& name = animation._parameterInterfaceDefinition[i->_parameterIndex];
                destinationCurves.push_back(Assets::RawAnimationCurve(*animCurve));
                AddAnimationDriver(
                    name, unsigned(destinationCurves.size()-1),
                    i->_samplerType, i->_samplerOffset);
            }
        }

        for (auto i=animation._constantDrivers.cbegin(); i!=animation._constantDrivers.end(); ++i) {
            const std::string& name = animation._parameterInterfaceDefinition[i->_parameterIndex];
            AddConstantDriver(name, PtrAdd(AsPointer(animation._constantData.begin()), i->_dataOffset), i->_samplerType, i->_samplerOffset);
        }

        _animations.push_back(Animation(name,
            (unsigned)startIndex, (unsigned)_animationDrivers.size(),
            (unsigned)constantStartIndex, (unsigned)_constantDrivers.size(),
            minTime, maxTime));
    }

    void NascentAnimationSet::AnimationDriver::Serialize(Serialization::NascentBlockSerializer& serializer) const
    {
        ::Serialize(serializer, unsigned(_curveIndex));
        ::Serialize(serializer, _parameterIndex);
        ::Serialize(serializer, _samplerOffset);
        ::Serialize(serializer, unsigned(_samplerType));
    }

    void NascentAnimationSet::ConstantDriver::Serialize(Serialization::NascentBlockSerializer& serializer) const
    {
        ::Serialize(serializer, _dataOffset);
        ::Serialize(serializer, _parameterIndex);
        ::Serialize(serializer, _samplerOffset);
        ::Serialize(serializer, unsigned(_samplerType));
    }

    struct AnimationDesc        // matches AnimationSet::Animation
    {
        uint64      _name;
        unsigned    _beginDriver, _endDriver;
        unsigned    _beginConstantDriver, _endConstantDriver;
        float       _beginTime, _endTime;

        AnimationDesc() {}
        void Serialize(Serialization::NascentBlockSerializer& serializer) const
        {
            ::Serialize(serializer, _name);
            ::Serialize(serializer, _beginDriver);
            ::Serialize(serializer, _endDriver);
            ::Serialize(serializer, _beginConstantDriver);
            ::Serialize(serializer, _endConstantDriver);
            ::Serialize(serializer, _beginTime);
            ::Serialize(serializer, _endTime);
        }
    };

    struct CompareAnimationName
    {
        bool operator()(const AnimationDesc& lhs, const AnimationDesc& rhs) const   { return lhs._name < rhs._name; }
        bool operator()(const AnimationDesc& lhs, uint64 rhs) const                 { return lhs._name < rhs; }
        bool operator()(uint64 lhs, const AnimationDesc& rhs) const                 { return lhs < rhs._name; }
    };

    void NascentAnimationSet::Serialize(Serialization::NascentBlockSerializer& serializer) const
    {
        serializer.SerializeSubBlock(AsPointer(_animationDrivers.begin()), AsPointer(_animationDrivers.end()));
        serializer.SerializeValue(_animationDrivers.size());
        serializer.SerializeSubBlock(AsPointer(_constantDrivers.begin()), AsPointer(_constantDrivers.end()));
        serializer.SerializeValue(_constantDrivers.size());
        serializer.SerializeSubBlock(AsPointer(_constantData.begin()), AsPointer(_constantData.end()));

            //      List of animations...

        auto outputAnimations = std::make_unique<AnimationDesc[]>(_animations.size());
        for (size_t c=0; c<_animations.size(); ++c) {
            AnimationDesc&o = outputAnimations[c];
            const Animation&i = _animations[c];
            o._name = Hash64(AsPointer(i._name.begin()), AsPointer(i._name.end()));
            o._beginDriver = i._begin; o._endDriver = i._end;
            o._beginConstantDriver = i._constantBegin; o._endConstantDriver = i._constantEnd;
            o._beginTime = i._startTime; o._endTime = i._endTime;
        }
        std::sort(outputAnimations.get(), &outputAnimations[_animations.size()], CompareAnimationName());
        serializer.SerializeSubBlock(outputAnimations.get(), &outputAnimations[_animations.size()]);
        serializer.SerializeValue(_animations.size());

        ConsoleRig::DebuggerOnlyWarning("Animation set output interface:\n");
        auto parameterNameHashes = std::make_unique<uint64[]>(_parameterInterfaceDefinition.size());
        for (size_t c=0; c<_parameterInterfaceDefinition.size(); ++c) {
            ConsoleRig::DebuggerOnlyWarning("  [%i] %s\n", c, _parameterInterfaceDefinition[c].c_str());
            parameterNameHashes[c] = Hash64(AsPointer(_parameterInterfaceDefinition[c].begin()), AsPointer(_parameterInterfaceDefinition[c].end()));
        }
        serializer.SerializeSubBlock(parameterNameHashes.get(), &parameterNameHashes[_parameterInterfaceDefinition.size()]);
        serializer.SerializeValue(_parameterInterfaceDefinition.size());
    }

    NascentAnimationSet::NascentAnimationSet() {}
    NascentAnimationSet::~NascentAnimationSet() {}
    NascentAnimationSet::NascentAnimationSet(NascentAnimationSet&& moveFrom)
    :   _animationDrivers(std::move(moveFrom._animationDrivers))
    ,   _constantDrivers(std::move(moveFrom._constantDrivers))
    ,   _animations(std::move(moveFrom._animations))
    ,   _parameterInterfaceDefinition(std::move(moveFrom._parameterInterfaceDefinition))
    ,   _constantData(std::move(moveFrom._constantData))
    {}
    NascentAnimationSet& NascentAnimationSet::operator=(NascentAnimationSet&& moveFrom)
    {
        _animationDrivers = std::move(moveFrom._animationDrivers);
        _constantDrivers = std::move(moveFrom._constantDrivers);
        _animations = std::move(moveFrom._animations);
        _parameterInterfaceDefinition = std::move(moveFrom._parameterInterfaceDefinition);
        _constantData = std::move(moveFrom._constantData);
        return *this;
    }

    void NascentSkeleton::Serialize(Serialization::NascentBlockSerializer& serializer) const
    {
        ::Serialize(serializer, _transformationMachine);
    }

    NascentSkeleton::NascentSkeleton() {}
    NascentSkeleton::~NascentSkeleton() {}
    NascentSkeleton::NascentSkeleton(NascentSkeleton&& moveFrom)
    :   _transformationMachine(std::move(moveFrom._transformationMachine))
    {}
    NascentSkeleton& NascentSkeleton::operator=(NascentSkeleton&& moveFrom)
    {
        _transformationMachine = std::move(moveFrom._transformationMachine);
        return *this;
    }

    class NascentModelCommandStream::TransformationMachineOutput
    {
    public:
        ObjectGuid _colladaId;
        std::string _name;
    };

    void NascentModelCommandStream::RegisterTransformationMachineOutput(const std::string& bindingName, ObjectGuid id, unsigned transformMarker)
    {
        if (_transformationMachineOutputs.size() < transformMarker+1)
            _transformationMachineOutputs.resize(transformMarker+1);
        _transformationMachineOutputs[transformMarker] = TransformationMachineOutput{id, bindingName};
    }

    unsigned    NascentModelCommandStream::FindTransformationMachineOutput(ObjectGuid nodeId) const
    {
        auto i2=_transformationMachineOutputs.cbegin();
        for (;i2!=_transformationMachineOutputs.cend(); ++i2) {
            if (i2->_colladaId == nodeId) {
                return (unsigned)std::distance(_transformationMachineOutputs.cbegin(), i2);
            }
        }
        return ~unsigned(0x0);
    }

    void NascentModelCommandStream::Add(GeometryInstance&& geoInstance)
    {
        _geometryInstances.emplace_back(std::move(geoInstance));
    }

    void NascentModelCommandStream::Add(CameraInstance&& camInstance)
    {
        _cameraInstances.emplace_back(std::move(camInstance));
    }

    void NascentModelCommandStream::Add(SkinControllerInstance&& skinControllerInstance)
    {
        _skinControllerInstances.emplace_back(std::move(skinControllerInstance));
    }

    NascentModelCommandStream::NascentModelCommandStream()
    {
    }

    NascentModelCommandStream::~NascentModelCommandStream()
    {

    }

    NascentModelCommandStream::NascentModelCommandStream(NascentModelCommandStream&& moveFrom)
    :       _transformationMachineOutputs(std::move(moveFrom._transformationMachineOutputs))
    ,       _geometryInstances(std::move(moveFrom._geometryInstances))
    ,       _cameraInstances(std::move(moveFrom._cameraInstances))
    ,       _skinControllerInstances(std::move(moveFrom._skinControllerInstances))
    {
    }

    NascentModelCommandStream& NascentModelCommandStream::operator=(NascentModelCommandStream&& moveFrom) never_throws
    {
        _transformationMachineOutputs = std::move(moveFrom._transformationMachineOutputs);
        _geometryInstances = std::move(moveFrom._geometryInstances);
        _cameraInstances = std::move(moveFrom._cameraInstances);
        _skinControllerInstances = std::move(moveFrom._skinControllerInstances);
        return *this;
    }

    void NascentModelCommandStream::GeometryInstance::Serialize(Serialization::NascentBlockSerializer& serializer) const
    {
        ::Serialize(serializer, _id);
        ::Serialize(serializer, _localToWorldId);
        serializer.SerializeSubBlock(AsPointer(_materials.begin()), AsPointer(_materials.end()));
        ::Serialize(serializer, _materials.size());
        ::Serialize(serializer, _levelOfDetail);
    }

    void NascentModelCommandStream::SkinControllerInstance::Serialize(Serialization::NascentBlockSerializer& serializer) const
    {
        ::Serialize(serializer, _id);
        ::Serialize(serializer, _localToWorldId);
        serializer.SerializeSubBlock(AsPointer(_materials.begin()), AsPointer(_materials.end()));
        ::Serialize(serializer, _materials.size());
        ::Serialize(serializer, _levelOfDetail);
    }

    void NascentModelCommandStream::Serialize(Serialization::NascentBlockSerializer& serializer) const
    {
        serializer.SerializeSubBlock(AsPointer(_geometryInstances.begin()), AsPointer(_geometryInstances.end()));
        serializer.SerializeValue(_geometryInstances.size());
        serializer.SerializeSubBlock(AsPointer(_skinControllerInstances.begin()), AsPointer(_skinControllerInstances.end()));
        serializer.SerializeValue(_skinControllerInstances.size());

            //      Turn our list of input matrices into hash values, and write out the
        ConsoleRig::DebuggerOnlyWarning("Command stream input interface:\n");
        auto inputInterface = GetInputInterface();
        serializer.SerializeSubBlock(AsPointer(inputInterface.cbegin()), AsPointer(inputInterface.cend()));
        serializer.SerializeValue(_transformationMachineOutputs.size());
    }

    std::vector<uint64> NascentModelCommandStream::GetInputInterface() const
    {
        std::vector<uint64> inputInterface(_transformationMachineOutputs.size());
        unsigned c=0;
        for (auto i=_transformationMachineOutputs.begin(); i!=_transformationMachineOutputs.end(); ++i, ++c)
            inputInterface[c] = Hash64(AsPointer(i->_name.begin()), AsPointer(i->_name.end()));
        return std::move(inputInterface);
    }

    unsigned NascentModelCommandStream::GetMaxLOD() const
    {
        unsigned maxLOD = 0u;
        for (const auto&i:_geometryInstances) maxLOD = std::max(i._levelOfDetail, maxLOD);
        for (const auto&i:_skinControllerInstances) maxLOD = std::max(i._levelOfDetail, maxLOD);
        return maxLOD;
    }

    std::ostream& operator<<(std::ostream& stream, const NascentModelCommandStream& cmdStream)
    {
        stream << " --- Geometry instances:" << std::endl;
        unsigned c=0;
        for (const auto& i:cmdStream._geometryInstances) {
            stream << "  [" << c++ << "] GeoId: " << i._id << " Transform: " << i._localToWorldId << " LOD: " << i._levelOfDetail << std::endl;
            stream << "     Materials: " << std::hex;
            for (size_t q=0; q<i._materials.size(); ++q) {
                if (q != 0) stream << ", ";
                stream << i._materials[q];
            }
            stream << std::dec << std::endl;
        }

        stream << " --- Skin controller instances:" << std::endl;
        c=0;
        for (const auto& i:cmdStream._skinControllerInstances) {
            stream << "  [" << c++ << "] GeoId: " << i._id << " Transform: " << i._localToWorldId << std::endl;
            stream << "     Materials: " << std::hex;
            for (size_t q=0; q<i._materials.size(); ++q) {
                if (q != 0) stream << ", ";
                stream << i._materials[q];
            }
            stream << std::dec << std::endl;
        }

        stream << " --- Camera instances:" << std::endl;
        c=0;
        for (const auto& i:cmdStream._cameraInstances)
            stream << "  [" << c++ << "] Transform: " << i._localToWorldId << std::endl;

        stream << " --- Input interface:" << std::endl;
        c=0;
        for (const auto& i:cmdStream._transformationMachineOutputs)
            stream << "  [" << c++ << "] " << i._name << std::endl;
        return stream;
    }

}}


#include "NascentCommandStream.h"
#include "../RenderCore/Assets/RawAnimationCurve.h"
#include "../Assets/BlockSerializer.h"
#include "../ConsoleRig/OutputStream.h"
#include "../ConsoleRig/Log.h"
#include "../Utility/MemoryUtils.h"
#include "../Utility/StringUtils.h"
#include "../Utility/IteratorUtils.h"

namespace RenderCore { namespace ColladaConversion
{
    using ::Assets::Exceptions::FormatError;

    class NascentAnimationSet::Animation
    {
    public:
        std::string     _name;
        unsigned        _begin, _end;
        unsigned        _constantBegin, _constantEnd;
        float           _startTime, _endTime;
        Animation() : _begin(0), _end(0), _constantBegin(0), _constantEnd(0), _startTime(0.f), _endTime(0.f) {}
        Animation(const std::string& name, unsigned begin, unsigned end, unsigned constantBegin, unsigned constantEnd, float startTime, float endTime)
            : _name(name), _begin(begin), _end(end), _constantBegin(constantBegin), _constantEnd(constantEnd), _startTime(startTime), _endTime(endTime) {}
    };

    AnimSamplerType      SamplerWidthToType(unsigned samplerWidth)
    {
        Assets::TransformationParameterSet::Type::Enum samplerType = Assets::TransformationParameterSet::Type::Float1;
        switch (samplerWidth) {
        case  1:    samplerType = Assets::TransformationParameterSet::Type::Float1;     break;
        case  3:    samplerType = Assets::TransformationParameterSet::Type::Float3;     break;
        case  4:    samplerType = Assets::TransformationParameterSet::Type::Float4;     break;
        case 16:    samplerType = Assets::TransformationParameterSet::Type::Float4x4;   break;
        default:
            Throw(
                FormatError(
                    "Strange sampler width encountered when adding animation driver!"));
        }

        return samplerType;
    }

    size_t      SamplerSize(AnimSamplerType samplerType)
    {
        switch (samplerType) {
        case Assets::TransformationParameterSet::Type::Float1:      return sizeof(float);
        case Assets::TransformationParameterSet::Type::Float3:      return sizeof(Float3);
        case Assets::TransformationParameterSet::Type::Float4:      return sizeof(Float4);
        case Assets::TransformationParameterSet::Type::Float4x4:    return sizeof(Float4x4);
        }
        return 0;
    }

    void    NascentAnimationSet::AddConstantDriver(
                                    const std::string&  parameterName,
                                    const void*         constantValue,
                                    AnimSamplerType     samplerType,
                                    unsigned            samplerOffset)
    {
        size_t parameterIndex = _parameterInterfaceDefinition.size();
        auto i = std::find( _parameterInterfaceDefinition.cbegin(),
                            _parameterInterfaceDefinition.cend(), parameterName);
        if (i!=_parameterInterfaceDefinition.end()) {
            parameterIndex = (unsigned)std::distance(_parameterInterfaceDefinition.cbegin(), i);
        } else {
            _parameterInterfaceDefinition.push_back(parameterName);
        }

        unsigned dataOffset = unsigned(_constantData.size());
        std::copy(
            (uint8*)constantValue, PtrAdd((uint8*)constantValue, SamplerSize(samplerType)),
            std::back_inserter(_constantData));

        _constantDrivers.push_back(
            ConstantDriver(dataOffset, (unsigned)parameterIndex, samplerType, samplerOffset));
    }

    void    NascentAnimationSet::AddAnimationDriver(
        const std::string& parameterName,
        unsigned curveId,
        AnimSamplerType samplerType, unsigned samplerOffset)
    {
        size_t parameterIndex = _parameterInterfaceDefinition.size();
        auto i = std::find( _parameterInterfaceDefinition.cbegin(),
                            _parameterInterfaceDefinition.cend(), parameterName);
        if (i!=_parameterInterfaceDefinition.end()) {
            parameterIndex = (unsigned)std::distance(_parameterInterfaceDefinition.cbegin(), i);
        } else {
            _parameterInterfaceDefinition.push_back(parameterName);
        }

        _animationDrivers.push_back(
            AnimationDriver(curveId, (unsigned)parameterIndex, samplerType, samplerOffset));
    }

    bool    NascentAnimationSet::HasAnimationDriver(const std::string&  parameterName) const
    {
        auto i = std::find( _parameterInterfaceDefinition.cbegin(),
                            _parameterInterfaceDefinition.cend(), parameterName);
        if (i==_parameterInterfaceDefinition.end())
            return false;

        auto parameterIndex = (unsigned)std::distance(_parameterInterfaceDefinition.cbegin(), i);

        for (auto i=_animationDrivers.begin(); i!=_animationDrivers.end(); ++i) {
            if (i->_parameterIndex == parameterIndex)
                return true;
        }

        for (auto i=_constantDrivers.begin(); i!=_constantDrivers.end(); ++i) {
            if (i->_parameterIndex == parameterIndex)
                return true;
        }
        return false;
    }

    void    NascentAnimationSet::MergeAnimation(
        const NascentAnimationSet& animation, const char name[],
        const std::vector<Assets::RawAnimationCurve>& sourceCurves,
        std::vector<Assets::RawAnimationCurve>& destinationCurves)
    {
            //      Merge the animation drivers in the given input animation, and give
            //      them the supplied name
        float minTime = FLT_MAX, maxTime = -FLT_MAX;
        size_t startIndex = _animationDrivers.size();
        size_t constantStartIndex = _constantDrivers.size();
        for (auto i=animation._animationDrivers.cbegin(); i!=animation._animationDrivers.end(); ++i) {
            if (i->_curveIndex >= sourceCurves.size()) continue;
            const auto* animCurve = &sourceCurves[i->_curveIndex];
            if (animCurve) {
                float curveStart = animCurve->StartTime();
                float curveEnd = animCurve->EndTime();
                minTime = std::min(minTime, curveStart);
                maxTime = std::max(maxTime, curveEnd);

                const std::string& name = animation._parameterInterfaceDefinition[i->_parameterIndex];
                destinationCurves.push_back(Assets::RawAnimationCurve(*animCurve));
                AddAnimationDriver(
                    name, unsigned(destinationCurves.size()-1),
                    i->_samplerType, i->_samplerOffset);
            }
        }

        for (auto i=animation._constantDrivers.cbegin(); i!=animation._constantDrivers.end(); ++i) {
            const std::string& name = animation._parameterInterfaceDefinition[i->_parameterIndex];
            AddConstantDriver(name, PtrAdd(AsPointer(animation._constantData.begin()), i->_dataOffset), i->_samplerType, i->_samplerOffset);
        }

        _animations.push_back(Animation(name,
            (unsigned)startIndex, (unsigned)_animationDrivers.size(),
            (unsigned)constantStartIndex, (unsigned)_constantDrivers.size(),
            minTime, maxTime));
    }

    void NascentAnimationSet::AnimationDriver::Serialize(Serialization::NascentBlockSerializer& serializer) const
    {
        ::Serialize(serializer, unsigned(_curveIndex));
        ::Serialize(serializer, _parameterIndex);
        ::Serialize(serializer, _samplerOffset);
        ::Serialize(serializer, unsigned(_samplerType));
    }

    void NascentAnimationSet::ConstantDriver::Serialize(Serialization::NascentBlockSerializer& serializer) const
    {
        ::Serialize(serializer, _dataOffset);
        ::Serialize(serializer, _parameterIndex);
        ::Serialize(serializer, _samplerOffset);
        ::Serialize(serializer, unsigned(_samplerType));
    }

    struct AnimationDesc        // matches AnimationSet::Animation
    {
        uint64      _name;
        unsigned    _beginDriver, _endDriver;
        unsigned    _beginConstantDriver, _endConstantDriver;
        float       _beginTime, _endTime;

        AnimationDesc() {}
        void Serialize(Serialization::NascentBlockSerializer& serializer) const
        {
            ::Serialize(serializer, _name);
            ::Serialize(serializer, _beginDriver);
            ::Serialize(serializer, _endDriver);
            ::Serialize(serializer, _beginConstantDriver);
            ::Serialize(serializer, _endConstantDriver);
            ::Serialize(serializer, _beginTime);
            ::Serialize(serializer, _endTime);
        }
    };

    struct CompareAnimationName
    {
        bool operator()(const AnimationDesc& lhs, const AnimationDesc& rhs) const   { return lhs._name < rhs._name; }
        bool operator()(const AnimationDesc& lhs, uint64 rhs) const                 { return lhs._name < rhs; }
        bool operator()(uint64 lhs, const AnimationDesc& rhs) const                 { return lhs < rhs._name; }
    };

    void NascentAnimationSet::Serialize(Serialization::NascentBlockSerializer& serializer) const
    {
        serializer.SerializeSubBlock(AsPointer(_animationDrivers.begin()), AsPointer(_animationDrivers.end()));
        serializer.SerializeValue(_animationDrivers.size());
        serializer.SerializeSubBlock(AsPointer(_constantDrivers.begin()), AsPointer(_constantDrivers.end()));
        serializer.SerializeValue(_constantDrivers.size());
        serializer.SerializeSubBlock(AsPointer(_constantData.begin()), AsPointer(_constantData.end()));

            //      List of animations...

        auto outputAnimations = std::make_unique<AnimationDesc[]>(_animations.size());
        for (size_t c=0; c<_animations.size(); ++c) {
            AnimationDesc&o = outputAnimations[c];
            const Animation&i = _animations[c];
            o._name = Hash64(AsPointer(i._name.begin()), AsPointer(i._name.end()));
            o._beginDriver = i._begin; o._endDriver = i._end;
            o._beginConstantDriver = i._constantBegin; o._endConstantDriver = i._constantEnd;
            o._beginTime = i._startTime; o._endTime = i._endTime;
        }
        std::sort(outputAnimations.get(), &outputAnimations[_animations.size()], CompareAnimationName());
        serializer.SerializeSubBlock(outputAnimations.get(), &outputAnimations[_animations.size()]);
        serializer.SerializeValue(_animations.size());

        ConsoleRig::DebuggerOnlyWarning("Animation set output interface:\n");
        auto parameterNameHashes = std::make_unique<uint64[]>(_parameterInterfaceDefinition.size());
        for (size_t c=0; c<_parameterInterfaceDefinition.size(); ++c) {
            ConsoleRig::DebuggerOnlyWarning("  [%i] %s\n", c, _parameterInterfaceDefinition[c].c_str());
            parameterNameHashes[c] = Hash64(AsPointer(_parameterInterfaceDefinition[c].begin()), AsPointer(_parameterInterfaceDefinition[c].end()));
        }
        serializer.SerializeSubBlock(parameterNameHashes.get(), &parameterNameHashes[_parameterInterfaceDefinition.size()]);
        serializer.SerializeValue(_parameterInterfaceDefinition.size());
    }

    NascentAnimationSet::NascentAnimationSet() {}
    NascentAnimationSet::~NascentAnimationSet() {}
    NascentAnimationSet::NascentAnimationSet(NascentAnimationSet&& moveFrom)
    :   _animationDrivers(std::move(moveFrom._animationDrivers))
    ,   _constantDrivers(std::move(moveFrom._constantDrivers))
    ,   _animations(std::move(moveFrom._animations))
    ,   _parameterInterfaceDefinition(std::move(moveFrom._parameterInterfaceDefinition))
    ,   _constantData(std::move(moveFrom._constantData))
    {}
    NascentAnimationSet& NascentAnimationSet::operator=(NascentAnimationSet&& moveFrom)
    {
        _animationDrivers = std::move(moveFrom._animationDrivers);
        _constantDrivers = std::move(moveFrom._constantDrivers);
        _animations = std::move(moveFrom._animations);
        _parameterInterfaceDefinition = std::move(moveFrom._parameterInterfaceDefinition);
        _constantData = std::move(moveFrom._constantData);
        return *this;
    }

    void NascentSkeleton::Serialize(Serialization::NascentBlockSerializer& serializer) const
    {
        ::Serialize(serializer, _transformationMachine);
    }

    NascentSkeleton::NascentSkeleton() {}
    NascentSkeleton::~NascentSkeleton() {}
    NascentSkeleton::NascentSkeleton(NascentSkeleton&& moveFrom)
    :   _transformationMachine(std::move(moveFrom._transformationMachine))
    {}
    NascentSkeleton& NascentSkeleton::operator=(NascentSkeleton&& moveFrom)
    {
        _transformationMachine = std::move(moveFrom._transformationMachine);
        return *this;
    }

    class NascentModelCommandStream::TransformationMachineOutput
    {
    public:
        ObjectGuid _colladaId;
        std::string _name;
    };

    void NascentModelCommandStream::RegisterTransformationMachineOutput(const std::string& bindingName, ObjectGuid id, unsigned transformMarker)
    {
        if (_transformationMachineOutputs.size() < transformMarker+1)
            _transformationMachineOutputs.resize(transformMarker+1);
        _transformationMachineOutputs[transformMarker] = TransformationMachineOutput{id, bindingName};
    }

    unsigned    NascentModelCommandStream::FindTransformationMachineOutput(ObjectGuid nodeId) const
    {
        auto i2=_transformationMachineOutputs.cbegin();
        for (;i2!=_transformationMachineOutputs.cend(); ++i2) {
            if (i2->_colladaId == nodeId) {
                return (unsigned)std::distance(_transformationMachineOutputs.cbegin(), i2);
            }
        }
        return ~unsigned(0x0);
    }

    void NascentModelCommandStream::Add(GeometryInstance&& geoInstance)
    {
        _geometryInstances.emplace_back(std::move(geoInstance));
    }

    void NascentModelCommandStream::Add(CameraInstance&& camInstance)
    {
        _cameraInstances.emplace_back(std::move(camInstance));
    }

    void NascentModelCommandStream::Add(SkinControllerInstance&& skinControllerInstance)
    {
        _skinControllerInstances.emplace_back(std::move(skinControllerInstance));
    }

    NascentModelCommandStream::NascentModelCommandStream()

    NascentModelCommandStream::~NascentModelCommandStream()
    {

    }

    NascentModelCommandStream::NascentModelCommandStream(NascentModelCommandStream&& moveFrom)
    :       _transformationMachineOutputs(std::move(moveFrom._transformationMachineOutputs))
    ,       _geometryInstances(std::move(moveFrom._geometryInstances))
    ,       _cameraInstances(std::move(moveFrom._cameraInstances))
    ,       _skinControllerInstances(std::move(moveFrom._skinControllerInstances))
    {
    }

    NascentModelCommandStream& NascentModelCommandStream::operator=(NascentModelCommandStream&& moveFrom) never_throws
    {
        _transformationMachineOutputs = std::move(moveFrom._transformationMachineOutputs);
        _geometryInstances = std::move(moveFrom._geometryInstances);
        _cameraInstances = std::move(moveFrom._cameraInstances);
        _skinControllerInstances = std::move(moveFrom._skinControllerInstances);
        return *this;
    }

    void NascentModelCommandStream::GeometryInstance::Serialize(Serialization::NascentBlockSerializer& serializer) const
    {
        ::Serialize(serializer, _id);
        ::Serialize(serializer, _localToWorldId);
        serializer.SerializeSubBlock(AsPointer(_materials.begin()), AsPointer(_materials.end()));
        ::Serialize(serializer, _materials.size());
        ::Serialize(serializer, _levelOfDetail);
    }

    void NascentModelCommandStream::SkinControllerInstance::Serialize(Serialization::NascentBlockSerializer& serializer) const
    {
        ::Serialize(serializer, _id);
        ::Serialize(serializer, _localToWorldId);
        serializer.SerializeSubBlock(AsPointer(_materials.begin()), AsPointer(_materials.end()));
        ::Serialize(serializer, _materials.size());
        ::Serialize(serializer, _levelOfDetail);
    }

    void NascentModelCommandStream::Serialize(Serialization::NascentBlockSerializer& serializer) const
    {
        serializer.SerializeSubBlock(AsPointer(_geometryInstances.begin()), AsPointer(_geometryInstances.end()));
        serializer.SerializeValue(_geometryInstances.size());
        serializer.SerializeSubBlock(AsPointer(_skinControllerInstances.begin()), AsPointer(_skinControllerInstances.end()));
        serializer.SerializeValue(_skinControllerInstances.size());

            //      Turn our list of input matrices into hash values, and write out the
        ConsoleRig::DebuggerOnlyWarning("Command stream input interface:\n");
        auto inputInterface = GetInputInterface();
        serializer.SerializeSubBlock(AsPointer(inputInterface.cbegin()), AsPointer(inputInterface.cend()));
        serializer.SerializeValue(_transformationMachineOutputs.size());
    }

    std::vector<uint64> NascentModelCommandStream::GetInputInterface() const
    {
        std::vector<uint64> inputInterface(_transformationMachineOutputs.size());
        unsigned c=0;
        for (auto i=_transformationMachineOutputs.begin(); i!=_transformationMachineOutputs.end(); ++i, ++c)
            inputInterface[c] = Hash64(AsPointer(i->_name.begin()), AsPointer(i->_name.end()));
        return std::move(inputInterface);
    }

    unsigned NascentModelCommandStream::GetMaxLOD() const
    {
        unsigned maxLOD = 0u;
        for (const auto&i:_geometryInstances) maxLOD = std::max(i._levelOfDetail, maxLOD);
        for (const auto&i:_skinControllerInstances) maxLOD = std::max(i._levelOfDetail, maxLOD);
        return maxLOD;
    }

    std::ostream& operator<<(std::ostream& stream, const NascentModelCommandStream& cmdStream)
    {
        stream << " --- Geometry instances:" << std::endl;
        unsigned c=0;
        for (const auto& i:cmdStream._geometryInstances) {
            stream << "  [" << c++ << "] GeoId: " << i._id << " Transform: " << i._localToWorldId << " LOD: " << i._levelOfDetail << std::endl;
            stream << "     Materials: " << std::hex;
            for (size_t q=0; q<i._materials.size(); ++q) {
                if (q != 0) stream << ", ";
                stream << i._materials[q];
            }
            stream << std::dec << std::endl;
        }

        stream << " --- Skin controller instances:" << std::endl;
        c=0;
        for (const auto& i:cmdStream._skinControllerInstances) {
            stream << "  [" << c++ << "] GeoId: " << i._id << " Transform: " << i._localToWorldId << std::endl;
            stream << "     Materials: " << std::hex;
            for (size_t q=0; q<i._materials.size(); ++q) {
                if (q != 0) stream << ", ";
                stream << i._materials[q];
            }
            stream << std::dec << std::endl;
        }

        stream << " --- Camera instances:" << std::endl;
        c=0;
        for (const auto& i:cmdStream._cameraInstances)
            stream << "  [" << c++ << "] Transform: " << i._localToWorldId << std::endl;

        stream << " --- Input interface:" << std::endl;
        c=0;
        for (const auto& i:cmdStream._transformationMachineOutputs)
            stream << "  [" << c++ << "] " << i._name << std::endl;
        return stream;
    }

}}