<commit_before>/*
 * Copyright (C) 2017 Smirnov Vladimir mapron1@gmail.com
 * Source code 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 or in file COPYING-APACHE-2.0.txt
 *
 * 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.h
 */

#include "RemoteToolClient.h"

#include "RemoteToolFrames.h"
#include "ToolBalancer.h"

#include <CoordinatorClient.h>
#include <SocketFrameService.h>
#include <ThreadUtils.h>
#include <FileUtils.h>

#include <stdio.h>
#include <stdlib.h>
#include <functional>
#include <fstream>
#include <algorithm>

namespace Wuild
{
static const size_t g_recommendedBufferSize = 64 * 1024;

class RemoteToolRequestWrap
{
public:
	TimePoint m_start;
	int64_t m_taskIndex = 0;
	ToolInvocation m_invocation;
	std::string m_originalFilename;
	RemoteToolRequest::Ptr m_toolRequest;
	RemoteToolClient::InvokeCallback m_callback;
	TimePoint m_expirationMoment;
	TimePoint m_requestTimeout;
	int m_attemptsRemain = 1;
};

class RemoteToolClientImpl
{
public:
	RemoteToolClient *m_parent; // ugly..
	ToolBalancer m_balancer;
	std::mutex m_clientsMutex;
	std::deque<SocketFrameHandler::Ptr> m_clients;
	std::mutex m_requestsMutex;
	std::deque<RemoteToolRequestWrap> m_requests;
	std::unique_ptr<SocketFrameService> m_server;
	CoordinatorClient m_coordinator;
	size_t m_clientIndex = 0;
	std::atomic_int m_pendingTasks {0};

	void QueueTask(const RemoteToolRequestWrap & task)
	{
		std::lock_guard<std::mutex> lock(m_requestsMutex);
		m_requests.push_back(task);
		m_pendingTasks++;
	}

	void ProcessTasks()
	{
		RemoteToolRequestWrap task;
		{
			std::lock_guard<std::mutex> lock(m_requestsMutex);
			if (m_requests.empty())
				return;
			TimePoint now(true);
			for (auto it = m_requests.begin(); it != m_requests.end(); )
			{
				if (it->m_expirationMoment < now)
				{
					Syslogger(Syslogger::Err) << "Task expired: " << SocketFrame::Ptr(it->m_toolRequest)
											  << " expiration moment:" << it->m_expirationMoment.ToString() << ", now:" << now.ToString();
					if (it->m_callback)
					{
						RemoteToolClient::TaskExecutionInfo info;
						info.m_stdOutput = "Timeout expired.";
						it->m_callback(info);
					}
					it = m_requests.erase(it);
				}
				else
				{
					it++;
				}
			}

			if (m_requests.empty())
				return;

			task = *m_requests.begin();
		}

		size_t clientIndex = m_balancer.FindFreeClient(task.m_invocation.m_id.m_toolId);
		if (clientIndex == std::numeric_limits<size_t>::max())
			return;

		SocketFrameHandler::Ptr handler;
		{
			std::lock_guard<std::mutex> lock2(m_clientsMutex);
			handler = m_clients[clientIndex];
		}
		auto frameCallback = [this, task, clientIndex](SocketFrame::Ptr responseFrame, SocketFrameHandler::ReplyState state)
		{
			m_balancer.FinishTask(clientIndex);
			const std::string outputFilename =  task.m_originalFilename;
			Syslogger(Syslogger::Info) << "RECIEVING [" << task.m_taskIndex << "]:" << outputFilename;
			RemoteToolClient::TaskExecutionInfo info;
			bool retry = false;
			if (state == SocketFrameHandler::ReplyState::Timeout)
			{
				info.m_stdOutput = "Timeout expired.";
				retry = true;
			}
			else if (state == SocketFrameHandler::ReplyState::Error)
			{
				info.m_stdOutput = "Internal error.";
				retry = true;
			}
			else
			{
				RemoteToolResponse::Ptr result = std::dynamic_pointer_cast<RemoteToolResponse>(responseFrame);
				info.m_toolExecutionTime = result->m_executionTime;
				info.m_networkRequestTime = task.m_start.GetElapsedTime();

				info.m_result = result->m_result;
				info.m_stdOutput = result->m_stdOut;
				std::replace(info.m_stdOutput.begin(), info.m_stdOutput.end(), '\r', ' ');

				if (info.m_result && !outputFilename.empty())
				{
					info.m_result = FileInfo(outputFilename).WriteCompressed(result->m_fileData, result->m_compression);
				}
			}
			m_parent->UpdateSessionInfo(info);
			if (task.m_attemptsRemain > 0 && retry)
			{
				Syslogger(Syslogger::Warning) << info.m_stdOutput << " Retrying (" << task.m_attemptsRemain << " attempts remain), args:" << task.m_invocation.GetArgsString(false);
				auto taskCopy = task;
				taskCopy.m_attemptsRemain--;
				taskCopy.m_taskIndex = this->m_parent->m_taskIndex++;
				taskCopy.m_expirationMoment = TimePoint(true) + m_parent->m_config.m_queueTimeout;
				this->QueueTask(taskCopy);
			}
			else
			{
				task.m_callback(info);
			}
		};
		m_balancer.StartTask(clientIndex);
		m_pendingTasks--;
		handler->QueueFrame(task.m_toolRequest, frameCallback, task.m_requestTimeout);
		{
			std::lock_guard<std::mutex> lock(m_requestsMutex);
			m_requests.pop_front();
		}
	}
};

RemoteToolClient::RemoteToolClient(IInvocationRewriter::Ptr invocationRewriter)
	: m_impl(new RemoteToolClientImpl()), m_invocationRewriter(invocationRewriter)
{
	m_impl->m_parent = this;
	m_impl->m_coordinator.SetInfoArrivedCallback([this](const CoordinatorInfo& info){
		for (const auto & client : info.m_toolServers)
			this->AddClient(client, true);
	});
}

RemoteToolClient::~RemoteToolClient()
{
	FinishSession();
	m_thread.Stop();

	for (auto & client : m_impl->m_clients)
		client->Stop();
}

bool RemoteToolClient::SetConfig(const RemoteToolClient::Config &config)
{
	std::ostringstream os;
	if (!config.Validate(&os))
	{
		Syslogger(Syslogger::Err) << os.str();
		return false;
	}
	m_config = config;
	return true;
}

int RemoteToolClient::GetFreeRemoteThreads() const
{
	return static_cast<int>(m_impl->m_balancer.GetFreeThreads()) - m_impl->m_pendingTasks; // may be negative.
}

void RemoteToolClient::Start(const StringVector & requiredToolIds)
{
	m_started = true;
	m_start = m_lastFinish = TimePoint(true);
	m_sessionInfo = ToolServerSessionInfo();
	m_sessionInfo.m_sessionId = m_sessionId = m_start.GetUS();
	m_sessionInfo.m_clientId = m_config.m_clientId;
	m_impl->m_balancer.SetRequiredTools(requiredToolIds);
	m_impl->m_balancer.SetSessionId(m_sessionId);

	for (auto & handler : m_impl->m_clients)
		handler->Start();

	if (!m_impl->m_coordinator.SetConfig(m_config.m_coordinator))
		return;
	m_impl->m_coordinator.Start();

	m_thread.Exec(std::bind(&RemoteToolClientImpl::ProcessTasks, m_impl.get()));
}

void RemoteToolClient::FinishSession()
{
	if (!m_started)
		return;
	m_started = false;
	m_sessionInfo.m_elapsedTime = m_lastFinish - m_start;
	m_impl->m_coordinator.SendToolServerSessionInfo(m_sessionInfo, true);
}

void RemoteToolClient::SetRemoteAvailableCallback(RemoteToolClient::RemoteAvailableCallback callback)
{
	m_remoteAvailableCallback = callback;
}

void RemoteToolClient::AddClient(const ToolServerInfo &info, bool start)
{
	size_t index = 0;
	ToolBalancer & balancer = m_impl->m_balancer;
	auto status = balancer.UpdateClient(info, index);
	if (status == ToolBalancer::ClientStatus::Skipped)
		return;

	AvailableCheck();

	if (status == ToolBalancer::ClientStatus::Updated)
		return;

	Syslogger() << "RemoteToolClient::AddClient " << info.m_connectionHost  << ":" <<  info.m_connectionPort;

	SocketFrameHandlerSettings settings;
	settings.m_channelProtocolVersion       = RemoteToolRequest::s_version + RemoteToolResponse::s_version;
	settings.m_recommendedRecieveBufferSize = g_recommendedBufferSize;
	settings.m_recommendedSendBufferSize    = g_recommendedBufferSize;
	settings.m_segmentSize = 8192;
	SocketFrameHandler::Ptr handler(new SocketFrameHandler( settings ));
	handler->RegisterFrameReader(SocketFrameReaderTemplate<RemoteToolResponse>::Create());
	handler->SetTcpChannel(info.m_connectionHost, info.m_connectionPort);

	handler->SetChannelNotifier([&balancer, index, this](bool state){
		balancer.SetClientActive(index, state);
		AvailableCheck();
	});
	if (start)
	   handler->Start();

	std::lock_guard<std::mutex> lock2(m_impl->m_clientsMutex);
	m_impl->m_clients.push_back(handler);
}

void RemoteToolClient::InvokeTool(const ToolInvocation & invocation, InvokeCallback callback)
{
	TimePoint start(true);
	const std::string inputFilename  = invocation.GetInput();
	ByteArrayHolder inputData;
	if (!inputFilename.empty() && !FileInfo(inputFilename).ReadCompressed(inputData, m_config.m_compression))
	{
		callback(RemoteToolClient::TaskExecutionInfo("failed to read " + inputFilename));
		return;
	}

	RemoteToolRequest::Ptr toolRequest(new RemoteToolRequest());
	toolRequest->m_invocation = m_invocationRewriter->PrepareRemote(invocation);
	toolRequest->m_fileData = inputData;
	toolRequest->m_compression = m_config.m_compression;
	toolRequest->m_sessionId = m_sessionId;
	toolRequest->m_clientId = m_config.m_clientId;

	RemoteToolRequestWrap wrap;
	wrap.m_start = start;
	wrap.m_toolRequest = toolRequest;
	wrap.m_taskIndex = m_taskIndex++;
	wrap.m_invocation = toolRequest->m_invocation;
	wrap.m_originalFilename = invocation.GetOutput();
	wrap.m_callback = callback;
	wrap.m_expirationMoment = wrap.m_start + m_config.m_queueTimeout;
	wrap.m_attemptsRemain = m_config.m_invocationAttempts;
	wrap.m_requestTimeout = m_config.m_requestTimeout;

	Syslogger(Syslogger::Info) << "QueueFrame [" << wrap.m_taskIndex << "] -> " << toolRequest->m_invocation.m_id.m_toolId
							   << " " << toolRequest->m_invocation.GetArgsString(false)
						<< ", balancerFree:" <<m_impl->m_balancer.GetFreeThreads()
						<< ", pending:" << m_impl->m_pendingTasks;

	m_impl->QueueTask(wrap);
}

void RemoteToolClient::UpdateSessionInfo(const RemoteToolClient::TaskExecutionInfo &executionResult)
{
	std::lock_guard<std::mutex> lock(m_sessionInfoMutex);
	m_lastFinish = TimePoint(true);
	m_sessionInfo.m_tasksCount ++;
	if (!executionResult.m_result)
		m_sessionInfo.m_failuresCount++;
	m_sessionInfo.m_totalNetworkTime += executionResult.m_networkRequestTime;
	m_sessionInfo.m_totalExecutionTime += executionResult.m_toolExecutionTime;
	m_sessionInfo.m_currentUsedThreads = m_impl->m_balancer.GetUsedThreads();
	m_sessionInfo.m_maxUsedThreads = std::max(m_sessionInfo.m_maxUsedThreads, m_sessionInfo.m_currentUsedThreads);

	m_impl->m_coordinator.SendToolServerSessionInfo(m_sessionInfo, false);
}

void RemoteToolClient::AvailableCheck()
{
	std::lock_guard<std::mutex> lock(m_availableCheckMutex);
	if (!m_remoteIsAvailable && m_impl->m_balancer.IsAllActive() && m_impl->m_balancer.GetFreeThreads() > 0)
	{
		m_remoteIsAvailable = true;
		if (m_remoteAvailableCallback)
			m_remoteAvailableCallback();
		const auto free  = m_impl->m_balancer.GetFreeThreads();
		const auto total = m_impl->m_balancer.GetTotalThreads();
		Syslogger(Syslogger::Notice) << "Recieved info from coordinator: total remote threads=" << total << ", free=" << free;
	}
}

std::string RemoteToolClient::TaskExecutionInfo::GetProfilingStr() const
{
	std::ostringstream os;
	auto cus = m_toolExecutionTime.GetUS();
	auto nus = m_networkRequestTime.GetUS();
	auto overheadPercent = ((nus - cus) * 100) / (cus ? cus : 1);
	os << "compilationTime: " << cus << " us., "
	   << "networkTime: "  << nus << " us., "
	   << "overhead: " << overheadPercent << "%";
	return os.str();
}

}
<commit_msg>improve timeouts diagnostics.<commit_after>/*
 * Copyright (C) 2017 Smirnov Vladimir mapron1@gmail.com
 * Source code 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 or in file COPYING-APACHE-2.0.txt
 *
 * 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.h
 */

