<commit_before>//
//  File: ShaderModule.cpp
//  Author: Hongtae Kim (tiff2766@gmail.com)
//
//  Copyright (c) 2016-2017 Hongtae Kim. All rights reserved.
//

#include "../GraphicsAPI.h"
#if DKGL_ENABLE_VULKAN
#include "Extensions.h"
#include "Types.h"
#include "ShaderModule.h"
#include "ShaderFunction.h"
#include "GraphicsDevice.h"

using namespace DKFramework;
using namespace DKFramework::Private::Vulkan;

ShaderModule::ShaderModule(DKGraphicsDevice* d, VkShaderModule s, const void* data, size_t size, DKShader::StageType st)
	: device(d)
	, module(s)
	, pushConstantLayout({})
{
	switch (st)
	{
	case DKShader::StageType::Vertex:
		stage = VK_SHADER_STAGE_VERTEX_BIT; break;
	case DKShader::StageType::Fragment:
		stage = VK_SHADER_STAGE_FRAGMENT_BIT; break;
	case DKShader::StageType::Compute:
		stage = VK_SHADER_STAGE_COMPUTE_BIT; break;
	default:
		DKASSERT_DEBUG(0);
		break;
	}

	GraphicsDevice* dev = (GraphicsDevice*)DKGraphicsDeviceInterface::Instance(device);

	spirv_cross::Compiler compiler(reinterpret_cast<const uint32_t*>(data), size / sizeof(uint32_t));
	auto active = compiler.get_active_interface_variables();
	spirv_cross::ShaderResources resources = compiler.get_shader_resources();

	auto GetResource = [&compiler, &active](const spirv_cross::Resource& resource, bool writable)->DKShaderResource
	{
		DKShaderResource out = {};
		out.set = compiler.get_decoration(resource.id, spv::DecorationDescriptorSet);
		out.binding = compiler.get_decoration(resource.id, spv::DecorationBinding);
		out.name = compiler.get_name(resource.id).c_str();
		out.stride = compiler.get_decoration(resource.id, spv::DecorationArrayStride);
		out.enabled = active.find(resource.id) != active.end();
		if (writable)
			out.access = DKShaderResource::AccessReadWrite;
		else
			out.access = DKShaderResource::AccessReadOnly;

		const spirv_cross::SPIRType& type = compiler.get_type(resource.type_id);
		out.count = 1;
		for (auto n : type.array)
			out.count = out.count * n;

		switch (type.basetype)
		{
		case spirv_cross::SPIRType::Image:
			out.type = DKShaderResource::TypeTexture;
			break;
		case spirv_cross::SPIRType::SampledImage:
			out.type = DKShaderResource::TypeSampledTexture;
			break;
		case spirv_cross::SPIRType::Sampler:
			out.type = DKShaderResource::TypeSampler;
			break;
		case spirv_cross::SPIRType::Struct:
			out.type = DKShaderResource::TypeBuffer;
			out.typeInfo.buffer.dataType = DKShaderDataType::Struct;
			out.typeInfo.buffer.alignment = compiler.get_decoration(resource.id, spv::DecorationAlignment);
			out.typeInfo.buffer.size = compiler.get_declared_struct_size(type);
			break;
		default:
			DKASSERT_DESC_DEBUG(0, "Should implement this!");
			DKLogE("ERROR: Unsupported SPIR-V type!");
		}

		if (out.type == DKShaderResource::TypeBuffer)
		{
			struct GetStructMembers
			{
				DKShaderResource& base; // buffer resource (base)
				spirv_cross::Compiler& compiler;
				auto operator () (const DKString& name, const spirv_cross::SPIRType& spType) -> DKShaderResourceStruct
				{
					DKShaderResourceStruct rst = {};
					// get struct members!
					rst.members.Reserve(spType.member_types.size());
					for (uint32_t i = 0; i < spType.member_types.size(); ++i)
					{
						DKShaderResourceStructMember member;
						uint32_t type = spType.member_types.at(i);
						const spirv_cross::SPIRType& memberType = compiler.get_type(type);
						member.dataType = ShaderDataTypeFromSPIRType(memberType);
						DKASSERT_DEBUG(member.dataType != DKShaderDataType::Unknown);
						DKASSERT_DEBUG(member.dataType != DKShaderDataType::None);

						if (member.dataType == DKShaderDataType::Struct)
						{
							member.typeInfoKey = DKString(name).Append(".").Append(member.name);
							GetStructMembers getMembers = { base, compiler };
							DKShaderResourceStruct memberStruct = getMembers(member.typeInfoKey, memberType);
							base.structTypeMemberMap.Update(member.typeInfoKey, memberStruct);
						}

						member.count = 1;
						for (auto n : spType.array)
							member.count = member.count * n;

						member.name = compiler.get_member_name(spType.self, i).c_str();
						member.offset = compiler.type_struct_member_offset(spType, i);
						//member.size = (memberType.width >> 3) * memberType.vecsize * memberType.columns;
						member.size = compiler.get_declared_struct_member_size(spType, i);
						DKASSERT_DEBUG(member.size > 0);

						if (member.count > 1)
							member.stride = compiler.type_struct_member_array_stride(spType, i);
						else
							member.stride = 0;
						rst.members.Add(member);
					}
					rst.members.ShrinkToFit();
					return rst;
				}
			};
			out.typeInfoKey = out.name;
			GetStructMembers getMembers = { out, compiler };
			DKShaderResourceStruct rst = getMembers(out.typeInfoKey, compiler.get_type(resource.base_type_id));
			out.structTypeMemberMap.Update(out.typeInfoKey, std::move(rst));
		}
		return out;
	};

	auto GetDescriptorBinding = [&compiler](const spirv_cross::Resource& resource, VkDescriptorType type)->DescriptorBinding
	{
		DescriptorBinding binding = {};
		binding.type = type;
		binding.set = compiler.get_decoration(resource.id, spv::DecorationDescriptorSet);
		binding.binding = compiler.get_decoration(resource.id, spv::DecorationBinding);

		const spirv_cross::SPIRType& spType = compiler.get_type_from_variable(resource.id);

		// get item count! (array size)
		binding.count = 1;
		if (spType.array.size() > 0)
		{
			for (auto i : spType.array)
				binding.count *= i;
		}
		return binding;
	};

	// https://github.com/KhronosGroup/SPIRV-Cross/wiki/Reflection-API-user-guide
	// uniform_buffers
	for (const spirv_cross::Resource& resource : resources.uniform_buffers)
	{
		this->resources.Add(GetResource(resource, false));
		this->descriptorBindings.Add(GetDescriptorBinding(resource, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER));
	}
	// storage_buffers
	for (const spirv_cross::Resource& resource : resources.storage_buffers)
	{
		this->resources.Add(GetResource(resource, true));
		this->descriptorBindings.Add(GetDescriptorBinding(resource, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
	}
	// storage_images
	for (const spirv_cross::Resource& resource : resources.storage_images)
	{
		this->resources.Add(GetResource(resource, true));
		this->descriptorBindings.Add(GetDescriptorBinding(resource, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE));
	}
	// sampled_images (sampler2D)
	for (const spirv_cross::Resource& resource : resources.sampled_images)
	{
		this->resources.Add(GetResource(resource, false));
		this->descriptorBindings.Add(GetDescriptorBinding(resource, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER));
	}
	// separate_images
	for (const spirv_cross::Resource& resource : resources.separate_images)
	{
		const spirv_cross::SPIRType& spType = compiler.get_type_from_variable(resource.id);
		VkDescriptorType type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
		if (spType.image.dim == spv::DimBuffer)
		{
			type = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
		}
		this->resources.Add(GetResource(resource, false));
		this->descriptorBindings.Add(GetDescriptorBinding(resource, type));
	}
	// separate_samplers
	for (const spirv_cross::Resource& resource : resources.separate_samplers)
	{
		this->resources.Add(GetResource(resource, false));
		this->descriptorBindings.Add(GetDescriptorBinding(resource, VK_DESCRIPTOR_TYPE_SAMPLER));
	}
	// stage inputs
	this->stageInputAttributes.Reserve(resources.stage_inputs.size());
	for (const spirv_cross::Resource& resource : resources.stage_inputs)
	{
		uint32_t location = compiler.get_decoration(resource.id, spv::DecorationLocation);
		DKStringU8 name = "";
		if (resource.name.size() > 0)
			name = resource.name.c_str();
		else
			name = compiler.get_fallback_name(resource.id).c_str();

		const spirv_cross::SPIRType& spType = compiler.get_type(resource.type_id);

		DKShaderDataType dataType = ShaderDataTypeFromSPIRType(spType);
		DKASSERT_DEBUG(dataType != DKShaderDataType::Unknown);

		// get item count! (array size)
		uint32_t count = 1;
		if (spType.array.size() > 0)
		{
			for (auto i : spType.array)
				count *= i;
		}

		DKShaderAttribute attr = {};
		attr.location = location;
		attr.name = name;
		attr.type = dataType;
		attr.active = true;

		this->stageInputAttributes.Add(attr);
	}

	// get pushConstant range.
	if (resources.push_constant_buffers.size() > 0)
	{
		const spirv_cross::Resource& resource = resources.push_constant_buffers[0];
		std::vector<spirv_cross::BufferRange> ranges = compiler.get_active_buffer_ranges(resource.id);
		this->pushConstantLayout.memberLayouts.Reserve(ranges.size());

		uint32_t pushConstantOffset = (uint32_t)ranges[0].offset;
		uint32_t pushConstantSize = 0;

		for (spirv_cross::BufferRange &range : ranges)
		{
			// get range.
			PushConstantLayout layout;
			layout.name = compiler.get_member_name(resource.id, range.index).c_str();
			layout.offset = range.offset;
			layout.size = range.range;
			pushConstantSize = (layout.offset - pushConstantOffset) + layout.size;

			this->pushConstantLayout.memberLayouts.Add(std::move(layout));
		}

		if (pushConstantSize % 4)	// size must be a multiple of 4
		{
			pushConstantSize += 4 - (pushConstantSize % 4);
		}

		DKASSERT_DEBUG((pushConstantOffset % 4) == 0);
		DKASSERT_DEBUG((pushConstantSize % 4) == 0);
		DKASSERT_DEBUG(pushConstantSize > 0);

		DKASSERT_DEBUG(pushConstantOffset < dev->properties.limits.maxPushConstantsSize);
		DKASSERT_DEBUG((pushConstantOffset + pushConstantSize) < dev->properties.limits.maxPushConstantsSize);

		this->pushConstantLayout.offset = pushConstantOffset;
		this->pushConstantLayout.size = pushConstantSize;
		this->pushConstantLayout.name = compiler.get_name(resource.id).c_str();

		//const spirv_cross::SPIRType& spType = compiler.get_type_from_variable(resource.id);
	}

	// get module entry points
	std::vector<spirv_cross::EntryPoint> entryPoints = compiler.get_entry_points_and_stages();
	for (spirv_cross::EntryPoint& ep : entryPoints)
	{
		functionNames.Add(ep.name.c_str());
	}

	// specialization constants
	std::vector<spirv_cross::SpecializationConstant> spConsts = compiler.get_specialization_constants();
	for (spirv_cross::SpecializationConstant& sc : spConsts)
	{
		//
	}

	// sort bindings
	this->descriptorBindings.Sort([](const DescriptorBinding& a, const DescriptorBinding& b)
	{
		if (a.set == b.set)
			return a.binding < b.binding;
		return a.set < b.set;
	});
	this->descriptorBindings.ShrinkToFit();
	this->resources.ShrinkToFit();
	this->stageInputAttributes.ShrinkToFit();
}

ShaderModule::~ShaderModule()
{
	GraphicsDevice* dev = (GraphicsDevice*)DKGraphicsDeviceInterface::Instance(device);
	vkDestroyShaderModule(dev->device, module, 0);
}

DKObject<DKShaderFunction> ShaderModule::CreateFunction(const DKString& name) const
{
	for (const DKString& fname : functionNames)
	{
		if (fname.Compare(name) == 0)
		{
			DKObject<ShaderFunction> func = DKOBJECT_NEW ShaderFunction(const_cast<ShaderModule*>(this), DKStringU8(name), 0, 0);
			return func.SafeCast<DKShaderFunction>();
		}
	}

	return NULL;
}

DKObject<DKShaderFunction> ShaderModule::CreateSpecializedFunction(const DKString& name, const DKShaderSpecialization* values, size_t numValues) const
{
	if (values && numValues > 0)
	{
		// TODO: verify values with SPIR-V Cross reflection

	}
	return NULL;
}

#endif //#if DKGL_ENABLE_VULKAN
<commit_msg>no message<commit_after>//
//  File: ShaderModule.cpp
//  Author: Hongtae Kim (tiff2766@gmail.com)
//
//  Copyright (c) 2016-2017 Hongtae Kim. All rights reserved.
//

#include "../GraphicsAPI.h"
#if DKGL_ENABLE_VULKAN
#include "Extensions.h"
#include "Types.h"
#include "ShaderModule.h"
#include "ShaderFunction.h"
#include "GraphicsDevice.h"

using namespace DKFramework;
using namespace DKFramework::Private::Vulkan;

ShaderModule::ShaderModule(DKGraphicsDevice* d, VkShaderModule s, const void* data, size_t size, DKShader::StageType st)
	: device(d)
	, module(s)
	, pushConstantLayout({})
{
	switch (st)
	{
	case DKShader::StageType::Vertex:
		stage = VK_SHADER_STAGE_VERTEX_BIT; break;
	case DKShader::StageType::Fragment:
		stage = VK_SHADER_STAGE_FRAGMENT_BIT; break;
	case DKShader::StageType::Compute:
		stage = VK_SHADER_STAGE_COMPUTE_BIT; break;
	default:
		DKASSERT_DEBUG(0);
		break;
	}

	GraphicsDevice* dev = (GraphicsDevice*)DKGraphicsDeviceInterface::Instance(device);

	spirv_cross::Compiler compiler(reinterpret_cast<const uint32_t*>(data), size / sizeof(uint32_t));
	auto active = compiler.get_active_interface_variables();
	spirv_cross::ShaderResources resources = compiler.get_shader_resources();

	auto GetResource = [&compiler, &active](const spirv_cross::Resource& resource, bool writable)->DKShaderResource
	{
		DKShaderResource out = {};
		out.set = compiler.get_decoration(resource.id, spv::DecorationDescriptorSet);
		out.binding = compiler.get_decoration(resource.id, spv::DecorationBinding);
		out.name = compiler.get_name(resource.id).c_str();
		out.stride = compiler.get_decoration(resource.id, spv::DecorationArrayStride);
		out.enabled = active.find(resource.id) != active.end();
		if (writable)
			out.access = DKShaderResource::AccessReadWrite;
		else
			out.access = DKShaderResource::AccessReadOnly;

		const spirv_cross::SPIRType& type = compiler.get_type(resource.type_id);
		out.count = 1;
		for (auto n : type.array)
			out.count = out.count * n;

		switch (type.basetype)
		{
		case spirv_cross::SPIRType::Image:
			out.type = DKShaderResource::TypeTexture;
			break;
		case spirv_cross::SPIRType::SampledImage:
			out.type = DKShaderResource::TypeSampledTexture;
			break;
		case spirv_cross::SPIRType::Sampler:
			out.type = DKShaderResource::TypeSampler;
			break;
		case spirv_cross::SPIRType::Struct:
			out.type = DKShaderResource::TypeBuffer;
			out.typeInfo.buffer.dataType = DKShaderDataType::Struct;
			out.typeInfo.buffer.alignment = compiler.get_decoration(resource.id, spv::DecorationAlignment);
			out.typeInfo.buffer.size = compiler.get_declared_struct_size(type);
			break;
		default:
			DKASSERT_DESC_DEBUG(0, "Should implement this!");
			DKLogE("ERROR: Unsupported SPIR-V type!");
		}

		if (out.type == DKShaderResource::TypeBuffer)
		{
			struct GetStructMembers
			{
				DKShaderResource& base; // buffer resource (base)
				spirv_cross::Compiler& compiler;
				auto operator () (const DKString& name, const spirv_cross::SPIRType& spType) -> DKShaderResourceStruct
				{
					DKShaderResourceStruct rst = {};
					// get struct members!
					rst.members.Reserve(spType.member_types.size());
					for (uint32_t i = 0; i < spType.member_types.size(); ++i)
					{
						DKShaderResourceStructMember member;
						uint32_t type = spType.member_types.at(i);
						const spirv_cross::SPIRType& memberType = compiler.get_type(type);
						member.dataType = ShaderDataTypeFromSPIRType(memberType);
						DKASSERT_DEBUG(member.dataType != DKShaderDataType::Unknown);
						DKASSERT_DEBUG(member.dataType != DKShaderDataType::None);

						if (member.dataType == DKShaderDataType::Struct)
						{
							member.typeInfoKey = DKString(name).Append(".").Append(member.name);
							GetStructMembers getMembers = { base, compiler };
							DKShaderResourceStruct memberStruct = getMembers(member.typeInfoKey, memberType);
							base.structTypeMemberMap.Update(member.typeInfoKey, memberStruct);
						}

						member.count = 1;
						for (auto n : memberType.array)
							member.count = member.count * n;

						member.name = compiler.get_member_name(spType.self, i).c_str();
						member.offset = compiler.type_struct_member_offset(spType, i);
						//member.size = (memberType.width >> 3) * memberType.vecsize * memberType.columns;
						member.size = compiler.get_declared_struct_member_size(spType, i);
						DKASSERT_DEBUG(member.size > 0);

						if (member.count > 1)
							member.stride = compiler.type_struct_member_array_stride(spType, i);
						else
							member.stride = 0;
						rst.members.Add(member);
					}
					rst.members.ShrinkToFit();
					return rst;
				}
			};
			out.typeInfoKey = out.name;
			GetStructMembers getMembers = { out, compiler };
			DKShaderResourceStruct rst = getMembers(out.typeInfoKey, compiler.get_type(resource.base_type_id));
			out.structTypeMemberMap.Update(out.typeInfoKey, std::move(rst));
		}
		return out;
	};

	auto GetDescriptorBinding = [&compiler](const spirv_cross::Resource& resource, VkDescriptorType type)->DescriptorBinding
	{
		DescriptorBinding binding = {};
		binding.type = type;
		binding.set = compiler.get_decoration(resource.id, spv::DecorationDescriptorSet);
		binding.binding = compiler.get_decoration(resource.id, spv::DecorationBinding);

		const spirv_cross::SPIRType& spType = compiler.get_type_from_variable(resource.id);

		// get item count! (array size)
		binding.count = 1;
		if (spType.array.size() > 0)
		{
			for (auto i : spType.array)
				binding.count *= i;
		}
		return binding;
	};

	// https://github.com/KhronosGroup/SPIRV-Cross/wiki/Reflection-API-user-guide
	// uniform_buffers
	for (const spirv_cross::Resource& resource : resources.uniform_buffers)
	{
		this->resources.Add(GetResource(resource, false));
		this->descriptorBindings.Add(GetDescriptorBinding(resource, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER));
	}
	// storage_buffers
	for (const spirv_cross::Resource& resource : resources.storage_buffers)
	{
		this->resources.Add(GetResource(resource, true));
		this->descriptorBindings.Add(GetDescriptorBinding(resource, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
	}
	// storage_images
	for (const spirv_cross::Resource& resource : resources.storage_images)
	{
		this->resources.Add(GetResource(resource, true));
		this->descriptorBindings.Add(GetDescriptorBinding(resource, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE));
	}
	// sampled_images (sampler2D)
	for (const spirv_cross::Resource& resource : resources.sampled_images)
	{
		this->resources.Add(GetResource(resource, false));
		this->descriptorBindings.Add(GetDescriptorBinding(resource, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER));
	}
	// separate_images
	for (const spirv_cross::Resource& resource : resources.separate_images)
	{
		const spirv_cross::SPIRType& spType = compiler.get_type_from_variable(resource.id);
		VkDescriptorType type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
		if (spType.image.dim == spv::DimBuffer)
		{
			type = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
		}
		this->resources.Add(GetResource(resource, false));
		this->descriptorBindings.Add(GetDescriptorBinding(resource, type));
	}
	// separate_samplers
	for (const spirv_cross::Resource& resource : resources.separate_samplers)
	{
		this->resources.Add(GetResource(resource, false));
		this->descriptorBindings.Add(GetDescriptorBinding(resource, VK_DESCRIPTOR_TYPE_SAMPLER));
	}
	// stage inputs
	this->stageInputAttributes.Reserve(resources.stage_inputs.size());
	for (const spirv_cross::Resource& resource : resources.stage_inputs)
	{
		uint32_t location = compiler.get_decoration(resource.id, spv::DecorationLocation);
		DKStringU8 name = "";
		if (resource.name.size() > 0)
			name = resource.name.c_str();
		else
			name = compiler.get_fallback_name(resource.id).c_str();

		const spirv_cross::SPIRType& spType = compiler.get_type(resource.type_id);

		DKShaderDataType dataType = ShaderDataTypeFromSPIRType(spType);
		DKASSERT_DEBUG(dataType != DKShaderDataType::Unknown);

		// get item count! (array size)
		uint32_t count = 1;
		if (spType.array.size() > 0)
		{
			for (auto i : spType.array)
				count *= i;
		}

		DKShaderAttribute attr = {};
		attr.location = location;
		attr.name = name;
		attr.type = dataType;
		attr.active = true;

		this->stageInputAttributes.Add(attr);
	}

	// get pushConstant range.
	if (resources.push_constant_buffers.size() > 0)
	{
		const spirv_cross::Resource& resource = resources.push_constant_buffers[0];
		std::vector<spirv_cross::BufferRange> ranges = compiler.get_active_buffer_ranges(resource.id);
		this->pushConstantLayout.memberLayouts.Reserve(ranges.size());

		uint32_t pushConstantOffset = (uint32_t)ranges[0].offset;
		uint32_t pushConstantSize = 0;

		for (spirv_cross::BufferRange &range : ranges)
		{
			// get range.
			PushConstantLayout layout;
			layout.name = compiler.get_member_name(resource.id, range.index).c_str();
			layout.offset = range.offset;
			layout.size = range.range;
			pushConstantSize = (layout.offset - pushConstantOffset) + layout.size;

			this->pushConstantLayout.memberLayouts.Add(std::move(layout));
		}

		if (pushConstantSize % 4)	// size must be a multiple of 4
		{
			pushConstantSize += 4 - (pushConstantSize % 4);
		}

		DKASSERT_DEBUG((pushConstantOffset % 4) == 0);
		DKASSERT_DEBUG((pushConstantSize % 4) == 0);
		DKASSERT_DEBUG(pushConstantSize > 0);

		DKASSERT_DEBUG(pushConstantOffset < dev->properties.limits.maxPushConstantsSize);
		DKASSERT_DEBUG((pushConstantOffset + pushConstantSize) < dev->properties.limits.maxPushConstantsSize);

		this->pushConstantLayout.offset = pushConstantOffset;
		this->pushConstantLayout.size = pushConstantSize;
		this->pushConstantLayout.name = compiler.get_name(resource.id).c_str();

		//const spirv_cross::SPIRType& spType = compiler.get_type_from_variable(resource.id);
	}

	// get module entry points
	std::vector<spirv_cross::EntryPoint> entryPoints = compiler.get_entry_points_and_stages();
	for (spirv_cross::EntryPoint& ep : entryPoints)
	{
		functionNames.Add(ep.name.c_str());
	}

	// specialization constants
	std::vector<spirv_cross::SpecializationConstant> spConsts = compiler.get_specialization_constants();
	for (spirv_cross::SpecializationConstant& sc : spConsts)
	{
		//
	}

	// sort bindings
	this->descriptorBindings.Sort([](const DescriptorBinding& a, const DescriptorBinding& b)
	{
		if (a.set == b.set)
			return a.binding < b.binding;
		return a.set < b.set;
	});
	this->descriptorBindings.ShrinkToFit();
	this->resources.ShrinkToFit();
	this->stageInputAttributes.ShrinkToFit();
}

ShaderModule::~ShaderModule()
{
	GraphicsDevice* dev = (GraphicsDevice*)DKGraphicsDeviceInterface::Instance(device);
	vkDestroyShaderModule(dev->device, module, 0);
}

DKObject<DKShaderFunction> ShaderModule::CreateFunction(const DKString& name) const
{
	for (const DKString& fname : functionNames)
	{
		if (fname.Compare(name) == 0)
		{
			DKObject<ShaderFunction> func = DKOBJECT_NEW ShaderFunction(const_cast<ShaderModule*>(this), DKStringU8(name), 0, 0);
			return func.SafeCast<DKShaderFunction>();
		}
	}

	return NULL;
}

DKObject<DKShaderFunction> ShaderModule::CreateSpecializedFunction(const DKString& name, const DKShaderSpecialization* values, size_t numValues) const
{
	if (values && numValues > 0)
	{
		// TODO: verify values with SPIR-V Cross reflection

	}
	return NULL;
}

#endif //#if DKGL_ENABLE_VULKAN
<|endoftext|>


<commit_before>/*
 * Neighbors.cc
 *
 * Copyright (C) 2014 OpenCog Foundation
 *
 * Author: William Ma <https://github.com/williampma>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <iostream>

#include <opencog/atomspace/Link.h>
#include <opencog/atomspace/Node.h>
#include "Neighbors.h"

namespace opencog
{

HandleSeq get_target_neighbors(const Handle& h, Type desiredLinkType)
{
    HandleSeq answer;
    for (const LinkPtr& link : h->getIncomingSet())
    {
        if (link->getType() != desiredLinkType) continue;
        if (classserver().isA(link->getType(), UNORDERED_LINK)) continue;
        if (link->getOutgoingAtom(0) != h) continue;

        for (const Handle& handle : link->getOutgoingSet()) {
           if (handle == h) continue;
           answer.emplace_back(handle);
        }
    }
    return answer;
}

HandleSeq get_source_neighbors(const Handle& h, Type desiredLinkType)
{
    HandleSeq answer;

    for (const LinkPtr& link : h->getIncomingSet())
    {
        if (link->getType() != desiredLinkType) continue;
        if (classserver().isA(link->getType(), UNORDERED_LINK)) continue;
        if (link->getOutgoingAtom(0) == h) continue;

        for (const Handle& handle : link->getOutgoingSet()) {
           if (handle == h) continue;
            answer.emplace_back(handle);
        }
    }
    return answer;
}

HandleSeq get_all_neighbors(const Handle& h,
                            Type desiredLinkType)
{
    HandleSeq answer;

    for (const LinkPtr& link : h->getIncomingSet())
    {
        Type linkType = link->getType();
        if (linkType == desiredLinkType)
        {
            for (const Handle& handle : link->getOutgoingSet()) {
                if (handle == h) continue;
                answer.emplace_back(handle);
            }
        }
    }
    return answer;
}

/* Tail-recursive helper function. We mark it static, so that
 * gcc can optimize this, i.e. call it without buying the stack
 * frame. */
static void get_distant_neighbors_rec(const Handle& h,
                                      UnorderedHandleSet& res,
                                      int dist)
{
    res.insert(h);

    // Recursive calls
    if (dist != 0) {
        // 1. Fetch incomings
        for (const LinkPtr& in_l : h->getIncomingSet()) {
            Handle in_h = in_l->getHandle();
            if (res.find(in_h) == res.cend()) // Do not re-explore
                get_distant_neighbors_rec(in_h, res, dist - 1);
        }
        // 2. Fetch outgoings
        LinkPtr link = LinkCast(h);
        if (link) {
            for (const Handle& out_h : link->getOutgoingSet()) {
                if (res.find(out_h) == res.cend()) // Do not re-explore
                    get_distant_neighbors_rec(out_h, res, dist - 1);
            }
        }
    }
}

UnorderedHandleSet get_distant_neighbors(const Handle& h, int dist)
{
    UnorderedHandleSet results;
    get_distant_neighbors_rec(h, results, dist);
    results.erase(h);
    return results;
}

} // namespace OpenCog
<commit_msg>More optimization<commit_after>/*
 * Neighbors.cc
 *
 * Copyright (C) 2014 OpenCog Foundation
 *
 * Author: William Ma <https://github.com/williampma>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <iostream>

#include <opencog/atomspace/Link.h>
#include <opencog/atomspace/Node.h>
#include "Neighbors.h"

namespace opencog
{

HandleSeq get_target_neighbors(const Handle& h, Type desiredLinkType)
{
    if (classserver().isA(desiredLinkType, UNORDERED_LINK))
        return HandleSeq();

    HandleSeq answer;
    for (const LinkPtr& link : h->getIncomingSet())
    {
        if (link->getType() != desiredLinkType) continue;
        if (link->getOutgoingAtom(0) != h) continue;

        for (const Handle& handle : link->getOutgoingSet()) {
           if (handle == h) continue;
           answer.emplace_back(handle);
        }
    }
    return answer;
}

HandleSeq get_source_neighbors(const Handle& h, Type desiredLinkType)
{
    if (classserver().isA(desiredLinkType, UNORDERED_LINK))
        return HandleSeq();

    HandleSeq answer;

    for (const LinkPtr& link : h->getIncomingSet())
    {
        if (link->getType() != desiredLinkType) continue;
        if (link->getOutgoingAtom(0) == h) continue;

        for (const Handle& handle : link->getOutgoingSet()) {
           if (handle == h) continue;
            answer.emplace_back(handle);
        }
    }
    return answer;
}

HandleSeq get_all_neighbors(const Handle& h,
                            Type desiredLinkType)
{
    HandleSeq answer;

    for (const LinkPtr& link : h->getIncomingSet())
    {
        Type linkType = link->getType();
        if (linkType == desiredLinkType)
        {
            for (const Handle& handle : link->getOutgoingSet()) {
                if (handle == h) continue;
                answer.emplace_back(handle);
            }
        }
    }
    return answer;
}

/* Tail-recursive helper function. We mark it static, so that
 * gcc can optimize this, i.e. call it without buying the stack
 * frame. */
static void get_distant_neighbors_rec(const Handle& h,
                                      UnorderedHandleSet& res,
                                      int dist)
{
    res.insert(h);

    // Recursive calls
    if (dist != 0) {
        // 1. Fetch incomings
        for (const LinkPtr& in_l : h->getIncomingSet()) {
            Handle in_h = in_l->getHandle();
            if (res.find(in_h) == res.cend()) // Do not re-explore
                get_distant_neighbors_rec(in_h, res, dist - 1);
        }
        // 2. Fetch outgoings
        LinkPtr link = LinkCast(h);
        if (link) {
            for (const Handle& out_h : link->getOutgoingSet()) {
                if (res.find(out_h) == res.cend()) // Do not re-explore
                    get_distant_neighbors_rec(out_h, res, dist - 1);
            }
        }
    }
}

UnorderedHandleSet get_distant_neighbors(const Handle& h, int dist)
{
    UnorderedHandleSet results;
    get_distant_neighbors_rec(h, results, dist);
    results.erase(h);
    return results;
}

} // namespace OpenCog
<|endoftext|>


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

# pragma once
# include <type_traits>
# include <tuple>

namespace s3d
{
	template <class Tag, class Type>
	class NamedParameter
	{
	private:

		Type m_value;

	public:

		constexpr NamedParameter()
			: m_value() {}

		explicit constexpr NamedParameter(Type value)
			: m_value(value) {}

		template <class U, class V = Type, std::enable_if_t<std::is_convertible_v<U, V>>* = nullptr>
		constexpr NamedParameter(const NamedParameter<Tag, U>& other)
			: m_value(other.value()) {}

		template <class... Args, class V = Type, std::enable_if_t<std::is_constructible_v<V, Args...>>* = nullptr>
		constexpr NamedParameter(const NamedParameter<Tag, std::tuple<Args...>>& tuple)
			: m_value(std::make_from_tuple<Type>(tuple.value())) {}

		constexpr const Type* operator ->() const
		{
			return std::addressof(m_value);
		}

		[[nodiscard]] constexpr const Type& operator *() const
		{
			return m_value;
		}

		[[nodiscard]] constexpr const Type& value() const
		{
			return m_value;
		}
	};

	template <class Tag, class Type>
	class NamedParameter<Tag, Type&>
	{
	private:

		Type* m_ref;

	public:

		constexpr NamedParameter() noexcept
			: m_ref(nullptr) {}

		constexpr NamedParameter(Type& value) noexcept
			: m_ref(std::addressof(value)) {}

		constexpr Type* operator ->() const
		{
			return m_ref;
		}

		[[nodiscard]] constexpr Type& operator *() const
		{
			return *m_ref;
		}

		[[nodiscard]] constexpr Type& value() const
		{
			return *m_ref;
		}
	};

	template <class Tag>
	struct NamedParameterHelper
	{
		template <class Type>
		using named_argument_type = NamedParameter<Tag, Type>;

		template <class Type>
		constexpr NamedParameter<Tag, std::decay_t<Type>> operator= (Type&& value) const
		{
			return NamedParameter<Tag, std::decay_t<Type>>(std::forward<Type>(value));
		}

		template <class... Args>
		constexpr NamedParameter<Tag, std::tuple<Args...>> operator() (const Args&... args) const
		{
			return NamedParameter<Tag, std::tuple<Args...>>(std::make_tuple(args...));
		}

		template <class Type>
		constexpr NamedParameter<Tag, Type&> operator= (std::reference_wrapper<Type> value) const
		{
			return NamedParameter<Tag, Type&>(value.get());
		}

		template <class Type>
		constexpr NamedParameter<Tag, Type&> operator() (std::reference_wrapper<Type> value) const
		{
			return NamedParameter<Tag, Type&>(value.get());
		}
	};

	# define SIV3D_NAMED_PARAMETER(name) \
	constexpr auto name = NamedParameterHelper<struct name##_tag>{};\
	template <class Type> using name##_ = NamedParameterHelper<struct name##_tag>::named_argument_type<Type>
}

namespace s3d
{
	namespace Arg
	{
		SIV3D_NAMED_PARAMETER(generator);
		SIV3D_NAMED_PARAMETER(generator0_1);
		SIV3D_NAMED_PARAMETER(radix);
		SIV3D_NAMED_PARAMETER(upperCase);
		SIV3D_NAMED_PARAMETER(r);
		SIV3D_NAMED_PARAMETER(theta);
		SIV3D_NAMED_PARAMETER(phi);
		SIV3D_NAMED_PARAMETER(y);
		SIV3D_NAMED_PARAMETER(center);
		SIV3D_NAMED_PARAMETER(topLeft);
		SIV3D_NAMED_PARAMETER(topRight);
		SIV3D_NAMED_PARAMETER(bottomLeft);
		SIV3D_NAMED_PARAMETER(bottomRight);
		SIV3D_NAMED_PARAMETER(left);
		SIV3D_NAMED_PARAMETER(right);
		SIV3D_NAMED_PARAMETER(top);
		SIV3D_NAMED_PARAMETER(bottom);
		SIV3D_NAMED_PARAMETER(topCenter);
		SIV3D_NAMED_PARAMETER(bottomCenter);
		SIV3D_NAMED_PARAMETER(leftCenter);
		SIV3D_NAMED_PARAMETER(rightCenter);
		SIV3D_NAMED_PARAMETER(source);
		SIV3D_NAMED_PARAMETER(loop);
		SIV3D_NAMED_PARAMETER(loopBegin);
		SIV3D_NAMED_PARAMETER(loopEnd);
		SIV3D_NAMED_PARAMETER(code);
		SIV3D_NAMED_PARAMETER(samplingRate);
	}
}
<commit_msg>fix #297<commit_after>//-----------------------------------------------
//
//	This file is part of the Siv3D Engine.
//
//	Copyright (c) 2008-2018 Ryo Suzuki
//	Copyright (c) 2016-2018 OpenSiv3D Project
//
//	Licensed under the MIT License.
//
//-----------------------------------------------

# pragma once
# include <type_traits>
# include <tuple>

namespace s3d
{
	template <class Tag, class Type>
	class NamedParameter
	{
	private:

		Type m_value;

	public:

		constexpr NamedParameter()
			: m_value() {}

		explicit constexpr NamedParameter(Type value)
			: m_value(value) {}

		template <class U, class V = Type, std::enable_if_t<std::is_convertible_v<U, V>>* = nullptr>
		constexpr NamedParameter(const NamedParameter<Tag, U>& other)
			: m_value(other.value()) {}

		template <class... Args, class V = Type, std::enable_if_t<std::is_constructible_v<V, Args...>>* = nullptr>
		constexpr NamedParameter(const NamedParameter<Tag, std::tuple<Args...>>& tuple)
			: m_value(std::make_from_tuple<Type>(tuple.value())) {}

		constexpr const Type* operator ->() const
		{
			return std::addressof(m_value);
		}

		[[nodiscard]] constexpr const Type& operator *() const
		{
			return m_value;
		}

		[[nodiscard]] constexpr const Type& value() const
		{
			return m_value;
		}
	};

	template <class Tag, class Type>
	class NamedParameter<Tag, Type&>
	{
	private:

		Type* m_ref;

	public:

		constexpr NamedParameter() noexcept
			: m_ref(nullptr) {}

		constexpr NamedParameter(Type& value) noexcept
			: m_ref(std::addressof(value)) {}

		constexpr Type* operator ->() const
		{
			return m_ref;
		}

		[[nodiscard]] constexpr Type& operator *() const
		{
			return *m_ref;
		}

		[[nodiscard]] constexpr Type& value() const
		{
			return *m_ref;
		}
	};

	template <class Tag>
	struct NamedParameterHelper
	{
		template <class Type>
		using named_argument_type = NamedParameter<Tag, Type>;

		template <class Type>
		constexpr NamedParameter<Tag, std::decay_t<Type>> operator= (Type&& value) const
		{
			return NamedParameter<Tag, std::decay_t<Type>>(std::forward<Type>(value));
		}

		template <class... Args>
		constexpr NamedParameter<Tag, std::tuple<Args...>> operator() (const Args&... args) const
		{
			return NamedParameter<Tag, std::tuple<Args...>>(std::make_tuple(args...));
		}

		template <class Type>
		constexpr NamedParameter<Tag, Type&> operator= (std::reference_wrapper<Type> value) const
		{
			return NamedParameter<Tag, Type&>(value.get());
		}

		template <class Type>
		constexpr NamedParameter<Tag, Type&> operator() (std::reference_wrapper<Type> value) const
		{
			return NamedParameter<Tag, Type&>(value.get());
		}
	};

	# define SIV3D_NAMED_PARAMETER(name) \
	constexpr auto name = NamedParameterHelper<struct name##_tag>{};\
	template <class Type> using name##_ = typename NamedParameterHelper<struct name##_tag>::template named_argument_type<Type>
}

namespace s3d
{
	namespace Arg
	{
		SIV3D_NAMED_PARAMETER(generator);
		SIV3D_NAMED_PARAMETER(generator0_1);
		SIV3D_NAMED_PARAMETER(radix);
		SIV3D_NAMED_PARAMETER(upperCase);
		SIV3D_NAMED_PARAMETER(r);
		SIV3D_NAMED_PARAMETER(theta);
		SIV3D_NAMED_PARAMETER(phi);
		SIV3D_NAMED_PARAMETER(y);
		SIV3D_NAMED_PARAMETER(center);
		SIV3D_NAMED_PARAMETER(topLeft);
		SIV3D_NAMED_PARAMETER(topRight);
		SIV3D_NAMED_PARAMETER(bottomLeft);
		SIV3D_NAMED_PARAMETER(bottomRight);
		SIV3D_NAMED_PARAMETER(left);
		SIV3D_NAMED_PARAMETER(right);
		SIV3D_NAMED_PARAMETER(top);
		SIV3D_NAMED_PARAMETER(bottom);
		SIV3D_NAMED_PARAMETER(topCenter);
		SIV3D_NAMED_PARAMETER(bottomCenter);
		SIV3D_NAMED_PARAMETER(leftCenter);
		SIV3D_NAMED_PARAMETER(rightCenter);
		SIV3D_NAMED_PARAMETER(source);
		SIV3D_NAMED_PARAMETER(loop);
		SIV3D_NAMED_PARAMETER(loopBegin);
		SIV3D_NAMED_PARAMETER(loopEnd);
		SIV3D_NAMED_PARAMETER(code);
		SIV3D_NAMED_PARAMETER(samplingRate);
	}
}
<|endoftext|>


<commit_before>// Copyright 2010-2013 RethinkDB, all rights reserved.
#include "rdb_protocol/terms/terms.hpp"

#include "rdb_protocol/error.hpp"
#include "rdb_protocol/op.hpp"

namespace ql {

template<int (*const F)(int)>
const char *case_name();
template<>
const char *case_name<::toupper>() { return "upcase"; }
template<>
const char *case_name<::tolower>() { return "downcase"; }

template<int (*const F)(int)>
class case_term_t : public op_term_t {
public:
    case_term_t(compile_env_t *env, const protob_t<const Term> &term)
        : op_term_t(env, term, argspec_t(1)) { }
private:
    virtual counted_t<val_t> eval_impl(scope_env_t *env, UNUSED eval_flags_t flags) {
        debugf("%s\n", name());
        std::string s = arg(env, 0)->as_str();
        std::transform(s.begin(), s.end(), s.begin(), F);
        return new_val(make_counted<const datum_t>(std::move(s)));
    }
    virtual const char *name() const { return case_name<F>(); }
};

counted_t<term_t> make_upcase_term(compile_env_t *env,
                                   const protob_t<const Term> &term) {
    return make_counted<case_term_t<::toupper> >(env, term);
}
counted_t<term_t> make_downcase_term(compile_env_t *env,
                                     const protob_t<const Term> &term) {
    return make_counted<case_term_t<::tolower> >(env, term);
}

}
<commit_msg>switched to using templates<commit_after>// Copyright 2010-2013 RethinkDB, all rights reserved.
#include "rdb_protocol/terms/terms.hpp"

#include "rdb_protocol/error.hpp"
#include "rdb_protocol/op.hpp"

namespace ql {

template<int (*const F)(int)>
const char *case_name();
template<>
const char *case_name<::toupper>() { return "upcase"; }
template<>
const char *case_name<::tolower>() { return "downcase"; }

template<int (*const F)(int)>
class case_term_t : public op_term_t {
public:
    case_term_t(compile_env_t *env, const protob_t<const Term> &term)
        : op_term_t(env, term, argspec_t(1)) { }
private:
    virtual counted_t<val_t> eval_impl(scope_env_t *env, UNUSED eval_flags_t flags) {
        std::string s = arg(env, 0)->as_str();
        std::transform(s.begin(), s.end(), s.begin(), F);
        return new_val(make_counted<const datum_t>(std::move(s)));
    }
    virtual const char *name() const { return case_name<F>(); }
};

counted_t<term_t> make_upcase_term(compile_env_t *env,
                                   const protob_t<const Term> &term) {
    return make_counted<case_term_t<::toupper> >(env, term);
}
counted_t<term_t> make_downcase_term(compile_env_t *env,
                                     const protob_t<const Term> &term) {
    return make_counted<case_term_t<::tolower> >(env, term);
}

}
<|endoftext|>


<commit_before>/**
 * OpenAL cross platform audio library
 * Copyright (C) 2018 by Raul Herraiz.
 * This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 *  Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the
 *  Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 * Or go to http://www.gnu.org/copyleft/lgpl.html
 */

#include "config.h"

#include <cmath>
#include <cstdlib>
#include <array>
#include <complex>
#include <algorithm>

#include "al/auxeffectslot.h"
#include "alcmain.h"
#include "alcontext.h"
#include "alu.h"

#include "alcomplex.h"

namespace {

using complex_d = std::complex<double>;

#define HIL_SIZE 1024
#define OVERSAMP (1<<2)

#define HIL_STEP     (HIL_SIZE / OVERSAMP)
#define FIFO_LATENCY (HIL_STEP * (OVERSAMP-1))

/* Define a Hann window, used to filter the HIL input and output. */
/* Making this constexpr seems to require C++14. */
std::array<ALdouble,HIL_SIZE> InitHannWindow()
{
    std::array<ALdouble,HIL_SIZE> ret;
    /* Create lookup table of the Hann window for the desired size, i.e. HIL_SIZE */
    for(ALsizei i{0};i < HIL_SIZE>>1;i++)
    {
        ALdouble val = std::sin(al::MathDefs<double>::Pi() * i / ALdouble{HIL_SIZE-1});
        ret[i] = ret[HIL_SIZE-1-i] = val * val;
    }
    return ret;
}
alignas(16) const std::array<ALdouble,HIL_SIZE> HannWindow = InitHannWindow();

struct FshifterState final : public EffectState {
    /* Effect parameters */
    ALsizei  mCount{};
    ALsizei  mPhaseStep[2]{};
    ALsizei  mPhase[2]{};
    ALdouble mSign[2]{};

    /*Effects buffers*/
    ALfloat   mInFIFO[HIL_SIZE]{};
    complex_d mOutFIFO[HIL_SIZE]{};
    complex_d mOutputAccum[HIL_SIZE]{};
    complex_d mAnalytic[HIL_SIZE]{};
    complex_d mOutdata[BUFFERSIZE]{};

    alignas(16) ALfloat mBufferOut[BUFFERSIZE]{};

    /* Effect gains for each output channel */
    struct {
        ALfloat Current[MAX_OUTPUT_CHANNELS]{};
        ALfloat Target[MAX_OUTPUT_CHANNELS]{};
    }mGains[2];

    ALboolean deviceUpdate(const ALCdevice *device) override;
    void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override;
    void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span<FloatBufferLine> samplesOut) override;

    DEF_NEWDEL(FshifterState)
};

ALboolean FshifterState::deviceUpdate(const ALCdevice*)
{
    /* (Re-)initializing parameters and clear the buffers. */
    mCount     = FIFO_LATENCY;

    std::fill(std::begin(mPhaseStep),   std::end(mPhaseStep),   0);
    std::fill(std::begin(mPhase),       std::end(mPhase),       0);
    std::fill(std::begin(mSign),        std::end(mSign),        1.0);
    std::fill(std::begin(mInFIFO),      std::end(mInFIFO),      0.0f);
    std::fill(std::begin(mOutFIFO),     std::end(mOutFIFO),     complex_d{});
    std::fill(std::begin(mOutputAccum), std::end(mOutputAccum), complex_d{});
    std::fill(std::begin(mAnalytic),    std::end(mAnalytic),    complex_d{});

    for (auto &gain : mGains)
    {
        std::fill(std::begin(gain.Current), std::end(gain.Current), 0.0f);
        std::fill(std::begin(gain.Target), std::end(gain.Target), 0.0f);
    }

    return AL_TRUE;
}

void FshifterState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target)
{
    const ALCdevice *device{context->mDevice.get()};

    ALfloat step{props->Fshifter.Frequency / static_cast<ALfloat>(device->Frequency)};
    mPhaseStep[0] = mPhaseStep[1]  = fastf2i(minf(step, 0.5f) * FRACTIONONE);

    switch(props->Fshifter.LeftDirection)
    {
        case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN:
            mSign[0] = -1.0;
            break;

        case AL_FREQUENCY_SHIFTER_DIRECTION_UP:
            mSign[0] = 1.0;
            break;

        case AL_FREQUENCY_SHIFTER_DIRECTION_OFF:
            mPhase[0]     = 0;
            mPhaseStep[0] = 0;
            break;
    }

    switch (props->Fshifter.RightDirection)
    {
        case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN:
            mSign[1] = -1.0;
        break;

        case AL_FREQUENCY_SHIFTER_DIRECTION_UP:
            mSign[1] = 1.0;
        break;

        case AL_FREQUENCY_SHIFTER_DIRECTION_OFF:
             mPhase[1]     = 0;
             mPhaseStep[1] = 0;
             break;
    }

    ALfloat coeffs[2][MAX_AMBI_CHANNELS];
    CalcDirectionCoeffs({-1.0f, 0.0f, -1.0f}, 0.0f, coeffs[0]);
    CalcDirectionCoeffs({1.0f, 0.0f, -1.0f }, 0.0f, coeffs[1]);

    mOutTarget = target.Main->Buffer;
    ComputePanGains(target.Main, coeffs[0], slot->Params.Gain, mGains[0].Target);
    ComputePanGains(target.Main, coeffs[1], slot->Params.Gain, mGains[1].Target);
}

void FshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span<FloatBufferLine> samplesOut)
{
    static constexpr complex_d complex_zero{0.0, 0.0};
    ALfloat *RESTRICT BufferOut = mBufferOut;
    ALsizei j, k, base;

    for(base = 0;base < samplesToDo;)
    {
        const ALsizei todo{mini(HIL_SIZE-mCount, samplesToDo-base)};

        ASSUME(todo > 0);

        /* Fill FIFO buffer with samples data */
        k = mCount;
        for(j = 0;j < todo;j++,k++)
        {
            mInFIFO[k] = samplesIn[0][base+j];
            mOutdata[base+j]  = mOutFIFO[k-FIFO_LATENCY];
        }
        mCount += todo;
        base += todo;

        /* Check whether FIFO buffer is filled */
        if(mCount < HIL_SIZE) continue;
        mCount = FIFO_LATENCY;

        /* Real signal windowing and store in Analytic buffer */
        for(k = 0;k < HIL_SIZE;k++)
        {
            mAnalytic[k].real(mInFIFO[k] * HannWindow[k]);
            mAnalytic[k].imag(0.0);
        }

        /* Processing signal by Discrete Hilbert Transform (analytical signal). */
        complex_hilbert(mAnalytic);

        /* Windowing and add to output accumulator */
        for(k = 0;k < HIL_SIZE;k++)
            mOutputAccum[k] += 2.0/OVERSAMP*HannWindow[k]*mAnalytic[k];

        /* Shift accumulator, input & output FIFO */
        for(k = 0;k < HIL_STEP;k++) mOutFIFO[k] = mOutputAccum[k];
        for(j = 0;k < HIL_SIZE;k++,j++) mOutputAccum[j] = mOutputAccum[k];
        for(;j < HIL_SIZE;j++) mOutputAccum[j] = complex_zero;
        for(k = 0;k < FIFO_LATENCY;k++)
            mInFIFO[k] = mInFIFO[k+HIL_STEP];
    }

    /* Process frequency shifter using the analytic signal obtained. */
    for (ALsizei c{0}; c < 2; c++)
    {
        for (k = 0; k < samplesToDo; k++)
        {
            double phase = mPhase[c] * ((1.0 / FRACTIONONE) * al::MathDefs<double>::Tau());
            BufferOut[k] = static_cast<float>(mOutdata[k].real()*std::cos(phase) +
                mOutdata[k].imag()*std::sin(phase)*mSign[c]);

            mPhase[c] += mPhaseStep[c];
            mPhase[c] &= FRACTIONMASK;
        }

        /* Now, mix the processed sound data to the output. */
        MixSamples(BufferOut, samplesOut, mGains[c].Current, mGains[c].Target, maxi(samplesToDo, 512), 0,
            samplesToDo);
    }
}

