<commit_before>/****************************************************************************
**
** GumpBook.cpp
**
** Copyright (C) October 2015 Hotride
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
*****************************************************************************
*/
//----------------------------------------------------------------------------
#include "stdafx.h"

TTextTexture TGumpBook::m_TextTitle;
TTextTexture TGumpBook::m_TextBy;
//----------------------------------------------------------------------------
TGumpBook::TGumpBook(DWORD serial, short x, short y, short pageCount, bool writable, bool unicode)
: TGump(GT_BOOK, serial, x, y), m_PageCount(pageCount), m_Writable(writable),
m_Unicode(unicode), m_Page(0)
{
	TextEntryAuthor = new TEntryText(0, 150);
	TextEntryTitle = new TEntryText(0, 150);

	TextEntry = new TEntryText[pageCount];
	m_ChangedPage = new bool[pageCount];
	m_PageIndexText = new TTextTexture[pageCount];

	IFOR(i, 0, pageCount)
	{
		FontManager->GenerateA(9, m_PageIndexText[i], std::to_string(i).c_str(), 0x0386);
		TextEntry[i].Width = 166;
		m_ChangedPage[i] = false;
	}
}
//----------------------------------------------------------------------------
TGumpBook::~TGumpBook()
{
	if (TextEntryAuthor != NULL)
	{
		delete TextEntryAuthor;
		TextEntryAuthor = NULL;
	}

	if (TextEntryTitle != NULL)
	{
		delete TextEntryTitle;
		TextEntryTitle = NULL;
	}

	if (TextEntry != NULL)
	{
		delete[] TextEntry;
		TextEntry = NULL;
	}

	if (m_ChangedPage != NULL)
	{
		delete m_ChangedPage;
		m_ChangedPage = NULL;
	}

	if (m_PageIndexText != NULL)
	{
		delete[] m_PageIndexText;
		m_PageIndexText = NULL;
	}
}
//----------------------------------------------------------------------------
void TGumpBook::InitTextTextures()
{
	FontManager->UnusePartialHue = true;
	FontManager->GenerateA(4, m_TextTitle, "TITLE", 0x0386);
	FontManager->GenerateA(4, m_TextBy, "by", 0x0386);
	FontManager->UnusePartialHue = false;
}
//----------------------------------------------------------------------------
void TGumpBook::ReleaseTextTextures()
{
	m_TextTitle.Clear();
	m_TextBy.Clear();
}
//----------------------------------------------------------------------------
void TGumpBook::PrepareTextures()
{
	UO->ExecuteGumpPart(0x01FE, 3);
}
//----------------------------------------------------------------------------
bool TGumpBook::EntryPointerHere()
{
	bool result = (EntryPointer == TextEntryAuthor || EntryPointer == TextEntryTitle);

	if (!result && TextEntry != NULL)
	{
		IFOR(i, 0, m_PageCount && !result)
			result = (EntryPointer == &TextEntry[i]);
	}

	return result;
}
//---------------------------------------------------------------------------
void TGumpBook::GenerateFrame()
{
	if (!g_DrawMode)
	{
		m_FrameRedraw = false;
		m_FrameCreated = false;

		return;
	}

	glNewList((GLuint)this, GL_COMPILE);

		UO->DrawGump(0x01FE, 0, 0, 0); //Body

		if (m_Page)
			UO->DrawGump(0x01FF, 0, 0, 0); //Last page

		if (m_Page + 2 < m_PageCount)
			UO->DrawGump(0x0200, 0, 356, 0); //Next page

		if (!m_Page)
		{
			//
			m_TextTitle.Draw(78, 32);
			if (m_Unicode)
				TextEntryTitle->DrawW(0, 0, 41, 65);
			else
				TextEntryTitle->DrawA(4, 0, 41, 65);

			//
			m_TextBy.Draw(88, 134);
			if (m_Unicode)
				TextEntryAuthor->DrawW(0, 0, 41, 160);
			else
				TextEntryAuthor->DrawA(4, 0, 41, 160);

			//
			FontManager->UnusePartialHue = true;
			if (m_Unicode)
				TextEntry[1].DrawW(0, 0x0012, 224, 34);
			else
				TextEntry[1].DrawA(4, 0x0012, 224, 34);
			m_PageIndexText[1].Draw(299, 202);
			FontManager->UnusePartialHue = false;
		}
		else
		{
			FontManager->UnusePartialHue = true;
			//
			if (m_Unicode)
				TextEntry[m_Page].DrawW(0, 0x0012, 38, 34);
			else
				TextEntry[m_Page].DrawA(4, 0x0012, 38, 34);
			m_PageIndexText[m_Page].Draw(112, 202);

			if (m_Page + 1 < m_PageCount)
			{
				//
				if (m_Unicode)
					TextEntry[m_Page + 1].DrawW(0, 0x0012, 224, 34);
				else
					TextEntry[m_Page + 1].DrawA(4, 0x0012, 224, 34);
				m_PageIndexText[m_Page + 1].Draw(299, 202);
			}
			FontManager->UnusePartialHue = false;
		}

	glEndList();

	m_FrameCreated = true;
	m_FrameRedraw = true;
}
//----------------------------------------------------------------------------
int TGumpBook::Draw(bool &mode)
{
	DWORD index = (DWORD)this;

	CalculateGumpState();

	if (mode) //
	{
		if (!m_FrameCreated || g_GumpMovingOffsetX || g_GumpMovingOffsetY)
			GenerateFrame();
		else if (m_FrameRedraw)
		{
			GenerateFrame();
			m_FrameRedraw = false;
		}

		glTranslatef(g_GumpTranslateX, g_GumpTranslateY, 0.0f);

		glCallList((GLuint)this);

		glTranslatef(-g_GumpTranslateX, -g_GumpTranslateY, 0.0f);
	}
	else //
	{
		int oldMouseX = g_MouseX;
		int oldMouseY = g_MouseY;
		g_MouseX -= (int)g_GumpTranslateX;
		g_MouseY -= (int)g_GumpTranslateY;

		int LSG = 0;

		if (UO->GumpPixelsInXY(0x01FE, 0, 0))
			g_LastSelectedGump = index;

		if (m_Page && UO->GumpPixelsInXY(0x01FF, 0, 0))
			LSG = ID_GB_BUTTON_PREV; //Last page
		else if (m_Page + 2 < m_PageCount && UO->GumpPixelsInXY(0x0200, 356, 0))
			LSG = ID_GB_BUTTON_NEXT; //Next page
		else if (!m_Page)
		{
			if (UO->PolygonePixelsInXY(41, 65, 150, (m_Unicode ? 22 : 44)))
				LSG = ID_GB_TEXT_AREA_TITLE; //Text title
			else if (UO->PolygonePixelsInXY(41, 160, 150, 22))
				LSG = ID_GB_TEXT_AREA_AUTHOR; //Text author
			else if (UO->PolygonePixelsInXY(224, 34, 160, 166))
				LSG = ID_GB_TEXT_AREA_PAGE_RIGHT; //Text right area
		}
		else
		{
			if (UO->PolygonePixelsInXY(38, 34, 160, 166))
				LSG = ID_GB_TEXT_AREA_PAGE_LEFT; //Text left area
			else if (UO->PolygonePixelsInXY(224, 34, 160, 166))
				LSG = ID_GB_TEXT_AREA_PAGE_RIGHT; //Text right area
		}

		g_MouseX = oldMouseX;
		g_MouseY = oldMouseY;

		return LSG;
	}

	return 0;
}
//----------------------------------------------------------------------------
void TGumpBook::OnLeftMouseUp()
{
	//
	if (g_LastObjectLeftMouseDown != g_LastSelectedObject || !g_LastObjectLeftMouseDown || !g_LastSelectedGump)
		return;

	int newPage = -1;

	if (g_LastObjectLeftMouseDown == ID_GB_BUTTON_PREV) //Prev
	{
		if (!g_ClickObjectReq && m_Page > 0) //
		{
			newPage = m_Page - 2;

			if (newPage < 0)
				newPage = 0;
		}
	}
	else if (g_LastObjectLeftMouseDown == ID_GB_BUTTON_NEXT) //Next
	{
		if (!g_ClickObjectReq && m_Page < m_PageCount) //
		{
			newPage = m_Page + 2;

			if (newPage >= m_PageCount)
				newPage = m_PageCount - 1;
		}
	}
	else if (m_Writable)
	{
		int x = g_MouseX - m_X;
		int y = g_MouseY - m_Y;

		TEntryText *entry = NULL;

		if (g_LastObjectLeftMouseDown == ID_GB_TEXT_AREA_AUTHOR)
		{
			entry = TextEntryAuthor;
			x -= 41;
			y -= 160;
		}
		else if (g_LastObjectLeftMouseDown == ID_GB_TEXT_AREA_TITLE)
		{
			entry = TextEntryTitle;
			x -= 41;
			y -= 65;
		}
		else if (g_LastObjectLeftMouseDown == ID_GB_TEXT_AREA_PAGE_LEFT)
		{
			entry = &TextEntry[m_Page];
			x -= 38;
			y -= 34;
		}
		else if (g_LastObjectLeftMouseDown == ID_GB_TEXT_AREA_PAGE_RIGHT)
		{
			entry = &TextEntry[m_Page + 1];
			x -= 224;
			y -= 34;
		}

		if (entry != NULL)
			entry->OnClick(this, (m_Unicode ? 0 : 4), m_Unicode, x, y);
	}

	if (newPage > -1)
	{
		//
		g_ClickObjectReq = true;

		// -
		g_ClickObject.Init(COT_GUMP);
		g_ClickObject.GumpType = GumpType;
		g_ClickObject.Serial = Serial;
		g_ClickObject.GumpID = ID;
		g_ClickObject.GumpButtonID = newPage;

		//TEST~>>
		m_Page = newPage;
		m_FrameCreated = false;
		g_ClickObjectReq = false;
		//TEST~<<

		//
		g_ClickObject.Timer = GetTickCount() + DCLICK_DELAY;
	}
}
//----------------------------------------------------------------------------
bool TGumpBook::OnLeftMouseDoubleClick()
{
	//     -
	if (!g_LastSelectedGump)
		return false;

	if (g_LastObjectLeftMouseDown == ID_GB_BUTTON_PREV) //Prev
	{
		//   "",    1
		m_Page = 0;

		//
		m_FrameCreated = false;

		return true;
	}
	else if (g_LastObjectLeftMouseDown == ID_GB_BUTTON_NEXT) //Next
	{
		//   "",
		if (m_PageCount % 2)
			m_Page = m_PageCount - 2;
		else
			m_Page = m_PageCount - 1;

		//
		m_FrameCreated = false;

		return true;
	}

	return false;
}
//----------------------------------------------------------------------------
void TGumpBook::InsertInContent(const WPARAM &wparam)
{
	int page = m_Page;

	if (page >= 0 && page < m_PageCount)
	{
		bool isSecondEntry = false;

		if (EntryPointer != &TextEntry[page])
		{
			if (page < m_PageCount - 1 && EntryPointer == &TextEntry[page + 1])
			{
				isSecondEntry = true;
				page++;
			}
			else
				return;
		}

		if (EntryPointer->Insert(wparam))
		{
			if (m_Unicode)
			{
				if (EntryPointer->GetLinesCountW(0) > 8)
					EntryPointer->Remove(true);
			}
			else
			{
				if (EntryPointer->GetLinesCountA(4) > 8)
					EntryPointer->Remove(true);
			}

			m_FrameCreated = false;
		}
		//page
	}
}
//----------------------------------------------------------------------------
void TGumpBook::OnCharPress(WPARAM &wparam, LPARAM &lparam)
{
	if (wparam == VK_RETURN || wparam == VK_BACK || wparam == VK_ESCAPE || EntryPointer == NULL || !m_Writable)
		return; //Ignore no print keys

	if (EntryPointer == TextEntryTitle || EntryPointer == TextEntryAuthor)
	{
		if (EntryPointer->Insert(wparam))
		{
			if (m_Unicode)
			{
				if (EntryPointer->GetLinesCountW(0) > 1)
					EntryPointer->Remove(true);
			}
			else
			{
				int count = 1;

				if (EntryPointer == TextEntryTitle)
					count++;

				if (EntryPointer->GetLinesCountA(4) > count)
					EntryPointer->Remove(true);
			}

			m_FrameCreated = false;
		}
	}
	else
		InsertInContent(wparam);
}
//----------------------------------------------------------------------------
void TGumpBook::OnKeyPress(WPARAM &wparam, LPARAM &lparam)
{
	if (!m_Writable)
		return;

	switch (wparam)
	{
		case VK_RETURN:
		{
			if (EntryPointer != TextEntryTitle && EntryPointer != TextEntryAuthor)
			{
				InsertInContent(L'\n');
				m_FrameCreated = false;
			}

			break;
		}
		case VK_HOME:
		case VK_END:
		case VK_LEFT:
		case VK_RIGHT:
		case VK_BACK:
		case VK_DELETE:
		{
			EntryPointer->OnKey(this, wparam);
			m_FrameCreated = false;
			break;
		}
		default:
			break;
	}
}
//----------------------------------------------------------------------------<commit_msg>0000009: Метки изменений на страницах книги (при изменении контента).<commit_after>/****************************************************************************
**
** GumpBook.cpp
**
** Copyright (C) October 2015 Hotride
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
*****************************************************************************
*/
//----------------------------------------------------------------------------
#include "stdafx.h"