#include "RemoteToolClient.h"

#include "RemoteToolFrames.h"
#include "ToolBalancer.h"

#include <CoordinatorClient.h>
#include <SocketFrameService.h>
#include <ThreadUtils.h>
#include <FileUtils.h>

#include <stdio.h>
#include <stdlib.h>
#include <functional>
#include <fstream>
#include <algorithm>

namespace Wuild
{
static const size_t g_recommendedBufferSize = 64 * 1024;

class RemoteToolRequestWrap
{
public:
	TimePoint m_start;
	int64_t m_taskIndex = 0;
	ToolInvocation m_invocation;
	std::string m_originalFilename;
	RemoteToolRequest::Ptr m_toolRequest;
	RemoteToolClient::InvokeCallback m_callback;
	TimePoint m_expirationMoment;
	TimePoint m_requestTimeout;
	int m_attemptsRemain = 1;
};

class RemoteToolClientImpl
{
public:
	RemoteToolClient *m_parent; // ugly..
	ToolBalancer m_balancer;
	std::mutex m_clientsMutex;
	std::deque<SocketFrameHandler::Ptr> m_clients;
	std::mutex m_requestsMutex;
	std::deque<RemoteToolRequestWrap> m_requests;
	std::unique_ptr<SocketFrameService> m_server;
	CoordinatorClient m_coordinator;
	size_t m_clientIndex = 0;
	std::atomic_int m_pendingTasks {0};

	void QueueTask(const RemoteToolRequestWrap & task)
	{
		std::lock_guard<std::mutex> lock(m_requestsMutex);
		m_requests.push_back(task);
		m_pendingTasks++;
	}

	void ProcessTasks()
	{
		RemoteToolRequestWrap task;
		{
			std::lock_guard<std::mutex> lock(m_requestsMutex);
			if (m_requests.empty())
				return;
			TimePoint now(true);
			for (auto it = m_requests.begin(); it != m_requests.end(); )
			{
				if (it->m_expirationMoment < now)
				{
					Syslogger(Syslogger::Err) << "Task expired: " << SocketFrame::Ptr(it->m_toolRequest)
											  << " expiration moment:" << it->m_expirationMoment.ToString() << ", now:" << now.ToString();
					if (it->m_callback)
					{
						RemoteToolClient::TaskExecutionInfo info;
						info.m_stdOutput = "Timeout expired.";
						it->m_callback(info);
					}
					it = m_requests.erase(it);
				}
				else
				{
					it++;
				}
			}

			if (m_requests.empty())
				return;

			task = *m_requests.begin();
		}

		size_t clientIndex = m_balancer.FindFreeClient(task.m_invocation.m_id.m_toolId);
		if (clientIndex == std::numeric_limits<size_t>::max())
			return;

		SocketFrameHandler::Ptr handler;
		{
			std::lock_guard<std::mutex> lock2(m_clientsMutex);
			handler = m_clients[clientIndex];
		}
		auto frameCallback = [this, task, clientIndex](SocketFrame::Ptr responseFrame, SocketFrameHandler::ReplyState state)
		{
			m_balancer.FinishTask(clientIndex);
			const std::string outputFilename =  task.m_originalFilename;
			Syslogger(Syslogger::Info) << "RECIEVING [" << task.m_taskIndex << "]:" << outputFilename;
			RemoteToolClient::TaskExecutionInfo info;
			bool retry = false;
			if (state == SocketFrameHandler::ReplyState::Timeout)
			{
				info.m_stdOutput = "Timeout expired:" + outputFilename + ", start:" + task.m_start.ToString() + " exp:" + task.m_expirationMoment.ToString() + ", att:" + std::to_string(task.m_attemptsRemain);
				retry = true;
			}
			else if (state == SocketFrameHandler::ReplyState::Error)
			{
				info.m_stdOutput = "Internal error.";
				retry = true;
			}
			else
			{
				RemoteToolResponse::Ptr result = std::dynamic_pointer_cast<RemoteToolResponse>(responseFrame);
				info.m_toolExecutionTime = result->m_executionTime;
				info.m_networkRequestTime = task.m_start.GetElapsedTime();

				info.m_result = result->m_result;
				info.m_stdOutput = result->m_stdOut;
				std::replace(info.m_stdOutput.begin(), info.m_stdOutput.end(), '\r', ' ');

				if (info.m_result && !outputFilename.empty())
				{
					info.m_result = FileInfo(outputFilename).WriteCompressed(result->m_fileData, result->m_compression);
				}
			}
			m_parent->UpdateSessionInfo(info);
			if (task.m_attemptsRemain > 0 && retry)
			{
				Syslogger(Syslogger::Warning) << info.m_stdOutput << " Retrying (" << task.m_attemptsRemain << " attempts remain), args:" << task.m_invocation.GetArgsString(false);
				auto taskCopy = task;
				taskCopy.m_attemptsRemain--;
				taskCopy.m_taskIndex = this->m_parent->m_taskIndex++;
				taskCopy.m_expirationMoment = TimePoint(true) + m_parent->m_config.m_queueTimeout;
				this->QueueTask(taskCopy);
			}
			else
			{
				task.m_callback(info);
			}
		};
		m_balancer.StartTask(clientIndex);
		m_pendingTasks--;
		handler->QueueFrame(task.m_toolRequest, frameCallback, task.m_requestTimeout);
		{
			std::lock_guard<std::mutex> lock(m_requestsMutex);
			m_requests.pop_front();
		}
	}
};

RemoteToolClient::RemoteToolClient(IInvocationRewriter::Ptr invocationRewriter)
	: m_impl(new RemoteToolClientImpl()), m_invocationRewriter(invocationRewriter)
{
	m_impl->m_parent = this;
	m_impl->m_coordinator.SetInfoArrivedCallback([this](const CoordinatorInfo& info){
		for (const auto & client : info.m_toolServers)
			this->AddClient(client, true);
	});
}

RemoteToolClient::~RemoteToolClient()
{
	FinishSession();
	m_thread.Stop();

	for (auto & client : m_impl->m_clients)
		client->Stop();
}

bool RemoteToolClient::SetConfig(const RemoteToolClient::Config &config)
{
	std::ostringstream os;
	if (!config.Validate(&os))
	{
		Syslogger(Syslogger::Err) << os.str();
		return false;
	}
	m_config = config;
	return true;
}

int RemoteToolClient::GetFreeRemoteThreads() const
{
	return static_cast<int>(m_impl->m_balancer.GetFreeThreads()) - m_impl->m_pendingTasks; // may be negative.
}

void RemoteToolClient::Start(const StringVector & requiredToolIds)
{
	m_started = true;
	m_start = m_lastFinish = TimePoint(true);
	m_sessionInfo = ToolServerSessionInfo();
	m_sessionInfo.m_sessionId = m_sessionId = m_start.GetUS();
	m_sessionInfo.m_clientId = m_config.m_clientId;
	m_impl->m_balancer.SetRequiredTools(requiredToolIds);
	m_impl->m_balancer.SetSessionId(m_sessionId);

	for (auto & handler : m_impl->m_clients)
		handler->Start();

	if (!m_impl->m_coordinator.SetConfig(m_config.m_coordinator))
		return;
	m_impl->m_coordinator.Start();

	m_thread.Exec(std::bind(&RemoteToolClientImpl::ProcessTasks, m_impl.get()));
}

void RemoteToolClient::FinishSession()
{
	if (!m_started)
		return;
	m_started = false;
	m_sessionInfo.m_elapsedTime = m_lastFinish - m_start;
	m_impl->m_coordinator.SendToolServerSessionInfo(m_sessionInfo, true);
}

void RemoteToolClient::SetRemoteAvailableCallback(RemoteToolClient::RemoteAvailableCallback callback)
{
	m_remoteAvailableCallback = callback;
}

void RemoteToolClient::AddClient(const ToolServerInfo &info, bool start)
{
	size_t index = 0;
	ToolBalancer & balancer = m_impl->m_balancer;
	auto status = balancer.UpdateClient(info, index);
	if (status == ToolBalancer::ClientStatus::Skipped)
		return;

	AvailableCheck();

	if (status == ToolBalancer::ClientStatus::Updated)
		return;

	Syslogger() << "RemoteToolClient::AddClient " << info.m_connectionHost  << ":" <<  info.m_connectionPort;

	SocketFrameHandlerSettings settings;
	settings.m_channelProtocolVersion       = RemoteToolRequest::s_version + RemoteToolResponse::s_version;
	settings.m_recommendedRecieveBufferSize = g_recommendedBufferSize;
	settings.m_recommendedSendBufferSize    = g_recommendedBufferSize;
	settings.m_segmentSize = 8192;
	SocketFrameHandler::Ptr handler(new SocketFrameHandler( settings ));
	handler->RegisterFrameReader(SocketFrameReaderTemplate<RemoteToolResponse>::Create());
	handler->SetTcpChannel(info.m_connectionHost, info.m_connectionPort);

	handler->SetChannelNotifier([&balancer, index, this](bool state){
		balancer.SetClientActive(index, state);
		AvailableCheck();
	});
	if (start)
	   handler->Start();

	std::lock_guard<std::mutex> lock2(m_impl->m_clientsMutex);
	m_impl->m_clients.push_back(handler);
}

void RemoteToolClient::InvokeTool(const ToolInvocation & invocation, InvokeCallback callback)
{
	TimePoint start(true);
	const std::string inputFilename  = invocation.GetInput();
	ByteArrayHolder inputData;
	if (!inputFilename.empty() && !FileInfo(inputFilename).ReadCompressed(inputData, m_config.m_compression))
	{
		callback(RemoteToolClient::TaskExecutionInfo("failed to read " + inputFilename));
		return;
	}

	RemoteToolRequest::Ptr toolRequest(new RemoteToolRequest());
	toolRequest->m_invocation = m_invocationRewriter->PrepareRemote(invocation);
	toolRequest->m_fileData = inputData;
	toolRequest->m_compression = m_config.m_compression;
	toolRequest->m_sessionId = m_sessionId;
	toolRequest->m_clientId = m_config.m_clientId;

	RemoteToolRequestWrap wrap;
	wrap.m_start = start;
	wrap.m_toolRequest = toolRequest;
	wrap.m_taskIndex = m_taskIndex++;
	wrap.m_invocation = toolRequest->m_invocation;
	wrap.m_originalFilename = invocation.GetOutput();
	wrap.m_callback = callback;
	wrap.m_expirationMoment = wrap.m_start + m_config.m_queueTimeout;
	wrap.m_attemptsRemain = m_config.m_invocationAttempts;
	wrap.m_requestTimeout = m_config.m_requestTimeout;

	Syslogger(Syslogger::Info) << "QueueFrame [" << wrap.m_taskIndex << "] -> " << toolRequest->m_invocation.m_id.m_toolId
							   << " " << toolRequest->m_invocation.GetArgsString(false)
						<< ", balancerFree:" <<m_impl->m_balancer.GetFreeThreads()
						<< ", pending:" << m_impl->m_pendingTasks;

	m_impl->QueueTask(wrap);
}

void RemoteToolClient::UpdateSessionInfo(const RemoteToolClient::TaskExecutionInfo &executionResult)
{
	std::lock_guard<std::mutex> lock(m_sessionInfoMutex);
	m_lastFinish = TimePoint(true);
	m_sessionInfo.m_tasksCount ++;
	if (!executionResult.m_result)
		m_sessionInfo.m_failuresCount++;
	m_sessionInfo.m_totalNetworkTime += executionResult.m_networkRequestTime;
	m_sessionInfo.m_totalExecutionTime += executionResult.m_toolExecutionTime;
	m_sessionInfo.m_currentUsedThreads = m_impl->m_balancer.GetUsedThreads();
	m_sessionInfo.m_maxUsedThreads = std::max(m_sessionInfo.m_maxUsedThreads, m_sessionInfo.m_currentUsedThreads);

	m_impl->m_coordinator.SendToolServerSessionInfo(m_sessionInfo, false);
}

void RemoteToolClient::AvailableCheck()
{
	std::lock_guard<std::mutex> lock(m_availableCheckMutex);
	if (!m_remoteIsAvailable && m_impl->m_balancer.IsAllActive() && m_impl->m_balancer.GetFreeThreads() > 0)
	{
		m_remoteIsAvailable = true;
		if (m_remoteAvailableCallback)
			m_remoteAvailableCallback();
		const auto free  = m_impl->m_balancer.GetFreeThreads();
		const auto total = m_impl->m_balancer.GetTotalThreads();
		Syslogger(Syslogger::Notice) << "Recieved info from coordinator: total remote threads=" << total << ", free=" << free;
	}
}

std::string RemoteToolClient::TaskExecutionInfo::GetProfilingStr() const
{
	std::ostringstream os;
	auto cus = m_toolExecutionTime.GetUS();
	auto nus = m_networkRequestTime.GetUS();
	auto overheadPercent = ((nus - cus) * 100) / (cus ? cus : 1);
	os << "compilationTime: " << cus << " us., "
	   << "networkTime: "  << nus << " us., "
	   << "overhead: " << overheadPercent << "%";
	return os.str();
}

}
<|endoftext|>