void Fshifter_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val)
{
    switch(param)
    {
        case AL_FREQUENCY_SHIFTER_FREQUENCY:
            if(!(val >= AL_FREQUENCY_SHIFTER_MIN_FREQUENCY && val <= AL_FREQUENCY_SHIFTER_MAX_FREQUENCY))
                SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter frequency out of range");
            props->Fshifter.Frequency = val;
            break;

        default:
            context->setError(AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x",
                param);
    }
}
void Fshifter_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals)
{ Fshifter_setParamf(props, context, param, vals[0]); }

void Fshifter_setParami(EffectProps *props, ALCcontext *context, ALenum param, ALint val)
{
    switch(param)
    {
        case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION:
            if(!(val >= AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION))
                SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter left direction out of range");
            props->Fshifter.LeftDirection = val;
            break;

        case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION:
            if(!(val >= AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION))
                SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter right direction out of range");
            props->Fshifter.RightDirection = val;
            break;

        default:
            context->setError(AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x",
                param);
    }
}
void Fshifter_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals)
{ Fshifter_setParami(props, context, param, vals[0]); }

void Fshifter_getParami(const EffectProps *props, ALCcontext *context, ALenum param, ALint *val)
{
    switch(param)
    {
        case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION:
            *val = props->Fshifter.LeftDirection;
            break;
        case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION:
            *val = props->Fshifter.RightDirection;
            break;
        default:
            context->setError(AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x",
                param);
    }
}
void Fshifter_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals)
{ Fshifter_getParami(props, context, param, vals); }