TTextTexture TGumpBook::m_TextTitle;
TTextTexture TGumpBook::m_TextBy;
//----------------------------------------------------------------------------
TGumpBook::TGumpBook(DWORD serial, short x, short y, short pageCount, bool writable, bool unicode)
: TGump(GT_BOOK, serial, x, y), m_PageCount(pageCount), m_Writable(writable),
m_Unicode(unicode), m_Page(0)
{
	TextEntryAuthor = new TEntryText(0, 150);
	TextEntryTitle = new TEntryText(0, 150);

	TextEntry = new TEntryText[pageCount];
	m_ChangedPage = new bool[pageCount];
	m_PageIndexText = new TTextTexture[pageCount];

	IFOR(i, 0, pageCount)
	{
		FontManager->GenerateA(9, m_PageIndexText[i], std::to_string(i).c_str(), 0x0386);
		TextEntry[i].Width = 166;
		m_ChangedPage[i] = false;
	}
}
//----------------------------------------------------------------------------
TGumpBook::~TGumpBook()
{
	if (TextEntryAuthor != NULL)
	{
		delete TextEntryAuthor;
		TextEntryAuthor = NULL;
	}

	if (TextEntryTitle != NULL)
	{
		delete TextEntryTitle;
		TextEntryTitle = NULL;
	}

	if (TextEntry != NULL)
	{
		delete[] TextEntry;
		TextEntry = NULL;
	}

	if (m_ChangedPage != NULL)
	{
		delete m_ChangedPage;
		m_ChangedPage = NULL;
	}

	if (m_PageIndexText != NULL)
	{
		delete[] m_PageIndexText;
		m_PageIndexText = NULL;
	}
}
//----------------------------------------------------------------------------
void TGumpBook::InitTextTextures()
{
	FontManager->UnusePartialHue = true;
	FontManager->GenerateA(4, m_TextTitle, "TITLE", 0x0386);
	FontManager->GenerateA(4, m_TextBy, "by", 0x0386);
	FontManager->UnusePartialHue = false;
}
//----------------------------------------------------------------------------
void TGumpBook::ReleaseTextTextures()
{
	m_TextTitle.Clear();
	m_TextBy.Clear();
}
//----------------------------------------------------------------------------
void TGumpBook::PrepareTextures()
{
	UO->ExecuteGumpPart(0x01FE, 3);
}
//----------------------------------------------------------------------------
bool TGumpBook::EntryPointerHere()
{
	bool result = (EntryPointer == TextEntryAuthor || EntryPointer == TextEntryTitle);

	if (!result && TextEntry != NULL)
	{
		IFOR(i, 0, m_PageCount && !result)
			result = (EntryPointer == &TextEntry[i]);
	}

	return result;
}
//---------------------------------------------------------------------------
void TGumpBook::GenerateFrame()
{
	if (!g_DrawMode)
	{
		m_FrameRedraw = false;
		m_FrameCreated = false;

		return;
	}

	glNewList((GLuint)this, GL_COMPILE);

		UO->DrawGump(0x01FE, 0, 0, 0); //Body

		if (m_Page)
			UO->DrawGump(0x01FF, 0, 0, 0); //Last page

		if (m_Page + 2 < m_PageCount)
			UO->DrawGump(0x0200, 0, 356, 0); //Next page

		if (!m_Page)
		{
			//
			m_TextTitle.Draw(78, 32);
			if (m_Unicode)
				TextEntryTitle->DrawW(0, 0, 41, 65);
			else
				TextEntryTitle->DrawA(4, 0, 41, 65);

			//
			m_TextBy.Draw(88, 134);
			if (m_Unicode)
				TextEntryAuthor->DrawW(0, 0, 41, 160);
			else
				TextEntryAuthor->DrawA(4, 0, 41, 160);

			//
			FontManager->UnusePartialHue = true;
			if (m_Unicode)
				TextEntry[1].DrawW(0, 0x0012, 224, 34);
			else
				TextEntry[1].DrawA(4, 0x0012, 224, 34);
			m_PageIndexText[1].Draw(299, 202);
			FontManager->UnusePartialHue = false;
		}
		else
		{
			FontManager->UnusePartialHue = true;
			//
			if (m_Unicode)
				TextEntry[m_Page].DrawW(0, 0x0012, 38, 34);
			else
				TextEntry[m_Page].DrawA(4, 0x0012, 38, 34);
			m_PageIndexText[m_Page].Draw(112, 202);

			if (m_Page + 1 < m_PageCount)
			{
				//
				if (m_Unicode)
					TextEntry[m_Page + 1].DrawW(0, 0x0012, 224, 34);
				else
					TextEntry[m_Page + 1].DrawA(4, 0x0012, 224, 34);
				m_PageIndexText[m_Page + 1].Draw(299, 202);
			}
			FontManager->UnusePartialHue = false;
		}

	glEndList();

	m_FrameCreated = true;
	m_FrameRedraw = true;
}
//----------------------------------------------------------------------------
int TGumpBook::Draw(bool &mode)
{
	DWORD index = (DWORD)this;

	CalculateGumpState();

	if (mode) //
	{
		if (!m_FrameCreated || g_GumpMovingOffsetX || g_GumpMovingOffsetY)
			GenerateFrame();
		else if (m_FrameRedraw)
		{
			GenerateFrame();
			m_FrameRedraw = false;
		}

		glTranslatef(g_GumpTranslateX, g_GumpTranslateY, 0.0f);

		glCallList((GLuint)this);

		glTranslatef(-g_GumpTranslateX, -g_GumpTranslateY, 0.0f);
	}
	else //
	{
		int oldMouseX = g_MouseX;
		int oldMouseY = g_MouseY;
		g_MouseX -= (int)g_GumpTranslateX;
		g_MouseY -= (int)g_GumpTranslateY;

		int LSG = 0;

		if (UO->GumpPixelsInXY(0x01FE, 0, 0))
			g_LastSelectedGump = index;

		if (m_Page && UO->GumpPixelsInXY(0x01FF, 0, 0))
			LSG = ID_GB_BUTTON_PREV; //Last page
		else if (m_Page + 2 < m_PageCount && UO->GumpPixelsInXY(0x0200, 356, 0))
			LSG = ID_GB_BUTTON_NEXT; //Next page
		else if (!m_Page)
		{
			if (UO->PolygonePixelsInXY(41, 65, 150, (m_Unicode ? 22 : 44)))
				LSG = ID_GB_TEXT_AREA_TITLE; //Text title
			else if (UO->PolygonePixelsInXY(41, 160, 150, 22))
				LSG = ID_GB_TEXT_AREA_AUTHOR; //Text author
			else if (UO->PolygonePixelsInXY(224, 34, 160, 166))
				LSG = ID_GB_TEXT_AREA_PAGE_RIGHT; //Text right area
		}
		else
		{
			if (UO->PolygonePixelsInXY(38, 34, 160, 166))
				LSG = ID_GB_TEXT_AREA_PAGE_LEFT; //Text left area
			else if (UO->PolygonePixelsInXY(224, 34, 160, 166))
				LSG = ID_GB_TEXT_AREA_PAGE_RIGHT; //Text right area
		}

		g_MouseX = oldMouseX;
		g_MouseY = oldMouseY;

		return LSG;
	}

	return 0;
}
//----------------------------------------------------------------------------
void TGumpBook::OnLeftMouseUp()
{
	//
	if (g_LastObjectLeftMouseDown != g_LastSelectedObject || !g_LastObjectLeftMouseDown || !g_LastSelectedGump)
		return;

	int newPage = -1;

	if (g_LastObjectLeftMouseDown == ID_GB_BUTTON_PREV) //Prev
	{
		if (!g_ClickObjectReq && m_Page > 0) //
		{
			newPage = m_Page - 2;

			if (newPage < 0)
				newPage = 0;
		}
	}
	else if (g_LastObjectLeftMouseDown == ID_GB_BUTTON_NEXT) //Next
	{
		if (!g_ClickObjectReq && m_Page < m_PageCount) //
		{
			newPage = m_Page + 2;

			if (newPage >= m_PageCount)
				newPage = m_PageCount - 1;
		}
	}
	else if (m_Writable)
	{
		int x = g_MouseX - m_X;
		int y = g_MouseY - m_Y;

		TEntryText *entry = NULL;

		if (g_LastObjectLeftMouseDown == ID_GB_TEXT_AREA_AUTHOR)
		{
			entry = TextEntryAuthor;
			x -= 41;
			y -= 160;
		}
		else if (g_LastObjectLeftMouseDown == ID_GB_TEXT_AREA_TITLE)
		{
			entry = TextEntryTitle;
			x -= 41;
			y -= 65;
		}
		else if (g_LastObjectLeftMouseDown == ID_GB_TEXT_AREA_PAGE_LEFT)
		{
			entry = &TextEntry[m_Page];
			x -= 38;
			y -= 34;
		}
		else if (g_LastObjectLeftMouseDown == ID_GB_TEXT_AREA_PAGE_RIGHT)
		{
			entry = &TextEntry[m_Page + 1];
			x -= 224;
			y -= 34;
		}

		if (entry != NULL)
			entry->OnClick(this, (m_Unicode ? 0 : 4), m_Unicode, x, y);
	}

	if (newPage > -1)
	{
		//
		g_ClickObjectReq = true;

		// -
		g_ClickObject.Init(COT_GUMP);
		g_ClickObject.GumpType = GumpType;
		g_ClickObject.Serial = Serial;
		g_ClickObject.GumpID = ID;
		g_ClickObject.GumpButtonID = newPage;

		//TEST~>>
		m_Page = newPage;
		m_FrameCreated = false;
		g_ClickObjectReq = false;
		//TEST~<<

		//
		g_ClickObject.Timer = GetTickCount() + DCLICK_DELAY;
	}
}
//----------------------------------------------------------------------------
bool TGumpBook::OnLeftMouseDoubleClick()
{
	//     -
	if (!g_LastSelectedGump)
		return false;

	if (g_LastObjectLeftMouseDown == ID_GB_BUTTON_PREV) //Prev
	{
		//   "",    1
		m_Page = 0;

		//
		m_FrameCreated = false;

		return true;
	}
	else if (g_LastObjectLeftMouseDown == ID_GB_BUTTON_NEXT) //Next
	{
		//   "",
		if (m_PageCount % 2)
			m_Page = m_PageCount - 2;
		else
			m_Page = m_PageCount - 1;

		//
		m_FrameCreated = false;

		return true;
	}

	return false;
}
//----------------------------------------------------------------------------
void TGumpBook::InsertInContent(const WPARAM &wparam)
{
	int page = m_Page;

	if (page >= 0 && page < m_PageCount)
	{
		bool isSecondEntry = false;

		if (EntryPointer != &TextEntry[page])
		{
			if (page < m_PageCount - 1 && EntryPointer == &TextEntry[page + 1])
			{
				isSecondEntry = true;
				page++;
			}
			else
				return;
		}

		if (EntryPointer->Insert(wparam))
		{
			if (m_Unicode)
			{
				if (EntryPointer->GetLinesCountW(0) > 8)
					EntryPointer->Remove(true);
				else
					m_ChangedPage[page] = true;
			}
			else
			{
				if (EntryPointer->GetLinesCountA(4) > 8)
					EntryPointer->Remove(true);
				else
					m_ChangedPage[page] = true;
			}

			m_FrameCreated = false;
		}
		//page
	}
}
//----------------------------------------------------------------------------
void TGumpBook::OnCharPress(WPARAM &wparam, LPARAM &lparam)
{
	if (wparam == VK_RETURN || wparam == VK_BACK || wparam == VK_ESCAPE || EntryPointer == NULL || !m_Writable)
		return; //Ignore no print keys

	if (EntryPointer == TextEntryTitle || EntryPointer == TextEntryAuthor)
	{
		if (EntryPointer->Insert(wparam))
		{
			if (m_Unicode)
			{
				if (EntryPointer->GetLinesCountW(0) > 1)
					EntryPointer->Remove(true);
			}
			else
			{
				int count = 1;

				if (EntryPointer == TextEntryTitle)
					count++;

				if (EntryPointer->GetLinesCountA(4) > count)
					EntryPointer->Remove(true);
			}

			m_FrameCreated = false;
		}
	}
	else
		InsertInContent(wparam);
}
//----------------------------------------------------------------------------
void TGumpBook::OnKeyPress(WPARAM &wparam, LPARAM &lparam)
{
	if (!m_Writable)
		return;

	switch (wparam)
	{
		case VK_RETURN:
		{
			if (EntryPointer != TextEntryTitle && EntryPointer != TextEntryAuthor)
			{
				InsertInContent(L'\n');
				m_FrameCreated = false;
			}

			break;
		}
		case VK_HOME:
		case VK_END:
		case VK_LEFT:
		case VK_RIGHT:
		case VK_BACK:
		case VK_DELETE:
		{
			EntryPointer->OnKey(this, wparam);
			m_FrameCreated = false;
			break;
		}
		default:
			break;
	}
}
//----------------------------------------------------------------------------<|endoftext|>