<commit_before>/**
 * Created by Jian Chen
 * @since  2016.05.24
 * @author Jian Chen <admin@chensoft.com>
 * @link   http://chensoft.com
 */
#pragma once

#include <algorithm>
#include <vector>

namespace chen
{
    class map
    {
    public:
        /**
         * Test if the key is in a map
         */
        template <typename M>
        static bool exist(const M &m, const typename M::key_type &k)
        {
            return m.find(k) != m.end();
        }

        /**
         * Find value in map
         */
        template <typename M>
        static typename M::mapped_type find(const M &m, const typename M::key_type &k)
        {
            auto it = m.find(k);
            return it != m.end() ? it->second : typename M::mapped_type();
        }

        template <typename M, typename R>
        static R find(const M &m, const typename M::key_type &k, R def)
        {
            auto it = m.find(k);
            return it != m.end() ? static_cast<R>(it->second) : def;
        }

        /**
         * Write value if find
         */
        template <typename M, typename O>
        static void write(const M &m, const typename M::key_type &k, O &o)
        {
            auto it = m.find(k);
            if (it != m.end())
                o = it->second;
        }

        /**
         * The keys of a map
         */
        template <typename M>
        static std::vector<typename M::key_type> keys(const M &m)
        {
            std::vector<typename M::key_type> ret;
            for (auto &pair : m)
                ret.emplace_back(pair.first);
            return ret;
        }

        /**
         * The values of a map
         */
        template <typename M>
        static std::vector<typename M::mapped_type> values(const M &m)
        {
            std::vector<typename M::mapped_type> ret;
            for (auto &pair : m)
                ret.emplace_back(pair.second);
            return ret;
        }

        /**
         * Invert the map, user should make sure the values are unique
         * otherwise the same keys will be override
         */
        template <typename M>
        static M flip(const M &m)
        {
            M ret;
            for (auto &pair : m)
                ret[pair.second] = pair.first;
            return ret;
        }
    };
}<commit_msg>map: cast to out variable's type<commit_after>/**
 * Created by Jian Chen
 * @since  2016.05.24
 * @author Jian Chen <admin@chensoft.com>
 * @link   http://chensoft.com
 */
#pragma once

#include <algorithm>
#include <vector>

namespace chen
{
    class map
    {
    public:
        /**
         * Test if the key is in a map
         */
        template <typename M>
        static bool exist(const M &m, const typename M::key_type &k)
        {
            return m.find(k) != m.end();
        }

        /**
         * Find value in map
         */
        template <typename M>
        static typename M::mapped_type find(const M &m, const typename M::key_type &k)
        {
            auto it = m.find(k);
            return it != m.end() ? it->second : typename M::mapped_type();
        }

        template <typename M, typename R>
        static R find(const M &m, const typename M::key_type &k, R def)
        {
            auto it = m.find(k);
            return it != m.end() ? static_cast<R>(it->second) : def;
        }

        /**
         * Write value if find
         */
        template <typename M, typename O>
        static void write(const M &m, const typename M::key_type &k, O &o)
        {
            auto it = m.find(k);
            if (it != m.end())
                o = static_cast<O>(it->second);
        }

        /**
         * The keys of a map
         */
        template <typename M>
        static std::vector<typename M::key_type> keys(const M &m)
        {
            std::vector<typename M::key_type> ret;
            for (auto &pair : m)
                ret.emplace_back(pair.first);
            return ret;
        }

        /**
         * The values of a map
         */
        template <typename M>
        static std::vector<typename M::mapped_type> values(const M &m)
        {
            std::vector<typename M::mapped_type> ret;
            for (auto &pair : m)
                ret.emplace_back(pair.second);
            return ret;
        }

        /**
         * Invert the map, user should make sure the values are unique
         * otherwise the same keys will be override
         */
        template <typename M>
        static M flip(const M &m)
        {
            M ret;
            for (auto &pair : m)
                ret[pair.second] = pair.first;
            return ret;
        }
    };
}<|endoftext|>


<commit_before>// Copyright (c) 2014-2017 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#include <string>
#include <iostream>

#include <tao/pegtl.hh>

#include "double.hh"

namespace sum
{
   struct padded_double
         : pegtl::pad< double_::grammar, pegtl::space > {};

   struct double_list
         : pegtl::list< padded_double, pegtl::one< ',' > > {};

   struct grammar
         : pegtl::seq< double_list, pegtl::eof > {};

   template< typename Rule >
   struct action
         : pegtl::nothing< Rule > {};

   template<> struct action< double_::grammar >
   {
      template< typename Input >
      static void apply( const Input & in, double & sum )
      {
         // assume all values will fit into a C++ double
         sum += std::stod( in.string() );
      }
   };

} // namespace sum

int main()
{
   std::cout << "Give me a comma separated list of numbers.\n";
   std::cout << "The numbers are added using the PEGTL.\n";
   std::cout << "Type [q or Q] to quit\n\n";

   std::string str;

   while ( std::getline( std::cin, str ) ) {
      if ( str.empty() || str[ 0 ] == 'q' || str[ 0 ] == 'Q' ) {
         break;
      }
      double d = 0.0;
      if ( pegtl::parse_string< sum::grammar, sum::action >( str, "std::cin", d ) ) {
         std::cout << "parsing OK; sum = " << d << std::endl;
      }
      else {
         std::cout << "parsing failed" << std::endl;
      }
   }
}
<commit_msg>Fix compile-problem on Android<commit_after>// Copyright (c) 2014-2017 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#include <string>
#include <iostream>

#include <tao/pegtl.hh>

#include "double.hh"

namespace sum
{
   struct padded_double
         : pegtl::pad< double_::grammar, pegtl::space > {};

   struct double_list
         : pegtl::list< padded_double, pegtl::one< ',' > > {};

   struct grammar
         : pegtl::seq< double_list, pegtl::eof > {};

   template< typename Rule >
   struct action
         : pegtl::nothing< Rule > {};

   template<> struct action< double_::grammar >
   {
      template< typename Input >
      static void apply( const Input & in, double & sum )
      {
         // assume all values will fit into a C++ double
         char* ptr = const_cast< char* >( in.end() );
         sum += std::strtod( const_cast< char* >( in.begin() ), & ptr );
      }
   };

} // namespace sum

int main()
{
   std::cout << "Give me a comma separated list of numbers.\n";
   std::cout << "The numbers are added using the PEGTL.\n";
   std::cout << "Type [q or Q] to quit\n\n";

   std::string str;

   while ( std::getline( std::cin, str ) ) {
      if ( str.empty() || str[ 0 ] == 'q' || str[ 0 ] == 'Q' ) {
         break;
      }
      double d = 0.0;
      if ( pegtl::parse_string< sum::grammar, sum::action >( str, "std::cin", d ) ) {
         std::cout << "parsing OK; sum = " << d << std::endl;
      }
      else {
         std::cout << "parsing failed" << std::endl;
      }
   }
}
<|endoftext|>


<commit_before>// This file is distributed under the MIT license.
// See the LICENSE file for details.

#include <exception>
#include <fstream>
#include <iostream>
#include <memory>
#include <ostream>
#include <string>

#include <GL/glew.h>

#include <Support/CmdLine.h>
#include <Support/CmdLineUtil.h>

