<commit_before>/*
* Vulkan Model loader using ASSIMP
*
* Copyright(C) 2016-2017 by Sascha Willems - www.saschawillems.de
*
* This code is licensed under the MIT license(MIT) (http://opensource.org/licenses/MIT)
*/

#pragma once

#include <stdlib.h>
#include <string>
#include <fstream>
#include <vector>
#include <map>

#include "vulkan/vulkan.h"

#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include <assimp/cimport.h>

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include "VulkanDevice.hpp"
#include "VulkanBuffer.hpp"

#if defined(__ANDROID__)
#include <android/asset_manager.h>
#endif

namespace vks
{
	/** @brief Vertex layout components */
	typedef enum Component {
		VERTEX_COMPONENT_POSITION = 0x0,
		VERTEX_COMPONENT_NORMAL = 0x1,
		VERTEX_COMPONENT_COLOR = 0x2,
		VERTEX_COMPONENT_UV = 0x3,
		VERTEX_COMPONENT_TANGENT = 0x4,
		VERTEX_COMPONENT_BITANGENT = 0x5,
		VERTEX_COMPONENT_DUMMY_FLOAT = 0x6,
		VERTEX_COMPONENT_DUMMY_VEC4 = 0x7
	} Component;

	/** @brief Stores vertex layout components for model loading and Vulkan vertex input and atribute bindings  */
	struct VertexLayout {
	public:
		/** @brief Components used to generate vertices from */
		std::vector<Component> components;

		VertexLayout(std::vector<Component> components)
		{
			this->components = std::move(components);
		}

		uint32_t stride()
		{
			uint32_t res = 0;
			for (auto& component : components)
			{
				switch (component)
				{
				case VERTEX_COMPONENT_UV:
					res += 2 * sizeof(float);
					break;
				case VERTEX_COMPONENT_DUMMY_FLOAT:
					res += sizeof(float);
					break;
				case VERTEX_COMPONENT_DUMMY_VEC4:
					res += 4 * sizeof(float);
					break;
				default:
					// All components except the ones listed above are made up of 3 floats
					res += 3 * sizeof(float);
				}
			}
			return res;
		}
	};

	/** @brief Used to parametrize model loading */
	struct ModelCreateInfo {
		glm::vec3 center;
		glm::vec3 scale;
		glm::vec2 uvscale;

		ModelCreateInfo() {};

		ModelCreateInfo(glm::vec3 scale, glm::vec3 uvscale, glm::vec3 center)
		{
			this->center = center;
			this->scale = scale;
			this->uvscale = uvscale;
		}

		ModelCreateInfo(float scale, float uvscale, float center)
		{
			this->center = glm::vec3(center);
			this->scale = glm::vec3(scale);
			this->uvscale = glm::vec3(uvscale);
		}

	};

	struct Model {
		VkDevice device = nullptr;
		vks::Buffer vertices;
		vks::Buffer indices;
		uint32_t indexCount = 0;
		uint32_t vertexCount = 0;

		/** @brief Stores vertex and index base and counts for each part of a model */
		struct ModelPart {
			uint32_t vertexBase;
			uint32_t vertexCount;
			uint32_t indexBase;
			uint32_t indexCount;
		};
		std::vector<ModelPart> parts;

		static const int defaultFlags = aiProcess_FlipWindingOrder | aiProcess_Triangulate | aiProcess_PreTransformVertices | aiProcess_CalcTangentSpace | aiProcess_GenSmoothNormals;

		struct Dimension
		{
			glm::vec3 min = glm::vec3(FLT_MAX);
			glm::vec3 max = glm::vec3(-FLT_MAX);
			glm::vec3 size;
		} dim;

		/** @brief Release all Vulkan resources of this model */
		void destroy()
		{
			assert(device);
			vkDestroyBuffer(device, vertices.buffer, nullptr);
			vkFreeMemory(device, vertices.memory, nullptr);
			if (indices.buffer != VK_NULL_HANDLE)
			{
				vkDestroyBuffer(device, indices.buffer, nullptr);
				vkFreeMemory(device, indices.memory, nullptr);
			}
		}

		/**
		* Loads a 3D model from a file into Vulkan buffers
		*
		* @param device Pointer to the Vulkan device used to generated the vertex and index buffers on
		* @param filename File to load (must be a model format supported by ASSIMP)
		* @param layout Vertex layout components (position, normals, tangents, etc.)
		* @param createInfo MeshCreateInfo structure for load time settings like scale, center, etc.
		* @param copyQueue Queue used for the memory staging copy commands (must support transfer)
		* @param (Optional) flags ASSIMP model loading flags
		*/
		bool loadFromFile(const std::string& filename, vks::VertexLayout layout, vks::ModelCreateInfo *createInfo, vks::VulkanDevice *device, VkQueue copyQueue, const int flags = defaultFlags)
		{
			this->device = device->logicalDevice;

			Assimp::Importer Importer;
			const aiScene* pScene;

			// Load file
#if defined(__ANDROID__)
			// Meshes are stored inside the apk on Android (compressed)
			// So they need to be loaded via the asset manager

			AAsset* asset = AAssetManager_open(androidApp->activity->assetManager, filename.c_str(), AASSET_MODE_STREAMING);
			assert(asset);
			size_t size = AAsset_getLength(asset);

			assert(size > 0);

			void *meshData = malloc(size);
			AAsset_read(asset, meshData, size);
			AAsset_close(asset);

			pScene = Importer.ReadFileFromMemory(meshData, size, flags);

			free(meshData);
#else
			pScene = Importer.ReadFile(filename.c_str(), flags);
#endif

			if (pScene)
			{
				parts.clear();
				parts.resize(pScene->mNumMeshes);

				glm::vec3 scale(1.0f);
				glm::vec2 uvscale(1.0f);
				glm::vec3 center(0.0f);
				if (createInfo)
				{
					scale = createInfo->scale;
					uvscale = createInfo->uvscale;
					center = createInfo->center;
				}

				std::vector<float> vertexBuffer;
				std::vector<uint32_t> indexBuffer;

				vertexCount = 0;
				indexCount = 0;

				// Load meshes
				for (unsigned int i = 0; i < pScene->mNumMeshes; i++)
				{
					const aiMesh* paiMesh = pScene->mMeshes[i];

					parts[i] = {};
					parts[i].vertexBase = vertexCount;
					parts[i].indexBase = indexCount;

					vertexCount += pScene->mMeshes[i]->mNumVertices;

					aiColor3D pColor(0.f, 0.f, 0.f);
					pScene->mMaterials[paiMesh->mMaterialIndex]->Get(AI_MATKEY_COLOR_DIFFUSE, pColor);

					const aiVector3D Zero3D(0.0f, 0.0f, 0.0f);

					for (unsigned int j = 0; j < paiMesh->mNumVertices; j++)
					{
						const aiVector3D* pPos = &(paiMesh->mVertices[j]);
						const aiVector3D* pNormal = &(paiMesh->mNormals[j]);
						const aiVector3D* pTexCoord = (paiMesh->HasTextureCoords(0)) ? &(paiMesh->mTextureCoords[0][j]) : &Zero3D;
						const aiVector3D* pTangent = (paiMesh->HasTangentsAndBitangents()) ? &(paiMesh->mTangents[j]) : &Zero3D;
						const aiVector3D* pBiTangent = (paiMesh->HasTangentsAndBitangents()) ? &(paiMesh->mBitangents[j]) : &Zero3D;

						for (auto& component : layout.components)
						{
							switch (component) {
							case VERTEX_COMPONENT_POSITION:
								vertexBuffer.push_back(pPos->x * scale.x + center.x);
								vertexBuffer.push_back(-pPos->y * scale.y + center.y);
								vertexBuffer.push_back(pPos->z * scale.z + center.z);
								break;
							case VERTEX_COMPONENT_NORMAL:
								vertexBuffer.push_back(pNormal->x);
								vertexBuffer.push_back(-pNormal->y);
								vertexBuffer.push_back(pNormal->z);
								break;
							case VERTEX_COMPONENT_UV:
								vertexBuffer.push_back(pTexCoord->x * uvscale.s);
								vertexBuffer.push_back(pTexCoord->y * uvscale.t);
								break;
							case VERTEX_COMPONENT_COLOR:
								vertexBuffer.push_back(pColor.r);
								vertexBuffer.push_back(pColor.g);
								vertexBuffer.push_back(pColor.b);
								break;
							case VERTEX_COMPONENT_TANGENT:
								vertexBuffer.push_back(pTangent->x);
								vertexBuffer.push_back(pTangent->y);
								vertexBuffer.push_back(pTangent->z);
								break;
							case VERTEX_COMPONENT_BITANGENT:
								vertexBuffer.push_back(pBiTangent->x);
								vertexBuffer.push_back(pBiTangent->y);
								vertexBuffer.push_back(pBiTangent->z);
								break;
							// Dummy components for padding
							case VERTEX_COMPONENT_DUMMY_FLOAT:
								vertexBuffer.push_back(0.0f);
								break;
							case VERTEX_COMPONENT_DUMMY_VEC4:
								vertexBuffer.push_back(0.0f);
								vertexBuffer.push_back(0.0f);
								vertexBuffer.push_back(0.0f);
								vertexBuffer.push_back(0.0f);
								break;
							};
						}

						dim.max.x = fmax(pPos->x, dim.max.x);
						dim.max.y = fmax(pPos->y, dim.max.y);
						dim.max.z = fmax(pPos->z, dim.max.z);

						dim.min.x = fmin(pPos->x, dim.min.x);
						dim.min.y = fmin(pPos->y, dim.min.y);
						dim.min.z = fmin(pPos->z, dim.min.z);
					}

					dim.size = dim.max - dim.min;

					parts[i].vertexCount = paiMesh->mNumVertices;

					uint32_t indexBase = static_cast<uint32_t>(indexBuffer.size());
					for (unsigned int j = 0; j < paiMesh->mNumFaces; j++)
					{
						const aiFace& Face = paiMesh->mFaces[j];
						if (Face.mNumIndices != 3)
							continue;
						indexBuffer.push_back(indexBase + Face.mIndices[0]);
						indexBuffer.push_back(indexBase + Face.mIndices[1]);
						indexBuffer.push_back(indexBase + Face.mIndices[2]);
						parts[i].indexCount += 3;
						indexCount += 3;
					}
				}

				uint32_t vBufferSize = static_cast<uint32_t>(vertexBuffer.size()) * sizeof(float);
				uint32_t iBufferSize = static_cast<uint32_t>(indexBuffer.size()) * sizeof(uint32_t);

				// Use staging buffer to move vertex and index buffer to device local memory
				// Create staging buffers
				vks::Buffer vertexStaging, indexStaging;

				// Vertex buffer
				VK_CHECK_RESULT(device->createBuffer(
					VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
					VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
					&vertexStaging,
					vBufferSize,
					vertexBuffer.data()));

				// Index buffer
				VK_CHECK_RESULT(device->createBuffer(
					VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
					VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
					&indexStaging,
					iBufferSize,
					indexBuffer.data()));

				// Create device local target buffers
				// Vertex buffer
				VK_CHECK_RESULT(device->createBuffer(
					VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
					VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
					&vertices,
					vBufferSize));

				// Index buffer
				VK_CHECK_RESULT(device->createBuffer(
					VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
					VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
					&indices,
					iBufferSize));

				// Copy from staging buffers
				VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);

				VkBufferCopy copyRegion{};

				copyRegion.size = vertices.size;
				vkCmdCopyBuffer(copyCmd, vertexStaging.buffer, vertices.buffer, 1, &copyRegion);

				copyRegion.size = indices.size;
				vkCmdCopyBuffer(copyCmd, indexStaging.buffer, indices.buffer, 1, &copyRegion);

				device->flushCommandBuffer(copyCmd, copyQueue);

				// Destroy staging resources
				vkDestroyBuffer(device->logicalDevice, vertexStaging.buffer, nullptr);
				vkFreeMemory(device->logicalDevice, vertexStaging.memory, nullptr);
				vkDestroyBuffer(device->logicalDevice, indexStaging.buffer, nullptr);
				vkFreeMemory(device->logicalDevice, indexStaging.memory, nullptr);

				return true;
			}
			else
			{
				printf("Error parsing '%s': '%s'\n", filename.c_str(), Importer.GetErrorString());
#if defined(__ANDROID__)
				LOGE("Error parsing '%s': '%s'", filename.c_str(), Importer.GetErrorString());
#endif
				return false;
			}
		};