<commit_before>#include "QmlChimera.h"

#include <QGuiApplication>

#include <QmlVlc/QmlVlc.h>

#include "DOM/Window.h"

#include "JSRootQmlApi.h"

#if defined( FB_WIN ) && !defined( QT_NO_DEBUG )
#include <Shellapi.h>
#endif

void QmlChimera::StaticInitialize()
{
    RegisterQmlVlc();

    // Place one-time initialization stuff here; As of FireBreath 1.4 this should only
    // be called once per process
    if( !qApp ) {
#if defined( QT_NO_DEBUG ) || !defined( FB_WIN )
        static int argc = 0;
        new QGuiApplication( argc, 0 );
#else
        //Q_ASSERT(allArguments.size() == origArgc); at qcoreapplication.cpp:2109 workaround
        int argc;
        LocalFree( CommandLineToArgvW( GetCommandLineW(), &argc ) );
        std::vector<char*> argv( argc, nullptr );
        new QGuiApplication( argc, argv.data() );
#endif
        QGuiApplication::processEvents();
    }
}

QmlChimera::QmlChimera()
    : m_qmlVlcPlayer( 0 )
{

}

FB::JSAPIPtr QmlChimera::createJSAPI()
{
    return boost::make_shared<JSRootQmlAPI>( FB::ptr_cast<QmlChimera>( shared_from_this() ), m_host );
}

QString QmlChimera::get_bgColor() const
{
    return QString::fromStdString( get_bg_color() );
}

void QmlChimera::fireQmlMessage( const QString& message )
{
    JSRootQmlAPIPtr api  = boost::static_pointer_cast<JSRootQmlAPI>( getRootJSAPI() );
    api->fire_QmlMessage( message.toStdString() );
}

void QmlChimera::load_startup_options()
{
   typedef boost::optional<std::string> param_type;
    typedef const FB::variant&          param_vtype;

    Chimera::load_startup_options();

    vlc_player_options& opts = get_options();

    param_type qml_source = getParam( "qmlsrc" );
    if ( qml_source )
        opts.set_qml_source( *qml_source );

    param_type qml = getParam( "qml" );
    if ( qml )
        opts.set_qml( *qml );
}

void QmlChimera::on_option_change( vlc_player_option_e o )
{
    Chimera::on_option_change( o );

    if( po_bg_color == o )
        Q_EMIT bgcolorChanged( get_bgColor() );
}

std::string QmlChimera::getQmlError()
{
    return m_qmlError;
}

QUrl QmlChimera::getQmlSource()
{
    QUrl qml = QStringLiteral( "qrc:/default.qml" );

    std::string url = m_host->getDOMWindow()->getLocation();
    QUrl baseUrl = QString::fromUtf8( url.data(), url.size() );

    vlc_player_options& opts = get_options();
    const std::string& qml_source = opts.get_qml_source();
    if( !qml_source.empty() ) {
        QUrl qmlTmp = QString::fromUtf8( qml_source.data(), qml_source.size() );
        if( qmlTmp.isRelative() ) {
            qmlTmp = baseUrl.resolved( qmlTmp );
        }
#ifdef NDEBUG
        if( !qmlTmp.isLocalFile() ) {
            qml = qmlTmp;
        }
#else
        qml = qmlTmp;
#endif
    }

    return qml;
}

bool QmlChimera::isOptionTrusted( const std::string& option )
{
    return QmlVlcConfig::isOptionTrusted( QString::fromStdString( option ) );
}
<commit_msg>allow use local qml files if "app:" protocol used<commit_after>#include "QmlChimera.h"

#include <boost/algorithm/string.hpp>

#include <QGuiApplication>

#include <QmlVlc/QmlVlc.h>

#include "DOM/Window.h"

#include "JSRootQmlApi.h"

#if defined( FB_WIN ) && !defined( QT_NO_DEBUG )
#include <Shellapi.h>
#endif

void QmlChimera::StaticInitialize()
{
    RegisterQmlVlc();

    // Place one-time initialization stuff here; As of FireBreath 1.4 this should only
    // be called once per process
    if( !qApp ) {
#if defined( QT_NO_DEBUG ) || !defined( FB_WIN )
        static int argc = 0;
        new QGuiApplication( argc, 0 );
#else
        //Q_ASSERT(allArguments.size() == origArgc); at qcoreapplication.cpp:2109 workaround
        int argc;
        LocalFree( CommandLineToArgvW( GetCommandLineW(), &argc ) );
        std::vector<char*> argv( argc, nullptr );
        new QGuiApplication( argc, argv.data() );
#endif
        QGuiApplication::processEvents();
    }
}

QmlChimera::QmlChimera()
    : m_qmlVlcPlayer( 0 )
{

}

FB::JSAPIPtr QmlChimera::createJSAPI()
{
    return boost::make_shared<JSRootQmlAPI>( FB::ptr_cast<QmlChimera>( shared_from_this() ), m_host );
}

QString QmlChimera::get_bgColor() const
{
    return QString::fromStdString( get_bg_color() );
}

void QmlChimera::fireQmlMessage( const QString& message )
{
    JSRootQmlAPIPtr api  = boost::static_pointer_cast<JSRootQmlAPI>( getRootJSAPI() );
    api->fire_QmlMessage( message.toStdString() );
}

void QmlChimera::load_startup_options()
{
   typedef boost::optional<std::string> param_type;
    typedef const FB::variant&          param_vtype;

    Chimera::load_startup_options();

    vlc_player_options& opts = get_options();

    param_type qml_source = getParam( "qmlsrc" );
    if ( qml_source )
        opts.set_qml_source( *qml_source );

    param_type qml = getParam( "qml" );
    if ( qml )
        opts.set_qml( *qml );
}

void QmlChimera::on_option_change( vlc_player_option_e o )
{
    Chimera::on_option_change( o );

    if( po_bg_color == o )
        Q_EMIT bgcolorChanged( get_bgColor() );
}

std::string QmlChimera::getQmlError()
{
    return m_qmlError;
}

QUrl QmlChimera::getQmlSource()
{
    QUrl qml = QStringLiteral( "qrc:/default.qml" );

    std::string url = m_host->getDOMWindow()->getLocation();
    QUrl baseUrl = QString::fromUtf8( url.data(), url.size() );

    vlc_player_options& opts = get_options();
    const std::string& qml_source = opts.get_qml_source();
    if( !qml_source.empty() ) {
        QUrl qmlTmp = QString::fromUtf8( qml_source.data(), qml_source.size() );
        bool isApp = boost::istarts_with( url, "app://" );
        if( qmlTmp.isRelative() && !isApp ) {
            qmlTmp = baseUrl.resolved( qmlTmp );
        }
#ifdef NDEBUG
        if( !qmlTmp.isLocalFile() || isApp ) {
            qml = qmlTmp;
        }
#else
        qml = qmlTmp;
#endif
    }

    return qml;
}

bool QmlChimera::isOptionTrusted( const std::string& option )
{
    return QmlVlcConfig::isOptionTrusted( QString::fromStdString( option ) );
}
<|endoftext|>


<commit_before>#include <stdlib.h>
#include <errno.h>
#include <QApplication>
#include <QFrame>
#include <QTextCodec>

#include "../typedef.h"
#include "../config.h"
#include "../console.h"
#include "../error.h"
#include "../osd.h"
#include "../pc60.h"

#ifdef SDL_VIDEO_DRIVER_X11
#include <X11/Xlib.h>
#endif
///////////////////////////////////////////////////////////
// メイン
///////////////////////////////////////////////////////////
int main( int argc, char *argv[] )
{
#ifdef SDL_VIDEO_DRIVER_X11
    //X11環境でSDLスレッドを使用するために必要。
    XInitThreads();
#endif

    VM6 *P6Core             = NULL;			// オブジェクトポインタ
    VM6::ReturnCode Restart = VM6::Quit;	// 再起動フラグ
    cConfig *Cfg            = NULL;			// 環境設定オブジェクト

    QApplication app(argc, argv);
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));

    // 環境変数設定(テスト用)
    //	putenv( "SDL_VIDEODRIVER=windib" );
    //	putenv( "SDL_VIDEODRIVER=directx" );
    //	putenv( "SDL_AUDIODRIVER=dsound" );

    // 二重起動禁止
    if( OSD_IsWorking() ) return FALSE;

    // 設定ファイルフォルダを作成
    if( !OSD_CreateConfigPath() ) return FALSE;

    // SDL初期化
    if( SDL_Init( SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_JOYSTICK ) < 0 ){
        Error::SetError( Error::LibInitFailed );
        OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDR_OK | OSDM_ICONERROR );
        OSD_Finish();	// 終了処理
        return FALSE;
    }

    // INIファイル読込み
    Cfg = new cConfig();
    if( !Cfg ){
        SDL_Quit();		// SDLシャットダウン
        OSD_Finish();	// 終了処理
    }
    if( !Cfg->Init() ){
        switch( Error::GetError() ){
        case Error::IniDefault:
            OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDR_OK | OSDM_ICONWARNING );
            Error::SetError( Error::NoError );
            break;

        default:
            OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDR_OK | OSDM_ICONERROR );
            SDL_Quit();				// SDLシャットダウン
            OSD_Finish();			// 終了処理
            if( Cfg ) delete Cfg;	// 環境設定オブジェクト開放
            return FALSE;
        }
    }

    // フォントファイルが無ければ作成する
    if( !OSD_FileExist( Cfg->GetFontFileH() ) ) OSD_CreateFont( Cfg->GetFontFileH(), NULL, FSIZE );
    if( !OSD_FileExist( Cfg->GetFontFileZ() ) ) OSD_CreateFont( NULL, Cfg->GetFontFileZ(), FSIZE );

    // P6オブジェクトを作成して実行
    do{
        // ROMファイル存在チェック&機種変更
        char RomSerch[PATH_MAX];
        int IniModel = Cfg->GetModel();
        sprintf( RomSerch, "%s*.%2d", Cfg->GetRomPath(), IniModel );
        if( !OSD_FileExist( RomSerch ) ){
            int models[] = { 60, 62, 66 };
            for( int i=0; i < COUNTOF(models); i++ ){
                sprintf( RomSerch, "%s*.%2d", Cfg->GetRomPath(), models[i] );
                if( OSD_FileExist( RomSerch ) ){
                    Cfg->SetModel( models[i] );
                    break;
                }
            }
            // ROMある?
            if( IniModel != Cfg->GetModel() ){
                Error::SetError( Error::RomChange );
                OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDR_OK | OSDM_ICONWARNING );
                Error::SetError( Error::NoError );
            }
        }

        // 機種別P6オブジェクト確保
        const char* iconRes = NULL;
        switch( Cfg->GetModel() ){
        case 62: P6Core = new VM62; iconRes = ":/res/PC-6001mk2.ico"; break;
        case 66: P6Core = new VM66; iconRes = ":/res/PC-6601.ico"; break;
        default: P6Core = new VM60; iconRes = ":/res/PC-6001.ico";
        }

        // アイコン設定
        QImage icon(iconRes);
        SDL_Surface *p6icon = SDL_CreateRGBSurfaceFrom( icon.bits(), icon.width(), icon.height(), icon.depth(), icon.bytesPerLine(), 0, 0, 0, 0 );
        SDL_WM_SetIcon( p6icon, icon.alphaChannel().bits() );
        SDL_FreeSurface( p6icon );

        // VMを初期化して実行
        if( P6Core->Init( Cfg ) ){
            switch( Restart ){
            case VM6::Doko:		// どこでもLOAD?
                P6Core->DokoDemoLoad( Cfg->GetDokoFile() );
                break;

            case VM6::Replay:	// リプレイ再生?
            {
                char temp[PATH_MAX];
                strncpy( temp, Cfg->GetDokoFile(), PATH_MAX );
                P6Core->DokoDemoLoad( temp );
                P6Core->REPLAY::StartReplay( temp );
            }
            break;

            default:
                break;
            }

            P6Core->Start();
            Restart = P6Core->EventLoop();
            P6Core->Stop();
        }else{
            // 失敗した場合
            OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDR_OK | OSDM_ICONERROR );
        }

        // P6オブジェクトを開放
        if( P6Core ) delete P6Core;

        // 再起動ならばINIファイル再読込み
        if( Restart == VM6::Restart ){
            if( !Cfg->Init() ){
                Error::SetError( Error::IniDefault );
                OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDR_OK | OSDM_ICONWARNING );
                Error::SetError( Error::NoError );
            }
        }

    }while( Restart != VM6::Quit );

    // 環境設定オブジェクト開放
    if( Cfg ) delete Cfg;

    // SDLシャットダウン
    SDL_Quit();

    // 終了処理
    OSD_Finish();

    return TRUE;
}
<commit_msg>romが存在しないフォルダをROMフォルダに設定すると無限ループになる不具合を修正<commit_after>#include <stdlib.h>
#include <errno.h>
#include <QApplication>
#include <QFrame>
#include <QTextCodec>