void Fshifter_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val)
{
    switch(param)
    {
        case AL_FREQUENCY_SHIFTER_FREQUENCY:
            *val = props->Fshifter.Frequency;
            break;

        default:
            context->setError(AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x",
                param);
    }
}
void Fshifter_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals)
{ Fshifter_getParamf(props, context, param, vals); }

DEFINE_ALEFFECT_VTABLE(Fshifter);

struct FshifterStateFactory final : public EffectStateFactory {
    EffectState *create() override { return new FshifterState{}; }
    EffectProps getDefaultProps() const noexcept override;
    const EffectVtable *getEffectVtable() const noexcept override { return &Fshifter_vtable; }
};

EffectProps FshifterStateFactory::getDefaultProps() const noexcept
{
    EffectProps props{};
    props.Fshifter.Frequency      = AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY;
    props.Fshifter.LeftDirection  = AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION;
    props.Fshifter.RightDirection = AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION;
    return props;
}

} // namespace

EffectStateFactory *FshifterStateFactory_getFactory()
{
    static FshifterStateFactory FshifterFactory{};
    return &FshifterFactory;
}
<commit_msg>Formatting cleanup<commit_after>/**
 * OpenAL cross platform audio library
 * Copyright (C) 2018 by Raul Herraiz.
 * This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 *  Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the
 *  Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 * Or go to http://www.gnu.org/copyleft/lgpl.html
 */