#include <visionaray/detail/platform.h>

#include <visionaray/bvh.h>
#include <visionaray/camera.h>
#include <visionaray/cpu_buffer_rt.h>
#include <visionaray/get_normal.h>
#include <visionaray/random_sampler.h>
#include <visionaray/scheduler.h>
#include <visionaray/traverse.h>

#include <common/manip/arcball_manipulator.h>
#include <common/manip/pan_manipulator.h>
#include <common/manip/zoom_manipulator.h>

#include <common/model.h>
#include <common/obj_loader.h>
#include <common/viewer_glut.h>

using namespace visionaray;

using viewer_type = viewer_glut;

//-------------------------------------------------------------------------------------------------
// struct with state variables
//

struct renderer : viewer_type
{
    using host_ray_type = basic_ray<simd::float4>;

    renderer()
        : viewer_type(512, 512, "Visionaray Ambient Occlusion Example")
        , host_sched(8)
    {
        using namespace support;

        add_cmdline_option( cl::makeOption<std::string&>(
            cl::Parser<>(),
            "filename",
            cl::Desc("Input file in wavefront obj format"),
            cl::Positional,
            cl::Required,
            cl::init(this->filename)
            ) );

        add_cmdline_option( cl::makeOption<std::string&>(
            cl::Parser<>(),
            "camera",
            cl::Desc("Text file with camera parameters"),
            cl::ArgRequired,
            cl::init(this->initial_camera)
            ) );

        add_cmdline_option( cl::makeOption<bvh_build_strategy&>({
                { "default",            Binned,         "Binned SAH" },
                { "split",              Split,          "Binned SAH with spatial splits" }
            },
            "bvh",
            cl::Desc("BVH build strategy"),
            cl::ArgRequired,
            cl::init(this->builder)
            ) );

        add_cmdline_option( cl::makeOption<int&>(
            cl::Parser<>(),
            "samples",
            cl::Desc("Number of shadow rays for ambient occlusion"),
            cl::ArgRequired,
            cl::init(this->AO_Samples)
            ) );

        add_cmdline_option( cl::makeOption<float&>(
            cl::Parser<>(),
            "radius",
            cl::Desc("Ambient occlusion radius"),
            cl::ArgRequired,
            cl::init(this->AO_Radius)
            ) );
    }

    enum bvh_build_strategy
    {
        Binned = 0,  // Binned SAH builder, no spatial splits
        Split        // Split BVH, also binned and with SAH
    };

    camera                                      cam;
    cpu_buffer_rt<PF_RGBA32F, PF_UNSPECIFIED>   host_rt;
    tiled_sched<host_ray_type>                  host_sched;
    bvh_build_strategy                          builder         = Binned;

    std::string                                 filename;
    std::string                                 initial_camera;

    model mod;
    index_bvh<model::triangle_type>             host_bvh;
    unsigned                                    frame_num       = 0;

    int                                         AO_Samples      = 8;
    float                                       AO_Radius       = 0.1f;

protected:

    void on_display();
    void on_key_press(visionaray::key_event const& event);
    void on_mouse_move(visionaray::mouse_event const& event);
    void on_resize(int w, int h);

};

//-------------------------------------------------------------------------------------------------
// I/O utility for camera lookat only - not fit for the general case!
//

std::istream& operator>>(std::istream& in, camera& cam)
{
    vec3 eye;
    vec3 center;
    vec3 up;

    in >> eye >> std::ws >> center >> std::ws >> up >> std::ws;
    cam.look_at(eye, center, up);

    return in;
}

std::ostream& operator<<(std::ostream& out, camera const& cam)
{
    out << cam.eye() << '\n';
    out << cam.center() << '\n';
    out << cam.up() << '\n';
    return out;
}

//-------------------------------------------------------------------------------------------------
// Display function, implements the AO kernel
//