#include "../typedef.h"
#include "../config.h"
#include "../console.h"
#include "../error.h"
#include "../osd.h"
#include "../pc60.h"

#ifdef SDL_VIDEO_DRIVER_X11
#include <X11/Xlib.h>
#endif
///////////////////////////////////////////////////////////
// メイン
///////////////////////////////////////////////////////////
int main( int argc, char *argv[] )
{
#ifdef SDL_VIDEO_DRIVER_X11
    //X11環境でSDLスレッドを使用するために必要。
    XInitThreads();
#endif

    VM6 *P6Core             = NULL;			// オブジェクトポインタ
    VM6::ReturnCode Restart = VM6::Quit;	// 再起動フラグ
    cConfig *Cfg            = NULL;			// 環境設定オブジェクト

    QApplication app(argc, argv);
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));

    // 環境変数設定(テスト用)
    //	putenv( "SDL_VIDEODRIVER=windib" );
    //	putenv( "SDL_VIDEODRIVER=directx" );
    //	putenv( "SDL_AUDIODRIVER=dsound" );

    // 二重起動禁止
    if( OSD_IsWorking() ) return FALSE;

    // 設定ファイルフォルダを作成
    if( !OSD_CreateConfigPath() ) return FALSE;

    // SDL初期化
    if( SDL_Init( SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_JOYSTICK ) < 0 ){
        Error::SetError( Error::LibInitFailed );
        OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDR_OK | OSDM_ICONERROR );
        OSD_Finish();	// 終了処理
        return FALSE;
    }

    // INIファイル読込み
    Cfg = new cConfig();
    if( !Cfg ){
        SDL_Quit();		// SDLシャットダウン
        OSD_Finish();	// 終了処理
    }
    if( !Cfg->Init() ){
        switch( Error::GetError() ){
        case Error::IniDefault:
            OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDR_OK | OSDM_ICONWARNING );
            Error::SetError( Error::NoError );
            break;

        default:
            OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDR_OK | OSDM_ICONERROR );
            SDL_Quit();				// SDLシャットダウン
            OSD_Finish();			// 終了処理
            if( Cfg ) delete Cfg;	// 環境設定オブジェクト開放
            return FALSE;
        }
    }

    // フォントファイルが無ければ作成する
    if( !OSD_FileExist( Cfg->GetFontFileH() ) ) OSD_CreateFont( Cfg->GetFontFileH(), NULL, FSIZE );
    if( !OSD_FileExist( Cfg->GetFontFileZ() ) ) OSD_CreateFont( NULL, Cfg->GetFontFileZ(), FSIZE );

    // P6オブジェクトを作成して実行
    do{
        Restart = VM6::Quit;

        // ROMファイル存在チェック&機種変更
        char RomSerch[PATH_MAX];
        int IniModel = Cfg->GetModel();
        sprintf( RomSerch, "%s*.%2d", Cfg->GetRomPath(), IniModel );
        if( !OSD_FileExist( RomSerch ) ){
            int models[] = { 60, 62, 66 };
            for( int i=0; i < COUNTOF(models); i++ ){
                sprintf( RomSerch, "%s*.%2d", Cfg->GetRomPath(), models[i] );
                if( OSD_FileExist( RomSerch ) ){
                    Cfg->SetModel( models[i] );
                    break;
                }
            }
            // ROMある?
            if( IniModel != Cfg->GetModel() ){
                Error::SetError( Error::RomChange );
                OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDR_OK | OSDM_ICONWARNING );
                Error::SetError( Error::NoError );
            }
        }

        // 機種別P6オブジェクト確保
        const char* iconRes = NULL;
        switch( Cfg->GetModel() ){
        case 62: P6Core = new VM62; iconRes = ":/res/PC-6001mk2.ico"; break;
        case 66: P6Core = new VM66; iconRes = ":/res/PC-6601.ico"; break;
        default: P6Core = new VM60; iconRes = ":/res/PC-6001.ico";
        }

        // アイコン設定
        QImage icon(iconRes);
        SDL_Surface *p6icon = SDL_CreateRGBSurfaceFrom( icon.bits(), icon.width(), icon.height(), icon.depth(), icon.bytesPerLine(), 0, 0, 0, 0 );
        SDL_WM_SetIcon( p6icon, icon.alphaChannel().bits() );
        SDL_FreeSurface( p6icon );

        // VMを初期化して実行
        if( P6Core->Init( Cfg ) ){
            switch( Restart ){
            case VM6::Doko:		// どこでもLOAD?
                P6Core->DokoDemoLoad( Cfg->GetDokoFile() );
                break;

            case VM6::Replay:	// リプレイ再生?
            {
                char temp[PATH_MAX];
                strncpy( temp, Cfg->GetDokoFile(), PATH_MAX );
                P6Core->DokoDemoLoad( temp );
                P6Core->REPLAY::StartReplay( temp );
            }
            break;

            default:
                break;
            }

            P6Core->Start();
            Restart = P6Core->EventLoop();
            P6Core->Stop();
        }else{
            // 失敗した場合
            OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDR_OK | OSDM_ICONERROR );
        }

        // P6オブジェクトを開放
        if( P6Core ) delete P6Core;

        // 再起動ならばINIファイル再読込み
        if( Restart == VM6::Restart ){
            if( !Cfg->Init() ){
                Error::SetError( Error::IniDefault );
                OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDR_OK | OSDM_ICONWARNING );
                Error::SetError( Error::NoError );
            }
        }

    }while( Restart != VM6::Quit );

    // 環境設定オブジェクト開放
    if( Cfg ) delete Cfg;

    // SDLシャットダウン
    SDL_Quit();

    // 終了処理
    OSD_Finish();

    return TRUE;
}
<|endoftext|>


<commit_before>#include "SkipStages.h"
#include "IRMutator.h"
#include "IRPrinter.h"
#include "IROperator.h"
#include "Scope.h"
#include "Simplify.h"
#include "Substitute.h"

namespace Halide {
namespace Internal {

using std::string;
using std::vector;

class PredicateFinder : public IRVisitor {
public:
    Expr predicate;
    PredicateFinder(const string &b) : predicate(const_false()), buffer(b), varies(false) {}

private:

    using IRVisitor::visit;
    string buffer;
    bool varies;
    Scope<int> varying;

    void visit(const Variable *op) {
        bool this_varies = varying.contains(op->name);
        varies |= this_varies;
    }

    void visit(const For *op) {
        op->min.accept(this);
        op->extent.accept(this);
        if (!is_one(op->extent)) {
            varying.push(op->name, 0);
        }
        op->body.accept(this);
        if (!is_one(op->extent)) {
            varying.pop(op->name);
        } else {
            predicate = substitute(op->name, op->min, predicate);
        }
    }

    template<typename T>
    void visit_let(const std::string &name, Expr value, T body) {
        bool old_varies = varies;
        varies = false;
        value.accept(this);
        bool value_varies = varies;
        varies |= old_varies;
        if (value_varies) {
            varying.push(name, 0);
        }
        body.accept(this);
        if (value_varies) {
            varying.pop(name);
        }
        predicate = substitute(name, value, predicate);
    }

    void visit(const LetStmt *op) {
        visit_let(op->name, op->value, op->body);
    }

    void visit(const Let *op) {
        visit_let(op->name, op->value, op->body);
    }

    void visit(const Pipeline *op) {
        if (op->name != buffer) {
            op->produce.accept(this);
            if (op->update.defined()) {
                op->update.accept(this);
            }
        }
        op->consume.accept(this);
    }

    template<typename T>
    void visit_conditional(Expr condition, T true_case, T false_case) {
        Expr old_predicate = predicate;

        predicate = const_false();
        true_case.accept(this);
        Expr true_predicate = predicate;

        predicate = const_false();
        if (false_case.defined()) false_case.accept(this);
        Expr false_predicate = predicate;

        bool old_varies = varies;
        predicate = const_false();
        varies = false;
        condition.accept(this);

        if (is_one(predicate) || is_one(old_predicate)) {
            predicate = const_true();
        } else if (varies) {
            if (is_one(true_predicate) || is_one(false_predicate)) {
                predicate = const_true();
            } else {
                predicate = (old_predicate || predicate ||
                             true_predicate || false_predicate);
            }
        } else {
            predicate = (old_predicate || predicate ||
                         (condition && true_predicate) ||
                         ((!condition) && false_predicate));
        }

        varies = varies || old_varies;
    }

    void visit(const Select *op) {
        visit_conditional(op->condition, op->true_value, op->false_value);
    }

    void visit(const IfThenElse *op) {
        visit_conditional(op->condition, op->then_case, op->else_case);
    }

    void visit(const Call *op) {
        IRVisitor::visit(op);

        if (op->name == buffer) {
            predicate = const_true();
        }
    }
};

class ProductionGuarder : public IRMutator {
public:
    ProductionGuarder(const string &b, Expr p): buffer(b), predicate(p) {}
private:
    string buffer;
    Expr predicate;

    using IRMutator::visit;

    void visit(const Pipeline *op) {
        if (op->name == buffer) {
            Stmt produce = op->produce, update = op->update;
            if (update.defined()) {
                Expr predicate_var = Variable::make(Bool(), buffer + ".needed");
                Stmt produce = IfThenElse::make(predicate_var, op->produce);
                Stmt update = IfThenElse::make(predicate_var, op->update);
                stmt = Pipeline::make(op->name, produce, update, op->consume);
                stmt = LetStmt::make(buffer + ".needed", predicate, stmt);
            } else {
                Stmt produce = IfThenElse::make(predicate, op->produce);
                stmt = Pipeline::make(op->name, produce, Stmt(), op->consume);
            }

        } else {
            IRMutator::visit(op);
        }
    }
};

class StageSkipper : public IRMutator {
public:
    StageSkipper(const string &f) : func(f) {}
private:
    string func;
    using IRMutator::visit;