#include "config.h"

#include <cmath>
#include <cstdlib>
#include <array>
#include <complex>
#include <algorithm>

#include "al/auxeffectslot.h"
#include "alcmain.h"
#include "alcontext.h"
#include "alu.h"

#include "alcomplex.h"

namespace {

using complex_d = std::complex<double>;

#define HIL_SIZE 1024
#define OVERSAMP (1<<2)

#define HIL_STEP     (HIL_SIZE / OVERSAMP)
#define FIFO_LATENCY (HIL_STEP * (OVERSAMP-1))

/* Define a Hann window, used to filter the HIL input and output. */
/* Making this constexpr seems to require C++14. */
std::array<ALdouble,HIL_SIZE> InitHannWindow()
{
    std::array<ALdouble,HIL_SIZE> ret;
    /* Create lookup table of the Hann window for the desired size, i.e. HIL_SIZE */
    for(ALsizei i{0};i < HIL_SIZE>>1;i++)
    {
        ALdouble val = std::sin(al::MathDefs<double>::Pi() * i / ALdouble{HIL_SIZE-1});
        ret[i] = ret[HIL_SIZE-1-i] = val * val;
    }
    return ret;
}
alignas(16) const std::array<ALdouble,HIL_SIZE> HannWindow = InitHannWindow();

struct FshifterState final : public EffectState {
    /* Effect parameters */
    ALsizei  mCount{};
    ALsizei  mPhaseStep[2]{};
    ALsizei  mPhase[2]{};
    ALdouble mSign[2]{};