void renderer::on_display()
{
    // some setup

    using R = renderer::host_ray_type;
    using S = R::scalar_type;
    using C = vector<4, S>;
    using V = vector<3, S>;

    auto sparams = make_sched_params(
            pixel_sampler::jittered_blend_type{},
            cam,
            host_rt
            );

    using bvh_ref = index_bvh<model::triangle_type>::bvh_ref;

    std::vector<bvh_ref> bvhs;
    bvhs.push_back(host_bvh.ref());

    auto prims_begin = bvhs.data();
    auto prims_end   = bvhs.data() + bvhs.size();

    auto bgcolor = background_color();

    host_sched.frame([&](R ray, random_sampler<S>& samp) -> result_record<S>
    {
        result_record<S> result;
        result.color = C(bgcolor, 1.0f);

        auto hit_rec = closest_hit(
                ray,
                prims_begin,
                prims_end
                );

        result.hit = hit_rec.hit;

        if (any(hit_rec.hit))
        {
            hit_rec.isect_pos = ray.ori + ray.dir * hit_rec.t;
            result.isect_pos  = hit_rec.isect_pos;

            C clr(1.0);

            auto n = get_normal(
                mod.geometric_normals.data(),
                hit_rec,
                bvh_ref{},
                normals_per_face_binding{}
                );

            V u;
            V v;
            V w = n;
            make_orthonormal_basis(u, v, w);

            S radius= AO_Radius;

            for (int i = 0; i < AO_Samples; ++i)
            {
                auto sp = cosine_sample_hemisphere(samp.next(), samp.next());

                auto dir = normalize( sp.x * u + sp.y * v + sp.z * w );

                R ao_ray;
                ao_ray.ori = hit_rec.isect_pos + dir * S(1E-3f);
                ao_ray.dir = dir;

                auto ao_rec = any_hit(
                        ao_ray,
                        prims_begin,
                        prims_end,
                        radius
                        );

                clr = select(
                        ao_rec.hit,
                        clr - S(1.0f / AO_Samples),
                        clr
                        );
            }

            result.color      = select( hit_rec.hit, C(clr.xyz(), S(1.0)), result.color );

        }

        return result;
    }, sparams, ++frame_num);

    // display the rendered image

    glClearColor(bgcolor.x, bgcolor.y, bgcolor.z, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    host_rt.display_color_buffer();
}

//-------------------------------------------------------------------------------------------------
// mouse handling
//

void renderer::on_mouse_move(visionaray::mouse_event const& event)
{
    if (event.get_buttons() != mouse::NoButton)
    {
        frame_num = 0;
        host_rt.clear_color_buffer();
    }

    viewer_type::on_mouse_move(event);
}

//-------------------------------------------------------------------------------------------------
// keyboard handling
//

void renderer::on_key_press(key_event const& event)
{
    static const std::string camera_filename = "visionaray-camera.txt";

    switch (event.key())
    {
    case 'u':
        {
            std::ofstream file( camera_filename );
            if (file.good())
            {
                std::cout << "Storing camera to file: " << camera_filename << '\n';
                file << cam;
            }
        }
        break;

    case 'v':
        {
            std::ifstream file( camera_filename );
            if (file.good())
            {
                file >> cam;
                host_rt.clear_color_buffer();
                std::cout << "Load camera from file: " << camera_filename << '\n';
            }
        }
        break;

    default:
        break;
    }

    viewer_type::on_key_press(event);
}

//-------------------------------------------------------------------------------------------------
// resize event
//

void renderer::on_resize(int w, int h)
{
    frame_num = 0;
    host_rt.clear_color_buffer();

    cam.set_viewport(0, 0, w, h);
    float aspect = w / static_cast<float>(h);
    cam.perspective(45.0f * constants::degrees_to_radians<float>(), aspect, 0.001f, 1000.0f);
    host_rt.resize(w, h);

    viewer_type::on_resize(w, h);
}

//-------------------------------------------------------------------------------------------------
// Main function, performs initialization
//

int main(int argc, char** argv)
{
    renderer rend;

    try
    {
        rend.init(argc, argv);
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << '\n';
        return EXIT_FAILURE;
    }

    try
    {
        visionaray::load_obj(rend.filename, rend.mod);
    }
    catch (std::exception& e)
    {
        std::cerr << "Failed loading obj model: " << e.what() << std::endl;
        return EXIT_FAILURE;
    }

    std::cout << "Creating BVH...\n";

    rend.host_bvh = build<index_bvh<model::triangle_type>>(
            rend.mod.primitives.data(),
            rend.mod.primitives.size(),
            rend.builder == renderer::Split
            );

    std::cout << "Ready\n";

    float aspect = rend.width() / static_cast<float>(rend.height());

    rend.cam.perspective(45.0f * constants::degrees_to_radians<float>(), aspect, 0.001f, 1000.0f);

    // Load camera from file or set view-all
    std::ifstream file(rend.initial_camera);
    if (file.good())
    {
        file >> rend.cam;
    }
    else
    {
        rend.cam.view_all( rend.mod.bbox );
    }

    rend.add_manipulator( std::make_shared<arcball_manipulator>(rend.cam, mouse::Left) );
    rend.add_manipulator( std::make_shared<pan_manipulator>(rend.cam, mouse::Middle) );
    // Additional "Alt + LMB" pan manipulator for setups w/o middle mouse button
    rend.add_manipulator( std::make_shared<pan_manipulator>(rend.cam, mouse::Left, keyboard::Alt) );
    rend.add_manipulator( std::make_shared<zoom_manipulator>(rend.cam, mouse::Right) );

    rend.event_loop();
}
<commit_msg>Missing include<commit_after>// This file is distributed under the MIT license.
// See the LICENSE file for details.

#include <exception>
#include <fstream>
#include <iostream>
#include <memory>
#include <ostream>
#include <string>

#include <GL/glew.h>

#include <Support/CmdLine.h>
#include <Support/CmdLineUtil.h>

#include <visionaray/detail/platform.h>

#include <visionaray/bvh.h>
#include <visionaray/camera.h>
#include <visionaray/cpu_buffer_rt.h>
#include <visionaray/get_normal.h>
#include <visionaray/random_sampler.h>
#include <visionaray/sampling.h>
#include <visionaray/scheduler.h>
#include <visionaray/traverse.h>

#include <common/manip/arcball_manipulator.h>
#include <common/manip/pan_manipulator.h>
#include <common/manip/zoom_manipulator.h>

#include <common/model.h>
#include <common/obj_loader.h>
#include <common/viewer_glut.h>

using namespace visionaray;

using viewer_type = viewer_glut;

//-------------------------------------------------------------------------------------------------
// struct with state variables
//

struct renderer : viewer_type
{
    using host_ray_type = basic_ray<simd::float4>;

    renderer()
        : viewer_type(512, 512, "Visionaray Ambient Occlusion Example")
        , host_sched(8)
    {
        using namespace support;

        add_cmdline_option( cl::makeOption<std::string&>(
            cl::Parser<>(),
            "filename",
            cl::Desc("Input file in wavefront obj format"),
            cl::Positional,
            cl::Required,
            cl::init(this->filename)
            ) );

        add_cmdline_option( cl::makeOption<std::string&>(
            cl::Parser<>(),
            "camera",
            cl::Desc("Text file with camera parameters"),
            cl::ArgRequired,
            cl::init(this->initial_camera)
            ) );

        add_cmdline_option( cl::makeOption<bvh_build_strategy&>({
                { "default",            Binned,         "Binned SAH" },
                { "split",              Split,          "Binned SAH with spatial splits" }
            },
            "bvh",
            cl::Desc("BVH build strategy"),
            cl::ArgRequired,
            cl::init(this->builder)
            ) );

        add_cmdline_option( cl::makeOption<int&>(
            cl::Parser<>(),
            "samples",
            cl::Desc("Number of shadow rays for ambient occlusion"),
            cl::ArgRequired,
            cl::init(this->AO_Samples)
            ) );

        add_cmdline_option( cl::makeOption<float&>(
            cl::Parser<>(),
            "radius",
            cl::Desc("Ambient occlusion radius"),
            cl::ArgRequired,
            cl::init(this->AO_Radius)
            ) );
    }

    enum bvh_build_strategy
    {
        Binned = 0,  // Binned SAH builder, no spatial splits
        Split        // Split BVH, also binned and with SAH
    };

    camera                                      cam;
    cpu_buffer_rt<PF_RGBA32F, PF_UNSPECIFIED>   host_rt;
    tiled_sched<host_ray_type>                  host_sched;
    bvh_build_strategy                          builder         = Binned;

    std::string                                 filename;
    std::string                                 initial_camera;

    model mod;
    index_bvh<model::triangle_type>             host_bvh;
    unsigned                                    frame_num       = 0;

    int                                         AO_Samples      = 8;
    float                                       AO_Radius       = 0.1f;

protected:

    void on_display();
    void on_key_press(visionaray::key_event const& event);
    void on_mouse_move(visionaray::mouse_event const& event);
    void on_resize(int w, int h);

};

//-------------------------------------------------------------------------------------------------
// I/O utility for camera lookat only - not fit for the general case!
//

std::istream& operator>>(std::istream& in, camera& cam)
{
    vec3 eye;
    vec3 center;
    vec3 up;

    in >> eye >> std::ws >> center >> std::ws >> up >> std::ws;
    cam.look_at(eye, center, up);

    return in;
}

std::ostream& operator<<(std::ostream& out, camera const& cam)
{
    out << cam.eye() << '\n';
    out << cam.center() << '\n';
    out << cam.up() << '\n';
    return out;
}

//-------------------------------------------------------------------------------------------------
// Display function, implements the AO kernel
//

void renderer::on_display()
{
    // some setup

    using R = renderer::host_ray_type;
    using S = R::scalar_type;
    using C = vector<4, S>;
    using V = vector<3, S>;

    auto sparams = make_sched_params(
            pixel_sampler::jittered_blend_type{},
            cam,
            host_rt
            );

    using bvh_ref = index_bvh<model::triangle_type>::bvh_ref;

    std::vector<bvh_ref> bvhs;
    bvhs.push_back(host_bvh.ref());

    auto prims_begin = bvhs.data();
    auto prims_end   = bvhs.data() + bvhs.size();

    auto bgcolor = background_color();

    host_sched.frame([&](R ray, random_sampler<S>& samp) -> result_record<S>
    {
        result_record<S> result;
        result.color = C(bgcolor, 1.0f);

        auto hit_rec = closest_hit(
                ray,
                prims_begin,
                prims_end
                );

        result.hit = hit_rec.hit;

        if (any(hit_rec.hit))
        {
            hit_rec.isect_pos = ray.ori + ray.dir * hit_rec.t;
            result.isect_pos  = hit_rec.isect_pos;

            C clr(1.0);

            auto n = get_normal(
                mod.geometric_normals.data(),
                hit_rec,
                bvh_ref{},
                normals_per_face_binding{}
                );

            V u;
            V v;
            V w = n;
            make_orthonormal_basis(u, v, w);

            S radius= AO_Radius;

            for (int i = 0; i < AO_Samples; ++i)
            {
                auto sp = cosine_sample_hemisphere(samp.next(), samp.next());

                auto dir = normalize( sp.x * u + sp.y * v + sp.z * w );

                R ao_ray;
                ao_ray.ori = hit_rec.isect_pos + dir * S(1E-3f);
                ao_ray.dir = dir;

                auto ao_rec = any_hit(
                        ao_ray,
                        prims_begin,
                        prims_end,
                        radius
                        );

                clr = select(
                        ao_rec.hit,
                        clr - S(1.0f / AO_Samples),
                        clr
                        );
            }

            result.color      = select( hit_rec.hit, C(clr.xyz(), S(1.0)), result.color );

        }

        return result;
    }, sparams, ++frame_num);

    // display the rendered image

    glClearColor(bgcolor.x, bgcolor.y, bgcolor.z, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    host_rt.display_color_buffer();
}

//-------------------------------------------------------------------------------------------------
// mouse handling
//

void renderer::on_mouse_move(visionaray::mouse_event const& event)
{
    if (event.get_buttons() != mouse::NoButton)
    {
        frame_num = 0;
        host_rt.clear_color_buffer();
    }

    viewer_type::on_mouse_move(event);
}

//-------------------------------------------------------------------------------------------------
// keyboard handling
//

void renderer::on_key_press(key_event const& event)
{
    static const std::string camera_filename = "visionaray-camera.txt";

    switch (event.key())
    {
    case 'u':
        {
            std::ofstream file( camera_filename );
            if (file.good())
            {
                std::cout << "Storing camera to file: " << camera_filename << '\n';
                file << cam;
            }
        }
        break;

    case 'v':
        {
            std::ifstream file( camera_filename );
            if (file.good())
            {
                file >> cam;
                host_rt.clear_color_buffer();
                std::cout << "Load camera from file: " << camera_filename << '\n';
            }
        }
        break;

    default:
        break;
    }

    viewer_type::on_key_press(event);
}

//-------------------------------------------------------------------------------------------------
// resize event
//

void renderer::on_resize(int w, int h)
{
    frame_num = 0;
    host_rt.clear_color_buffer();

    cam.set_viewport(0, 0, w, h);
    float aspect = w / static_cast<float>(h);
    cam.perspective(45.0f * constants::degrees_to_radians<float>(), aspect, 0.001f, 1000.0f);
    host_rt.resize(w, h);

    viewer_type::on_resize(w, h);
}

//-------------------------------------------------------------------------------------------------
// Main function, performs initialization
//

int main(int argc, char** argv)
{
    renderer rend;

    try
    {
        rend.init(argc, argv);
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << '\n';
        return EXIT_FAILURE;
    }

    try
    {
        visionaray::load_obj(rend.filename, rend.mod);
    }
    catch (std::exception& e)
    {
        std::cerr << "Failed loading obj model: " << e.what() << std::endl;
        return EXIT_FAILURE;
    }

    std::cout << "Creating BVH...\n";

    rend.host_bvh = build<index_bvh<model::triangle_type>>(
            rend.mod.primitives.data(),
            rend.mod.primitives.size(),
            rend.builder == renderer::Split
            );

    std::cout << "Ready\n";

    float aspect = rend.width() / static_cast<float>(rend.height());

    rend.cam.perspective(45.0f * constants::degrees_to_radians<float>(), aspect, 0.001f, 1000.0f);

    // Load camera from file or set view-all
    std::ifstream file(rend.initial_camera);
    if (file.good())
    {
        file >> rend.cam;
    }
    else
    {
        rend.cam.view_all( rend.mod.bbox );
    }

    rend.add_manipulator( std::make_shared<arcball_manipulator>(rend.cam, mouse::Left) );
    rend.add_manipulator( std::make_shared<pan_manipulator>(rend.cam, mouse::Middle) );
    // Additional "Alt + LMB" pan manipulator for setups w/o middle mouse button
    rend.add_manipulator( std::make_shared<pan_manipulator>(rend.cam, mouse::Left, keyboard::Alt) );
    rend.add_manipulator( std::make_shared<zoom_manipulator>(rend.cam, mouse::Right) );

    rend.event_loop();
}
<|endoftext|>


<commit_before>#include <zip.hpp>

#include "helpers.hpp"

#include <iterator>
#include <sstream>
#include <string>
#include <tuple>
#include <utility>
#include <vector>

#include "catch.hpp"

using iter::zip;
using itertest::BasicIterable;
using itertest::SolidInt;

TEST_CASE("zip: Simple case, same length", "[zip]") {
  using Tu = std::tuple<int, char, double>;
  using ResVec = const std::vector<Tu>;
  std::vector<int> iv{10, 20, 30};
  std::string s{"hey"};
  double arr[] = {1.0, 2.0, 4.0};

  auto z = zip(iv, s, arr);
  ResVec v(std::begin(z), std::end(z));
  ResVec vc{Tu{10, 'h', 1.0}, Tu{20, 'e', 2.0}, Tu{30, 'y', 4.0}};
  REQUIRE(v == vc);
}

TEST_CASE("zip: const iteration", "[zip][const]") {
  using Tu = std::tuple<int, char, double>;
  using ResVec = const std::vector<Tu>;
  std::vector<int> iv{10, 20, 30};
  std::string s{"hey"};
  double arr[] = {1.0, 2.0, 4.0};

  const auto z = zip(iv, s, arr);
  ResVec v(std::begin(z), std::end(z));
  ResVec vc{Tu{10, 'h', 1.0}, Tu{20, 'e', 2.0}, Tu{30, 'y', 4.0}};
  REQUIRE(v == vc);
}

TEST_CASE("zip: const iterators can be compared to non-const iterators", "[zip][const]") {
  std::vector<int> v;
  std::string s;
  auto z = zip(v, s);
  const auto& cz = z;
  (void)(std::begin(z) == std::end(cz));
}

TEST_CASE(
    "zip: three sequences, one sequence has different begin and end", "[zip]") {
  using Tu = std::tuple<int, char, double>;
  using ResVec = const std::vector<Tu>;
  std::vector<int> iv{10, 20, 30};
  CharRange cr('d');
  double arr[] = {1.0, 2.0, 4.0};

  auto z = zip(iv, cr, arr);
  ResVec v(std::begin(z), std::end(z));
  ResVec vc{Tu{10, 'a', 1.0}, Tu{20, 'b', 2.0}, Tu{30, 'c', 4.0}};
  REQUIRE(v == vc);
}

TEST_CASE("zip: One empty, all empty", "[zip]") {
  std::vector<int> iv = {1, 2, 3};
  std::string s{};
  auto z = zip(iv, s);
  REQUIRE_FALSE(std::begin(z) != std::end(z));
  auto z2 = zip(s, iv);
  REQUIRE_FALSE(std::begin(z2) != std::end(z2));
}

TEST_CASE("zip: terminates on shortest sequence", "[zip]") {
  std::vector<int> iv{1, 2, 3, 4, 5};
  std::string s{"hi"};
  auto z = zip(iv, s);

  REQUIRE(std::distance(std::begin(z), std::end(z)) == 2);
}

TEST_CASE("zip: Empty", "[zip]") {
  auto z = zip();
  REQUIRE_FALSE(std::begin(z) != std::end(z));
}

TEST_CASE("zip: Modify sequence through zip", "[zip]") {
  std::vector<int> iv{1, 2, 3};
  std::vector<int> iv2{1, 2, 3, 4};
  for (auto&& t : zip(iv, iv2)) {
    std::get<0>(t) = -1;
    std::get<1>(t) = -1;
  }

  const std::vector<int> vc{-1, -1, -1};
  const std::vector<int> vc2{-1, -1, -1, 4};
  REQUIRE(iv == vc);
  REQUIRE(iv2 == vc2);
}

TEST_CASE("zip: binds reference when it should", "[zip]") {
  BasicIterable<char> bi{'x', 'y', 'z'};
  zip(bi);
  REQUIRE_FALSE(bi.was_moved_from());
}

TEST_CASE("zip: moves rvalues", "[zip]") {
  BasicIterable<char> bi{'x', 'y', 'z'};
  zip(std::move(bi));
  REQUIRE(bi.was_moved_from());
}

TEST_CASE("zip: Can bind ref and move in single zip", "[zip]") {
  BasicIterable<char> b1{'x', 'y', 'z'};
  BasicIterable<char> b2{'a', 'b'};
  zip(b1, std::move(b2));
  REQUIRE_FALSE(b1.was_moved_from());
  REQUIRE(b2.was_moved_from());
}

TEST_CASE("zip: doesn't move or copy elements of iterable", "[zip]") {
  constexpr SolidInt arr[] = {{6}, {7}, {8}};
  for (auto&& t : zip(arr)) {
    (void)std::get<0>(t);
  }
}

TEST_CASE("zip: postfix ++", "[zip]") {
  const std::vector<int> v = {1};
  auto z = zip(v);
  auto it = std::begin(z);
  it++;
  REQUIRE(it == std::end(z));
}

TEST_CASE("zip: iterator meets requirements", "[zip]") {
  std::string s{};
  auto c = zip(s);
  REQUIRE(itertest::IsIterator<decltype(std::begin(c))>::value);
  auto c2 = zip(s, s);
  REQUIRE(itertest::IsIterator<decltype(std::begin(c2))>::value);
}

template <typename... Ts>
using ImpT = decltype(zip(std::declval<Ts>()...));
TEST_CASE("zip: has correct ctor and assign ops", "[zip]") {
  using T = ImpT<std::string&, std::vector<double>, std::vector<std::string>>;
  REQUIRE(itertest::IsMoveConstructibleOnly<T>::value);
}
<commit_msg>formatting<commit_after>#include <zip.hpp>

#include "helpers.hpp"

#include <iterator>
#include <sstream>
#include <string>
#include <tuple>
#include <utility>
#include <vector>

#include "catch.hpp"

using iter::zip;
using itertest::BasicIterable;
using itertest::SolidInt;

TEST_CASE("zip: Simple case, same length", "[zip]") {
  using Tu = std::tuple<int, char, double>;
  using ResVec = const std::vector<Tu>;
  std::vector<int> iv{10, 20, 30};
  std::string s{"hey"};
  double arr[] = {1.0, 2.0, 4.0};

  auto z = zip(iv, s, arr);
  ResVec v(std::begin(z), std::end(z));
  ResVec vc{Tu{10, 'h', 1.0}, Tu{20, 'e', 2.0}, Tu{30, 'y', 4.0}};
  REQUIRE(v == vc);
}

TEST_CASE("zip: const iteration", "[zip][const]") {
  using Tu = std::tuple<int, char, double>;
  using ResVec = const std::vector<Tu>;
  std::vector<int> iv{10, 20, 30};
  std::string s{"hey"};
  double arr[] = {1.0, 2.0, 4.0};

  const auto z = zip(iv, s, arr);
  ResVec v(std::begin(z), std::end(z));
  ResVec vc{Tu{10, 'h', 1.0}, Tu{20, 'e', 2.0}, Tu{30, 'y', 4.0}};
  REQUIRE(v == vc);
}

TEST_CASE("zip: const iterators can be compared to non-const iterators",
    "[zip][const]") {
  std::vector<int> v;
  std::string s;
  auto z = zip(v, s);
  const auto& cz = z;
  (void)(std::begin(z) == std::end(cz));
}

TEST_CASE(
    "zip: three sequences, one sequence has different begin and end", "[zip]") {
  using Tu = std::tuple<int, char, double>;
  using ResVec = const std::vector<Tu>;
  std::vector<int> iv{10, 20, 30};
  CharRange cr('d');
  double arr[] = {1.0, 2.0, 4.0};

  auto z = zip(iv, cr, arr);
  ResVec v(std::begin(z), std::end(z));
  ResVec vc{Tu{10, 'a', 1.0}, Tu{20, 'b', 2.0}, Tu{30, 'c', 4.0}};
  REQUIRE(v == vc);
}

TEST_CASE("zip: One empty, all empty", "[zip]") {
  std::vector<int> iv = {1, 2, 3};
  std::string s{};
  auto z = zip(iv, s);
  REQUIRE_FALSE(std::begin(z) != std::end(z));
  auto z2 = zip(s, iv);
  REQUIRE_FALSE(std::begin(z2) != std::end(z2));
}

TEST_CASE("zip: terminates on shortest sequence", "[zip]") {
  std::vector<int> iv{1, 2, 3, 4, 5};
  std::string s{"hi"};
  auto z = zip(iv, s);

  REQUIRE(std::distance(std::begin(z), std::end(z)) == 2);
}

TEST_CASE("zip: Empty", "[zip]") {
  auto z = zip();
  REQUIRE_FALSE(std::begin(z) != std::end(z));
}

TEST_CASE("zip: Modify sequence through zip", "[zip]") {
  std::vector<int> iv{1, 2, 3};
  std::vector<int> iv2{1, 2, 3, 4};
  for (auto&& t : zip(iv, iv2)) {
    std::get<0>(t) = -1;
    std::get<1>(t) = -1;
  }

  const std::vector<int> vc{-1, -1, -1};
  const std::vector<int> vc2{-1, -1, -1, 4};
  REQUIRE(iv == vc);
  REQUIRE(iv2 == vc2);
}

TEST_CASE("zip: binds reference when it should", "[zip]") {
  BasicIterable<char> bi{'x', 'y', 'z'};
  zip(bi);
  REQUIRE_FALSE(bi.was_moved_from());
}

TEST_CASE("zip: moves rvalues", "[zip]") {
  BasicIterable<char> bi{'x', 'y', 'z'};
  zip(std::move(bi));
  REQUIRE(bi.was_moved_from());
}

TEST_CASE("zip: Can bind ref and move in single zip", "[zip]") {
  BasicIterable<char> b1{'x', 'y', 'z'};
  BasicIterable<char> b2{'a', 'b'};
  zip(b1, std::move(b2));
  REQUIRE_FALSE(b1.was_moved_from());
  REQUIRE(b2.was_moved_from());
}

TEST_CASE("zip: doesn't move or copy elements of iterable", "[zip]") {
  constexpr SolidInt arr[] = {{6}, {7}, {8}};
  for (auto&& t : zip(arr)) {
    (void)std::get<0>(t);
  }
}

TEST_CASE("zip: postfix ++", "[zip]") {
  const std::vector<int> v = {1};
  auto z = zip(v);
  auto it = std::begin(z);
  it++;
  REQUIRE(it == std::end(z));
}

TEST_CASE("zip: iterator meets requirements", "[zip]") {
  std::string s{};
  auto c = zip(s);
  REQUIRE(itertest::IsIterator<decltype(std::begin(c))>::value);
  auto c2 = zip(s, s);
  REQUIRE(itertest::IsIterator<decltype(std::begin(c2))>::value);
}

template <typename... Ts>
using ImpT = decltype(zip(std::declval<Ts>()...));
TEST_CASE("zip: has correct ctor and assign ops", "[zip]") {
  using T = ImpT<std::string&, std::vector<double>, std::vector<std::string>>;
  REQUIRE(itertest::IsMoveConstructibleOnly<T>::value);
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <string>

#include "base/logging.h"
#include "base/mime_util.h"
#include "net/base/platform_mime_util.h"

namespace net {

bool PlatformMimeUtil::GetPlatformMimeTypeFromExtension(
    const FilePath::StringType& ext, std::string* result) const {
  FilePath::StringType dummy_path = "foo." + ext;
  std::string out = mime_util::GetFileMimeType(dummy_path);
  // GetFileMimeType likes to return application/octet-stream
  // for everything it doesn't know - ignore that.
  if (out == "application/octet-stream" || !out.length())
    return false;
  *result = out;
  return true;
}

bool PlatformMimeUtil::GetPreferredExtensionForMimeType(
    const std::string& mime_type, FilePath::StringType* ext) const {
  // Unlike GetPlatformMimeTypeFromExtension, this method doesn't have a
  // default list that it uses, but for now we are also returning false since
  // this doesn't really matter as much under Linux.
  //
  // If we wanted to do this properly, we would read the mime.cache file which
  // has a section where they assign a glob (*.gif) to a mimetype
  // (image/gif). We look up the "heaviest" glob for a certain mime type and
  // then then try to chop off "*.".

  NOTIMPLEMENTED();
  return false;
}

}  // namespace net
<commit_msg>Override .ico file's mime type on Linux. XDG's mime database has a bogus "image/x-ico" entry whereas the rest of the world uses "image/x-icon".<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <string>

#include "base/logging.h"
#include "base/mime_util.h"
#include "net/base/platform_mime_util.h"

namespace net {

bool PlatformMimeUtil::GetPlatformMimeTypeFromExtension(
    const FilePath::StringType& ext, std::string* result) const {
  FilePath::StringType dummy_path = "foo." + ext;
  std::string out = mime_util::GetFileMimeType(dummy_path);

  // GetFileMimeType likes to return application/octet-stream
  // for everything it doesn't know - ignore that.
  if (out == "application/octet-stream" || !out.length())
    return false;

  // GetFileMimeType returns image/x-ico because that's what's in the XDG
  // mime database. That database is the merger of the Gnome and KDE mime
  // databases. Apparently someone working on KDE in 2001 decided .ico
  // resolves to image/x-ico, whereas the rest of the world uses image/x-icon.
  // FWIW, image/vnd.microsoft.icon is the official IANA assignment.
  if (out == "image/x-ico")
    out = "image/x-icon";

  *result = out;
  return true;
}

bool PlatformMimeUtil::GetPreferredExtensionForMimeType(
    const std::string& mime_type, FilePath::StringType* ext) const {
  // Unlike GetPlatformMimeTypeFromExtension, this method doesn't have a
  // default list that it uses, but for now we are also returning false since
  // this doesn't really matter as much under Linux.
  //
  // If we wanted to do this properly, we would read the mime.cache file which
  // has a section where they assign a glob (*.gif) to a mimetype
  // (image/gif). We look up the "heaviest" glob for a certain mime type and
  // then then try to chop off "*.".

  NOTIMPLEMENTED();
  return false;
}

}  // namespace net
<|endoftext|>


<commit_before>#include "GRenderContext.h"
#include <fstream>
#include <cmath>
#include "GFrameBufferObject.h"
#include "GLUtil.h"
#include "Util.h"

namespace NodeBinding
{
GRenderContext::GRenderContext(int width, int height)
    : mWidth(width), mHeight(height), mRatio(2.0) {
    GCanvasConfig config = {true, true};
    this->mCanvas = std::make_shared<gcanvas::GCanvas>("node-gcanvas", config, nullptr);
    mCanvasWidth = width * mRatio;
    mCanvasHeight = height * mRatio;
}

GRenderContext::GRenderContext(int width, int height, int ratio)
    : mWidth(width), mHeight(height), mRatio(ratio) {
    GCanvasConfig config = {true, true};
    this->mCanvas = std::make_shared<gcanvas::GCanvas>("node-gcanvas", config, nullptr);
    mCanvasWidth = width * mRatio;
    mCanvasHeight = height * mRatio;
}

void GRenderContext::initRenderEnviroment()
{
#ifdef CONTEXT_ES20
    EGLint ai32ContextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
#endif

    // Step 1 - Get the default display.
    mEglDisplay = eglGetDisplay((EGLNativeDisplayType)0);

    // Step 2 - Initialize EGL.
    eglInitialize(mEglDisplay, 0, 0);

#ifdef CONTEXT_ES20
    // Step 3 - Make OpenGL ES the current API.
    eglBindAPI(EGL_OPENGL_ES_API);

    // Step 4 - Specify the required configuration attributes.
    EGLint pi32ConfigAttribs[5];
    pi32ConfigAttribs[0] = EGL_SURFACE_TYPE;
    pi32ConfigAttribs[1] = EGL_WINDOW_BIT;
    pi32ConfigAttribs[2] = EGL_RENDERABLE_TYPE;
    pi32ConfigAttribs[3] = EGL_OPENGL_ES2_BIT;
    pi32ConfigAttribs[4] = EGL_NONE;
#else
    EGLint pi32ConfigAttribs[3];
    pi32ConfigAttribs[0] = EGL_SURFACE_TYPE;
    pi32ConfigAttribs[1] = EGL_WINDOW_BIT;
    pi32ConfigAttribs[2] = EGL_NONE;
#endif

    // Step 5 - Find a config that matches all requirements.
    int iConfigs;
    EGLConfig eglConfig;
    eglChooseConfig(mEglDisplay, pi32ConfigAttribs, &eglConfig, 1,
                    &iConfigs);

    if (iConfigs != 1)
    {
        printf("Error: eglChooseConfig(): config not found \n");
        exit(-1);
    }

    // Step 6 - Create a surface to draw to.

    mEglSurface = eglCreatePbufferSurface(mEglDisplay, eglConfig, NULL);
    // Step 7 - Create a context.

#ifdef CONTEXT_ES20
    mEglContext = eglCreateContext(mEglDisplay, eglConfig, NULL, ai32ContextAttribs);
#else
    mEglContext = eglCreateContext(eglDisplay, eglConfig, NULL, NULL);
#endif

    // Step 8 - Bind the context to the current thread
    eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
    // end of standard gl context setup

    // Step 9 - create framebuffer object

    GLuint renderBuffer;
    glGenRenderbuffers(1, &renderBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB565, mCanvasWidth, mCanvasHeight);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBuffer);
    GLuint depthRenderbuffer;
    glGenRenderbuffers(1, &depthRenderbuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, mCanvasWidth, mCanvasHeight);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);

    // check FBO status
    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if (status != GL_FRAMEBUFFER_COMPLETE)
    {
        printf("Problem with OpenGL framebuffer after specifying color render buffer: n%xn", status);
    }
    else
    {
        // printf("FBO creation succeddedn \n ");
    }

    GLint format = 0, type = 0;
    glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &format);
    glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &type);
    this->initCanvas();
}
void GRenderContext::initCanvas()
{
    mCanvas->CreateContext();
    mCanvas->GetGCanvasContext()->SetClearColor(gcanvas::StrValueToColorRGBA("white"));
    mCanvas->GetGCanvasContext()->ClearScreen();
    mCanvas->GetGCanvasContext()->SetDevicePixelRatio(mRatio);
    mCanvas->OnSurfaceChanged(0, 0, mCanvasWidth, mCanvasHeight);
}
void GRenderContext::drawFrame()
{
    mCanvas->drawFrame();
    this->drawCount++;
}