    void visit(const Realize *op) {
        if (op->name == func) {
            PredicateFinder f(op->name);
            op->body.accept(&f);
            Expr predicate = simplify(f.predicate);
            debug(3) << "Realization " << op->name << " only used when " << predicate << "\n";
            if (!is_one(predicate)) {
                ProductionGuarder g(op->name, predicate);
                Stmt body = g.mutate(op->body);
                // In the future we may be able to shrink the size
                // opdated, but right now those values may be
                // loaded. They can be incorrect, but they must be
                // loadable. Perhaps we can mmap some readable junk memory
                // (e.g. lots of pages of /dev/zero).
                stmt = Realize::make(op->name, op->types, op->bounds, body);
            } else {
                IRMutator::visit(op);
            }
        } else {
            IRMutator::visit(op);
        }
    }
};

Stmt skip_stages(Stmt stmt, const vector<string> &order) {
    for (size_t i = order.size()-1; i > 0; i--) {
        StageSkipper skipper(order[i-1]);
        stmt = skipper.mutate(stmt);
    }
    return stmt;
}

}
}
<commit_msg>Added an early-out to skip-stages to speed it up<commit_after>#include "SkipStages.h"
#include "IRMutator.h"
#include "IRPrinter.h"
#include "IROperator.h"
#include "Scope.h"
#include "Simplify.h"
#include "Substitute.h"

namespace Halide {
namespace Internal {

using std::string;
using std::vector;
using std::map;

class PredicateFinder : public IRVisitor {
public:
    Expr predicate;
    PredicateFinder(const string &b) : predicate(const_false()), buffer(b), varies(false) {}

private:

    using IRVisitor::visit;
    string buffer;
    bool varies;
    Scope<int> varying;

    void visit(const Variable *op) {
        bool this_varies = varying.contains(op->name);
        varies |= this_varies;
    }

    void visit(const For *op) {
        op->min.accept(this);
        op->extent.accept(this);
        if (!is_one(op->extent)) {
            varying.push(op->name, 0);
        }
        op->body.accept(this);
        if (!is_one(op->extent)) {
            varying.pop(op->name);
        } else {
            predicate = substitute(op->name, op->min, predicate);
        }
    }

    template<typename T>
    void visit_let(const std::string &name, Expr value, T body) {
        bool old_varies = varies;
        varies = false;
        value.accept(this);
        bool value_varies = varies;
        varies |= old_varies;
        if (value_varies) {
            varying.push(name, 0);
        }
        body.accept(this);
        if (value_varies) {
            varying.pop(name);
        }
        predicate = substitute(name, value, predicate);
    }

    void visit(const LetStmt *op) {
        visit_let(op->name, op->value, op->body);
    }

    void visit(const Let *op) {
        visit_let(op->name, op->value, op->body);
    }

    void visit(const Pipeline *op) {
        if (op->name != buffer) {
            op->produce.accept(this);
            if (op->update.defined()) {
                op->update.accept(this);
            }
        }
        op->consume.accept(this);
    }

    template<typename T>
    void visit_conditional(Expr condition, T true_case, T false_case) {
        Expr old_predicate = predicate;

        predicate = const_false();
        true_case.accept(this);
        Expr true_predicate = predicate;

        predicate = const_false();
        if (false_case.defined()) false_case.accept(this);
        Expr false_predicate = predicate;

        bool old_varies = varies;
        predicate = const_false();
        varies = false;
        condition.accept(this);

        if (is_one(predicate) || is_one(old_predicate)) {
            predicate = const_true();
        } else if (varies) {
            if (is_one(true_predicate) || is_one(false_predicate)) {
                predicate = const_true();
            } else {
                predicate = (old_predicate || predicate ||
                             true_predicate || false_predicate);
            }
        } else {
            predicate = (old_predicate || predicate ||
                         (condition && true_predicate) ||
                         ((!condition) && false_predicate));
        }

        varies = varies || old_varies;
    }

    void visit(const Select *op) {
        visit_conditional(op->condition, op->true_value, op->false_value);
    }

    void visit(const IfThenElse *op) {
        visit_conditional(op->condition, op->then_case, op->else_case);
    }

    void visit(const Call *op) {
        IRVisitor::visit(op);

        if (op->name == buffer) {
            predicate = const_true();
        }
    }
};

class ProductionGuarder : public IRMutator {
public:
    ProductionGuarder(const string &b, Expr p): buffer(b), predicate(p) {}
private:
    string buffer;
    Expr predicate;

    using IRMutator::visit;

    void visit(const Pipeline *op) {
        if (op->name == buffer) {
            Stmt produce = op->produce, update = op->update;
            if (update.defined()) {
                Expr predicate_var = Variable::make(Bool(), buffer + ".needed");
                Stmt produce = IfThenElse::make(predicate_var, op->produce);
                Stmt update = IfThenElse::make(predicate_var, op->update);
                stmt = Pipeline::make(op->name, produce, update, op->consume);
                stmt = LetStmt::make(buffer + ".needed", predicate, stmt);
            } else {
                Stmt produce = IfThenElse::make(predicate, op->produce);
                stmt = Pipeline::make(op->name, produce, Stmt(), op->consume);
            }

        } else {
            IRMutator::visit(op);
        }
    }
};

class StageSkipper : public IRMutator {
public:
    StageSkipper(const string &f) : func(f) {}
private:
    string func;
    using IRMutator::visit;

    void visit(const Realize *op) {
        if (op->name == func) {
            PredicateFinder f(op->name);
            op->body.accept(&f);
            Expr predicate = simplify(f.predicate);
            debug(3) << "Realization " << op->name << " only used when " << predicate << "\n";
            if (!is_one(predicate)) {
                ProductionGuarder g(op->name, predicate);
                Stmt body = g.mutate(op->body);
                // In the future we may be able to shrink the size
                // updated, but right now those values may be
                // loaded. They can be incorrect, but they must be
                // loadable. Perhaps we can mmap some readable junk memory
                // (e.g. lots of pages of /dev/zero).
                stmt = Realize::make(op->name, op->types, op->bounds, body);
            } else {
                IRMutator::visit(op);
            }
        } else {
            IRMutator::visit(op);
        }
    }
};

// Check if all calls to a given function are behind an if of some
// sort (but don't worry about what it is).
class MightBeSkippable : public IRVisitor {

    using IRVisitor::visit;

    void visit(const Call *op) {
        IRVisitor::visit(op);
        if (op->name == func) {
            if (!found_call) {
                result = guarded;
                found_call = true;
            } else {
                result &= guarded;
            }
        }
    }

    void visit(const IfThenElse *op) {
        op->condition.accept(this);

        bool old = guarded;
        guarded = true;

        op->then_case.accept(this);
        if (op->else_case.defined()) {
            op->else_case.accept(this);
        }

        guarded = old;
    }

    void visit(const Select *op) {
        op->condition.accept(this);

        bool old = guarded;
        guarded = true;

        op->true_value.accept(this);
        op->false_value.accept(this);

        guarded = old;
    }

    void visit(const Realize *op) {
        if (op->name == func) {
            guarded = false;
        }
        IRVisitor::visit(op);
    }

    string func;
    bool guarded;

public:
    bool result;
    bool found_call;

    MightBeSkippable(string f) : func(f), result(false), found_call(false) {}
};

Stmt skip_stages(Stmt stmt, const vector<string> &order) {
    for (size_t i = order.size()-1; i > 0; i--) {
        MightBeSkippable check(order[i-1]);
        stmt.accept(&check);
        if (check.result) {
            StageSkipper skipper(order[i-1]);
            stmt = skipper.mutate(stmt);
        }
    }
    return stmt;
}

}
}
<|endoftext|>


<commit_before>#include <fstream>
#include <cassert>
#include <string>

#include <TextOutput.h>

void TextOutput::format(Playlist &playlist)
{
  file.open("resultat.txt", std::ofstream::out | std::ofstream::app);
  assert(file.is_open());

  for(Playlist::iterator i = Playlist.begin(); i != Playlist.end(); i++)
  {
  	file << *i.getTitle() << " - " << *i.getContextData().getArtist().getName()
  		<< "(" << *i.getContextData().getAlbum().getReleaseDate() << ")" << endl;
	}
	file.close();
}<commit_msg>modification de TextOutput.cpp<commit_after>#include <fstream>
#include <cassert>
#include <string>

#include <TextOutput.h>

void TextOutput::format(Playlist &playlist)
{
  file.open("resultat.txt", std::ofstream::out | std::ofstream::app);
  assert(file.is_open());

  for(auto i = Playlist.begin(); i != Playlist.end(); i++)
  {
  	file << *i.getTitle() << " - " << *i.getContextData().getArtist().getName()
  		<< "(" << *i.getContextData().getAlbum().getName() << " - " <<
  		*i.getContextData().getAlbum().getReleaseDate() << ")" << endl;
	}
	file.close();
}<|endoftext|>


<commit_before>// This file was developed by Thomas Müller <thomas94@gmx.net>.
// It is published under the BSD 3-Clause License within the LICENSE file.

#include <tev/FalseColor.h>
#include <tev/UberShader.h>

using namespace Eigen;
using namespace nanogui;
using namespace std;

TEV_NAMESPACE_BEGIN