    /*Effects buffers*/
    ALfloat   mInFIFO[HIL_SIZE]{};
    complex_d mOutFIFO[HIL_SIZE]{};
    complex_d mOutputAccum[HIL_SIZE]{};
    complex_d mAnalytic[HIL_SIZE]{};
    complex_d mOutdata[BUFFERSIZE]{};

    alignas(16) ALfloat mBufferOut[BUFFERSIZE]{};

    /* Effect gains for each output channel */
    struct {
        ALfloat Current[MAX_OUTPUT_CHANNELS]{};
        ALfloat Target[MAX_OUTPUT_CHANNELS]{};
    } mGains[2];

    ALboolean deviceUpdate(const ALCdevice *device) override;
    void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override;
    void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span<FloatBufferLine> samplesOut) override;

    DEF_NEWDEL(FshifterState)
};

ALboolean FshifterState::deviceUpdate(const ALCdevice*)
{
    /* (Re-)initializing parameters and clear the buffers. */
    mCount = FIFO_LATENCY;

    std::fill(std::begin(mPhaseStep),   std::end(mPhaseStep),   0);
    std::fill(std::begin(mPhase),       std::end(mPhase),       0);
    std::fill(std::begin(mSign),        std::end(mSign),        1.0);
    std::fill(std::begin(mInFIFO),      std::end(mInFIFO),      0.0f);
    std::fill(std::begin(mOutFIFO),     std::end(mOutFIFO),     complex_d{});
    std::fill(std::begin(mOutputAccum), std::end(mOutputAccum), complex_d{});
    std::fill(std::begin(mAnalytic),    std::end(mAnalytic),    complex_d{});

    for(auto &gain : mGains)
    {
        std::fill(std::begin(gain.Current), std::end(gain.Current), 0.0f);
        std::fill(std::begin(gain.Target), std::end(gain.Target), 0.0f);
    }

    return AL_TRUE;
}

void FshifterState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target)
{
    const ALCdevice *device{context->mDevice.get()};

    ALfloat step{props->Fshifter.Frequency / static_cast<ALfloat>(device->Frequency)};
    mPhaseStep[0] = mPhaseStep[1]  = fastf2i(minf(step, 0.5f) * FRACTIONONE);

    switch(props->Fshifter.LeftDirection)
    {
    case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN:
        mSign[0] = -1.0;
        break;

    case AL_FREQUENCY_SHIFTER_DIRECTION_UP:
        mSign[0] = 1.0;
        break;

    case AL_FREQUENCY_SHIFTER_DIRECTION_OFF:
        mPhase[0]     = 0;
        mPhaseStep[0] = 0;
        break;
    }

    switch (props->Fshifter.RightDirection)
    {
    case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN:
        mSign[1] = -1.0;
        break;

    case AL_FREQUENCY_SHIFTER_DIRECTION_UP:
        mSign[1] = 1.0;
        break;

    case AL_FREQUENCY_SHIFTER_DIRECTION_OFF:
        mPhase[1]     = 0;
        mPhaseStep[1] = 0;
        break;
    }

    ALfloat coeffs[2][MAX_AMBI_CHANNELS];
    CalcDirectionCoeffs({-1.0f, 0.0f, -1.0f}, 0.0f, coeffs[0]);
    CalcDirectionCoeffs({ 1.0f, 0.0f, -1.0f}, 0.0f, coeffs[1]);

    mOutTarget = target.Main->Buffer;
    ComputePanGains(target.Main, coeffs[0], slot->Params.Gain, mGains[0].Target);
    ComputePanGains(target.Main, coeffs[1], slot->Params.Gain, mGains[1].Target);
}

void FshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span<FloatBufferLine> samplesOut)
{
    static constexpr complex_d complex_zero{0.0, 0.0};
    ALfloat *RESTRICT BufferOut = mBufferOut;
    ALsizei j, k, base;

    for(base = 0;base < samplesToDo;)
    {
        const ALsizei todo{mini(HIL_SIZE-mCount, samplesToDo-base)};

        ASSUME(todo > 0);

        /* Fill FIFO buffer with samples data */
        k = mCount;
        for(j = 0;j < todo;j++,k++)
        {
            mInFIFO[k] = samplesIn[0][base+j];
            mOutdata[base+j] = mOutFIFO[k-FIFO_LATENCY];
        }
        mCount += todo;
        base += todo;

        /* Check whether FIFO buffer is filled */
        if(mCount < HIL_SIZE) continue;
        mCount = FIFO_LATENCY;

        /* Real signal windowing and store in Analytic buffer */
        for(k = 0;k < HIL_SIZE;k++)
        {
            mAnalytic[k].real(mInFIFO[k] * HannWindow[k]);
            mAnalytic[k].imag(0.0);
        }

        /* Processing signal by Discrete Hilbert Transform (analytical signal). */
        complex_hilbert(mAnalytic);

        /* Windowing and add to output accumulator */
        for(k = 0;k < HIL_SIZE;k++)
            mOutputAccum[k] += 2.0/OVERSAMP*HannWindow[k]*mAnalytic[k];

        /* Shift accumulator, input & output FIFO */
        for(k = 0;k < HIL_STEP;k++) mOutFIFO[k] = mOutputAccum[k];
        for(j = 0;k < HIL_SIZE;k++,j++) mOutputAccum[j] = mOutputAccum[k];
        for(;j < HIL_SIZE;j++) mOutputAccum[j] = complex_zero;
        for(k = 0;k < FIFO_LATENCY;k++)
            mInFIFO[k] = mInFIFO[k+HIL_STEP];
    }

    /* Process frequency shifter using the analytic signal obtained. */
    for(ALsizei c{0};c < 2;++c)
    {
        for(k = 0;k < samplesToDo;++k)
        {
            double phase = mPhase[c] * ((1.0 / FRACTIONONE) * al::MathDefs<double>::Tau());
            BufferOut[k] = static_cast<float>(mOutdata[k].real()*std::cos(phase) +
                mOutdata[k].imag()*std::sin(phase)*mSign[c]);

            mPhase[c] += mPhaseStep[c];
            mPhase[c] &= FRACTIONMASK;
        }

        /* Now, mix the processed sound data to the output. */
        MixSamples(BufferOut, samplesOut, mGains[c].Current, mGains[c].Target,
            maxi(samplesToDo, 512), 0, samplesToDo);
    }
}

void Fshifter_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val)
{
    switch(param)
    {
        case AL_FREQUENCY_SHIFTER_FREQUENCY:
            if(!(val >= AL_FREQUENCY_SHIFTER_MIN_FREQUENCY && val <= AL_FREQUENCY_SHIFTER_MAX_FREQUENCY))
                SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter frequency out of range");
            props->Fshifter.Frequency = val;
            break;

        default:
            context->setError(AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x",
                param);
    }
}
void Fshifter_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals)
{ Fshifter_setParamf(props, context, param, vals[0]); }

void Fshifter_setParami(EffectProps *props, ALCcontext *context, ALenum param, ALint val)
{
    switch(param)
    {
        case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION:
            if(!(val >= AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION))
                SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter left direction out of range");
            props->Fshifter.LeftDirection = val;
            break;

        case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION:
            if(!(val >= AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION))
                SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter right direction out of range");
            props->Fshifter.RightDirection = val;
            break;

        default:
            context->setError(AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x",
                param);
    }
}
void Fshifter_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals)
{ Fshifter_setParami(props, context, param, vals[0]); }

void Fshifter_getParami(const EffectProps *props, ALCcontext *context, ALenum param, ALint *val)
{
    switch(param)
    {
        case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION:
            *val = props->Fshifter.LeftDirection;
            break;
        case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION:
            *val = props->Fshifter.RightDirection;
            break;
        default:
            context->setError(AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x",
                param);
    }
}
void Fshifter_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals)
{ Fshifter_getParami(props, context, param, vals); }

void Fshifter_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val)
{
    switch(param)
    {
        case AL_FREQUENCY_SHIFTER_FREQUENCY:
            *val = props->Fshifter.Frequency;
            break;

        default:
            context->setError(AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x",
                param);
    }
}
void Fshifter_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals)
{ Fshifter_getParamf(props, context, param, vals); }

DEFINE_ALEFFECT_VTABLE(Fshifter);

struct FshifterStateFactory final : public EffectStateFactory {
    EffectState *create() override { return new FshifterState{}; }
    EffectProps getDefaultProps() const noexcept override;
    const EffectVtable *getEffectVtable() const noexcept override { return &Fshifter_vtable; }
};

EffectProps FshifterStateFactory::getDefaultProps() const noexcept
{
    EffectProps props{};
    props.Fshifter.Frequency      = AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY;
    props.Fshifter.LeftDirection  = AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION;
    props.Fshifter.RightDirection = AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION;
    return props;
}

} // namespace

EffectStateFactory *FshifterStateFactory_getFactory()
{
    static FshifterStateFactory FshifterFactory{};
    return &FshifterFactory;
}
<|endoftext|>


<commit_before>/*
 * VRJuggler
 *   Copyright (C) 1997,1998,1999,2000
 *   Iowa State University Research Foundation, Inc.
 *   All Rights Reserved
 *
 * Original Authors:
 *   Allen Bierbaum, Christopher Just,
 *   Patrick Hartling, Kevin Meinert,
 *   Carolina Cruz-Neira, Albert Baker
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 * -----------------------------------------------------------------
 * File:          $RCSfile$
 * Date modified: $Date$
 * Version:       $Revision$
 * -----------------------------------------------------------------
 */

#include <vjConfig.h>

#include <Kernel/GL/vjGlPipe.h>
#include <Kernel/GL/vjGlApp.h>
#include <Threads/vjThread.h>
#include <Sync/vjGuard.h>
#include <Kernel/vjDebug.h>

#include <Kernel/vjSurfaceDisplay.h>
#include <Kernel/vjSimDisplay.h>
//**//#include <Environment/vjEnvironmentManager.h>

#include <GL/gl.h>

//: Start the pipe running
//! POST: The pipe has it's own thread of control and is ready to operate
int vjGlPipe::start()
{
    vjASSERT(mThreadRunning == false);        // We should not be running yet

    // Create a new thread to handle the control loop
    vjThreadMemberFunctor<vjGlPipe>* memberFunctor =
         new vjThreadMemberFunctor<vjGlPipe>(this, &vjGlPipe::controlLoop, NULL);

    mActiveThread = new vjThread(memberFunctor, 0);

    vjDEBUG(vjDBG_DRAW_MGR,1) << "vjGlPipe::start: Started control loop. " << mActiveThread << endl << vjDEBUG_FLUSH;
    return 1;
}

//: Trigger rendering of the pipe to start
//! POST: The pipe has be told to start rendering
void vjGlPipe::triggerRender()
{
   //vjASSERT(mThreadRunning == true);      // We must be running
   while(!mThreadRunning)
   {
      vjDEBUG(vjDBG_DRAW_MGR,3) << "Waiting in for thread to start triggerRender.\n" << vjDEBUG_FLUSH;
   }

   renderTriggerSema.release();
}

//: Blocks until rendering of the windows is completed
//! POST: The pipe has completed its rendering
void vjGlPipe::completeRender()
{
   vjASSERT(mThreadRunning == true);      // We must be running

   renderCompleteSema.acquire();
}

//: Trigger swapping of all pipe's windows
void vjGlPipe::triggerSwap()
{
   vjASSERT(mThreadRunning == true);
   swapTriggerSema.release();
}

//: Blocks until swapping of the windows is completed
void vjGlPipe::completeSwap()
{
   vjASSERT(mThreadRunning == true);
   swapCompleteSema.acquire();
}

/// Add a GLWindow to the window list
// Control loop must now open the window on the next frame
void vjGlPipe::addWindow(vjGlWindow* win)
{
   vjGuard<vjMutex> guardNew(newWinLock);       // Protect the data
   vjDEBUG(vjDBG_DRAW_MGR,3) << "vjGlPipe::addWindow: Pipe: " << mPipeNum << " adding window (to new wins):\n" << win << endl << vjDEBUG_FLUSH;
   newWins.push_back(win);
}

//: Remove a GLWindow from the window list
//! NOTE: The window is not actually removed until the next draw trigger
void vjGlPipe::removeWindow(vjGlWindow* win)
{
   vjGuard<vjMutex> guardClosing(mClosingWinLock);
   vjDEBUG(vjDBG_DRAW_MGR,3) << "vjGlPipe:: removeWindow: Pipe: " << mPipeNum << " window added to closingWins.\n" << win << endl << vjDEBUG_FLUSH;
   mClosingWins.push_back(win);
}

// The main loop routine
// while running

// - Check for windows to open/close

// - Wait for render signal

// - Render all the windows

// - Signal render completed

// - Wait for swap signal

// - Swap all windows

// - Signal swap completed

//
void vjGlPipe::controlLoop(void* nullParam)
{
   mThreadRunning = true;     // We are running so set flag
   // this should really not be here...
//**//   vjKernel::instance()->getEnvironmentManager()->addPerfDataBuffer (mPerfBuffer);

   while (!controlExit)
   {
      checkForWindowsToClose();  // Checks for closing windows
      checkForNewWindows();      // Checks for new windows to open

      // --- handle EVENTS for the windows --- //
      // XXX: This may have to be here because of need to get open window event (Win32)
      // otherwise I would like to move it to being after the swap to get better performance
      {
         for(unsigned int winId=0;winId<openWins.size();winId++)
            openWins[winId]->checkEvents();
      }

      // --- RENDER the windows ---- //
      {
         renderTriggerSema.acquire();

         vjGlApp* theApp = glManager->getApp();

            mPerfBuffer->set(mPerfPhase = 0);
         // --- pipe PRE-draw function ---- //
         theApp->pipePreDraw();      // Can't get a context since I may not be guaranteed a window
            mPerfBuffer->set(++mPerfPhase);

         // Render the windows
         for (unsigned int winId=0;winId < openWins.size();winId++)
            renderWindow(openWins[winId]);

         renderCompleteSema.release();
            mPerfBuffer->set(35);
      }

      // ----- SWAP the windows ------ //
      {
         swapTriggerSema.acquire();

         // Swap all the windows
         for(unsigned int winId=0;winId < openWins.size();winId++)
            swapWindowBuffers(openWins[winId]);

         swapCompleteSema.release();
      }
   }

   mThreadRunning = false;     // We are not running
}