void GRenderContext::render2file(std::string fileName, PIC_FORMAT format)
{
    int size = 4 * mCanvasWidth * mCanvasHeight;
    unsigned char *inputData = new unsigned char[size];
    if( !inputData ){
        printf("Error: allocate inputData memeroy faied! \n");
        return;
    }
    glReadPixels(0, 0, mWidth * 2, mHeight * 2, GL_RGBA, GL_UNSIGNED_BYTE, inputData);

    unsigned char *data = new unsigned char[4 * mWidth * mHeight];
    if( !data ){
        printf("Error: allocate data memeroy faied! \n");
        return;
    }

    gcanvas::PixelsSampler(mWidth * 2, mHeight * 2, reinterpret_cast<int *>(inputData), mWidth, mHeight, reinterpret_cast<int *>(data));
    gcanvas::FlipPixel(data, mWidth, mHeight);

    delete inputData;
    inputData = nullptr;

    if (format == PNG_FORAMT)
    {
        encodePixelsToPNGFile(fileName + ".png", data, mWidth, mHeight);
    }
    else if (format == JPEG_FORMAT)
    {
        encodePixelsToJPEGFile(fileName + ".jpg", data, mWidth, mHeight);
    }
    delete data;
    data = nullptr;
}

void GRenderContext::destoryRenderEnviroment()
{
    if (this->mFboId != 0)
    {
        glDeleteFramebuffers(1, &this->mFboId);
    }
    if (this->mRenderBuffer != 0)
    {
        glDeleteRenderbuffers(1, &this->mRenderBuffer);
    }
    if (this->mDepthRenderbuffer != 0)
    {
        glDeleteRenderbuffers(1, &this->mDepthRenderbuffer);
    }
    if (this->textures.size() > 0)
    {
        glDeleteTextures(this->textures.size(), (GLuint *)&textures[0]);
    }
    if (mEglDisplay != EGL_NO_DISPLAY)
    {
        eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
        if (mEglContext != EGL_NO_CONTEXT)
        {
            eglDestroyContext(mEglDisplay, mEglContext);
        }
        if (mEglSurface != EGL_NO_SURFACE)
        {
            eglDestroySurface(mEglDisplay, mEglSurface);
        }
        eglTerminate(mEglDisplay);
    }
    mEglDisplay = EGL_NO_DISPLAY;
    mEglContext = EGL_NO_CONTEXT;
    mEglSurface = EGL_NO_SURFACE;
}