UberShader::UberShader()
: mColorMap{GL_CLAMP_TO_EDGE, GL_LINEAR, false} {
    mShader.define("SRGB",        to_string(ETonemap::SRGB));
    mShader.define("GAMMA",       to_string(ETonemap::Gamma));
    mShader.define("FALSE_COLOR", to_string(ETonemap::FalseColor));
    mShader.define("POS_NEG",     to_string(ETonemap::PositiveNegative));

    mShader.define("ERROR",                   to_string(EMetric::Error));
    mShader.define("ABSOLUTE_ERROR",          to_string(EMetric::AbsoluteError));
    mShader.define("SQUARED_ERROR",           to_string(EMetric::SquaredError));
    mShader.define("RELATIVE_ABSOLUTE_ERROR", to_string(EMetric::RelativeAbsoluteError));
    mShader.define("RELATIVE_SQUARED_ERROR",  to_string(EMetric::RelativeSquaredError));

    mShader.init(
        "ubershader",

        // Vertex shader
        R"(#version 330

        uniform vec2 pixelSize;
        uniform vec2 checkerSize;

        uniform mat3 imageTransform;
        uniform mat3 referenceTransform;

        in vec2 position;

        out vec2 checkerUv;
        out vec2 imageUv;
        out vec2 referenceUv;

        void main() {
            checkerUv = position / (pixelSize * checkerSize);
            imageUv = (imageTransform * vec3(position, 1.0)).xy;
            referenceUv = (referenceTransform * vec3(position, 1.0)).xy;

            gl_Position = vec4(position, 1.0, 1.0);
        })",

        // Fragment shader
        R"(#version 330

        uniform sampler2D image;
        uniform bool hasImage;

        uniform sampler2D reference;
        uniform bool hasReference;

        uniform sampler2D colormap;

        uniform float exposure;
        uniform float offset;
        uniform int tonemap;
        uniform int metric;

        uniform vec4 bgColor;

        in vec2 checkerUv;
        in vec2 imageUv;
        in vec2 referenceUv;

        out vec4 color;

        float average(vec3 col) {
            return (col.r + col.g + col.b) / 3.0;
        }

        vec3 applyExposureAndOffset(vec3 col) {
            return pow(2.0, exposure) * col + offset;
        }

        vec3 falseColor(float v) {
            v = clamp(v, 0.0, 1.0);
            return texture(colormap, vec2(v, 0.5)).rgb;
        }

        float sRGB(float linear) {
            if (linear > 1.0) {
                return 1.0;
            } else if (linear < 0.0) {
                return 0.0;
            } else if (linear < 0.0031308) {
                return 12.92 * linear;
            } else {
                return 1.055 * pow(linear, 0.41666) - 0.055;
            }
        }

        vec3 applyTonemap(vec3 col) {
            switch (tonemap) {
                case SRGB:        return vec3(sRGB(col.r), sRGB(col.g), sRGB(col.b));
                case GAMMA:       return pow(col, vec3(1.0 / 2.2));
                // Here grayscale is compressed such that the darkest color is is 1/1024th as bright as the brightest color.
                case FALSE_COLOR: return falseColor(log2(average(col)) / 10.0 + 0.5);
                case POS_NEG:     return vec3(-average(min(col, vec3(0.0))) * 2.0, average(max(col, vec3(0.0))) * 2.0, 0.0);
            }
            return vec3(0.0);
        }

        vec3 applyMetric(vec3 col, vec3 reference) {
            switch (metric) {
                case ERROR:                   return col;
                case ABSOLUTE_ERROR:          return abs(col);
                case SQUARED_ERROR:           return col * col;
                case RELATIVE_ABSOLUTE_ERROR: return abs(col) / (reference + vec3(0.01));
                case RELATIVE_SQUARED_ERROR:  return col * col / (reference * reference + vec3(0.01));
            }
            return vec3(0.0);
        }

        vec4 sample(sampler2D sampler, vec2 uv) {
            if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) {
                return vec4(0.0);
            }
            return texture(sampler, uv);
        }

        void main() {
            vec3 darkGray = vec3(0.5, 0.5, 0.5);
            vec3 lightGray = vec3(0.55, 0.55, 0.55);

            vec3 checker = mod(int(floor(checkerUv.x) + floor(checkerUv.y)), 2) == 0 ? darkGray : lightGray;
            checker = bgColor.rgb * bgColor.a + checker * (1.0 - bgColor.a);
            if (!hasImage) {
                color = vec4(checker, 1.0);
                return;
            }

            vec4 imageVal = sample(image, imageUv);
            if (!hasReference) {
                color = vec4(
                    applyTonemap(applyExposureAndOffset(imageVal.rgb)) * imageVal.a +
                    checker * (1.0 - imageVal.a),
                    1.0
                );
                return;
            }

            vec4 referenceVal = sample(reference, referenceUv);

            vec3 difference = imageVal.rgb - referenceVal.rgb;
            float alpha = (imageVal.a + referenceVal.a) * 0.5;
            color = vec4(
                applyTonemap(applyExposureAndOffset(applyMetric(difference, referenceVal.rgb))) * alpha +
                checker * (1.0 - alpha),
                1.0
            );
        })"
    );

    // 2 Triangles
    MatrixXu indices(3, 2);
    indices.col(0) << 0, 1, 2;
    indices.col(1) << 2, 3, 0;

    MatrixXf positions(2, 4);
    positions.col(0) << -1, -1;
    positions.col(1) <<  1, -1;
    positions.col(2) <<  1,  1;
    positions.col(3) << -1,  1;

    mShader.bind();
    mShader.uploadIndices(indices);
    mShader.uploadAttrib("position", positions);

    const auto& fcd = falseColorData();
    mColorMap.setData(fcd, Vector2i{(int)fcd.size() / 4, 1}, 4);
}

UberShader::~UberShader() {
    mShader.free();
}

void UberShader::draw(const Vector2f& pixelSize, const Vector2f& checkerSize) {
    mShader.bind();
    bindCheckerboardData(pixelSize, checkerSize);
    mShader.setUniform("hasImage", false);
    mShader.setUniform("hasReference", false);
    mShader.drawIndexed(GL_TRIANGLES, 0, 2);
}

void UberShader::draw(
    const Vector2f& pixelSize,
    const Vector2f& checkerSize,
    const GlTexture* textureImage,
    const Matrix3f& transformImage,
    float exposure,
    float offset,
    ETonemap tonemap
) {
    mShader.bind();
    bindCheckerboardData(pixelSize, checkerSize);
    bindImageData(textureImage, transformImage, exposure, offset, tonemap);
    mShader.setUniform("hasImage", true);
    mShader.setUniform("hasReference", false);
    mShader.setUniform("bgColor", mBackgroundColor);
    mShader.drawIndexed(GL_TRIANGLES, 0, 2);
}

void UberShader::draw(
    const Vector2f& pixelSize,
    const Vector2f& checkerSize,
    const GlTexture* textureImage,
    const Matrix3f& transformImage,
    const GlTexture* textureReference,
    const Matrix3f& transformReference,
    float exposure,
    float offset,
    ETonemap tonemap,
    EMetric metric
) {
    mShader.bind();
    bindCheckerboardData(pixelSize, checkerSize);
    bindImageData(textureImage, transformImage, exposure, offset, tonemap);
    bindReferenceData(textureReference, transformReference, metric);
    mShader.setUniform("hasImage", true);
    mShader.setUniform("hasReference", true);
    mShader.drawIndexed(GL_TRIANGLES, 0, 2);
}

void UberShader::bindCheckerboardData(const Vector2f& pixelSize, const Vector2f& checkerSize) {
    mShader.setUniform("pixelSize", pixelSize);
    mShader.setUniform("checkerSize", checkerSize);
}

void UberShader::bindImageData(
    const GlTexture* textureImage,
    const Matrix3f& transformImage,
    float exposure,
    float offset,
    ETonemap tonemap
) {
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, textureImage->id());

    mShader.bind();
    mShader.setUniform("image", 0);
    mShader.setUniform("imageTransform", transformImage);

    mShader.setUniform("exposure", exposure);
    mShader.setUniform("offset", offset);
    mShader.setUniform("tonemap", static_cast<int>(tonemap));

    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_2D, mColorMap.id());
    mShader.setUniform("colormap", 2);
}

void UberShader::bindReferenceData(
    const GlTexture* textureReference,
    const Matrix3f& transformReference,
    EMetric metric
) {
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, textureReference->id());

    mShader.setUniform("reference", 1);
    mShader.setUniform("referenceTransform", transformReference);

    mShader.setUniform("metric", static_cast<int>(metric));
}

TEV_NAMESPACE_END
<commit_msg>Fix background color not always being updated correctly<commit_after>// This file was developed by Thomas Müller <thomas94@gmx.net>.
// It is published under the BSD 3-Clause License within the LICENSE file.

#include <tev/FalseColor.h>
#include <tev/UberShader.h>

using namespace Eigen;
using namespace nanogui;
using namespace std;

TEV_NAMESPACE_BEGIN

UberShader::UberShader()
: mColorMap{GL_CLAMP_TO_EDGE, GL_LINEAR, false} {
    mShader.define("SRGB",        to_string(ETonemap::SRGB));
    mShader.define("GAMMA",       to_string(ETonemap::Gamma));
    mShader.define("FALSE_COLOR", to_string(ETonemap::FalseColor));
    mShader.define("POS_NEG",     to_string(ETonemap::PositiveNegative));

    mShader.define("ERROR",                   to_string(EMetric::Error));
    mShader.define("ABSOLUTE_ERROR",          to_string(EMetric::AbsoluteError));
    mShader.define("SQUARED_ERROR",           to_string(EMetric::SquaredError));
    mShader.define("RELATIVE_ABSOLUTE_ERROR", to_string(EMetric::RelativeAbsoluteError));
    mShader.define("RELATIVE_SQUARED_ERROR",  to_string(EMetric::RelativeSquaredError));

    mShader.init(
        "ubershader",

        // Vertex shader
        R"(#version 330

        uniform vec2 pixelSize;
        uniform vec2 checkerSize;

        uniform mat3 imageTransform;
        uniform mat3 referenceTransform;

        in vec2 position;

        out vec2 checkerUv;
        out vec2 imageUv;
        out vec2 referenceUv;

        void main() {
            checkerUv = position / (pixelSize * checkerSize);
            imageUv = (imageTransform * vec3(position, 1.0)).xy;
            referenceUv = (referenceTransform * vec3(position, 1.0)).xy;

            gl_Position = vec4(position, 1.0, 1.0);
        })",

        // Fragment shader
        R"(#version 330

        uniform sampler2D image;
        uniform bool hasImage;

        uniform sampler2D reference;
        uniform bool hasReference;

        uniform sampler2D colormap;

        uniform float exposure;
        uniform float offset;
        uniform int tonemap;
        uniform int metric;

        uniform vec4 bgColor;

        in vec2 checkerUv;
        in vec2 imageUv;
        in vec2 referenceUv;

        out vec4 color;

        float average(vec3 col) {
            return (col.r + col.g + col.b) / 3.0;
        }

        vec3 applyExposureAndOffset(vec3 col) {
            return pow(2.0, exposure) * col + offset;
        }

        vec3 falseColor(float v) {
            v = clamp(v, 0.0, 1.0);
            return texture(colormap, vec2(v, 0.5)).rgb;
        }

        float sRGB(float linear) {
            if (linear > 1.0) {
                return 1.0;
            } else if (linear < 0.0) {
                return 0.0;
            } else if (linear < 0.0031308) {
                return 12.92 * linear;
            } else {
                return 1.055 * pow(linear, 0.41666) - 0.055;
            }
        }

        vec3 applyTonemap(vec3 col) {
            switch (tonemap) {
                case SRGB:        return vec3(sRGB(col.r), sRGB(col.g), sRGB(col.b));
                case GAMMA:       return pow(col, vec3(1.0 / 2.2));
                // Here grayscale is compressed such that the darkest color is is 1/1024th as bright as the brightest color.
                case FALSE_COLOR: return falseColor(log2(average(col)) / 10.0 + 0.5);
                case POS_NEG:     return vec3(-average(min(col, vec3(0.0))) * 2.0, average(max(col, vec3(0.0))) * 2.0, 0.0);
            }
            return vec3(0.0);
        }

        vec3 applyMetric(vec3 col, vec3 reference) {
            switch (metric) {
                case ERROR:                   return col;
                case ABSOLUTE_ERROR:          return abs(col);
                case SQUARED_ERROR:           return col * col;
                case RELATIVE_ABSOLUTE_ERROR: return abs(col) / (reference + vec3(0.01));
                case RELATIVE_SQUARED_ERROR:  return col * col / (reference * reference + vec3(0.01));
            }
            return vec3(0.0);
        }

        vec4 sample(sampler2D sampler, vec2 uv) {
            if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) {
                return vec4(0.0);
            }
            return texture(sampler, uv);
        }

        void main() {
            vec3 darkGray = vec3(0.5, 0.5, 0.5);
            vec3 lightGray = vec3(0.55, 0.55, 0.55);

            vec3 checker = mod(int(floor(checkerUv.x) + floor(checkerUv.y)), 2) == 0 ? darkGray : lightGray;
            checker = bgColor.rgb * bgColor.a + checker * (1.0 - bgColor.a);
            if (!hasImage) {
                color = vec4(checker, 1.0);
                return;
            }

            vec4 imageVal = sample(image, imageUv);
            if (!hasReference) {
                color = vec4(
                    applyTonemap(applyExposureAndOffset(imageVal.rgb)) * imageVal.a +
                    checker * (1.0 - imageVal.a),
                    1.0
                );
                return;
            }

            vec4 referenceVal = sample(reference, referenceUv);

            vec3 difference = imageVal.rgb - referenceVal.rgb;
            float alpha = (imageVal.a + referenceVal.a) * 0.5;
            color = vec4(
                applyTonemap(applyExposureAndOffset(applyMetric(difference, referenceVal.rgb))) * alpha +
                checker * (1.0 - alpha),
                1.0
            );
        })"
    );

    // 2 Triangles
    MatrixXu indices(3, 2);
    indices.col(0) << 0, 1, 2;
    indices.col(1) << 2, 3, 0;

    MatrixXf positions(2, 4);
    positions.col(0) << -1, -1;
    positions.col(1) <<  1, -1;
    positions.col(2) <<  1,  1;
    positions.col(3) << -1,  1;

    mShader.bind();
    mShader.uploadIndices(indices);
    mShader.uploadAttrib("position", positions);

    const auto& fcd = falseColorData();
    mColorMap.setData(fcd, Vector2i{(int)fcd.size() / 4, 1}, 4);
}

UberShader::~UberShader() {
    mShader.free();
}

void UberShader::draw(const Vector2f& pixelSize, const Vector2f& checkerSize) {
    mShader.bind();
    bindCheckerboardData(pixelSize, checkerSize);
    mShader.setUniform("hasImage", false);
    mShader.setUniform("hasReference", false);
    mShader.drawIndexed(GL_TRIANGLES, 0, 2);
}