		/**
		* Loads a 3D model from a file into Vulkan buffers
		*
		* @param device Pointer to the Vulkan device used to generated the vertex and index buffers on
		* @param filename File to load (must be a model format supported by ASSIMP)
		* @param layout Vertex layout components (position, normals, tangents, etc.)
		* @param scale Load time scene scale
		* @param copyQueue Queue used for the memory staging copy commands (must support transfer)
		* @param (Optional) flags ASSIMP model loading flags
		*/
		bool loadFromFile(const std::string& filename, vks::VertexLayout layout, float scale, vks::VulkanDevice *device, VkQueue copyQueue, const int flags = defaultFlags)
		{
			vks::ModelCreateInfo modelCreateInfo(scale, 1.0f, 0.0f);
			return loadFromFile(filename, layout, &modelCreateInfo, device, copyQueue, flags);
		}
	};
};<commit_msg>uvscale argument as vec2 (Fixes #282)<commit_after>/*
* Vulkan Model loader using ASSIMP
*
* Copyright(C) 2016-2017 by Sascha Willems - www.saschawillems.de
*
* This code is licensed under the MIT license(MIT) (http://opensource.org/licenses/MIT)
*/

#pragma once

#include <stdlib.h>
#include <string>
#include <fstream>
#include <vector>
#include <map>

#include "vulkan/vulkan.h"

#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include <assimp/cimport.h>

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include "VulkanDevice.hpp"
#include "VulkanBuffer.hpp"

#if defined(__ANDROID__)
#include <android/asset_manager.h>
#endif

namespace vks
{
	/** @brief Vertex layout components */
	typedef enum Component {
		VERTEX_COMPONENT_POSITION = 0x0,
		VERTEX_COMPONENT_NORMAL = 0x1,
		VERTEX_COMPONENT_COLOR = 0x2,
		VERTEX_COMPONENT_UV = 0x3,
		VERTEX_COMPONENT_TANGENT = 0x4,
		VERTEX_COMPONENT_BITANGENT = 0x5,
		VERTEX_COMPONENT_DUMMY_FLOAT = 0x6,
		VERTEX_COMPONENT_DUMMY_VEC4 = 0x7
	} Component;

	/** @brief Stores vertex layout components for model loading and Vulkan vertex input and atribute bindings  */
	struct VertexLayout {
	public:
		/** @brief Components used to generate vertices from */
		std::vector<Component> components;

		VertexLayout(std::vector<Component> components)
		{
			this->components = std::move(components);
		}

		uint32_t stride()
		{
			uint32_t res = 0;
			for (auto& component : components)
			{
				switch (component)
				{
				case VERTEX_COMPONENT_UV:
					res += 2 * sizeof(float);
					break;
				case VERTEX_COMPONENT_DUMMY_FLOAT:
					res += sizeof(float);
					break;
				case VERTEX_COMPONENT_DUMMY_VEC4:
					res += 4 * sizeof(float);
					break;
				default:
					// All components except the ones listed above are made up of 3 floats
					res += 3 * sizeof(float);
				}
			}
			return res;
		}
	};

	/** @brief Used to parametrize model loading */
	struct ModelCreateInfo {
		glm::vec3 center;
		glm::vec3 scale;
		glm::vec2 uvscale;

		ModelCreateInfo() {};

		ModelCreateInfo(glm::vec3 scale, glm::vec2 uvscale, glm::vec3 center)
		{
			this->center = center;
			this->scale = scale;
			this->uvscale = uvscale;
		}

		ModelCreateInfo(float scale, float uvscale, float center)
		{
			this->center = glm::vec3(center);
			this->scale = glm::vec3(scale);
			this->uvscale = glm::vec3(uvscale);
		}

	};

	struct Model {
		VkDevice device = nullptr;
		vks::Buffer vertices;
		vks::Buffer indices;
		uint32_t indexCount = 0;
		uint32_t vertexCount = 0;

		/** @brief Stores vertex and index base and counts for each part of a model */
		struct ModelPart {
			uint32_t vertexBase;
			uint32_t vertexCount;
			uint32_t indexBase;
			uint32_t indexCount;
		};
		std::vector<ModelPart> parts;

		static const int defaultFlags = aiProcess_FlipWindingOrder | aiProcess_Triangulate | aiProcess_PreTransformVertices | aiProcess_CalcTangentSpace | aiProcess_GenSmoothNormals;

		struct Dimension
		{
			glm::vec3 min = glm::vec3(FLT_MAX);
			glm::vec3 max = glm::vec3(-FLT_MAX);
			glm::vec3 size;
		} dim;

		/** @brief Release all Vulkan resources of this model */
		void destroy()
		{
			assert(device);
			vkDestroyBuffer(device, vertices.buffer, nullptr);
			vkFreeMemory(device, vertices.memory, nullptr);
			if (indices.buffer != VK_NULL_HANDLE)
			{
				vkDestroyBuffer(device, indices.buffer, nullptr);
				vkFreeMemory(device, indices.memory, nullptr);
			}
		}

		/**
		* Loads a 3D model from a file into Vulkan buffers
		*
		* @param device Pointer to the Vulkan device used to generated the vertex and index buffers on
		* @param filename File to load (must be a model format supported by ASSIMP)
		* @param layout Vertex layout components (position, normals, tangents, etc.)
		* @param createInfo MeshCreateInfo structure for load time settings like scale, center, etc.
		* @param copyQueue Queue used for the memory staging copy commands (must support transfer)
		* @param (Optional) flags ASSIMP model loading flags
		*/
		bool loadFromFile(const std::string& filename, vks::VertexLayout layout, vks::ModelCreateInfo *createInfo, vks::VulkanDevice *device, VkQueue copyQueue, const int flags = defaultFlags)
		{
			this->device = device->logicalDevice;

			Assimp::Importer Importer;
			const aiScene* pScene;

			// Load file
#if defined(__ANDROID__)
			// Meshes are stored inside the apk on Android (compressed)
			// So they need to be loaded via the asset manager

			AAsset* asset = AAssetManager_open(androidApp->activity->assetManager, filename.c_str(), AASSET_MODE_STREAMING);
			assert(asset);
			size_t size = AAsset_getLength(asset);

			assert(size > 0);

			void *meshData = malloc(size);
			AAsset_read(asset, meshData, size);
			AAsset_close(asset);

			pScene = Importer.ReadFileFromMemory(meshData, size, flags);

			free(meshData);
#else
			pScene = Importer.ReadFile(filename.c_str(), flags);
#endif

			if (pScene)
			{
				parts.clear();
				parts.resize(pScene->mNumMeshes);

				glm::vec3 scale(1.0f);
				glm::vec2 uvscale(1.0f);
				glm::vec3 center(0.0f);
				if (createInfo)
				{
					scale = createInfo->scale;
					uvscale = createInfo->uvscale;
					center = createInfo->center;
				}

				std::vector<float> vertexBuffer;
				std::vector<uint32_t> indexBuffer;

				vertexCount = 0;
				indexCount = 0;

				// Load meshes
				for (unsigned int i = 0; i < pScene->mNumMeshes; i++)
				{
					const aiMesh* paiMesh = pScene->mMeshes[i];

					parts[i] = {};
					parts[i].vertexBase = vertexCount;
					parts[i].indexBase = indexCount;

					vertexCount += pScene->mMeshes[i]->mNumVertices;

					aiColor3D pColor(0.f, 0.f, 0.f);
					pScene->mMaterials[paiMesh->mMaterialIndex]->Get(AI_MATKEY_COLOR_DIFFUSE, pColor);

					const aiVector3D Zero3D(0.0f, 0.0f, 0.0f);

					for (unsigned int j = 0; j < paiMesh->mNumVertices; j++)
					{
						const aiVector3D* pPos = &(paiMesh->mVertices[j]);
						const aiVector3D* pNormal = &(paiMesh->mNormals[j]);
						const aiVector3D* pTexCoord = (paiMesh->HasTextureCoords(0)) ? &(paiMesh->mTextureCoords[0][j]) : &Zero3D;
						const aiVector3D* pTangent = (paiMesh->HasTangentsAndBitangents()) ? &(paiMesh->mTangents[j]) : &Zero3D;
						const aiVector3D* pBiTangent = (paiMesh->HasTangentsAndBitangents()) ? &(paiMesh->mBitangents[j]) : &Zero3D;

						for (auto& component : layout.components)
						{
							switch (component) {
							case VERTEX_COMPONENT_POSITION:
								vertexBuffer.push_back(pPos->x * scale.x + center.x);
								vertexBuffer.push_back(-pPos->y * scale.y + center.y);
								vertexBuffer.push_back(pPos->z * scale.z + center.z);
								break;
							case VERTEX_COMPONENT_NORMAL:
								vertexBuffer.push_back(pNormal->x);
								vertexBuffer.push_back(-pNormal->y);
								vertexBuffer.push_back(pNormal->z);
								break;
							case VERTEX_COMPONENT_UV:
								vertexBuffer.push_back(pTexCoord->x * uvscale.s);
								vertexBuffer.push_back(pTexCoord->y * uvscale.t);
								break;
							case VERTEX_COMPONENT_COLOR:
								vertexBuffer.push_back(pColor.r);
								vertexBuffer.push_back(pColor.g);
								vertexBuffer.push_back(pColor.b);
								break;
							case VERTEX_COMPONENT_TANGENT:
								vertexBuffer.push_back(pTangent->x);
								vertexBuffer.push_back(pTangent->y);
								vertexBuffer.push_back(pTangent->z);
								break;
							case VERTEX_COMPONENT_BITANGENT:
								vertexBuffer.push_back(pBiTangent->x);
								vertexBuffer.push_back(pBiTangent->y);
								vertexBuffer.push_back(pBiTangent->z);
								break;
							// Dummy components for padding
							case VERTEX_COMPONENT_DUMMY_FLOAT:
								vertexBuffer.push_back(0.0f);
								break;
							case VERTEX_COMPONENT_DUMMY_VEC4:
								vertexBuffer.push_back(0.0f);
								vertexBuffer.push_back(0.0f);
								vertexBuffer.push_back(0.0f);
								vertexBuffer.push_back(0.0f);
								break;
							};
						}

						dim.max.x = fmax(pPos->x, dim.max.x);
						dim.max.y = fmax(pPos->y, dim.max.y);
						dim.max.z = fmax(pPos->z, dim.max.z);

						dim.min.x = fmin(pPos->x, dim.min.x);
						dim.min.y = fmin(pPos->y, dim.min.y);
						dim.min.z = fmin(pPos->z, dim.min.z);
					}

					dim.size = dim.max - dim.min;

					parts[i].vertexCount = paiMesh->mNumVertices;

					uint32_t indexBase = static_cast<uint32_t>(indexBuffer.size());
					for (unsigned int j = 0; j < paiMesh->mNumFaces; j++)
					{
						const aiFace& Face = paiMesh->mFaces[j];
						if (Face.mNumIndices != 3)
							continue;
						indexBuffer.push_back(indexBase + Face.mIndices[0]);
						indexBuffer.push_back(indexBase + Face.mIndices[1]);
						indexBuffer.push_back(indexBase + Face.mIndices[2]);
						parts[i].indexCount += 3;
						indexCount += 3;
					}
				}

				uint32_t vBufferSize = static_cast<uint32_t>(vertexBuffer.size()) * sizeof(float);
				uint32_t iBufferSize = static_cast<uint32_t>(indexBuffer.size()) * sizeof(uint32_t);

				// Use staging buffer to move vertex and index buffer to device local memory
				// Create staging buffers
				vks::Buffer vertexStaging, indexStaging;

				// Vertex buffer
				VK_CHECK_RESULT(device->createBuffer(
					VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
					VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
					&vertexStaging,
					vBufferSize,
					vertexBuffer.data()));

				// Index buffer
				VK_CHECK_RESULT(device->createBuffer(
					VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
					VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
					&indexStaging,
					iBufferSize,
					indexBuffer.data()));

				// Create device local target buffers
				// Vertex buffer
				VK_CHECK_RESULT(device->createBuffer(
					VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
					VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
					&vertices,
					vBufferSize));

				// Index buffer
				VK_CHECK_RESULT(device->createBuffer(
					VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
					VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
					&indices,
					iBufferSize));

				// Copy from staging buffers
				VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);

				VkBufferCopy copyRegion{};

				copyRegion.size = vertices.size;
				vkCmdCopyBuffer(copyCmd, vertexStaging.buffer, vertices.buffer, 1, &copyRegion);

				copyRegion.size = indices.size;
				vkCmdCopyBuffer(copyCmd, indexStaging.buffer, indices.buffer, 1, &copyRegion);

				device->flushCommandBuffer(copyCmd, copyQueue);

				// Destroy staging resources
				vkDestroyBuffer(device->logicalDevice, vertexStaging.buffer, nullptr);
				vkFreeMemory(device->logicalDevice, vertexStaging.memory, nullptr);
				vkDestroyBuffer(device->logicalDevice, indexStaging.buffer, nullptr);
				vkFreeMemory(device->logicalDevice, indexStaging.memory, nullptr);

				return true;
			}
			else
			{
				printf("Error parsing '%s': '%s'\n", filename.c_str(), Importer.GetErrorString());
#if defined(__ANDROID__)
				LOGE("Error parsing '%s': '%s'", filename.c_str(), Importer.GetErrorString());
#endif
				return false;
			}
		};

		/**
		* Loads a 3D model from a file into Vulkan buffers
		*
		* @param device Pointer to the Vulkan device used to generated the vertex and index buffers on
		* @param filename File to load (must be a model format supported by ASSIMP)
		* @param layout Vertex layout components (position, normals, tangents, etc.)
		* @param scale Load time scene scale
		* @param copyQueue Queue used for the memory staging copy commands (must support transfer)
		* @param (Optional) flags ASSIMP model loading flags
		*/
		bool loadFromFile(const std::string& filename, vks::VertexLayout layout, float scale, vks::VulkanDevice *device, VkQueue copyQueue, const int flags = defaultFlags)
		{
			vks::ModelCreateInfo modelCreateInfo(scale, 1.0f, 0.0f);
			return loadFromFile(filename, layout, &modelCreateInfo, device, copyQueue, flags);
		}
	};
};<|endoftext|>


<commit_before>/*
 * This is part of the FL library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2014 Jan Issac (jan.issac@gmail.com)
 * Copyright (c) 2014 Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 * Max-Planck Institute for Intelligent Systems, AMD Lab
 * University of Southern California, CLMC Lab
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * \file discrete_distribution.hpp
 * \date 05/25/2014
 * \author Manuel Wuthrich (manuel.wuthrich@gmail.com)
 * \author Jan Issac (jan.issac@gmail.com)
 */

#ifndef FL__DISTRIBUTION__DISCRETE_DISTRIBUTION_HPP
#define FL__DISTRIBUTION__DISCRETE_DISTRIBUTION_HPP

#include <Eigen/Core>

// std
#include <vector>

#include <fl/util/types.hpp>
#include <fl/util/traits.hpp>
#include <fl/util/assertions.hpp>
#include <fl/distribution/interface/moments.hpp>
#include <fl/distribution/interface/standard_gaussian_mapping.hpp>

namespace fl
{

template <typename Variate, int Locations = Eigen::Dynamic>
class DiscreteDistribution
    : public Moments<typename FirstMomentOf<Variate>::Type>,
      public StandardGaussianMapping<Variate, 1>
{
public:
    typedef DiscreteDistribution<Variate, Locations> This;
    typedef Moments<typename FirstMomentOf<Variate>::Type> MomentsInterface;
    typedef StandardGaussianMapping<Variate,1> StandardGaussianMappingInterface;

    typedef typename MomentsInterface::Variate      Mean;
    typedef typename MomentsInterface::SecondMoment Covariance;
    typedef Eigen::Array<Real,    Locations, 1> Function;
    typedef Eigen::Array<Variate, Locations, 1> LocationArray;
    typedef Eigen::Array<Real,    Locations, 1> CommulativeDistribution;

public:
    /// constructor and destructor *********************************************
    explicit
    DiscreteDistribution(int dim = DimensionOf<Variate>(),
                         int locations = MaxOf<Locations, 1>::value)
        : locations_(locations),
          log_prob_mass_(Function::Zero(locations)),
          cumul_distr_(CommulativeDistribution(locations))
    {
        locations_(0) = Variate::Zero(dim);
    }

    virtual ~DiscreteDistribution() { }

    /// non-const functions ****************************************************

    // set ---------------------------------------------------------------------
    virtual void log_unnormalized_prob_mass(const Function& log_prob_mass)
    {
        // rescale for numeric stability
        log_prob_mass_ = log_prob_mass - log_prob_mass.maxCoeff();

        // copy to prob mass
        prob_mass_ = log_prob_mass_.exp();
        Real sum = prob_mass_.sum();

        // normalize
        prob_mass_ /= sum;
        log_prob_mass_ -= std::log(sum);

        // compute cdf
        cumul_distr_.resize(log_prob_mass_.size());

        cumul_distr_[0] = prob_mass_[0];
        for(int i = 1; i < cumul_distr_.size(); i++)
        {
            cumul_distr_[i] = cumul_distr_[i-1] + prob_mass_[i];
        }

        // resize locations
        locations_.resize(log_prob_mass_.size());
    }

    virtual void delta_log_prob_mass(const Function& delta)
    {
        log_unnormalized_prob_mass(log_prob_mass_ + delta);
    }

    virtual void set_uniform(int new_size = size())
    {
        log_unnormalized_prob_mass(Function::Zero(new_size));
    }

    virtual Variate& location(int i)
    {
        return locations_[i];
    }

    template <typename Distribution>
    void from_distribution(const Distribution& distribution, const int& new_size)
    {
        // we first create a local array to sample to. this way, if this
        // is passed as an argument the locations and pmf are not overwritten
        // while sampling
        LocationArray new_locations(new_size);

        for(int i = 0; i < new_size; i++)
        {
            new_locations[i] = distribution.sample();
        }

        set_uniform(new_size);
        locations_ = new_locations;
    }

    /// const functions ********************************************************

    // sampling ----------------------------------------------------------------
    virtual Variate map_standard_normal(const Real& gaussian_sample) const
    {
        Real uniform_sample =
                0.5 * (1.0 + std::erf(gaussian_sample / std::sqrt(2.0)));

        return map_standard_uniform(uniform_sample);
    }

    virtual Variate map_standard_uniform(const Real& uniform_sample) const
    {
        int i = 0;
        for (i = 0; i < cumul_distr_.size(); ++i)
        {
            if (cumul_distr_[i] >= uniform_sample) break;
        }

        return locations_[i];
    }

    // get ---------------------------------------------------------------------
    virtual const Variate& location(int i) const
    {
        return locations_[i];
    }

    virtual const LocationArray& locations() const
    {
        return locations_;
    }

    virtual Real log_prob_mass(const int& i) const
    {
        return log_prob_mass_(i);
    }

    virtual Function log_prob_mass() const
    {
        return log_prob_mass_;
    }

    virtual Real prob_mass(const int& i) const
    {
        return prob_mass_(i);
    }

    virtual Function prob_mass() const
    {
        return prob_mass_;
    }

    virtual int size() const
    {
        return locations_.size();
    }

    virtual int dimension() const
    {
        return locations_[0].rows();
    }

    // compute properties ------------------------------------------------------
    virtual const Mean& mean() const
    {
        mu_ = Mean::Zero(dimension());

        for(int i = 0; i < locations_.size(); i++)
        {
            mu_ += prob_mass(i) * locations_[i].template cast<Real>();
        }

        return mu_;
    }

    virtual const Covariance& covariance() const
    {
        Mean mu = mean();
        cov_ = Covariance::Zero(dimension(), dimension());
        for(int i = 0; i < locations_.size(); i++)
        {
            Mean delta = (locations_[i].template cast<Real>()-mu);
            cov_ += prob_mass(i) * delta * delta.transpose();
        }

        return cov_;
    }

    virtual Real entropy() const
    {
        return - log_prob_mass_.cwiseProduct(prob_mass_).sum();
    }

    // implements KL(p||u) where p is this distr, and u is the uniform distr
    virtual Real kl_given_uniform() const
    {
        return std::log(Real(size())) - entropy();
    }

protected:
    /// member variables *******************************************************
    LocationArray locations_;

    Function log_prob_mass_;
    Function prob_mass_;
    CommulativeDistribution cumul_distr_;

    mutable Mean mu_;
    mutable Covariance cov_;
};

}

#endif
<commit_msg>added cumul_distr_ initialization<commit_after>/*
 * This is part of the FL library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2014 Jan Issac (jan.issac@gmail.com)
 * Copyright (c) 2014 Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 * Max-Planck Institute for Intelligent Systems, AMD Lab
 * University of Southern California, CLMC Lab
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * \file discrete_distribution.hpp
 * \date 05/25/2014
 * \author Manuel Wuthrich (manuel.wuthrich@gmail.com)
 * \author Jan Issac (jan.issac@gmail.com)
 */

#ifndef FL__DISTRIBUTION__DISCRETE_DISTRIBUTION_HPP
#define FL__DISTRIBUTION__DISCRETE_DISTRIBUTION_HPP

#include <Eigen/Core>

// std
#include <vector>

#include <fl/util/types.hpp>
#include <fl/util/traits.hpp>
#include <fl/util/assertions.hpp>
#include <fl/distribution/interface/moments.hpp>
#include <fl/distribution/interface/standard_gaussian_mapping.hpp>

namespace fl
{

template <typename Variate, int Locations = Eigen::Dynamic>
class DiscreteDistribution
    : public Moments<typename FirstMomentOf<Variate>::Type>,
      public StandardGaussianMapping<Variate, 1>
{
public:
    typedef DiscreteDistribution<Variate, Locations> This;
    typedef Moments<typename FirstMomentOf<Variate>::Type> MomentsInterface;
    typedef StandardGaussianMapping<Variate,1> StandardGaussianMappingInterface;

    typedef typename MomentsInterface::Variate      Mean;
    typedef typename MomentsInterface::SecondMoment Covariance;
    typedef Eigen::Array<Real,    Locations, 1> Function;
    typedef Eigen::Array<Variate, Locations, 1> LocationArray;
    typedef Eigen::Array<Real,    Locations, 1> CommulativeDistribution;

public:
    /// constructor and destructor *********************************************
    explicit
    DiscreteDistribution(int dim = DimensionOf<Variate>(),
                         int locations = MaxOf<Locations, 1>::value)
        : locations_(locations),
          log_prob_mass_(Function::Zero(locations)),
          cumul_distr_(CommulativeDistribution(locations))
    {
        locations_(0) = Variate::Zero(dim);

        cumul_distr_.setOnes();
        cumul_distr_ /= Real(cumul_distr_.size());
    }

    virtual ~DiscreteDistribution() { }

    /// non-const functions ****************************************************

    // set ---------------------------------------------------------------------
    virtual void log_unnormalized_prob_mass(const Function& log_prob_mass)
    {
        // rescale for numeric stability
        log_prob_mass_ = log_prob_mass - log_prob_mass.maxCoeff();

        // copy to prob mass
        prob_mass_ = log_prob_mass_.exp();
        Real sum = prob_mass_.sum();

        // normalize
        prob_mass_ /= sum;
        log_prob_mass_ -= std::log(sum);

        // compute cdf
        cumul_distr_.resize(log_prob_mass_.size());

        cumul_distr_[0] = prob_mass_[0];
        for(int i = 1; i < cumul_distr_.size(); i++)
        {
            cumul_distr_[i] = cumul_distr_[i-1] + prob_mass_[i];
        }

        // resize locations
        locations_.resize(log_prob_mass_.size());
    }

    virtual void delta_log_prob_mass(const Function& delta)
    {
        log_unnormalized_prob_mass(log_prob_mass_ + delta);
    }

    virtual void set_uniform(int new_size = size())
    {
        log_unnormalized_prob_mass(Function::Zero(new_size));
    }

    virtual Variate& location(int i)
    {
        return locations_[i];
    }

    template <typename Distribution>
    void from_distribution(const Distribution& distribution, const int& new_size)
    {
        // we first create a local array to sample to. this way, if this
        // is passed as an argument the locations and pmf are not overwritten
        // while sampling
        LocationArray new_locations(new_size);

        for(int i = 0; i < new_size; i++)
        {
            new_locations[i] = distribution.sample();
        }

        set_uniform(new_size);
        locations_ = new_locations;
    }

    /// const functions ********************************************************

    // sampling ----------------------------------------------------------------
    virtual Variate map_standard_normal(const Real& gaussian_sample) const
    {
        Real uniform_sample =
                0.5 * (1.0 + std::erf(gaussian_sample / std::sqrt(2.0)));

        return map_standard_uniform(uniform_sample);
    }

    virtual Variate map_standard_uniform(const Real& uniform_sample) const
    {
        int i = 0;
        for (i = 0; i < cumul_distr_.size(); ++i)
        {
            if (cumul_distr_[i] >= uniform_sample) break;
        }

        return locations_[i];
    }

    // get ---------------------------------------------------------------------
    virtual const Variate& location(int i) const
    {
        return locations_[i];
    }

    virtual const LocationArray& locations() const
    {
        return locations_;
    }

    virtual Real log_prob_mass(const int& i) const
    {
        return log_prob_mass_(i);
    }

    virtual Function log_prob_mass() const
    {
        return log_prob_mass_;
    }

    virtual Real prob_mass(const int& i) const
    {
        return prob_mass_(i);
    }

    virtual Function prob_mass() const
    {
        return prob_mass_;
    }

    virtual int size() const
    {
        return locations_.size();
    }

    virtual int dimension() const
    {
        return locations_[0].rows();
    }

    // compute properties ------------------------------------------------------
    virtual const Mean& mean() const
    {
        mu_ = Mean::Zero(dimension());

        for(int i = 0; i < locations_.size(); i++)
        {
            mu_ += prob_mass(i) * locations_[i].template cast<Real>();
        }

        return mu_;
    }

    virtual const Covariance& covariance() const
    {
        Mean mu = mean();
        cov_ = Covariance::Zero(dimension(), dimension());
        for(int i = 0; i < locations_.size(); i++)
        {
            Mean delta = (locations_[i].template cast<Real>()-mu);
            cov_ += prob_mass(i) * delta * delta.transpose();
        }

        return cov_;
    }

    virtual Real entropy() const
    {
        return - log_prob_mass_.cwiseProduct(prob_mass_).sum();
    }

    // implements KL(p||u) where p is this distr, and u is the uniform distr
    virtual Real kl_given_uniform() const
    {
        return std::log(Real(size())) - entropy();
    }

protected:
    /// member variables *******************************************************
    LocationArray locations_;

    Function log_prob_mass_;
    Function prob_mass_;
    CommulativeDistribution cumul_distr_;

    mutable Mean mu_;
    mutable Covariance cov_;
};

}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2016.  All rights reserved
 */
#include    "../StroikaPreComp.h"

#include    "../Characters/Format.h"
#include    "../Debug/Trace.h"

#include    "SQLite.h"

using   namespace   Stroika::Foundation;

using   namespace   Characters;
using   namespace   Debug;
using   namespace   Database;
using   namespace   Database::SQLite;
using   namespace   Execution;

// Comment this in to turn on aggressive noisy DbgTrace in this module
//#define   USE_NOISY_TRACE_IN_THIS_MODULE_       1

#if     qHasFeature_sqlite
/*
 ********************************************************************************
 ************************* SQLite::DB::Statement ********************************
 ********************************************************************************
 */
DB::Statement::Statement (sqlite3* db, const String& query)
{
    int rc = ::sqlite3_prepare_v2 (db, query.AsUTF8 ().c_str (), -1, &stmt, NULL);
    if (rc != SQLITE_OK) {
        Execution::Throw (StringException (Characters::Format (L"SQLite Error %s:", String::FromUTF8 (::sqlite3_errmsg (db)).c_str ())));
    }
    AssertNotNull (stmt);
    nParams = ::sqlite3_column_count (stmt);
    for (size_t i = 0; i < nParams; ++i) {
        fColNames += String::FromUTF8 (::sqlite3_column_name (stmt, i));
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
        DbgTrace (L"sqlite3_column_decltype(i) = %s", String::FromUTF8 (::sqlite3_column_decltype (stmt, i)).c_str ());
#endif

        // add VaroamtVa;ue"::Type list based on sqlite3_column_decltype
    }
}

/// returns 'missing' on EOF, exception on error
auto   DB::Statement::GetNextRow () -> Optional<RowType> {
    // @todo redo with https://www.sqlite.org/c3ref/value.html
    int rc;
    AssertNotNull (stmt);
    if (( rc = ::sqlite3_step (stmt)) == SQLITE_ROW)
    {
        RowType row;
        for (size_t i = 0; i < nParams; ++i) {
            // redo as sqlite3_column_text16
            // @todo AND iether use value object or check INTERANL TYOPE  - https://www.sqlite.org/c3ref/column_blob.html and return the right one  - NULL, INTEGER, FLOAT, TEXT, BLOB
            VariantValue    v;
            switch (::sqlite3_column_type (stmt, i)) {
                case SQLITE_INTEGER: {
                        v = VariantValue (::sqlite3_column_int (stmt, i));
                    }
                    break;
                case SQLITE_FLOAT: {
                        v = VariantValue (::sqlite3_column_double (stmt, i));
                    }
                    break;
                case SQLITE_BLOB: {
#if 1
                        // this will work badly, so dont use!!!
                        AssertNotImplemented ();
                        v = VariantValue (String::FromUTF8 (reinterpret_cast<const char*> (::sqlite3_column_text (stmt, i))));
#else
                        // @todo - support this once we support BLOB in VariantValue
                        const void* sqlite3_column_blob(sqlite3_stmt*, int iCol);
                        int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
                        v = VariantValue (String::FromUTF8 (reinterpret_cast<const char*> (::sqlite3_column_text (stmt, i))));
#endif
                    }
                    break;
                case SQLITE_NULL: {
                        v = VariantValue ();
                    }
                    break;
                case SQLITE_TEXT: {
                        v = VariantValue (String::FromUTF8 (reinterpret_cast<const char*> (::sqlite3_column_text (stmt, i))));
                    }
                    break;
                default: {
                        AssertNotReached ();
                    }
                    break;
            }
            row.Add (fColNames[i], v);
        }
        return row;
    }
    return Optional<RowType> ();
}

DB::Statement::~Statement ()
{
    AssertNotNull (stmt);
    ::sqlite3_finalize (stmt);
}

/*
 ********************************************************************************
 ********************************** SQLite::DB **********************************
 ********************************************************************************
 */
DB::DB (const String& experimentDBFullPath, const function<void(DB&)>& dbInitializer)
{
    TraceContextBumper ctx (SDKSTR ("SQLite::DB::DB"));
    // @todo - code cleanup!!!
    int e;
    if ((e = ::sqlite3_open_v2 ((L"file://" + experimentDBFullPath).AsUTF8 ().c_str (), &fDB_,  SQLITE_OPEN_URI | SQLITE_OPEN_READWRITE, nullptr)) == SQLITE_CANTOPEN) {
        if ((e = ::sqlite3_open_v2 ((L"file://" + experimentDBFullPath).AsUTF8 ().c_str (), &fDB_,  SQLITE_OPEN_URI |  SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, nullptr)) == SQLITE_OK) {
            try {
                dbInitializer (*this);
            }
            catch (...) {
                ::sqlite3_close (fDB_);
                Execution::ReThrow ();
            }
        }
    }
    else if (e != SQLITE_OK) {
        Assert (fDB_ == nullptr);
        // @todo add error string
        Execution::Throw (StringException (Characters::Format (L"SQLite Error %d:", e)));
    }
}

DB:: ~DB ()
{
    AssertNotNull (fDB_);
    ::sqlite3_close (fDB_);
}

void    DB::Exec (const String& cmd2Exec)
{
    char* db_err {};
    int e = ::sqlite3_exec (fDB_, cmd2Exec.AsUTF8 ().c_str (), NULL, 0, &db_err);
    if (e != SQLITE_OK) {
        if (db_err == nullptr or * db_err == '\0') {
            DbgTrace (L"Failed doing sqllite command: %s", cmd2Exec.c_str ());
            Execution::Throw (StringException (Characters::Format (L"SQLite Error %d", e)));
        }
        else {
            Execution::Throw (StringException (Characters::Format (L"SQLite Error %d: %s", e, String::FromUTF8 (db_err).c_str ())));
        }
    }
}
#endif
<commit_msg>SQLite code cleanups - DbgTrace cleanups and assertions<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2016.  All rights reserved
 */
#include    "../StroikaPreComp.h"

#include    "../Characters/Format.h"
#include    "../Debug/Trace.h"

#include    "SQLite.h"

using   namespace   Stroika::Foundation;

using   namespace   Characters;
using   namespace   Debug;
using   namespace   Database;
using   namespace   Database::SQLite;
using   namespace   Execution;

// Comment this in to turn on aggressive noisy DbgTrace in this module
//#define   USE_NOISY_TRACE_IN_THIS_MODULE_       1

#if     qHasFeature_sqlite
/*
 ********************************************************************************
 ************************* SQLite::DB::Statement ********************************
 ********************************************************************************
 */
DB::Statement::Statement (sqlite3* db, const String& query)
{
    int rc = ::sqlite3_prepare_v2 (db, query.AsUTF8 ().c_str (), -1, &stmt, NULL);
    if (rc != SQLITE_OK) {
        Execution::Throw (StringException (Characters::Format (L"SQLite Error %s:", String::FromUTF8 (::sqlite3_errmsg (db)).c_str ())));
    }
    AssertNotNull (stmt);
    nParams = ::sqlite3_column_count (stmt);
    for (size_t i = 0; i < nParams; ++i) {
        fColNames += String::FromUTF8 (::sqlite3_column_name (stmt, i));
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
        DbgTrace (L"sqlite3_column_decltype(i) = %s", ::sqlite3_column_decltype (stmt, i) == nullptr ? L"{nullptr}" : String::FromUTF8 (::sqlite3_column_decltype (stmt, i)).c_str ());
#endif
        // add VaroamtVa;ue"::Type list based on sqlite3_column_decltype
    }
}

/// returns 'missing' on EOF, exception on error
auto   DB::Statement::GetNextRow () -> Optional<RowType> {
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
    TraceContextBumper ctx (SDKSTR ("SQLite::DB::Statement::GetNextRow"));
#endif
    // @todo redo with https://www.sqlite.org/c3ref/value.html
    int rc;
    AssertNotNull (stmt);
    if (( rc = ::sqlite3_step (stmt)) == SQLITE_ROW)
    {
        RowType row;
        for (size_t i = 0; i < nParams; ++i) {
            // redo as sqlite3_column_text16
            // @todo AND iether use value object or check INTERANL TYOPE  - https://www.sqlite.org/c3ref/column_blob.html and return the right one  - NULL, INTEGER, FLOAT, TEXT, BLOB
            VariantValue    v;
            switch (::sqlite3_column_type (stmt, i)) {
                case SQLITE_INTEGER: {
                        v = VariantValue (::sqlite3_column_int (stmt, i));
                    }
                    break;
                case SQLITE_FLOAT: {
                        v = VariantValue (::sqlite3_column_double (stmt, i));
                    }
                    break;
                case SQLITE_BLOB: {
#if 1
                        // this will work badly, so dont use!!!
                        AssertNotImplemented ();
                        v = VariantValue (String::FromUTF8 (reinterpret_cast<const char*> (::sqlite3_column_text (stmt, i))));
#else
                        // @todo - support this once we support BLOB in VariantValue
                        const void* sqlite3_column_blob(sqlite3_stmt*, int iCol);
                        int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
                        v = VariantValue (String::FromUTF8 (reinterpret_cast<const char*> (::sqlite3_column_text (stmt, i))));
#endif
                    }
                    break;
                case SQLITE_NULL: {
                        // default to null value
                    }
                    break;
                case SQLITE_TEXT: {
                        AssertNotNull (::sqlite3_column_text (stmt, i));
                        v = VariantValue (String::FromUTF8 (reinterpret_cast<const char*> (::sqlite3_column_text (stmt, i))));
                    }
                    break;
                default: {
                        AssertNotReached ();
                    }
                    break;
            }
            row.Add (fColNames[i], v);
        }
        return row;
    }
    return Optional<RowType> ();
}

DB::Statement::~Statement ()
{
    AssertNotNull (stmt);
    ::sqlite3_finalize (stmt);
}

/*
 ********************************************************************************
 ********************************** SQLite::DB **********************************
 ********************************************************************************
 */
DB::DB (const String& experimentDBFullPath, const function<void(DB&)>& dbInitializer)
{
    TraceContextBumper ctx (SDKSTR ("SQLite::DB::DB"));
    // @todo - code cleanup!!!
    int e;
    if ((e = ::sqlite3_open_v2 ((L"file://" + experimentDBFullPath).AsUTF8 ().c_str (), &fDB_,  SQLITE_OPEN_URI | SQLITE_OPEN_READWRITE, nullptr)) == SQLITE_CANTOPEN) {
        if ((e = ::sqlite3_open_v2 ((L"file://" + experimentDBFullPath).AsUTF8 ().c_str (), &fDB_,  SQLITE_OPEN_URI |  SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, nullptr)) == SQLITE_OK) {
            try {
                dbInitializer (*this);
            }
            catch (...) {
                Verify (::sqlite3_close (fDB_) == SQLITE_OK);
                Execution::ReThrow ();
            }
        }
    }
    else if (e != SQLITE_OK) {
        Assert (fDB_ == nullptr);
        // @todo add error string
        Execution::Throw (StringException (Characters::Format (L"SQLite Error %d:", e)));
    }
}

DB:: ~DB ()
{
    AssertNotNull (fDB_);
    Verify (::sqlite3_close (fDB_) == SQLITE_OK);
}

void    DB::Exec (const String& cmd2Exec)
{
    char* db_err {};
    int e = ::sqlite3_exec (fDB_, cmd2Exec.AsUTF8 ().c_str (), NULL, 0, &db_err);
    if (e != SQLITE_OK) {
        if (db_err == nullptr or * db_err == '\0') {
            DbgTrace (L"Failed doing sqllite command: %s", cmd2Exec.c_str ());
            Execution::Throw (StringException (Characters::Format (L"SQLite Error %d", e)));
        }
        else {
            Execution::Throw (StringException (Characters::Format (L"SQLite Error %d: %s", e, String::FromUTF8 (db_err).c_str ())));
        }
    }
}
#endif
<|endoftext|>


<commit_before>#include <stdio.h>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <wiringPi.h>
#include "camera.hpp"
#include "../motor.h"

#pragma comment(lib,"opencv_world320.lib")

static const int ROTATE_POWER = 100;
static const int ROTATE_MILLISECONDS = 200;
static const int LEFT_MAX = -100;
static const int RIGHT_MAX = 100;
static const int CENTER_THRESHOLD = 30;//-30~30で直進するようにする
static const double EXIST_THRESHOLD = 0.7;//ゴール存在判定 パーセンテージ
static const int TIME_LIMIT = 360000;

//TODO turn millisecondどんどん大きくしていくPI制御にする
int main (void)
{
	int start_time  = millis();
	int last_time = millis();
	pwm_initialize();
	while(last_time-start_time<TIME_LIMIT)
	{

		cv::Mat red = Mred();
		double count = countArea(red);
		if(count < EXIST_THRESHOLD)
		{
			//回転するだけ
			motor_right(ROTATE_POWER);
			delay(ROTATE_MILLISECONDS);
			motor_stop();
			delay(10);
		}
		else
		{
			//見つけれたら前進
			motor_forward(100);
			delay(400);
			motor_stop();
			delay(10);
		}
	}
	return 0;
}
<commit_msg>debug<commit_after>#include <stdio.h>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <wiringPi.h>
#include "camera.hpp"
#include "../motor.h"

#pragma comment(lib,"opencv_world320.lib")

static const int ROTATE_POWER = 100;
static const int ROTATE_MILLISECONDS = 200;
static const int LEFT_MAX = -100;
static const int RIGHT_MAX = 100;
static const int CENTER_THRESHOLD = 30;//-30~30で直進するようにする
static const double EXIST_THRESHOLD = 0.7;//ゴール存在判定 パーセンテージ
static const int TIME_LIMIT = 360000;//6分

//TODO turn millisecondどんどん大きくしていくPI制御にする
int main (void)
{
	int startTime  = millis();
	int lastTime = millis();
	pwm_initialize();
	while(lastTime-startTime<TIME_LIMIT)
	{
		lastTime = millis();
		cv::Mat red = Mred();
		double count = countArea(red);
		if(count < EXIST_THRESHOLD)
		{
			//回転するだけ
			motor_right(ROTATE_POWER);
			delay(ROTATE_MILLISECONDS);
			motor_stop();
			delay(10);
		}
		else
		{
			//見つけれたら前進
			motor_forward(100);
			delay(400);
			motor_stop();
			delay(10);
		}
	}
	return 0;
}
<|endoftext|>


<commit_before><commit_msg>"no matching function for call to 'get_pointer'," use lambda instead<commit_after><|endoftext|>


<commit_before>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date: 2009-05-13 14:52:01 +0200 (Mi, 13. Mai 2009) $
Version:   $Revision: 17230 $

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "mitkNavigationDataRecorder.h"
#include "mitkNavigationData.h"

#include "mitkTestingMacros.h"

#include <iostream>
#include <sstream>

/**Documentation
 *  test for the class "NavigationDataRecorder".
 */
int mitkNavigationDataRecorderTest(int /* argc */, char* /*argv*/[])
{
  MITK_TEST_BEGIN("NavigationDataRecorder");
  std::string tmp = "";
  std::ostringstream* stream = new std::ostringstream( std::ostringstream::trunc );

  // let's create an object of our class
  mitk::NavigationDataRecorder::Pointer recorder = mitk::NavigationDataRecorder::New();

  // first test: did this work?
  // using MITK_TEST_CONDITION_REQUIRED makes the test stop after failure, since
  // it makes no sense to continue without an object.
  MITK_TEST_CONDITION_REQUIRED(recorder.IsNotNull(), "Testing instantiation");

  MITK_TEST_CONDITION(recorder->GetInputs().size() == 0, "testing initial number of inputs");
  MITK_TEST_CONDITION(recorder->GetOutputs().size() == 0, "testing initial number of outputs");

  std::vector<mitk::NavigationData::Pointer> naviDatas;

  mitk::NavigationData::Pointer naviData = mitk::NavigationData::New();
  recorder->AddNavigationData( naviData );
  //recorder->SetFileName("e:/test");
  //recorder->SetRecordingMode( mitk::NavigationDataRecorder::NormalFile );
  recorder->StartRecording( stream );
  for ( unsigned int i=0; i<5; i++ )
  {
    mitk::Point3D pnt;
    pnt[0] = i+1;
    pnt[1] = i+1/2;
    pnt[2] = i+1*3;
    naviData->SetPosition(pnt);
    //naviData->Modified();
    recorder->Update();

    //Sleep(80 + i*10);

  }

  recorder->StopRecording();

  std::string str = stream->str();
  int pos = str.find( "ToolCount=" );
  std::string sub = stream->str().substr(pos+11, 1);
  MITK_TEST_CONDITION( sub.compare("1") == 0, "check if number of inputs is correct by stringstream");

  pos = str.find( "X=" );
  sub = stream->str().substr(pos+3, 3);
  MITK_TEST_CONDITION( sub.compare("1.0") == 0, "check if the X coordinate is correct");

  pos = str.find( "Y=" );
  sub = stream->str().substr(pos+3, 3);
  MITK_TEST_CONDITION( sub.compare("0.0") == 0, "check if the Y coordinate is correct");

  pos = str.find( "Z=" );
  sub = stream->str().substr(pos+3, 3);
  MITK_TEST_CONDITION( sub.compare("3.0") == 0, "check if the Z coordinate is correct");

  recorder->SetFileName("blablabla");
  const char* string = recorder->GetFileName();
  MITK_TEST_CONDITION( strcmp(string, "blablabla") == 0, "check if set- and getName-methods work");

  // always end with this!
  MITK_TEST_END();
}
<commit_msg>STYLE: removed unused variable<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date: 2009-05-13 14:52:01 +0200 (Mi, 13. Mai 2009) $
Version:   $Revision: 17230 $

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "mitkNavigationDataRecorder.h"
#include "mitkNavigationData.h"

#include "mitkTestingMacros.h"

#include <iostream>
#include <sstream>

/**Documentation
 *  test for the class "NavigationDataRecorder".
 */
int mitkNavigationDataRecorderTest(int /* argc */, char* /*argv*/[])
{
  MITK_TEST_BEGIN("NavigationDataRecorder");
  std::string tmp = "";
  std::ostringstream* stream = new std::ostringstream( std::ostringstream::trunc );

  // let's create an object of our class
  mitk::NavigationDataRecorder::Pointer recorder = mitk::NavigationDataRecorder::New();

  // first test: did this work?
  // using MITK_TEST_CONDITION_REQUIRED makes the test stop after failure, since
  // it makes no sense to continue without an object.
  MITK_TEST_CONDITION_REQUIRED(recorder.IsNotNull(), "Testing instantiation");

  MITK_TEST_CONDITION(recorder->GetInputs().size() == 0, "testing initial number of inputs");
  MITK_TEST_CONDITION(recorder->GetOutputs().size() == 0, "testing initial number of outputs");

  mitk::NavigationData::Pointer naviData = mitk::NavigationData::New();
  recorder->AddNavigationData( naviData );
  //recorder->SetFileName("e:/test");
  //recorder->SetRecordingMode( mitk::NavigationDataRecorder::NormalFile );
  recorder->StartRecording( stream );
  for ( unsigned int i=0; i<5; i++ )
  {
    mitk::Point3D pnt;
    pnt[0] = i+1;
    pnt[1] = i+1/2;
    pnt[2] = i+1*3;
    naviData->SetPosition(pnt);
    //naviData->Modified();
    recorder->Update();

    //Sleep(80 + i*10);

  }

  recorder->StopRecording();

  std::string str = stream->str();
  int pos = str.find( "ToolCount=" );
  std::string sub = stream->str().substr(pos+11, 1);
  MITK_TEST_CONDITION( sub.compare("1") == 0, "check if number of inputs is correct by stringstream");

  pos = str.find( "X=" );
  sub = stream->str().substr(pos+3, 3);
  MITK_TEST_CONDITION( sub.compare("1.0") == 0, "check if the X coordinate is correct");

  pos = str.find( "Y=" );
  sub = stream->str().substr(pos+3, 3);
  MITK_TEST_CONDITION( sub.compare("0.0") == 0, "check if the Y coordinate is correct");

  pos = str.find( "Z=" );
  sub = stream->str().substr(pos+3, 3);
  MITK_TEST_CONDITION( sub.compare("3.0") == 0, "check if the Z coordinate is correct");

  recorder->SetFileName("blablabla");
  const char* string = recorder->GetFileName();
  MITK_TEST_CONDITION( strcmp(string, "blablabla") == 0, "check if set- and getName-methods work");

  // always end with this!
  MITK_TEST_END();
}
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright NumFOCUS
 *
 *  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.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.
 *
 *=========================================================================*/

#include "itkGDCMImageIO.h"
#include "itkImageSeriesReader.h"
#include "itkGDCMSeriesFileNames.h"
#include "itkRescaleIntensityImageFilter.h"
#include "itkImageSeriesWriter.h"
#include "itkNumericSeriesFileNames.h"
#include "itkSimpleFilterWatcher.h"

int
itkImageSeriesWriterTest(int ac, char * av[])
{

  if (ac < 4)
  {
    std::cerr << "Usage: " << av[0] << " DicomDirectory OutputDirectory FileSuffix\n";
    return EXIT_FAILURE;
  }

  using ImageNDType = itk::Image<short, 3>;
  using ReaderType = itk::ImageSeriesReader<ImageNDType>;

  itk::GDCMImageIO::Pointer io = itk::GDCMImageIO::New();

  // Get the DICOM filenames from the directory
  itk::GDCMSeriesFileNames::Pointer nameGenerator = itk::GDCMSeriesFileNames::New();
  nameGenerator->SetDirectory(av[1]);

  using SeriesIdContainer = std::vector<std::string>;
  const SeriesIdContainer & seriesUID = nameGenerator->GetSeriesUIDs();
  std::string               seriesIdentifier = seriesUID.begin()->c_str();

  ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileNames(nameGenerator->GetFileNames(seriesIdentifier));
  reader->SetImageIO(io);

  itk::SimpleFilterWatcher watcher(reader);

  try
  {
    reader->Update();
    reader->GetOutput()->Print(std::cout);
  }
  catch (const itk::ExceptionObject & ex)
  {
    std::cout << ex;
    return EXIT_FAILURE;
  }

  using WritePixelType = unsigned char;
  using RescaleImageType = itk::Image<WritePixelType, 3>;
  using OutputImageType = itk::Image<WritePixelType, 2>;

  using RescaleFilterType = itk::RescaleIntensityImageFilter<ImageNDType, RescaleImageType>;
  RescaleFilterType::Pointer rescaler = RescaleFilterType::New();
  rescaler->SetInput(reader->GetOutput());
  rescaler->SetOutputMinimum(0);
  rescaler->SetOutputMaximum(255);
  rescaler->UpdateLargestPossibleRegion();

  { // This API is being deprecated. Please use NumericSeriesFileNames in the future
    // for generating the list of filenames.  This API will be removed after ITK 1.8
    using WriterType = itk::ImageSeriesWriter<RescaleImageType, OutputImageType>;

    WriterType::Pointer writer = WriterType::New();

    itk::SimpleFilterWatcher watcher2(writer);

    writer->SetInput(rescaler->GetOutput());
    char format[4096];
    sprintf(format, "%s/series.%%d.%s", av[2], av[3]);
    writer->SetSeriesFormat(format);

    try
    {
      writer->Update();
    }
    catch (const itk::ExceptionObject & excp)
    {
      std::cerr << "Error while writing the series with old API" << std::endl;
      std::cerr << excp << std::endl;
      return EXIT_FAILURE;
    }

    // Verify that attempting to use a MetaDataDictionary without setting the ImageIO
    // should throw an exception.
    writer->SetMetaDataDictionaryArray(reader->GetMetaDataDictionaryArray());
    try
    {
      writer->Update();
      std::cerr << "Failed to throw expected exception of using MetaDataDictionary without ImageIO" << std::endl;
      return EXIT_FAILURE;
    }
    catch (itk::ExceptionObject &)
    {
      std::cout << "Exercised expected exception" << std::endl;
    }

    std::cout << "Old API PASSED !" << std::endl;
  }

  { // This is the new API, using the NumericSeriesFileNames (or any other filename generator).
    itk::NumericSeriesFileNames::Pointer fit = itk::NumericSeriesFileNames::New();

    using WriterType = itk::ImageSeriesWriter<RescaleImageType, OutputImageType>;

    WriterType::Pointer writer = WriterType::New();

    char format[4096];
    sprintf(format, "%s/series.%%d.%s", av[2], av[3]);

    std::cout << "Format = " << format << std::endl;

    ImageNDType::RegionType region = reader->GetOutput()->GetBufferedRegion();
    ImageNDType::SizeType   size = region.GetSize();

    fit->SetStartIndex(0);
    fit->SetEndIndex(size[2] - 1); // The number of slices to write
    fit->SetIncrementIndex(1);
    fit->SetSeriesFormat(format);

    writer->SetInput(rescaler->GetOutput());
    writer->SetFileNames(fit->GetFileNames());

    // experiment the UseCompression methods and values
    if (writer->GetUseCompression())
    {
      std::cerr << "Wrong default use compression value" << std::endl;
      return EXIT_FAILURE;
    }
    writer->SetUseCompression(true);
    writer->UseCompressionOn();
    writer->UseCompressionOff();

    try
    {
      writer->Update();
    }
    catch (const itk::ExceptionObject & excp)
    {
      std::cerr << "Error while writing the series with SeriesFileNames generator" << std::endl;
      std::cerr << excp << std::endl;
      return EXIT_FAILURE;
    }

    // Verify that attempting to use a MetaDataDictionary without setting the ImageIO
    // should throw an exception.
    writer->SetMetaDataDictionaryArray(reader->GetMetaDataDictionaryArray());
    try
    {
      writer->Update();
      std::cerr << "Failed to throw expected exception of using MetaDataDictionary without ImageIO" << std::endl;
      return EXIT_FAILURE;
    }
    catch (itk::ExceptionObject &)
    {
      std::cout << "Exercised expected exception" << std::endl;
    }

    std::cout << "Test with NumericSeriesFileNames PASSED !" << std::endl;
  }

  return EXIT_SUCCESS;
}
<commit_msg>STYLE: Improve `itk::ImageSeriesWriter` class test file style<commit_after>/*=========================================================================
 *
 *  Copyright NumFOCUS
 *
 *  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.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.
 *
 *=========================================================================*/

#include "itkGDCMImageIO.h"
#include "itkImageSeriesReader.h"
#include "itkGDCMSeriesFileNames.h"
#include "itkRescaleIntensityImageFilter.h"
#include "itkImageSeriesWriter.h"
#include "itkNumericSeriesFileNames.h"
#include "itkSimpleFilterWatcher.h"
#include "itkTestingMacros.h"

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

  if (argc < 4)
  {
    std::cerr << "Missing Parameters." << std::endl;
    std::cerr << "Usage: " << itkNameOfTestExecutableMacro(argv) << " DicomDirectory OutputDirectory FileSuffix"
              << std::endl;
    return EXIT_FAILURE;
  }

  using ImageNDType = itk::Image<short, 3>;
  using ReaderType = itk::ImageSeriesReader<ImageNDType>;

  itk::GDCMImageIO::Pointer io = itk::GDCMImageIO::New();

  // Get the DICOM filenames from the directory
  itk::GDCMSeriesFileNames::Pointer nameGenerator = itk::GDCMSeriesFileNames::New();
  nameGenerator->SetDirectory(argv[1]);

  using SeriesIdContainer = std::vector<std::string>;
  const SeriesIdContainer & seriesUID = nameGenerator->GetSeriesUIDs();
  std::string               seriesIdentifier = seriesUID.begin()->c_str();

  ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileNames(nameGenerator->GetFileNames(seriesIdentifier));
  reader->SetImageIO(io);

  itk::SimpleFilterWatcher watcher(reader);

  ITK_TRY_EXPECT_NO_EXCEPTION(reader->Update());

  reader->GetOutput()->Print(std::cout);

  using WritePixelType = unsigned char;
  using RescaleImageType = itk::Image<WritePixelType, 3>;
  using OutputImageType = itk::Image<WritePixelType, 2>;

  using RescaleFilterType = itk::RescaleIntensityImageFilter<ImageNDType, RescaleImageType>;
  RescaleFilterType::Pointer rescaler = RescaleFilterType::New();
  rescaler->SetInput(reader->GetOutput());
  rescaler->SetOutputMinimum(0);
  rescaler->SetOutputMaximum(255);
  rescaler->UpdateLargestPossibleRegion();

  { // This API is being deprecated. Please use NumericSeriesFileNames in the future
    // for generating the list of filenames.  This API will be removed after ITK 1.8
    using WriterType = itk::ImageSeriesWriter<RescaleImageType, OutputImageType>;

    WriterType::Pointer writer = WriterType::New();

    itk::SimpleFilterWatcher watcher2(writer);

    writer->SetInput(rescaler->GetOutput());
    char format[4096];
    sprintf(format, "%s/series.%%d.%s", argv[2], argv[3]);
    writer->SetSeriesFormat(format);

    ITK_TRY_EXPECT_NO_EXCEPTION(writer->Update());

    // Verify that attempting to use a MetaDataDictionary without setting the ImageIO
    // should throw an exception.
    writer->SetMetaDataDictionaryArray(reader->GetMetaDataDictionaryArray());

    ITK_TRY_EXPECT_EXCEPTION(writer->Update());

    std::cout << "Old API PASSED !" << std::endl;
  }

  { // This is the new API, using the NumericSeriesFileNames (or any other filename generator).
    itk::NumericSeriesFileNames::Pointer fit = itk::NumericSeriesFileNames::New();

    using WriterType = itk::ImageSeriesWriter<RescaleImageType, OutputImageType>;

    WriterType::Pointer writer = WriterType::New();

    char format[4096];
    sprintf(format, "%s/series.%%d.%s", argv[2], argv[3]);

    std::cout << "Format = " << format << std::endl;

    ImageNDType::RegionType region = reader->GetOutput()->GetBufferedRegion();
    ImageNDType::SizeType   size = region.GetSize();

    fit->SetStartIndex(0);
    fit->SetEndIndex(size[2] - 1); // The number of slices to write
    fit->SetIncrementIndex(1);
    fit->SetSeriesFormat(format);

    writer->SetInput(rescaler->GetOutput());
    writer->SetFileNames(fit->GetFileNames());

    // experiment the UseCompression methods and values
    if (writer->GetUseCompression())
    {
      std::cerr << "Wrong default use compression value" << std::endl;
      return EXIT_FAILURE;
    }
    writer->SetUseCompression(true);
    writer->UseCompressionOn();
    writer->UseCompressionOff();

    ITK_TRY_EXPECT_NO_EXCEPTION(writer->Update());

    // Verify that attempting to use a MetaDataDictionary without setting the ImageIO
    // should throw an exception.
    writer->SetMetaDataDictionaryArray(reader->GetMetaDataDictionaryArray());

    ITK_TRY_EXPECT_EXCEPTION(writer->Update());

    std::cout << "Test with NumericSeriesFileNames PASSED !" << std::endl;
  }

  std::cout << "Test finished" << std::endl;
  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>//-----------------------------------------------
//
//	This file is part of the Siv3D Engine.
//
//	Copyright (c) 2008-2021 Ryo Suzuki
//	Copyright (c) 2016-2021 OpenSiv3D Project
//
//	Licensed under the MIT License.
//
//-----------------------------------------------

# pragma once

namespace s3d
{
	constexpr Vec2 GlyphInfo::getOffset(const double scale) const noexcept
	{
		return{ (left - (buffer * scale)), (ascent - (top * scale) - (buffer * scale)) };
	}
}
<commit_msg>[共通] GlyphInfo fix<commit_after>//-----------------------------------------------
//
//	This file is part of the Siv3D Engine.
//
//	Copyright (c) 2008-2021 Ryo Suzuki
//	Copyright (c) 2016-2021 OpenSiv3D Project
//
//	Licensed under the MIT License.
//
//-----------------------------------------------

# pragma once

namespace s3d
{
	constexpr Vec2 GlyphInfo::getOffset(const double scale) const noexcept
	{
		return{ ((left - buffer) * scale), ((ascent - top - buffer) * scale) };
	}
}
<|endoftext|>


<commit_before>#include "GolfBall.hpp"
#include "../Resources.hpp"
#include "Default3D.vert.hpp"
#include "Default3D.geom.hpp"
#include "Default3D.frag.hpp"
#include "glm/gtc/constants.hpp"
#include "../Util/Log.hpp"
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/quaternion.hpp>

GolfBall::GolfBall(BallType ballType, TerrainObject* terrain, Water* water) : ModelObject(modelGeometry = Resources().CreateOBJModel("Resources/Models/GolfBall/GolfBall.obj"),
                                                                            "Resources/Models/GolfBall/Diffuse.png",
                                                                            "Resources/Models/GolfBall/Normal.png",
                                                                            "Resources/Models/GolfBall/Specular.png") {
    state = GolfBall::INITIAL;

    restitution = ballType == TWOPIECE ? 0.78f : 0.68f;
    this->terrain = terrain;
    this->water = water;
    origin = glm::vec3(1.f, 0.f, 1.f);

    mass = 0.0459f;
    this->ballType = ballType;

    sphere.position = Position();
    SetRadius(0.0214f);
}

GolfBall::~GolfBall() {
    Resources().FreeOBJModel(modelGeometry);
}

void GolfBall::Reset(){
    state = GolfBall::INITIAL;
    velocity = glm::vec3(0.f, 0.f, 0.f);
    angularVelocity = glm::vec3(0.f, 0.f, 0.f);
    SetPosition(origin);
    sphere.position = Position();
    orientation = glm::quat();
}

void GolfBall::Update(double time, const glm::vec3& wind, std::vector<PlayerObject>& players) {
	if (state == GolfBall::ACTIVE) {
		Move(static_cast<float>(time)* velocity);
		sphere.position = Position();

		if (glm::length(angularVelocity) > 0.0001f) {
			glm::quat deltaQuat = glm::angleAxis(static_cast<float>(time)* glm::length(angularVelocity), glm::normalize(angularVelocity));
			orientation = deltaQuat * orientation;
		}

		glm::vec3 dragForce, magnusForce = glm::vec3(0.f, 0.f, 0.f);

		float groundLevel = terrain->GetY(Position().x, Position().z);
        float waterLevel = water->Position().y;

        // Check if in water.
        if ((sphere.position.y - sphere.radius < groundLevel && groundLevel + sphere.radius < waterLevel) || sphere.position.y + sphere.radius < waterLevel) {
            state = GolfBall::OUT;
            return;
        }

        // Check for collision
		if (glm::length(velocity) > 0.0001f && (sphere.position.y - sphere.radius) < groundLevel){
			float vCritical = 0.3f;
			float e = 0.35f;
			float muSliding = 0.51f;
			float muRolling = 0.096f;
			SetPosition(Position().x, groundLevel + sphere.radius, Position().z);
			sphere.position = Position();
			//glm::vec3 eRoh = glm::normalize(glm::vec3(0.f, 1.f, 0.f));
			glm::vec3 eRoh = terrain->GetNormal(Position().x, Position().z);
			glm::vec3 tangentialVelocity = velocity - glm::dot(velocity, eRoh) * eRoh;
			glm::vec3 eFriction = glm::vec3(0.f, 0.f, 0.f);
			if (glm::length(glm::cross(eRoh, angularVelocity) + tangentialVelocity) > 0.0001f){
				eFriction = glm::normalize(sphere.radius * glm::cross(eRoh, angularVelocity) + tangentialVelocity);
			}
			float vRoh = glm::dot(velocity, eRoh);
			float deltaU = -(e + 1.f) * vRoh;
			glm::vec3 angularDirection = glm::cross(eRoh, glm::normalize(tangentialVelocity));
			float w = glm::dot(angularVelocity, angularDirection);

			if (fabs(vRoh) < vCritical && glm::length(tangentialVelocity) > 0.0001f) {
				glm::vec3 mg = (9.82f)*glm::vec3(0.f, -1.f, 0.f);
				glm::vec3 tangentialGravityAcceleration = glm::dot(mg, eRoh)*eRoh;
				glm::vec3 tangentialSlidingFrictionDeceleration = muSliding*eFriction;
				glm::vec3 tangentialRollingFrictionDeceleration = muRolling*eFriction;
				glm::vec3 tangentialDelta = tangentialVelocity + (tangentialGravityAcceleration - tangentialSlidingFrictionDeceleration)*static_cast<float>(time);
				if (w * sphere.radius + 0.0001f < glm::length(tangentialVelocity)) {
					//Rolling
					if (glm::length(tangentialGravityAcceleration) < glm::length(tangentialRollingFrictionDeceleration))
						tangentialRollingFrictionDeceleration = glm::length(tangentialGravityAcceleration)*eFriction;
					velocity = tangentialVelocity - (tangentialGravityAcceleration + tangentialRollingFrictionDeceleration)*static_cast<float>(time);
					angularVelocity = (glm::length(velocity) / sphere.radius) * cross(eRoh,eFriction);
				} else {
					//Sliding
					velocity = tangentialVelocity - (tangentialGravityAcceleration - tangentialSlidingFrictionDeceleration)*static_cast<float>(time);
					angularVelocity += (5.f / 2.f) * (muSliding * 9.82f / sphere.radius * static_cast<float>(time)) * cross(eRoh, eFriction);
				}
			} else {
				float deltaTime = pow(mass * mass / (fabs(vRoh) * sphere.radius), 0.2f) * 0.00251744f;
				float velocityRoh = glm::dot(velocity, eRoh);
				float velocityNormal = glm::dot(velocity, eFriction);
				float uRoh = -e*velocityRoh;
				float deltauRoh = uRoh - (velocityRoh);
				float deltaUn = muSliding*deltauRoh;
				float rollUn = (5.f / 7.f)*velocityNormal;
				float slideUn = velocityNormal - deltaUn;

				if (velocityNormal > rollUn){
					velocity = uRoh*eRoh + rollUn*eFriction;
					angularVelocity += muRolling * (deltaU + 9.82f*eRoh.y * deltaTime) / sphere.radius * glm::cross(eRoh, eFriction);
				} else {
					velocity = uRoh*eRoh + slideUn*eFriction;
					angularVelocity += muSliding * (deltaU + 9.82f *eRoh.y* deltaTime) / sphere.radius * glm::cross(eRoh, eFriction);
				}
			}
		} else {
			// Calculate magnus force.
			float v = glm::length(velocity);
			float u = glm::length(velocity - wind);
			float w = glm::length(angularVelocity);
			glm::vec3 eU = (velocity - wind) / u;
			magnusForce = glm::vec3(0.f, 0.f, 0.f);
			if (u > 0.f && v > 0.f && w > 0.f) {
				float Cm = (sqrt(1.f + 0.31f * (w / v)) - 1.f) / 20.f;
				float Fm = 0.5f * Cm * 1.23f * area * u * u;
				magnusForce = Fm * glm::cross(eU, glm::normalize(angularVelocity));
			}

			// Calculate drag force.
			float cD;
			if (ballType == TWOPIECE)
				cD = v < 65.f ? -0.0051f * v + 0.53f : 0.21f;
			else
				cD = v < 60.f ? -0.0084f * v + 0.73f : 0.22f;
			dragForce = glm::vec3(0.f, 0.f, 0.f);
			if (u > 0.f)
				dragForce = -0.5f * 1.23f * area * cD * u * u * eU;
		}
		// Calculate gravitational force.
		glm::vec3 gravitationForce = glm::vec3(0.f, mass * -9.82f, 0.f);
		// Get acceleration from total force.
		glm::vec3 acceleration = (dragForce + magnusForce + gravitationForce) / mass;
		velocity += acceleration * static_cast<float>(time);

	}
}

void GolfBall::Render(Camera* camera, const glm::vec2& screenSize, const glm::vec4& clippingPlane) const{
    if (state != GolfBall::EXPLODED && state != GolfBall::OUT)
        ModelObject::Render(camera, screenSize, clippingPlane);
}

void GolfBall::Explode(std::vector<PlayerObject>& players){
    //@TODO: Set mass equivalent depending on material used.
    float equivalenceFactor = 1.0f;
    float massEquivalent = mass*equivalenceFactor;
    for (auto &player : players){
        glm::vec3 distanceV = (Position() - player.Position());
        float distance = glm::length(distanceV);
        //pow(meq, 1.f/3.f) => cube root of meq
        float z = distance / (pow(massEquivalent, 1.f / 3.f));
        float alpha = 1 + pow((z / 4.5f), 2.f);
        float beta = 1 + pow((z / 0.048f), 2.f);
        float gamma = 1 + pow((z / 1.35f), 2.f);
        float delta = 1 + pow((z / 0.32f), 2.f);
        //float Pf = 8.08f*pow(10.f, 7.f)*alpha;
		float Pf = ((8.08e7)*alpha) / sqrt(beta*gamma*delta);
        player.TakeDamage(Pf);
    }
    state = GolfBall::EXPLODED;
}

void GolfBall::Strike(ClubType club, const glm::vec3& clubVelocity) {
    state = GolfBall::ACTIVE;

    // Club velocity in strike plane.
    float v = glm::length(clubVelocity);
    if (v > 0.f)
    {
        float sinLoft = sin(club.loft);
        float cosLoft = cos(club.loft);

        // Ball velocity.
        float massCoefficient = club.mass / (club.mass + mass);
        float Up = (1.f + restitution) * massCoefficient * v * cosLoft;
        float Un = (2.f / 7.f) * massCoefficient * v * sinLoft;

        // Go back from strike plane to 3D.
        glm::vec3 forward = clubVelocity / v;
        glm::vec3 up = glm::cross(forward, glm::cross(glm::vec3(0.f, 1.f, 0.f), forward));
        glm::vec3 ep = glm::normalize(cosLoft * forward + sinLoft * up);
        glm::vec3 en = glm::normalize(sinLoft * forward - cosLoft * up);

        // Total velocity.
        velocity = Up * ep + Un * en;
        angularVelocity = -Un / sphere.radius * glm::cross(ep, en);
    } else {
        velocity = glm::vec3(0.f, 0.f, 0.f);
        angularVelocity = glm::vec3(0.f, 0.f, 0.f);
    }
}

float GolfBall::Radius() const {
    return sphere.radius;
}

void GolfBall::SetRadius(float radius) {
    sphere.radius = radius;
    SetScale(glm::vec3(radius, radius, radius));
    area = glm::pi<float>() * radius * radius;
}

glm::mat4 GolfBall::Orientation() const {
    return glm::toMat4(orientation);
}

GolfBall::State GolfBall::GetState() const {
    return state;
}
<commit_msg>Fixed rolling and sliding<commit_after>#include "GolfBall.hpp"
#include "../Resources.hpp"
#include "Default3D.vert.hpp"
#include "Default3D.geom.hpp"
#include "Default3D.frag.hpp"
#include "glm/gtc/constants.hpp"
#include "../Util/Log.hpp"
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/quaternion.hpp>

GolfBall::GolfBall(BallType ballType, TerrainObject* terrain, Water* water) : ModelObject(modelGeometry = Resources().CreateOBJModel("Resources/Models/GolfBall/GolfBall.obj"),
                                                                            "Resources/Models/GolfBall/Diffuse.png",
                                                                            "Resources/Models/GolfBall/Normal.png",
                                                                            "Resources/Models/GolfBall/Specular.png") {
    state = GolfBall::INITIAL;

    restitution = ballType == TWOPIECE ? 0.78f : 0.68f;
    this->terrain = terrain;
    this->water = water;
    origin = glm::vec3(1.f, 0.f, 1.f);

    mass = 0.0459f;
    this->ballType = ballType;

    sphere.position = Position();
    SetRadius(0.0214f);
}

GolfBall::~GolfBall() {
    Resources().FreeOBJModel(modelGeometry);
}

void GolfBall::Reset(){
    state = GolfBall::INITIAL;
    velocity = glm::vec3(0.f, 0.f, 0.f);
    angularVelocity = glm::vec3(0.f, 0.f, 0.f);
    SetPosition(origin);
    sphere.position = Position();
    orientation = glm::quat();
}

void GolfBall::Update(double time, const glm::vec3& wind, std::vector<PlayerObject>& players) {
	if (state == GolfBall::ACTIVE) {
		Move(static_cast<float>(time)* velocity);
		sphere.position = Position();

		if (glm::length(angularVelocity) > 0.0001f) {
			glm::quat deltaQuat = glm::angleAxis(static_cast<float>(time)* glm::length(angularVelocity), glm::normalize(angularVelocity));
			orientation = deltaQuat * orientation;
		}

		glm::vec3 dragForce, magnusForce, acceleration = glm::vec3(0.f, 0.f, 0.f);

		float groundLevel = terrain->GetY(Position().x, Position().z);
        float waterLevel = water->Position().y;

        // Check if in water.
        if ((sphere.position.y - sphere.radius < groundLevel && groundLevel + sphere.radius < waterLevel) || sphere.position.y + sphere.radius < waterLevel) {
            state = GolfBall::OUT;
            return;
        }

        // Check for collision
		if (glm::length(velocity) > 0.0001f && (sphere.position.y - sphere.radius) < groundLevel){
			float vCritical = 0.3f;
			float e = 0.35f;
			float muSliding = 0.51f;
			float muRolling = 0.096f;
			SetPosition(Position().x, groundLevel + sphere.radius, Position().z);
			sphere.position = Position();
			//glm::vec3 eRoh = glm::normalize(glm::vec3(0.f, 1.f, 0.f));
			glm::vec3 eRoh = terrain->GetNormal(Position().x, Position().z);
			glm::vec3 tangentialVelocity = velocity - glm::dot(velocity, eRoh) * eRoh;
			glm::vec3 eFriction = glm::vec3(0.f, 0.f, 0.f);
			if (glm::length(glm::cross(eRoh, angularVelocity) + tangentialVelocity) > 0.0001f){
				eFriction = glm::normalize(sphere.radius * glm::cross(eRoh, angularVelocity) + tangentialVelocity);
			}
			float vRoh = glm::dot(velocity, eRoh);
			float deltaU = -(e + 1.f) * vRoh;
			glm::vec3 angularDirection = glm::cross(eRoh, glm::normalize(tangentialVelocity));
			float w = glm::dot(angularVelocity, angularDirection);

			if (fabs(vRoh) < vCritical && glm::length(tangentialVelocity) > 0.0001f) {
				glm::vec3 mg = (9.82f)*glm::vec3(0.f, -1.f, 0.f);
				glm::vec3 tangentialGravityAcceleration = mg - glm::dot(mg, eRoh)*eRoh;
				glm::vec3 tangentialSlidingFrictionDeceleration = muSliding*eFriction;
				glm::vec3 tangentialRollingFrictionDeceleration = muRolling*eFriction;
				glm::vec3 tangentialDelta = tangentialVelocity + (tangentialGravityAcceleration - tangentialSlidingFrictionDeceleration)*static_cast<float>(time);
				if (w * sphere.radius + 0.0001f < glm::length(tangentialVelocity)) {
					//Rolling
					if (glm::length(tangentialGravityAcceleration) < glm::length(tangentialRollingFrictionDeceleration))
						tangentialRollingFrictionDeceleration = glm::length(tangentialGravityAcceleration)*eFriction;
					velocity = tangentialVelocity + (tangentialGravityAcceleration + tangentialRollingFrictionDeceleration)*static_cast<float>(time);
					angularVelocity = (glm::length(velocity) / sphere.radius) * cross(eRoh,eFriction);
				} else {
					//Sliding
					velocity = tangentialVelocity + (tangentialGravityAcceleration + tangentialSlidingFrictionDeceleration)*static_cast<float>(time);
					angularVelocity += (5.f / 2.f) * (muSliding * 9.82f / sphere.radius * static_cast<float>(time)) * cross(eRoh, eFriction);
				}
			} else {
				float deltaTime = pow(mass * mass / (fabs(vRoh) * sphere.radius), 0.2f) * 0.00251744f;
				float velocityRoh = glm::dot(velocity, eRoh);
				float velocityNormal = glm::dot(velocity, eFriction);
				float uRoh = -e*velocityRoh;
				float deltauRoh = uRoh - (velocityRoh);
				float deltaUn = muSliding*deltauRoh;
				float rollUn = (5.f / 7.f)*velocityNormal;
				float slideUn = velocityNormal - deltaUn;

				if (velocityNormal > rollUn){
					velocity = uRoh*eRoh + rollUn*eFriction;
					angularVelocity += muRolling * (deltaU + 9.82f*eRoh.y * deltaTime) / sphere.radius * glm::cross(eRoh, eFriction);
				} else {
					velocity = uRoh*eRoh + slideUn*eFriction;
					angularVelocity += muSliding * (deltaU + 9.82f *eRoh.y* deltaTime) / sphere.radius * glm::cross(eRoh, eFriction);
				}
			}
		} else {
			// Calculate magnus force.
			float v = glm::length(velocity);
			float u = glm::length(velocity - wind);
			float w = glm::length(angularVelocity);
			glm::vec3 eU = (velocity - wind) / u;
			magnusForce = glm::vec3(0.f, 0.f, 0.f);
			if (u > 0.f && v > 0.f && w > 0.f) {
				float Cm = (sqrt(1.f + 0.31f * (w / v)) - 1.f) / 20.f;
				float Fm = 0.5f * Cm * 1.23f * area * u * u;
				magnusForce = Fm * glm::cross(eU, glm::normalize(angularVelocity));
			}

			// Calculate drag force.
			float cD;
			if (ballType == TWOPIECE)
				cD = v < 65.f ? -0.0051f * v + 0.53f : 0.21f;
			else
				cD = v < 60.f ? -0.0084f * v + 0.73f : 0.22f;
			dragForce = glm::vec3(0.f, 0.f, 0.f);
			if (u > 0.f)
				dragForce = -0.5f * 1.23f * area * cD * u * u * eU;

			// Calculate gravitational force.
			glm::vec3 gravitationForce = glm::vec3(0.f, mass * -9.82f, 0.f);
			// Get acceleration from total force.
			acceleration = (dragForce + magnusForce + gravitationForce) / mass;
		}
		velocity += acceleration * static_cast<float>(time);
	}
}

void GolfBall::Render(Camera* camera, const glm::vec2& screenSize, const glm::vec4& clippingPlane) const{
    if (state != GolfBall::EXPLODED && state != GolfBall::OUT)
        ModelObject::Render(camera, screenSize, clippingPlane);
}

void GolfBall::Explode(std::vector<PlayerObject>& players){
    //@TODO: Set mass equivalent depending on material used.
    float equivalenceFactor = 1.0f;
    float massEquivalent = mass*equivalenceFactor;
    for (auto &player : players){
        glm::vec3 distanceV = (Position() - player.Position());
        float distance = glm::length(distanceV);
        //pow(meq, 1.f/3.f) => cube root of meq
        float z = distance / (pow(massEquivalent, 1.f / 3.f));
        float alpha = 1 + pow((z / 4.5f), 2.f);
        float beta = 1 + pow((z / 0.048f), 2.f);
        float gamma = 1 + pow((z / 1.35f), 2.f);
        float delta = 1 + pow((z / 0.32f), 2.f);
        //float Pf = 8.08f*pow(10.f, 7.f)*alpha;
		float Pf = ((8.08e7)*alpha) / sqrt(beta*gamma*delta);
        player.TakeDamage(Pf);
    }
    state = GolfBall::EXPLODED;
}

void GolfBall::Strike(ClubType club, const glm::vec3& clubVelocity) {
    state = GolfBall::ACTIVE;

    // Club velocity in strike plane.
    float v = glm::length(clubVelocity);
    if (v > 0.f)
    {
        float sinLoft = sin(club.loft);
        float cosLoft = cos(club.loft);

        // Ball velocity.
        float massCoefficient = club.mass / (club.mass + mass);
        float Up = (1.f + restitution) * massCoefficient * v * cosLoft;
        float Un = (2.f / 7.f) * massCoefficient * v * sinLoft;

        // Go back from strike plane to 3D.
        glm::vec3 forward = clubVelocity / v;
        glm::vec3 up = glm::cross(forward, glm::cross(glm::vec3(0.f, 1.f, 0.f), forward));
        glm::vec3 ep = glm::normalize(cosLoft * forward + sinLoft * up);
        glm::vec3 en = glm::normalize(sinLoft * forward - cosLoft * up);

        // Total velocity.
        velocity = Up * ep + Un * en;
        angularVelocity = -Un / sphere.radius * glm::cross(ep, en);
    } else {
        velocity = glm::vec3(0.f, 0.f, 0.f);
        angularVelocity = glm::vec3(0.f, 0.f, 0.f);
    }
}

float GolfBall::Radius() const {
    return sphere.radius;
}

void GolfBall::SetRadius(float radius) {
    sphere.radius = radius;
    SetScale(glm::vec3(radius, radius, radius));
    area = glm::pi<float>() * radius * radius;
}

glm::mat4 GolfBall::Orientation() const {
    return glm::toMat4(orientation);
}

GolfBall::State GolfBall::GetState() const {
    return state;
}
<|endoftext|>


<commit_before>#pragma once
#include <vector>
#include <memory>
#include <atomic>
#include "Fifo.hpp"
#include "ThreadsCount.hpp"
#include "JoiningThread.hpp"
#include "detail/Command.hpp"

namespace But
{
namespace Threading
{

template<typename Policy>
class ThreadPool final
{
public:
  template<typename T>
  using promise_type = typename Policy::template promise_type<T>;
  using thread_type = typename Policy::thread_type;

  explicit ThreadPool(const ThreadsCount tc):
    quit_{false}
  {
    threads_.reserve( tc.count() );
    for(ThreadsCount::value_type i=0; i < tc.count(); ++i)
      threads_.emplace_back( &ThreadPool::processingLoop, this );
  }

  ~ThreadPool()
  {
    try
    {
      quit_ = true;
      // unblock all threads, if needed
      Queue::lock_type lock{q_};
      for(ThreadsCount::value_type i=0; i < size(); ++i)
        q_.push(Queue::value_type{});
    }
    catch(...)
    {
      BUT_ASSERT(!"failed to stop thread - givin up...");
      abort();
    }
  }

  template<typename F>
  auto run(F f)
  {
    auto cmd = std::make_unique< detail::Task<F,Policy> >( std::move(f) );
    auto fut = cmd->promise_.get_future();
    {
      const Queue::lock_type lock{q_};
      q_.push( std::move(cmd) );
    }
    return fut;
  }

  auto size() const { return threads_.size(); }

private:
  auto getCommand()
  {
    Queue::lock_type lock{q_};
    auto cmd = std::move( q_.top() );
    q_.pop();
    return cmd;
  }

  void processingLoop() noexcept
  {
    while(not quit_)
    {
      try
      {
        auto cmd = getCommand();
        if(cmd)
          cmd->run();
      }
      catch(...)
      {
        BUT_ASSERT(!"unexpected exception from processing thread - this should never happen");
      }
    }
  }

  using Queue = Fifo<std::unique_ptr<detail::Command>>;

  Queue q_;
  std::atomic<bool> quit_;
  std::vector<JoiningThread<thread_type>> threads_;
};

}
}
<commit_msg>fixed usage that dependen on top() to block<commit_after>#pragma once
#include <vector>
#include <memory>
#include <atomic>
#include "Fifo.hpp"
#include "ThreadsCount.hpp"
#include "JoiningThread.hpp"
#include "detail/Command.hpp"

namespace But
{
namespace Threading
{

template<typename Policy>
class ThreadPool final
{
public:
  template<typename T>
  using promise_type = typename Policy::template promise_type<T>;
  using thread_type = typename Policy::thread_type;

  explicit ThreadPool(const ThreadsCount tc):
    quit_{false}
  {
    threads_.reserve( tc.count() );
    for(ThreadsCount::value_type i=0; i < tc.count(); ++i)
      threads_.emplace_back( &ThreadPool::processingLoop, this );
  }

  ~ThreadPool()
  {
    try
    {
      quit_ = true;
      // unblock all threads, if needed
      Queue::lock_type lock{q_};
      for(ThreadsCount::value_type i=0; i < size(); ++i)
        q_.push(Queue::value_type{});
    }
    catch(...)
    {
      BUT_ASSERT(!"failed to stop thread - givin up...");
      abort();
    }
  }

  template<typename F>
  auto run(F f)
  {
    auto cmd = std::make_unique< detail::Task<F,Policy> >( std::move(f) );
    auto fut = cmd->promise_.get_future();
    {
      const Queue::lock_type lock{q_};
      q_.push( std::move(cmd) );
    }
    return fut;
  }

  auto size() const { return threads_.size(); }

private:
  auto getCommand()
  {
    Queue::lock_type lock{q_};
    q_.waitForNonEmpty(lock);
    auto cmd = std::move( q_.top() );
    q_.pop();
    return cmd;
  }

  void processingLoop() noexcept
  {
    while(not quit_)
    {
      try
      {
        auto cmd = getCommand();
        if(cmd)
          cmd->run();
      }
      catch(...)
      {
        BUT_ASSERT(!"unexpected exception from processing thread - this should never happen");
      }
    }
  }

  using Queue = Fifo<std::unique_ptr<detail::Command>>;

  Queue q_;
  std::atomic<bool> quit_;
  std::vector<JoiningThread<thread_type>> threads_;
};

}
}
<|endoftext|>


<commit_before>/*
===========================================================================
Copyright (C) 2009 Robert Beckebans <trebor_7@users.sourceforge.net>

This file is part of Daemon source code.

Daemon source code 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.

Daemon source code 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.

You should have received a copy of the GNU General Public License
along with Daemon source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
===========================================================================
*/
// tr_image_exr.c

#ifdef __cplusplus
extern "C"
{
#endif
//#include "tr_local.h"
#include "../qcommon/q_shared.h"
#ifdef __cplusplus
}
#endif

//#include <OpenEXR/half.h>
#include "../openexr/half.h"

#ifdef __cplusplus
extern          "C"
{
#endif

	void LoadRGBEToFloats( const char *name, float **pic, int *width, int *height, qboolean doGamma, qboolean toneMap, qboolean compensate );

	void LoadRGBEToHalfs( const char *name, unsigned short **halfImage, int *width, int *height )
	{
		int            i, j;
		int            w, h;
		float          *hdrImage;
		float          *floatbuf;
		unsigned short *halfbuf;

#if 0
		w = h = 0;
		LoadRGBEToFloats( name, &hdrImage, &w, &h, qtrue, qtrue, qtrue );

		*width = w;
		*height = h;

		*ldrImage = ri.Malloc( w * h * 4 );
		pixbuf = *ldrImage;

		floatbuf = hdrImage;

		for ( i = 0; i < ( w * h ); i++ )
		{
			for ( j = 0; j < 3; j++ )
			{
				sample[ j ] = *floatbuf++;
			}

			NormalizeColor( sample, sample );

			*pixbuf++ = ( byte )( sample[ 0 ] * 255 );
			*pixbuf++ = ( byte )( sample[ 1 ] * 255 );
			*pixbuf++ = ( byte )( sample[ 2 ] * 255 );
			*pixbuf++ = ( byte ) 255;
		}

#else
		w = h = 0;
		LoadRGBEToFloats( name, &hdrImage, &w, &h, qtrue, qfalse, qtrue );

		*width = w;
		*height = h;

		*halfImage = ( unsigned short * ) Com_Allocate( w * h * 3 * 6 );

		halfbuf = *halfImage;
		floatbuf = hdrImage;

		for ( i = 0; i < ( w * h ); i++ )
		{
			for ( j = 0; j < 3; j++ )
			{
				half sample( *floatbuf++ );
				*halfbuf++ = sample.bits();
			}
		}

#endif

		Com_Dealloc( hdrImage );
	}

#ifdef __cplusplus
}
#endif
<commit_msg>Update include path for openexr<commit_after>/*
===========================================================================
Copyright (C) 2009 Robert Beckebans <trebor_7@users.sourceforge.net>

This file is part of Daemon source code.

Daemon source code 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.

Daemon source code 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.

You should have received a copy of the GNU General Public License
along with Daemon source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
===========================================================================
*/
// tr_image_exr.c

#ifdef __cplusplus
extern "C"
{
#endif
//#include "tr_local.h"
#include "../qcommon/q_shared.h"
#ifdef __cplusplus
}
#endif

//#include <OpenEXR/half.h>
#include "../../openexr/half.h"

#ifdef __cplusplus
extern          "C"
{
#endif

	void LoadRGBEToFloats( const char *name, float **pic, int *width, int *height, qboolean doGamma, qboolean toneMap, qboolean compensate );

	void LoadRGBEToHalfs( const char *name, unsigned short **halfImage, int *width, int *height )
	{
		int            i, j;
		int            w, h;
		float          *hdrImage;
		float          *floatbuf;
		unsigned short *halfbuf;

#if 0
		w = h = 0;
		LoadRGBEToFloats( name, &hdrImage, &w, &h, qtrue, qtrue, qtrue );

		*width = w;
		*height = h;

		*ldrImage = ri.Malloc( w * h * 4 );
		pixbuf = *ldrImage;

		floatbuf = hdrImage;

		for ( i = 0; i < ( w * h ); i++ )
		{
			for ( j = 0; j < 3; j++ )
			{
				sample[ j ] = *floatbuf++;
			}

			NormalizeColor( sample, sample );

			*pixbuf++ = ( byte )( sample[ 0 ] * 255 );
			*pixbuf++ = ( byte )( sample[ 1 ] * 255 );
			*pixbuf++ = ( byte )( sample[ 2 ] * 255 );
			*pixbuf++ = ( byte ) 255;
		}

#else
		w = h = 0;
		LoadRGBEToFloats( name, &hdrImage, &w, &h, qtrue, qfalse, qtrue );

		*width = w;
		*height = h;

		*halfImage = ( unsigned short * ) Com_Allocate( w * h * 3 * 6 );

		halfbuf = *halfImage;
		floatbuf = hdrImage;

		for ( i = 0; i < ( w * h ); i++ )
		{
			for ( j = 0; j < 3; j++ )
			{
				half sample( *floatbuf++ );
				*halfbuf++ = sample.bits();
			}
		}

#endif

		Com_Dealloc( hdrImage );
	}

#ifdef __cplusplus
}
#endif
<|endoftext|>