void GRenderContext::recordTextures(int textureId)
{
    this->textures.push_back(textureId);
}

GRenderContext::~GRenderContext()
{
    this->destoryRenderEnviroment();
}
} // namespace NodeBinding
<commit_msg>fix: merge problem<commit_after>#include "GRenderContext.h"
#include <fstream>
#include <cmath>
#include "GFrameBufferObject.h"
#include "GLUtil.h"
#include "Util.h"

namespace NodeBinding
{
GRenderContext::GRenderContext(int width, int height)
    : mWidth(width), mHeight(height), mRatio(2.0) {
    GCanvasConfig config = {true, true};
    this->mCanvas = std::make_shared<gcanvas::GCanvas>("node-gcanvas", config, nullptr);
    mCanvasWidth = width * mRatio;
    mCanvasHeight = height * mRatio;
}

GRenderContext::GRenderContext(int width, int height, int ratio)
    : mWidth(width), mHeight(height), mRatio(ratio) {
    GCanvasConfig config = {true, true};
    this->mCanvas = std::make_shared<gcanvas::GCanvas>("node-gcanvas", config, nullptr);
    mCanvasWidth = width * mRatio;
    mCanvasHeight = height * mRatio;
}

void GRenderContext::initRenderEnviroment()
{
#ifdef CONTEXT_ES20
    EGLint ai32ContextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
#endif

    // Step 1 - Get the default display.
    mEglDisplay = eglGetDisplay((EGLNativeDisplayType)0);

    // Step 2 - Initialize EGL.
    eglInitialize(mEglDisplay, 0, 0);

#ifdef CONTEXT_ES20
    // Step 3 - Make OpenGL ES the current API.
    eglBindAPI(EGL_OPENGL_ES_API);

    // Step 4 - Specify the required configuration attributes.
    EGLint pi32ConfigAttribs[5];
    pi32ConfigAttribs[0] = EGL_SURFACE_TYPE;
    pi32ConfigAttribs[1] = EGL_WINDOW_BIT;
    pi32ConfigAttribs[2] = EGL_RENDERABLE_TYPE;
    pi32ConfigAttribs[3] = EGL_OPENGL_ES2_BIT;
    pi32ConfigAttribs[4] = EGL_NONE;
#else
    EGLint pi32ConfigAttribs[3];
    pi32ConfigAttribs[0] = EGL_SURFACE_TYPE;
    pi32ConfigAttribs[1] = EGL_WINDOW_BIT;
    pi32ConfigAttribs[2] = EGL_NONE;
#endif

    // Step 5 - Find a config that matches all requirements.
    int iConfigs;
    EGLConfig eglConfig;
    eglChooseConfig(mEglDisplay, pi32ConfigAttribs, &eglConfig, 1,
                    &iConfigs);

    if (iConfigs != 1)
    {
        printf("Error: eglChooseConfig(): config not found \n");
        exit(-1);
    }

    // Step 6 - Create a surface to draw to.

    mEglSurface = eglCreatePbufferSurface(mEglDisplay, eglConfig, NULL);
    // Step 7 - Create a context.

#ifdef CONTEXT_ES20
    mEglContext = eglCreateContext(mEglDisplay, eglConfig, NULL, ai32ContextAttribs);
#else
    mEglContext = eglCreateContext(eglDisplay, eglConfig, NULL, NULL);
#endif

    // Step 8 - Bind the context to the current thread
    eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
    // end of standard gl context setup

    // Step 9 - create framebuffer object
    glGenFramebuffers(1, &mFboId);
    glBindFramebuffer(GL_FRAMEBUFFER, mFboId);

    GLuint renderBuffer;
    glGenRenderbuffers(1, &renderBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB565, mCanvasWidth, mCanvasHeight);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBuffer);
    GLuint depthRenderbuffer;
    glGenRenderbuffers(1, &depthRenderbuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, mCanvasWidth, mCanvasHeight);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);

    // check FBO status
    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if (status != GL_FRAMEBUFFER_COMPLETE)
    {
        printf("Problem with OpenGL framebuffer after specifying color render buffer: n%xn", status);
    }
    else
    {
        // printf("FBO creation succeddedn \n ");
    }

    GLint format = 0, type = 0;
    glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &format);
    glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &type);
    this->initCanvas();
}
void GRenderContext::initCanvas()
{
    mCanvas->CreateContext();
    mCanvas->GetGCanvasContext()->SetClearColor(gcanvas::StrValueToColorRGBA("white"));
    mCanvas->GetGCanvasContext()->ClearScreen();
    mCanvas->GetGCanvasContext()->SetDevicePixelRatio(mRatio);
    mCanvas->OnSurfaceChanged(0, 0, mCanvasWidth, mCanvasHeight);
}
void GRenderContext::drawFrame()
{
    mCanvas->drawFrame();
    this->drawCount++;
}