void UberShader::draw(
    const Vector2f& pixelSize,
    const Vector2f& checkerSize,
    const GlTexture* textureImage,
    const Matrix3f& transformImage,
    float exposure,
    float offset,
    ETonemap tonemap
) {
    mShader.bind();
    bindCheckerboardData(pixelSize, checkerSize);
    bindImageData(textureImage, transformImage, exposure, offset, tonemap);
    mShader.setUniform("hasImage", true);
    mShader.setUniform("hasReference", false);
    mShader.drawIndexed(GL_TRIANGLES, 0, 2);
}

void UberShader::draw(
    const Vector2f& pixelSize,
    const Vector2f& checkerSize,
    const GlTexture* textureImage,
    const Matrix3f& transformImage,
    const GlTexture* textureReference,
    const Matrix3f& transformReference,
    float exposure,
    float offset,
    ETonemap tonemap,
    EMetric metric
) {
    mShader.bind();
    bindCheckerboardData(pixelSize, checkerSize);
    bindImageData(textureImage, transformImage, exposure, offset, tonemap);
    bindReferenceData(textureReference, transformReference, metric);
    mShader.setUniform("hasImage", true);
    mShader.setUniform("hasReference", true);
    mShader.drawIndexed(GL_TRIANGLES, 0, 2);
}

void UberShader::bindCheckerboardData(const Vector2f& pixelSize, const Vector2f& checkerSize) {
    mShader.setUniform("pixelSize", pixelSize);
    mShader.setUniform("checkerSize", checkerSize);
    mShader.setUniform("bgColor", mBackgroundColor);
}

void UberShader::bindImageData(
    const GlTexture* textureImage,
    const Matrix3f& transformImage,
    float exposure,
    float offset,
    ETonemap tonemap
) {
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, textureImage->id());

    mShader.bind();
    mShader.setUniform("image", 0);
    mShader.setUniform("imageTransform", transformImage);

    mShader.setUniform("exposure", exposure);
    mShader.setUniform("offset", offset);
    mShader.setUniform("tonemap", static_cast<int>(tonemap));

    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_2D, mColorMap.id());
    mShader.setUniform("colormap", 2);
}

void UberShader::bindReferenceData(
    const GlTexture* textureReference,
    const Matrix3f& transformReference,
    EMetric metric
) {
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, textureReference->id());

    mShader.setUniform("reference", 1);
    mShader.setUniform("referenceTransform", transformReference);

    mShader.setUniform("metric", static_cast<int>(metric));
}

TEV_NAMESPACE_END
<|endoftext|>


<commit_before>/*
   VanCittert.cxx

   Author:      Benjamin A. Thomas

   Copyright 2015 Institute of Nuclear Medicine, University College London.

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

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

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

   This program implements the reblurred Van-Cittert (RVC) partial volume correction
   technique. Please cite the following paper:

	Tohka, J. and Reilhac A., (2008). "Deconvolution-based partial volume
	correction in Raclopride-PET and Monte Carlo comparison to MR-based
	method", NeuroImage, vol. 39. 1570--1584.

 */

#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include <metaCommand.h>

#include "petpvcVanCittertPVCImageFilter.h"

const char * const VERSION_NO = "0.0.1";
const char * const AUTHOR = "Benjamin A. Thomas";
const char * const APP_TITLE = "Reblurred Van-Cittert (RVC)";

typedef itk::Vector<float, 3> VectorType;
typedef itk::Image<float, 3> PETImageType;

typedef itk::ImageFileReader<PETImageType> PETReaderType;
typedef itk::ImageFileWriter<PETImageType> PETWriterType;

//Produces the text for the acknowledgments dialog in Slicer.
std::string getAcknowledgments(void);

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

    typedef petpvc::VanCittertPVCImageFilter< PETImageType >  FilterType;

    //Setting up command line argument list.
    MetaCommand command;

    command.SetVersion(VERSION_NO);
    command.SetAuthor(AUTHOR);
    command.SetName(APP_TITLE);
    command.SetDescription(
        "Performs reblurred Van-Cittert (RVC) partial volume correction");

    std::string sAcks = getAcknowledgments();
    command.SetAcknowledgments(sAcks.c_str());

    command.SetCategory("PETPVC");

    command.AddField("petfile", "PET filename", MetaCommand::IMAGE, MetaCommand::DATA_IN);
    command.AddField("outputfile", "output filename", MetaCommand::IMAGE, MetaCommand::DATA_OUT);

    command.SetOption("FWHMx", "x", true,
                      "The full-width at half maximum in mm along x-axis");
    command.AddOptionField("FWHMx", "X", MetaCommand::FLOAT, true, "");

    command.SetOption("FWHMy", "y", true,
                      "The full-width at half maximum in mm along y-axis");
    command.AddOptionField("FWHMy", "Y", MetaCommand::FLOAT, true, "");

    command.SetOption("FWHMz", "z", true,
                      "The full-width at half maximum in mm along z-axis");
    command.AddOptionField("FWHMz", "Z", MetaCommand::FLOAT, true, "");

    command.SetOption("Iterations", "i", false, "Number of iterations");
    command.SetOptionLongTag("Iterations", "iter");
    command.AddOptionField("Iterations", "Val", MetaCommand::INT, false, "30");

    command.SetOption("Alpha", "a", false, "Alpha value");
    command.SetOptionLongTag("Alpha", "alpha");
    command.AddOptionField("Alpha", "aval", MetaCommand::FLOAT, false, "1.5");

    command.SetOption("Stop", "s", false, "Stopping criterion");
    command.SetOptionLongTag("Stop", "stop");
    command.AddOptionField("Stop", "stopval", MetaCommand::FLOAT, false, "0.01");

    command.SetOption("debug", "d", false,"Prints debug information");
    command.SetOptionLongTag("debug", "debug");

    //Parse command line.
    if (!command.Parse(argc, argv)) {
        return EXIT_FAILURE;
    }

    //Get image filenames
    std::string sPETFileName = command.GetValueAsString("petfile");
    std::string sOutputFileName = command.GetValueAsString("outputfile");

    //Get values for PSF.
    float fFWHM_x = command.GetValueAsFloat("FWHMx", "X");
    float fFWHM_y = command.GetValueAsFloat("FWHMy", "Y");
    float fFWHM_z = command.GetValueAsFloat("FWHMz", "Z");

    //Get number of iterations
    int nNumOfIters = command.GetValueAsInt("Iterations", "Val");

    //Get value for alpha.
    float fAlpha = command.GetValueAsFloat("Alpha", "aval");

    //Get value for stopping criterion.
    float fStop = command.GetValueAsFloat("Stop", "stopval");

    //Make vector of FWHM in x,y and z.
    VectorType vFWHM;
    vFWHM[0] = fFWHM_x;
    vFWHM[1] = fFWHM_y;
    vFWHM[2] = fFWHM_z;

    //Toggle debug mode
    bool bDebug = command.GetValueAsBool("debug");

    //Create reader for PET image.
    PETReaderType::Pointer petReader = PETReaderType::New();
    petReader->SetFileName(sPETFileName);

    //Try to read PET.
    try {
        petReader->Update();
    } catch (itk::ExceptionObject & err) {
        std::cerr << "[Error]\tCannot read PET input file: " << sPETFileName
                  << std::endl;
        return EXIT_FAILURE;
    }

    //Calculate the variance for a given FWHM.
    VectorType vVariance;
    vVariance = vFWHM / (2.0 * sqrt(2.0 * log(2.0)));
    //std::cout << vVariance << std::endl;

    VectorType vVoxelSize = petReader->GetOutput()->GetSpacing();
    //std::cout << vVoxelSize << std::endl;

    vVariance[0] = pow(vVariance[0], 2);
    vVariance[1] = pow(vVariance[1], 2);
    vVariance[2] = pow(vVariance[2], 2);

    FilterType::Pointer vcFilter = FilterType::New();
    vcFilter->SetInput( petReader->GetOutput() );
    vcFilter->SetPSF(vVariance);
    vcFilter->SetIterations( nNumOfIters );
	vcFilter->SetAlpha( fAlpha );
    vcFilter->SetStoppingCond( fStop );
    vcFilter->SetVerbose ( bDebug );

    //Perform VC.
    try {
        vcFilter->Update();
    } catch (itk::ExceptionObject & err) {
        std::cerr << "[Error]\tfailure applying Van Cittert on: " << sPETFileName
                  << "\n" << err
                  << std::endl;
        return EXIT_FAILURE;
    }

    PETWriterType::Pointer petWriter = PETWriterType::New();
    petWriter->SetFileName(sOutputFileName);
    petWriter->SetInput( vcFilter->GetOutput() );

    try {
        petWriter->Update();
    } catch (itk::ExceptionObject & err) {
        std::cerr << "\n[Error]\tCannot write output file: " << sOutputFileName
                  << std::endl;

        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

std::string getAcknowledgments(void)
{
    //Produces acknowledgments string for 3DSlicer.
    std::string sAck = "This program implements the reblurred Van-Cittert (RVC) partial volume correction technique. Please cite the following paper:\n"
                       "\tTohka, J. and Reilhac A., (2008). \"Deconvolution-based partial volume correction in Raclopride-PET\n\tand Monte Carlo comparison to MR-based method\", NeuroImage, vol. 39. 1570--1584.";

    return sAck;
}

<commit_msg>Update VanCittert.cxx<commit_after>/*
   VanCittert.cxx

   Author:      Benjamin A. Thomas

   Copyright 2015 Clinical Imaging Research Centre, A*STAR-NUS.

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

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

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

   This program implements the reblurred Van-Cittert (RVC) partial volume correction
   technique. Please cite the following paper:

	Tohka, J. and Reilhac A., (2008). "Deconvolution-based partial volume
	correction in Raclopride-PET and Monte Carlo comparison to MR-based
	method", NeuroImage, vol. 39. 1570--1584.

 */

#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include <metaCommand.h>

#include "petpvcVanCittertPVCImageFilter.h"

const char * const VERSION_NO = "0.0.1";
const char * const AUTHOR = "Benjamin A. Thomas";
const char * const APP_TITLE = "Reblurred Van-Cittert (RVC)";

typedef itk::Vector<float, 3> VectorType;
typedef itk::Image<float, 3> PETImageType;

typedef itk::ImageFileReader<PETImageType> PETReaderType;
typedef itk::ImageFileWriter<PETImageType> PETWriterType;

//Produces the text for the acknowledgments dialog in Slicer.
std::string getAcknowledgments(void);

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

    typedef petpvc::VanCittertPVCImageFilter< PETImageType >  FilterType;

    //Setting up command line argument list.
    MetaCommand command;

    command.SetVersion(VERSION_NO);
    command.SetAuthor(AUTHOR);
    command.SetName(APP_TITLE);
    command.SetDescription(
        "Performs reblurred Van-Cittert (RVC) partial volume correction");

    std::string sAcks = getAcknowledgments();
    command.SetAcknowledgments(sAcks.c_str());

    command.SetCategory("PETPVC");

    command.AddField("petfile", "PET filename", MetaCommand::IMAGE, MetaCommand::DATA_IN);
    command.AddField("outputfile", "output filename", MetaCommand::IMAGE, MetaCommand::DATA_OUT);

    command.SetOption("FWHMx", "x", true,
                      "The full-width at half maximum in mm along x-axis");
    command.AddOptionField("FWHMx", "X", MetaCommand::FLOAT, true, "");

    command.SetOption("FWHMy", "y", true,
                      "The full-width at half maximum in mm along y-axis");
    command.AddOptionField("FWHMy", "Y", MetaCommand::FLOAT, true, "");

    command.SetOption("FWHMz", "z", true,
                      "The full-width at half maximum in mm along z-axis");
    command.AddOptionField("FWHMz", "Z", MetaCommand::FLOAT, true, "");

    command.SetOption("Iterations", "i", false, "Number of iterations");
    command.SetOptionLongTag("Iterations", "iter");
    command.AddOptionField("Iterations", "Val", MetaCommand::INT, false, "30");

    command.SetOption("Alpha", "a", false, "Alpha value");
    command.SetOptionLongTag("Alpha", "alpha");
    command.AddOptionField("Alpha", "aval", MetaCommand::FLOAT, false, "1.5");

    command.SetOption("Stop", "s", false, "Stopping criterion");
    command.SetOptionLongTag("Stop", "stop");
    command.AddOptionField("Stop", "stopval", MetaCommand::FLOAT, false, "0.01");

    command.SetOption("debug", "d", false,"Prints debug information");
    command.SetOptionLongTag("debug", "debug");

    //Parse command line.
    if (!command.Parse(argc, argv)) {
        return EXIT_FAILURE;
    }

    //Get image filenames
    std::string sPETFileName = command.GetValueAsString("petfile");
    std::string sOutputFileName = command.GetValueAsString("outputfile");

    //Get values for PSF.
    float fFWHM_x = command.GetValueAsFloat("FWHMx", "X");
    float fFWHM_y = command.GetValueAsFloat("FWHMy", "Y");
    float fFWHM_z = command.GetValueAsFloat("FWHMz", "Z");

    //Get number of iterations
    int nNumOfIters = command.GetValueAsInt("Iterations", "Val");

    //Get value for alpha.
    float fAlpha = command.GetValueAsFloat("Alpha", "aval");

    //Get value for stopping criterion.
    float fStop = command.GetValueAsFloat("Stop", "stopval");

    //Make vector of FWHM in x,y and z.
    VectorType vFWHM;
    vFWHM[0] = fFWHM_x;
    vFWHM[1] = fFWHM_y;
    vFWHM[2] = fFWHM_z;

    //Toggle debug mode
    bool bDebug = command.GetValueAsBool("debug");

    //Create reader for PET image.
    PETReaderType::Pointer petReader = PETReaderType::New();
    petReader->SetFileName(sPETFileName);

    //Try to read PET.
    try {
        petReader->Update();
    } catch (itk::ExceptionObject & err) {
        std::cerr << "[Error]\tCannot read PET input file: " << sPETFileName
                  << std::endl;
        return EXIT_FAILURE;
    }

    //Calculate the variance for a given FWHM.
    VectorType vVariance;
    vVariance = vFWHM / (2.0 * sqrt(2.0 * log(2.0)));
    //std::cout << vVariance << std::endl;

    VectorType vVoxelSize = petReader->GetOutput()->GetSpacing();
    //std::cout << vVoxelSize << std::endl;

    vVariance[0] = pow(vVariance[0], 2);
    vVariance[1] = pow(vVariance[1], 2);
    vVariance[2] = pow(vVariance[2], 2);

    FilterType::Pointer vcFilter = FilterType::New();
    vcFilter->SetInput( petReader->GetOutput() );
    vcFilter->SetPSF(vVariance);
    vcFilter->SetIterations( nNumOfIters );
	vcFilter->SetAlpha( fAlpha );
    vcFilter->SetStoppingCond( fStop );
    vcFilter->SetVerbose ( bDebug );

    //Perform VC.
    try {
        vcFilter->Update();
    } catch (itk::ExceptionObject & err) {
        std::cerr << "[Error]\tfailure applying Van Cittert on: " << sPETFileName
                  << "\n" << err
                  << std::endl;
        return EXIT_FAILURE;
    }

    PETWriterType::Pointer petWriter = PETWriterType::New();
    petWriter->SetFileName(sOutputFileName);
    petWriter->SetInput( vcFilter->GetOutput() );

    try {
        petWriter->Update();
    } catch (itk::ExceptionObject & err) {
        std::cerr << "\n[Error]\tCannot write output file: " << sOutputFileName
                  << std::endl;

        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

std::string getAcknowledgments(void)
{
    //Produces acknowledgments string for 3DSlicer.
    std::string sAck = "This program implements the reblurred Van-Cittert (RVC) partial volume correction technique. Please cite the following paper:\n"
                       "\tTohka, J. and Reilhac A., (2008). \"Deconvolution-based partial volume correction in Raclopride-PET\n\tand Monte Carlo comparison to MR-based method\", NeuroImage, vol. 39. 1570--1584.";

    return sAck;
}

<|endoftext|>


<commit_before>/**
 * Appcelerator Kroll - licensed under the Apache Public License 2
 * see LICENSE in the root folder for details on the license.
 * Copyright (c) 2008 Appcelerator, Inc. All Rights Reserved.
 */
#include <iostream>
#include <vector>
#include <cstring>
#include <dlfcn.h>
#include <string>
#import <Cocoa/Cocoa.h>
#include "host.h"

namespace kroll
{
	OSXHost::OSXHost(int _argc, const char **_argv) : Host(_argc,_argv)
	{
	}

	OSXHost::~OSXHost()
	{
	}

	const char* OSXHost::GetPlatform()
	{
		return "osx";
	}

	const char* OSXHost::GetModuleSuffix()
	{
		return "module.dylib";
	}

	bool OSXHost::Start()
	{
		Host::Start();
		NSApplication *app = [NSApplication sharedApplication];
		[app finishLaunching];
		return true;
	}

	bool OSXHost::RunLoop()
	{
		NSApplication *app = [NSApplication sharedApplication];
		// we pull out an event from the queue, blocking a little bit before returning
		NSEvent *event = [app nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate dateWithTimeIntervalSinceNow:10] inMode:NSDefaultRunLoopMode dequeue:YES];
		if (event)
		{
			[app sendEvent:event];
		}
		return true;
	}

	Module* OSXHost::CreateModule(std::string& path)
	{
		void* lib_handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL);
		if (!lib_handle)
		{
			std::cerr << "Error load module: " << path << ", error: " << dlerror() << std::endl;
			return 0;
		}

		// get the module factory
		ModuleCreator* create = (ModuleCreator*)dlsym(lib_handle, "CreateModule");
		if (!create)
		{
			std::cerr << "Error load create entry from module: " << path << std::endl;
			return 0;
		}

		return create(this,FileUtils::GetDirectory(path));
	}
}