// Closes all the windows in the list of windows to close
//! POST: The window to close is removed from the list of open windows
//+       and the list of newWins
void vjGlPipe::checkForWindowsToClose()
{
   if(mClosingWins.size() > 0)   // If there are windows to close
   {
      vjGuard<vjMutex> guardClosing(mClosingWinLock);
      vjGuard<vjMutex> guardNew(newWinLock);
      vjGuard<vjMutex> guardOpen(openWinLock);

      for(unsigned int i=0;i<mClosingWins.size();i++)
      {
         vjGlWindow* win = mClosingWins[i];

         // Call contextClose
         vjGlApp* theApp = glManager->getApp();       // Get application for easy access
         vjDisplay* theDisplay = win->getDisplay();   // Get the display for easy access

         glManager->setCurrentContext(win->getId());     // Set TS data of context id
         glManager->currentUserData()->setUser(theDisplay->getUser());         // Set user data
         glManager->currentUserData()->setProjection(NULL);

         win->makeCurrent();              // Make the context current
         theApp->contextClose();          // Call context close function

         // Close the window
         win->close();

         // Remove it from the lists
         newWins.erase(std::remove(newWins.begin(), newWins.end(), win), newWins.end());
         openWins.erase(std::remove(openWins.begin(), openWins.end(), win), openWins.end());

         // Delete the window
         delete win;
         mClosingWins[i] = NULL;
      }

      mClosingWins.erase(mClosingWins.begin(), mClosingWins.end());
      vjASSERT(mClosingWins.size() == 0);;
   }
}

//:  Checks for any new windows to add to the pipe
//! POST: Any new windows will be opened and added to the pipe's rendering list
void vjGlPipe::checkForNewWindows()
{
   if (newWins.size() > 0)  // If there are new windows added
   {
      vjGuard<vjMutex> guardNew(newWinLock);
      vjGuard<vjMutex> guardOpen(openWinLock);

      for (unsigned int winNum=0; winNum<newWins.size(); winNum++)
      {
         newWins[winNum]->open();
         newWins[winNum]->makeCurrent();
         vjDEBUG(vjDBG_DRAW_MGR,1) << "vjGlPipe::checkForNewWindows: Just opened window:\n" << newWins[winNum] << endl << vjDEBUG_FLUSH;
         openWins.push_back(newWins[winNum]);
      }

      newWins.erase(newWins.begin(), newWins.end());
      vjASSERT(newWins.size() == 0);
   }
}

//: Renders the window using OpenGL
//! POST: win is rendered (In stereo if it is a stereo window)
void vjGlPipe::renderWindow(vjGlWindow* win)
{
   vjGlApp* theApp = glManager->getApp();       // Get application for easy access
   vjDisplay* theDisplay = win->getDisplay();   // Get the display for easy access

   glManager->setCurrentContext(win->getId());     // Set TSS data of context id

   vjDEBUG(vjDBG_DRAW_MGR,5) << "vjGlPipe::renderWindow: Set context to: " << vjGlDrawManager::instance()->getCurrentContext() << endl << vjDEBUG_FLUSH;
      mPerfBuffer->set(++mPerfPhase);

   // --- SET CONTEXT --- //
   win->makeCurrent();

   // CONTEXT INIT(): Check if we need to call contextInit()
   if(win->hasDirtyContext())
   {
         // Have dirty context
      glManager->currentUserData()->setUser(theDisplay->getUser());         // Set user data
      glManager->currentUserData()->setProjection(NULL);

      theApp->contextInit();              // Call context init function
      win->setDirtyContext(false);        // All clean now
   }

      mPerfBuffer->set(++mPerfPhase);
   theApp->contextPreDraw();                 // Do any context pre-drawing
      mPerfBuffer->set(++mPerfPhase);

   // ---- SURFACE --- //
   if (theDisplay->isSurface())
   {
      vjSurfaceDisplay* surface_disp = dynamic_cast<vjSurfaceDisplay*>(theDisplay);
      vjDisplay::DisplayView view = theDisplay->getView();        // Get the view we are rendering

      if((vjDisplay::STEREO == view) || (vjDisplay::LEFT_EYE == view))
      {
         win->setLeftEyeProjection();
            mPerfBuffer->set(++mPerfPhase);
         glManager->currentUserData()->setUser(surface_disp->getUser());         // Set user data
         glManager->currentUserData()->setProjection(surface_disp->getLeftProj());

            mPerfBuffer->set(++mPerfPhase);

         theApp->draw();
            mPerfBuffer->set(4);
         glManager->drawObjects();
            mPerfBuffer->set(5);
      }
      if ((vjDisplay::STEREO == view) || (vjDisplay::RIGHT_EYE == theDisplay->getView()))
      {
         win->setRightEyeProjection();
         glManager->currentUserData()->setUser(surface_disp->getUser());         // Set user data
         glManager->currentUserData()->setProjection(surface_disp->getRightProj());

            mPerfBuffer->set(++mPerfPhase);
         theApp->draw();
            mPerfBuffer->set(++mPerfPhase);

         glManager->drawObjects();
      }
      else
         mPerfPhase += 2;
   }
   // ---- SIMULATOR ---------- //
   else if(theDisplay->isSimulator())
   {
      vjSimDisplay* sim_disp = dynamic_cast<vjSimDisplay*>(theDisplay);

      win->setCameraProjection();
      glManager->currentUserData()->setUser(sim_disp->getUser());         // Set user data
      glManager->currentUserData()->setProjection(sim_disp->getCameraProj());

         mPerfBuffer->set(++mPerfPhase);
      theApp->draw();
         mPerfBuffer->set(++mPerfPhase);
         mPerfPhase += 2;

      glManager->drawObjects();
      glManager->drawSimulator(sim_disp);
   }
}

//: Swaps the buffers of the given window
// Make the context current, and swap the window
void vjGlPipe::swapWindowBuffers(vjGlWindow* win)
{
   win->makeCurrent();           // Set correct context
   win->swapBuffers();           // Implicitly calls a glFlush
   //vjTimeStamp* stamp = win->getDisplay()->getUser()->getHeadUpdateTime();
   //cout << "timestamp time is: " << stamp->usecs() << " usecs" << endl;
}
<commit_msg>tweaked performance measuring datapoints<commit_after>/*
 * VRJuggler
 *   Copyright (C) 1997,1998,1999,2000
 *   Iowa State University Research Foundation, Inc.
 *   All Rights Reserved
 *
 * Original Authors:
 *   Allen Bierbaum, Christopher Just,
 *   Patrick Hartling, Kevin Meinert,
 *   Carolina Cruz-Neira, Albert Baker
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 * -----------------------------------------------------------------
 * File:          $RCSfile$
 * Date modified: $Date$
 * Version:       $Revision$
 * -----------------------------------------------------------------
 */

#include <vjConfig.h>

#include <Kernel/GL/vjGlPipe.h>
#include <Kernel/GL/vjGlApp.h>
#include <Threads/vjThread.h>
#include <Sync/vjGuard.h>
#include <Kernel/vjDebug.h>

#include <Kernel/vjSurfaceDisplay.h>
#include <Kernel/vjSimDisplay.h>
#include <Environment/vjEnvironmentManager.h>

#include <GL/gl.h>

//: Start the pipe running
//! POST: The pipe has it's own thread of control and is ready to operate
int vjGlPipe::start()
{
    vjASSERT(mThreadRunning == false);        // We should not be running yet

    // Create a new thread to handle the control loop
    vjThreadMemberFunctor<vjGlPipe>* memberFunctor =
         new vjThreadMemberFunctor<vjGlPipe>(this, &vjGlPipe::controlLoop, NULL);

    mActiveThread = new vjThread(memberFunctor, 0);

    vjDEBUG(vjDBG_DRAW_MGR,1) << "vjGlPipe::start: Started control loop. " << mActiveThread << endl << vjDEBUG_FLUSH;
    return 1;
}

//: Trigger rendering of the pipe to start
//! POST: The pipe has be told to start rendering
void vjGlPipe::triggerRender()
{
   //vjASSERT(mThreadRunning == true);      // We must be running
   while(!mThreadRunning)
   {
      vjDEBUG(vjDBG_DRAW_MGR,3) << "Waiting in for thread to start triggerRender.\n" << vjDEBUG_FLUSH;
   }

   renderTriggerSema.release();
}

//: Blocks until rendering of the windows is completed
//! POST: The pipe has completed its rendering
void vjGlPipe::completeRender()
{
   vjASSERT(mThreadRunning == true);      // We must be running

   renderCompleteSema.acquire();
}

//: Trigger swapping of all pipe's windows
void vjGlPipe::triggerSwap()
{
   vjASSERT(mThreadRunning == true);
   swapTriggerSema.release();
}

//: Blocks until swapping of the windows is completed
void vjGlPipe::completeSwap()
{
   vjASSERT(mThreadRunning == true);
   swapCompleteSema.acquire();
}

/// Add a GLWindow to the window list
// Control loop must now open the window on the next frame
void vjGlPipe::addWindow(vjGlWindow* win)
{
   vjGuard<vjMutex> guardNew(newWinLock);       // Protect the data
   vjDEBUG(vjDBG_DRAW_MGR,3) << "vjGlPipe::addWindow: Pipe: " << mPipeNum << " adding window (to new wins):\n" << win << endl << vjDEBUG_FLUSH;
   newWins.push_back(win);
}

//: Remove a GLWindow from the window list
//! NOTE: The window is not actually removed until the next draw trigger
void vjGlPipe::removeWindow(vjGlWindow* win)
{
   vjGuard<vjMutex> guardClosing(mClosingWinLock);
   vjDEBUG(vjDBG_DRAW_MGR,3) << "vjGlPipe:: removeWindow: Pipe: " << mPipeNum << " window added to closingWins.\n" << win << endl << vjDEBUG_FLUSH;
   mClosingWins.push_back(win);
}

// The main loop routine
// while running

// - Check for windows to open/close

// - Wait for render signal

// - Render all the windows

// - Signal render completed

// - Wait for swap signal

// - Swap all windows

// - Signal swap completed

//
void vjGlPipe::controlLoop(void* nullParam)
{
   mThreadRunning = true;     // We are running so set flag
   // this should really not be here...
   vjKernel::instance()->getEnvironmentManager()->addPerfDataBuffer (mPerfBuffer);

   while (!controlExit)
   {
      checkForWindowsToClose();  // Checks for closing windows
      checkForNewWindows();      // Checks for new windows to open

      // --- handle EVENTS for the windows --- //
      // XXX: This may have to be here because of need to get open window event (Win32)
      // otherwise I would like to move it to being after the swap to get better performance
      {
         for(unsigned int winId=0;winId<openWins.size();winId++)
            openWins[winId]->checkEvents();
      }

      // --- RENDER the windows ---- //
      {
         renderTriggerSema.acquire();

         vjGlApp* theApp = glManager->getApp();

            mPerfBuffer->set(mPerfPhase = 0);
         // --- pipe PRE-draw function ---- //
         theApp->pipePreDraw();      // Can't get a context since I may not be guaranteed a window
            mPerfBuffer->set(++mPerfPhase);

         // Render the windows
         for (unsigned int winId=0;winId < openWins.size();winId++)
            renderWindow(openWins[winId]);

         renderCompleteSema.release();
            mPerfBuffer->set(35);
      }

      // ----- SWAP the windows ------ //
      {
         swapTriggerSema.acquire();

         // Swap all the windows
         for(unsigned int winId=0;winId < openWins.size();winId++)
            swapWindowBuffers(openWins[winId]);

         swapCompleteSema.release();
      }
   }

   mThreadRunning = false;     // We are not running
}

// Closes all the windows in the list of windows to close
//! POST: The window to close is removed from the list of open windows
//+       and the list of newWins
void vjGlPipe::checkForWindowsToClose()
{
   if(mClosingWins.size() > 0)   // If there are windows to close
   {
      vjGuard<vjMutex> guardClosing(mClosingWinLock);
      vjGuard<vjMutex> guardNew(newWinLock);
      vjGuard<vjMutex> guardOpen(openWinLock);

      for(unsigned int i=0;i<mClosingWins.size();i++)
      {
         vjGlWindow* win = mClosingWins[i];

         // Call contextClose
         vjGlApp* theApp = glManager->getApp();       // Get application for easy access
         vjDisplay* theDisplay = win->getDisplay();   // Get the display for easy access

         glManager->setCurrentContext(win->getId());     // Set TS data of context id
         glManager->currentUserData()->setUser(theDisplay->getUser());         // Set user data
         glManager->currentUserData()->setProjection(NULL);

         win->makeCurrent();              // Make the context current
         theApp->contextClose();          // Call context close function

         // Close the window
         win->close();

         // Remove it from the lists
         newWins.erase(std::remove(newWins.begin(), newWins.end(), win), newWins.end());
         openWins.erase(std::remove(openWins.begin(), openWins.end(), win), openWins.end());

         // Delete the window
         delete win;
         mClosingWins[i] = NULL;
      }

      mClosingWins.erase(mClosingWins.begin(), mClosingWins.end());
      vjASSERT(mClosingWins.size() == 0);;
   }
}