void GRenderContext::render2file(std::string fileName, PIC_FORMAT format)
{
    int size = 4 * mCanvasWidth * mCanvasHeight;
    unsigned char *inputData = new unsigned char[size];
    if( !inputData ){
        printf("Error: allocate inputData memeroy faied! \n");
        return;
    }
    glReadPixels(0, 0, mWidth * 2, mHeight * 2, GL_RGBA, GL_UNSIGNED_BYTE, inputData);

    unsigned char *data = new unsigned char[4 * mWidth * mHeight];
    if( !data ){
        printf("Error: allocate data memeroy faied! \n");
        delete inputData;
        inputData = nullptr;
        return;
    }

    gcanvas::PixelsSampler(mWidth * 2, mHeight * 2, reinterpret_cast<int *>(inputData), mWidth, mHeight, reinterpret_cast<int *>(data));
    gcanvas::FlipPixel(data, mWidth, mHeight);

    delete inputData;
    inputData = nullptr;

    if (format == PNG_FORAMT)
    {
        encodePixelsToPNGFile(fileName + ".png", data, mWidth, mHeight);
    }
    else if (format == JPEG_FORMAT)
    {
        encodePixelsToJPEGFile(fileName + ".jpg", data, mWidth, mHeight);
    }
    delete data;
    data = nullptr;
}

void GRenderContext::destoryRenderEnviroment()
{
    if (this->mFboId != 0)
    {
        glDeleteFramebuffers(1, &this->mFboId);
    }
    if (this->mRenderBuffer != 0)
    {
        glDeleteRenderbuffers(1, &this->mRenderBuffer);
    }
    if (this->mDepthRenderbuffer != 0)
    {
        glDeleteRenderbuffers(1, &this->mDepthRenderbuffer);
    }
    if (this->textures.size() > 0)
    {
        glDeleteTextures(this->textures.size(), (GLuint *)&textures[0]);
    }
    if (mEglDisplay != EGL_NO_DISPLAY)
    {
        eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
        if (mEglContext != EGL_NO_CONTEXT)
        {
            eglDestroyContext(mEglDisplay, mEglContext);
        }
        if (mEglSurface != EGL_NO_SURFACE)
        {
            eglDestroySurface(mEglDisplay, mEglSurface);
        }
        eglTerminate(mEglDisplay);
    }
    mEglDisplay = EGL_NO_DISPLAY;
    mEglContext = EGL_NO_CONTEXT;
    mEglSurface = EGL_NO_SURFACE;
}

void GRenderContext::recordTextures(int textureId)
{
    this->textures.push_back(textureId);
}

GRenderContext::~GRenderContext()
{
    this->destoryRenderEnviroment();
}
} // namespace NodeBinding
<|endoftext|>


<commit_before>/*
Author: Ethan Coon

Painter's permafrost model.

 */

#ifndef AMANZI_FLOWRELATIONS_WRM_IMPLICIT_PERMAFROST_MODEL_
#define AMANZI_FLOWRELATIONS_WRM_IMPLICIT_PERMAFROST_MODEL_

#include <boost/math/tools/roots.hpp>
#include <boost/cstdint.hpp>

#include "wrm_permafrost_model.hh"
#include "wrm_permafrost_factory.hh"

namespace Amanzi {
namespace Flow {
namespace FlowRelations {

class WRM;

class WRMImplicitPermafrostModel : public WRMPermafrostModel {

 public:
  explicit
  WRMImplicitPermafrostModel(Teuchos::ParameterList& plist);

  // required methods from the base class
  // sats[0] = sg, sats[1] = sl, sats[2] = si
  virtual bool freezing(double T, double pc_liq, double pc_ice) { return T < 273.15; }
  virtual void saturations(double pc_liq, double pc_ice, double (&sats)[3]);
  virtual void dsaturations_dpc_liq(double pc_liq, double pc_ice, double (&dsats)[3]);
  virtual void dsaturations_dpc_ice(double pc_liq, double pc_ice, double (&dsats)[3]);

 protected:
  // calculation if unfrozen
  bool sats_unfrozen_(double pc_liq, double pc_ice, double (&sats)[3]);
  bool dsats_dpc_liq_unfrozen_(double pc_liq, double pc_ice, double (&dsats)[3]);
  bool dsats_dpc_ice_unfrozen_(double pc_liq, double pc_ice, double (&dsats)[3]);

  // calculation if saturated
  bool sats_saturated_(double pc_liq, double pc_ice, double (&sats)[3]);
  bool dsats_dpc_liq_saturated_(double pc_liq, double pc_ice, double (&dsats)[3]);
  bool dsats_dpc_ice_saturated_(double pc_liq, double pc_ice, double (&dsats)[3]);

  // calculation if unfrozen and saturated
  bool sats_frozen_unsaturated_(double pc_liq, double pc_ice, double (&sats)[3]);
  bool dsats_dpc_liq_frozen_unsaturated_(double pc_liq, double pc_ice,
          double (&dsats)[3]);
  bool dsats_dpc_ice_frozen_unsaturated_(double pc_liq, double pc_ice,
          double (&dsats)[3]);

  double si_frozen_unsaturated_(double pc_liq, double pc_ice);
  double dsi_dpc_liq_frozen_unsaturated_(double pc_liq, double pc_ice, double si);
  double dsi_dpc_ice_frozen_unsaturated_(double pc_liq, double pc_ice, double si);

  double si_frozen_unsaturated_nospline_(double pc_liq, double pc_ice, bool throw_ok=false);
  double dsi_dpc_liq_frozen_unsaturated_nospline_(double pc_liq, double pc_ice,
          double si);
  double dsi_dpc_ice_frozen_unsaturated_nospline_(double pc_liq, double pc_ice,
          double si);

  bool DetermineSplineCutoff_(double pc_liq, double pc_ice, double& cutoff, double& si);
  bool FitSpline_(double pc_ice, double cutoff, double si_cutoff, double (&coefs)[4]);

 protected:
  double eps_;
  boost::uintmax_t max_it_;
  double deriv_regularization_;
  std::string solver_;

 private:
  // Functor for ice saturation, gets used within a root-finding algorithm
  class SatIceFunctor_ {
   public:
    SatIceFunctor_(double pc_liq, double pc_ice,
                   const Teuchos::RCP<WRM>& wrm) :
        pc_liq_(pc_liq), pc_ice_(pc_ice), wrm_(wrm) {}

    double operator()(double si) {
      double tmp = (1.0 - si) * wrm_->saturation(pc_liq_);
      double result = tmp - wrm_->saturation( pc_ice_ + wrm_->capillaryPressure( tmp + si));
      return result;
    }

   private:
    double pc_liq_;
    double pc_ice_;
    Teuchos::RCP<WRM> wrm_;
  };

  // Convergence criteria for root-finding
  struct Tol_ {
    Tol_(double eps) : eps_(eps) {}
    bool operator()(const double& a, const double& b) const {
      return std::abs(a - b) <= eps_;
    }
    double eps_;
  };

 private:
  // factory registration
  static Utils::RegisteredFactory<WRMPermafrostModel,WRMImplicitPermafrostModel> factory_;

};

} //namespace
} //namespace
} //namespace

#endif
<commit_msg>Automated merge with https://software.lanl.gov/ats/hg/ats<commit_after>/*
Author: Ethan Coon

Painter's permafrost model.

 */

#ifndef AMANZI_FLOWRELATIONS_WRM_IMPLICIT_PERMAFROST_MODEL_
#define AMANZI_FLOWRELATIONS_WRM_IMPLICIT_PERMAFROST_MODEL_

#include <boost/cstdint.hpp>
#include <boost/math/tools/roots.hpp>
#include <boost/cstdint.hpp>

#include "wrm_permafrost_model.hh"
#include "wrm_permafrost_factory.hh"

namespace Amanzi {
namespace Flow {
namespace FlowRelations {

class WRM;

class WRMImplicitPermafrostModel : public WRMPermafrostModel {

 public:
  explicit
  WRMImplicitPermafrostModel(Teuchos::ParameterList& plist);

  // required methods from the base class
  // sats[0] = sg, sats[1] = sl, sats[2] = si
  virtual bool freezing(double T, double pc_liq, double pc_ice) { return T < 273.15; }
  virtual void saturations(double pc_liq, double pc_ice, double (&sats)[3]);
  virtual void dsaturations_dpc_liq(double pc_liq, double pc_ice, double (&dsats)[3]);
  virtual void dsaturations_dpc_ice(double pc_liq, double pc_ice, double (&dsats)[3]);

 protected:
  // calculation if unfrozen
  bool sats_unfrozen_(double pc_liq, double pc_ice, double (&sats)[3]);
  bool dsats_dpc_liq_unfrozen_(double pc_liq, double pc_ice, double (&dsats)[3]);
  bool dsats_dpc_ice_unfrozen_(double pc_liq, double pc_ice, double (&dsats)[3]);

  // calculation if saturated
  bool sats_saturated_(double pc_liq, double pc_ice, double (&sats)[3]);
  bool dsats_dpc_liq_saturated_(double pc_liq, double pc_ice, double (&dsats)[3]);
  bool dsats_dpc_ice_saturated_(double pc_liq, double pc_ice, double (&dsats)[3]);

  // calculation if unfrozen and saturated
  bool sats_frozen_unsaturated_(double pc_liq, double pc_ice, double (&sats)[3]);
  bool dsats_dpc_liq_frozen_unsaturated_(double pc_liq, double pc_ice,
          double (&dsats)[3]);
  bool dsats_dpc_ice_frozen_unsaturated_(double pc_liq, double pc_ice,
          double (&dsats)[3]);

  double si_frozen_unsaturated_(double pc_liq, double pc_ice);
  double dsi_dpc_liq_frozen_unsaturated_(double pc_liq, double pc_ice, double si);
  double dsi_dpc_ice_frozen_unsaturated_(double pc_liq, double pc_ice, double si);

  double si_frozen_unsaturated_nospline_(double pc_liq, double pc_ice, bool throw_ok=false);
  double dsi_dpc_liq_frozen_unsaturated_nospline_(double pc_liq, double pc_ice,
          double si);
  double dsi_dpc_ice_frozen_unsaturated_nospline_(double pc_liq, double pc_ice,
          double si);

  bool DetermineSplineCutoff_(double pc_liq, double pc_ice, double& cutoff, double& si);
  bool FitSpline_(double pc_ice, double cutoff, double si_cutoff, double (&coefs)[4]);

 protected:
  double eps_;
  boost::uintmax_t max_it_;
  double deriv_regularization_;
  std::string solver_;

 private:
  // Functor for ice saturation, gets used within a root-finding algorithm
  class SatIceFunctor_ {
   public:
    SatIceFunctor_(double pc_liq, double pc_ice,
                   const Teuchos::RCP<WRM>& wrm) :
        pc_liq_(pc_liq), pc_ice_(pc_ice), wrm_(wrm) {}

    double operator()(double si) {
      double tmp = (1.0 - si) * wrm_->saturation(pc_liq_);
      double result = tmp - wrm_->saturation( pc_ice_ + wrm_->capillaryPressure( tmp + si));
      return result;
    }

   private:
    double pc_liq_;
    double pc_ice_;
    Teuchos::RCP<WRM> wrm_;
  };

  // Convergence criteria for root-finding
  struct Tol_ {
    Tol_(double eps) : eps_(eps) {}
    bool operator()(const double& a, const double& b) const {
      return std::abs(a - b) <= eps_;
    }
    double eps_;
  };

 private:
  // factory registration
  static Utils::RegisteredFactory<WRMPermafrostModel,WRMImplicitPermafrostModel> factory_;

};

} //namespace
} //namespace
} //namespace

#endif
<|endoftext|>