@interface KrollMainThreadCaller : NSObject
{
	kroll::BoundMethod *method;
	SharedPtr<kroll::Value> *result;
	const ValueList* args;
	SharedPtr<kroll::Value> *exception;
}
- (id)initWithBoundMethod:(SharedPtr<kroll::BoundMethod>)method args:(const ValueList*)args;
- (void)call;
- (SharedPtr<kroll::Value>)getResult;
- (SharedPtr<kroll::Value>)getException;
@end

@implementation KrollMainThreadCaller
- (id)initWithBoundMethod:(SharedPtr<kroll::BoundMethod>)m args:(const ValueList*)a
{
	self = [super init];
	if (self)
	{
		method = m.get();
		args = a;
		result = new SharedPtr<kroll::Value>();
		exception = new SharedPtr<kroll::Value>();
	}
	return self;
}
- (void)dealloc
{
	delete result;
	delete exception;
	[super dealloc];
}
- (SharedPtr<kroll::Value>)getResult
{
	return *result;
}
- (SharedPtr<kroll::Value>)getException
{
	return *exception;
}
- (void)call
{
	try
	{
		result->assign(method->Call(*args));
	}
	catch (ValueException &e)
	{
		exception->assign(e.GetValue());
	}
	catch (std::exception &e)
	{
		exception->assign(Value::NewString(e.what()));
	}
	catch (...)
	{
		exception->assign(Value::NewString("unhandled exception"));
	}
}
@end

namespace kroll
{
	SharedValue OSXHost::InvokeMethodOnMainThread(SharedBoundMethod method,
	                                              const ValueList& args)
	{
		// make sure to just invoke if we're already on the
		// main thread
		if ([NSThread isMainThread])
		{
			return method->Call(args);
		}
		NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
		KrollMainThreadCaller *caller = [[[KrollMainThreadCaller alloc] initWithBoundMethod:method args:&args] autorelease];
		[caller performSelectorOnMainThread:@selector(call) withObject:nil waitUntilDone:YES];
		SharedValue exception = [caller getException];
		if (exception.isNull())
		{
			SharedValue result = [caller getResult];
			[pool release];
			return result;
		}
		[pool release];
		return exception;
	}
}

extern "C"
{
	int Execute(int argc,const char **argv)
	{
		kroll::Host *host = new kroll::OSXHost(argc,argv);
		return host->Run();
	}
}
<commit_msg>compiler fix for osx<commit_after>/**
 * Appcelerator Kroll - licensed under the Apache Public License 2
 * see LICENSE in the root folder for details on the license.
 * Copyright (c) 2008 Appcelerator, Inc. All Rights Reserved.
 */
#include <iostream>
#include <vector>
#include <cstring>
#include <dlfcn.h>
#include <string>
#import <Cocoa/Cocoa.h>
#include "host.h"

namespace kroll
{
	OSXHost::OSXHost(int _argc, const char **_argv) : Host(_argc,_argv)
	{
	}

	OSXHost::~OSXHost()
	{
	}

	const char* OSXHost::GetPlatform()
	{
		return "osx";
	}

	const char* OSXHost::GetModuleSuffix()
	{
		return "module.dylib";
	}

	bool OSXHost::Start()
	{
		Host::Start();
		NSApplication *app = [NSApplication sharedApplication];
		[app finishLaunching];
		return true;
	}

	bool OSXHost::RunLoop()
	{
		NSApplication *app = [NSApplication sharedApplication];
		// we pull out an event from the queue, blocking a little bit before returning
		NSEvent *event = [app nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate dateWithTimeIntervalSinceNow:10] inMode:NSDefaultRunLoopMode dequeue:YES];
		if (event)
		{
			[app sendEvent:event];
		}
		return true;
	}

	Module* OSXHost::CreateModule(std::string& path)
	{
		void* lib_handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL);
		if (!lib_handle)
		{
			std::cerr << "Error load module: " << path << ", error: " << dlerror() << std::endl;
			return 0;
		}

		// get the module factory
		ModuleCreator* create = (ModuleCreator*)dlsym(lib_handle, "CreateModule");
		if (!create)
		{
			std::cerr << "Error load create entry from module: " << path << std::endl;
			return 0;
		}

		std::string dir = FileUtils::GetDirectory(path);
		return create(this,dir.c_str());
	}
}

@interface KrollMainThreadCaller : NSObject
{
	kroll::BoundMethod *method;
	SharedPtr<kroll::Value> *result;
	const ValueList* args;
	SharedPtr<kroll::Value> *exception;
}
- (id)initWithBoundMethod:(SharedPtr<kroll::BoundMethod>)method args:(const ValueList*)args;
- (void)call;
- (SharedPtr<kroll::Value>)getResult;
- (SharedPtr<kroll::Value>)getException;
@end

@implementation KrollMainThreadCaller
- (id)initWithBoundMethod:(SharedPtr<kroll::BoundMethod>)m args:(const ValueList*)a
{
	self = [super init];
	if (self)
	{
		method = m.get();
		args = a;
		result = new SharedPtr<kroll::Value>();
		exception = new SharedPtr<kroll::Value>();
	}
	return self;
}
- (void)dealloc
{
	delete result;
	delete exception;
	[super dealloc];
}
- (SharedPtr<kroll::Value>)getResult
{
	return *result;
}
- (SharedPtr<kroll::Value>)getException
{
	return *exception;
}
- (void)call
{
	try
	{
		result->assign(method->Call(*args));
	}
	catch (ValueException &e)
	{
		exception->assign(e.GetValue());
	}
	catch (std::exception &e)
	{
		exception->assign(Value::NewString(e.what()));
	}
	catch (...)
	{
		exception->assign(Value::NewString("unhandled exception"));
	}
}
@end

namespace kroll
{
	SharedValue OSXHost::InvokeMethodOnMainThread(SharedBoundMethod method,
	                                              const ValueList& args)
	{
		// make sure to just invoke if we're already on the
		// main thread
		if ([NSThread isMainThread])
		{
			return method->Call(args);
		}
		NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
		KrollMainThreadCaller *caller = [[[KrollMainThreadCaller alloc] initWithBoundMethod:method args:&args] autorelease];
		[caller performSelectorOnMainThread:@selector(call) withObject:nil waitUntilDone:YES];
		SharedValue exception = [caller getException];
		if (exception.isNull())
		{
			SharedValue result = [caller getResult];
			[pool release];
			return result;
		}
		[pool release];
		return exception;
	}
}

extern "C"
{
	int Execute(int argc,const char **argv)
	{
		kroll::Host *host = new kroll::OSXHost(argc,argv);
		return host->Run();
	}
}
<|endoftext|>