//:  Checks for any new windows to add to the pipe
//! POST: Any new windows will be opened and added to the pipe's rendering list
void vjGlPipe::checkForNewWindows()
{
   if (newWins.size() > 0)  // If there are new windows added
   {
      vjGuard<vjMutex> guardNew(newWinLock);
      vjGuard<vjMutex> guardOpen(openWinLock);

      for (unsigned int winNum=0; winNum<newWins.size(); winNum++)
      {
         newWins[winNum]->open();
         newWins[winNum]->makeCurrent();
         vjDEBUG(vjDBG_DRAW_MGR,1) << "vjGlPipe::checkForNewWindows: Just opened window:\n" << newWins[winNum] << endl << vjDEBUG_FLUSH;
         openWins.push_back(newWins[winNum]);
      }

      newWins.erase(newWins.begin(), newWins.end());
      vjASSERT(newWins.size() == 0);
   }
}

//: Renders the window using OpenGL
//! POST: win is rendered (In stereo if it is a stereo window)
void vjGlPipe::renderWindow(vjGlWindow* win)
{
   vjGlApp* theApp = glManager->getApp();       // Get application for easy access
   vjDisplay* theDisplay = win->getDisplay();   // Get the display for easy access

   glManager->setCurrentContext(win->getId());     // Set TSS data of context id

   vjDEBUG(vjDBG_DRAW_MGR,5) << "vjGlPipe::renderWindow: Set context to: " << vjGlDrawManager::instance()->getCurrentContext() << endl << vjDEBUG_FLUSH;
      mPerfBuffer->set(++mPerfPhase);

   // --- SET CONTEXT --- //
   win->makeCurrent();

   // CONTEXT INIT(): Check if we need to call contextInit()
   if(win->hasDirtyContext())
   {
         // Have dirty context
      glManager->currentUserData()->setUser(theDisplay->getUser());         // Set user data
      glManager->currentUserData()->setProjection(NULL);

      theApp->contextInit();              // Call context init function
      win->setDirtyContext(false);        // All clean now
   }

      mPerfBuffer->set(++mPerfPhase);
   theApp->contextPreDraw();                 // Do any context pre-drawing
      mPerfBuffer->set(++mPerfPhase);

   // ---- SURFACE --- //
   if (theDisplay->isSurface())
   {
      vjSurfaceDisplay* surface_disp = dynamic_cast<vjSurfaceDisplay*>(theDisplay);
      vjDisplay::DisplayView view = theDisplay->getView();        // Get the view we are rendering

      if((vjDisplay::STEREO == view) || (vjDisplay::LEFT_EYE == view))
      {
         win->setLeftEyeProjection();
            mPerfBuffer->set(++mPerfPhase);
         glManager->currentUserData()->setUser(surface_disp->getUser());         // Set user data
         glManager->currentUserData()->setProjection(surface_disp->getLeftProj());

            mPerfBuffer->set(++mPerfPhase);

         theApp->draw();
            mPerfBuffer->set(++mPerfPhase);
         glManager->drawObjects();
            mPerfBuffer->set(++mPerfPhase);
      }
      if ((vjDisplay::STEREO == view) || (vjDisplay::RIGHT_EYE == theDisplay->getView()))
      {
         win->setRightEyeProjection();
         glManager->currentUserData()->setUser(surface_disp->getUser());         // Set user data
         glManager->currentUserData()->setProjection(surface_disp->getRightProj());

            mPerfBuffer->set(++mPerfPhase);
         theApp->draw();
            mPerfBuffer->set(++mPerfPhase);

         glManager->drawObjects();
      }
      else
         mPerfPhase += 2;
   }
   // ---- SIMULATOR ---------- //
   else if(theDisplay->isSimulator())
   {
      vjSimDisplay* sim_disp = dynamic_cast<vjSimDisplay*>(theDisplay);

      win->setCameraProjection();
      glManager->currentUserData()->setUser(sim_disp->getUser());         // Set user data
      glManager->currentUserData()->setProjection(sim_disp->getCameraProj());

         mPerfBuffer->set(++mPerfPhase);
      theApp->draw();
         mPerfBuffer->set(++mPerfPhase);

      glManager->drawObjects();
      glManager->drawSimulator(sim_disp);
      mPerfBuffer->set (++mPerfPhase);
      mPerfPhase += 3;
   }
}

//: Swaps the buffers of the given window
// Make the context current, and swap the window
void vjGlPipe::swapWindowBuffers(vjGlWindow* win)
{
   win->makeCurrent();           // Set correct context
   win->swapBuffers();           // Implicitly calls a glFlush
   //vjTimeStamp* stamp = win->getDisplay()->getUser()->getHeadUpdateTime();
   //cout << "timestamp time is: " << stamp->usecs() << " usecs" << endl;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <climits>
#include <ctime>

#define minVal adj[i][j].value < min &&  adj[i][j].value != -1
#define setMin min = adj[i][j].value; k = i; l = j;

const char* nn = "ABCDEFG"; // node names

using namespace std;

//const static int n = 40;
const static int n = 7;

struct data
{
  bool marked, connected; int value;
  data(){marked = connected = 0; value = -1;};
};

data adj[n][n];  //Adjacency Matrix Searching O(|V|^2)

void print_adj()
{
  for(int i = 0; i < n; ++i)
  {
    for(int j = 0; j < n; ++j)
    {
      cout << adj[i][j].value << "|";
      if(adj[i][j].connected) cout << "1|"; else cout << "0|";
      if(adj[i][j].marked) cout << "1"; else cout << "0";
      if(j + 1 < n) cout << "  " ; else cout << "\n";
    }
  }
}

void initialize(int & initial)
{
  char temp;
  ifstream in;
  in.open("n2.txt");
  for(int i = 0; i < n; i++)
  {
    for(int j = 0; j < n; j++)
    {
      temp = in.peek();
      if(temp == '-')in >> temp;
      else
      {
        in >> adj[i][j].value;
        initial += adj[i][j].value;
      }
      j == n - 1 ? in.ignore(1, '\n') : in >> temp;
    }
  }
  in.close();
}

bool connected()
{
  for(int i = 0; i < n; i++)
    if(!adj[0][i].connected) return false;
  return true;
}

void markConnected(const int & jj, const int & ll)
{
  for(int i = 0; i < n; i++)
  {
    if(i == jj)
      for(int j = 0; j < n; j++)
        adj[i][j].marked = true;
    adj[i][ll].connected = true;
  }
}

void optimize(int & pruned, int & k, int & l)
{
  int i, j, min;
  do{
    min = INT_MAX;
    for(i = 0; i < n; i++)
    {
      if(adj[i][0].marked)
      {
        for(j = 1; j < n; j++)
          if(!adj[i][j].connected && minVal){setMin}
      }
    }
    pruned += min;
    cout << "Add Edge: " << nn[k] << "--"     << nn[l]  << " weight: "
         << min          << " total weight: " << pruned << endl;
    adj[k][l].value = -1;
    markConnected(l, l);
  }while(!connected());
}

/**
 * Main Implements Prims Algorithm For MST (GREEDY)
 *
 * -,2,4,6,-,-,-
 * 2,-,2,-,6,-,-
 * 4,2,-,1,3,-,-
 * 6,-,1,-,2,3,-
 * -,6,3,2,-,-,5
 * -,-,-,3,-,-,4
 * -,-,-,-,5,4,-
 *
 *     B----E----G
 * G = |\  /|    |
 *     |  C |    |
 *     | / \|    |
 *     A----D----F
 *
 *     0 1 2 3 4 5 6
 *     A B C D E F G
 **/
int main()
{
  clock_t start, end;
  int initial = 0, pruned = 0, i = 0, j = 0, min, k, l;
  start = clock();
  initialize(initial);
  while(adj[i++][j].value == -1)
  setMin
  for(i; i < n; i++)
    if(minVal){setMin}
  adj[k][l].value = -1;
  markConnected(0, l);
  optimize(pruned, k, l);
  return 0;
}
<commit_msg>Update prims.cpp<commit_after>#include <iostream>
#include <fstream>
#include <climits>
#include <ctime>

#define minVal adj[i][j].value < min &&  adj[i][j].value != -1
#define setMin min = adj[i][j].value; k = i; l = j;

const char* nn = "ABCDEFG"; // node names

using namespace std;

//const static int n = 40;
const static int n = 7;

struct data
{
  bool marked, connected; int value;
  data(){marked = connected = 0; value = -1;};
};

data adj[n][n];  //Adjacency Matrix Searching O(|V|^2)

void print_adj()
{
  for(int i = 0; i < n; ++i)
  {
    for(int j = 0; j < n; ++j)
    {
      cout << adj[i][j].value << "|";
      if(adj[i][j].connected) cout << "1|"; else cout << "0|";
      if(adj[i][j].marked) cout << "1"; else cout << "0";
      if(j + 1 < n) cout << "  " ; else cout << "\n";
    }
  }
}

void initialize(int & initial)
{
  char temp;
  ifstream in;
  in.open("n2.txt");
  for(int i = 0; i < n; i++)
  {
    for(int j = 0; j < n; j++)
    {
      temp = in.peek();
      if(temp == '-')in >> temp;
      else
      {
        in >> adj[i][j].value;
        initial += adj[i][j].value;
      }
      j == n - 1 ? in.ignore(1, '\n') : in >> temp;
    }
  }
  in.close();
}

bool connected()
{
  for(int i = 0; i < n; i++)
    if(!adj[0][i].connected) return false;
  return true;
}

void markConnected(const int & jj, const int & ll)
{
  for(int i = 0; i < n; i++)
  {
    if(i == jj)
      for(int j = 0; j < n; j++)
        adj[i][j].marked = true;
    adj[i][ll].connected = true;
  }
}

void optimize(int & pruned, int & k, int & l)
{
  int i, j, min;
  do{
    min = INT_MAX;
    for(i = 0; i < n; i++)
    {
      if(adj[i][0].marked)
      {
        for(j = 1; j < n; j++)
          if(!adj[i][j].connected && minVal){setMin}
      }
    }
    pruned += min;
    cout << "Add Edge: " << nn[k] << "--"     << nn[l]  << " weight: "
         << min          << " total weight: " << pruned << endl;
    adj[k][l].value = -1;
    markConnected(l, l);
  }while(!connected());
}

/**
 * Main Implements Prims Algorithm For MST (GREEDY)
 *    A B C D E F G
 * A  -,2,4,6,-,-,-
 * B  2,-,2,-,6,-,-
 * C  4,2,-,1,3,-,-
 * D  6,-,1,-,2,3,-
 * E  -,6,3,2,-,-,5
 * F  -,-,-,3,-,-,4
 * G  -,-,-,-,5,4,-
 *
 *     B----E----G
 * G = |\  /|    |
 *     |  C |    |
 *     | / \|    |
 *     A----D----F
 *
 *     0 1 2 3 4 5 6
 *     A B C D E F G
 *   http://en.wikipedia.org/wiki/Prim%27s_algorithm
 **/
int main()
{
  clock_t start, end;
  int initial = 0, pruned = 0, i = 0, j = 0, min, k, l;
  start = clock();
  initialize(initial);
  while(adj[i++][j].value == -1)
  setMin
  for(i; i < n; i++)
    if(minVal){setMin}
  adj[k][l].value = -1;
  markConnected(0, l);
  optimize(pruned, k, l);
  return 0;
}
<|endoftext|>