<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2009 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#include "OgreStableHeaders.h"
#include "OgreInstanceBatchShader.h"
#include "OgreSubMesh.h"
#include "OgreRenderOperation.h"
#include "OgreHardwareBufferManager.h"
#include "OgreInstancedEntity.h"
#include "OgreMaterial.h"
#include "OgreTechnique.h"

namespace Ogre
{
	InstanceBatchShader::InstanceBatchShader( InstanceManager *creator, MeshPtr &meshReference,
										const MaterialPtr &material, size_t instancesPerBatch,
										const Mesh::IndexMap *indexToBoneMap, const String &batchName ) :
				InstanceBatch( creator, meshReference, material, instancesPerBatch,
								indexToBoneMap, batchName ),
				mNumWorldMatrices( instancesPerBatch )
	{
	}

	InstanceBatchShader::~InstanceBatchShader()
	{
	}

	//-----------------------------------------------------------------------
	size_t InstanceBatchShader::calculateMaxNumInstances( const SubMesh *baseSubMesh, uint16 flags ) const
	{
		const size_t numBones = std::max<size_t>( 1, baseSubMesh->blendIndexToBoneIndexMap.size() );

		mMaterial->load();
		Technique *technique = mMaterial->getBestTechnique();
		if( technique )
		{
			GpuProgramParametersSharedPtr vertexParam = technique->getPass(0)->getVertexProgramParameters();
			GpuConstantDefinitionIterator itor = vertexParam->getConstantDefinitionIterator();
			while( itor.hasMoreElements() )
			{
				const GpuConstantDefinition &constDef = itor.getNext();
				if( constDef.constType == GCT_MATRIX_3X4 ||
					constDef.constType == GCT_MATRIX_4X3 ||		//OGL GLSL bitches without this
					constDef.constType == GCT_MATRIX_2X4 ||
					constDef.constType == GCT_FLOAT4			//OGL GLSL bitches without this
					&& constDef.isFloat() )
				{
					const GpuProgramParameters::AutoConstantEntry *entry =
									vertexParam->_findRawAutoConstantEntryFloat( constDef.physicalIndex );
					if( entry && (entry->paramType == GpuProgramParameters::ACT_WORLD_MATRIX_ARRAY_3x4 || entry->paramType == GpuProgramParameters::ACT_WORLD_DUALQUATERNION_ARRAY_2x4))
					{
						//Material is correctly done!
						size_t arraySize = constDef.arraySize;

						//Deal with GL "hacky" way of doing 4x3 matrices
						if( constDef.constType == GCT_FLOAT4 )
							arraySize /= 3;

						//Check the num of arrays
						size_t retVal = arraySize / numBones;

						if( flags & IM_USE16BIT )
						{
							if( baseSubMesh->vertexData->vertexCount * retVal > 0xFFFF )
								retVal = 0xFFFF / baseSubMesh->vertexData->vertexCount;
						}

						if( retVal < 3 )
						{
							LogManager::getSingleton().logMessage( "InstanceBatchShader: Mesh " +
										mMeshReference->getName() + " using material " +
										mMaterial->getName() + " contains many bones. The amount of "
										"instances per batch is very low. Performance benefits will "
										"be minimal, if any. It might be even slower!",
										LML_NORMAL );
						}

						return retVal;
					}
				}
			}

			//Reaching here means material is supported, but malformed
			OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS,
			"Material '" + mMaterial->getName() + "' is malformed for this instancing technique",
			"InstanceBatchShader::calculateMaxNumInstances");
		}

		//Reaching here the material is just unsupported.

		return 0;
	}
	//-----------------------------------------------------------------------
	void InstanceBatchShader::buildFrom( const SubMesh *baseSubMesh, const RenderOperation &renderOperation )
	{
		if( mMeshReference->hasSkeleton() && !mMeshReference->getSkeleton().isNull() )
			mNumWorldMatrices = mInstancesPerBatch * baseSubMesh->blendIndexToBoneIndexMap.size();
		InstanceBatch::buildFrom( baseSubMesh, renderOperation );
	}
	//-----------------------------------------------------------------------
	void InstanceBatchShader::setupVertices( const SubMesh* baseSubMesh )
	{
		mRenderOperation.vertexData = OGRE_NEW VertexData();

		VertexData *thisVertexData = mRenderOperation.vertexData;
		VertexData *baseVertexData = baseSubMesh->vertexData;

		thisVertexData->vertexStart = 0;
		thisVertexData->vertexCount = baseVertexData->vertexCount * mInstancesPerBatch;

		HardwareBufferManager::getSingleton().destroyVertexDeclaration( thisVertexData->vertexDeclaration );
		thisVertexData->vertexDeclaration = baseVertexData->vertexDeclaration->clone();

		if( mMeshReference->hasSkeleton() && !mMeshReference->getSkeleton().isNull() )
		{
			//Building hw skinned batches follow a different path
			setupHardwareSkinned( baseSubMesh, thisVertexData, baseVertexData );
			return;
		}

		//TODO: Can't we, instead of using another source, put the index ID in the same source?
		thisVertexData->vertexDeclaration->addElement(
										thisVertexData->vertexDeclaration->getMaxSource() + 1, 0,
										VET_UBYTE4, VES_BLEND_INDICES );

		for( size_t i=0; i<thisVertexData->vertexDeclaration->getMaxSource(); ++i )
		{
			//Create our own vertex buffer
			HardwareVertexBufferSharedPtr vertexBuffer =
											HardwareBufferManager::getSingleton().createVertexBuffer(
											thisVertexData->vertexDeclaration->getVertexSize(i),
											thisVertexData->vertexCount,
											HardwareBuffer::HBU_STATIC_WRITE_ONLY );
			thisVertexData->vertexBufferBinding->setBinding( i, vertexBuffer );

			//Grab the base submesh data
			HardwareVertexBufferSharedPtr baseVertexBuffer =
													baseVertexData->vertexBufferBinding->getBuffer(i);

			char* thisBuf = static_cast<char*>(vertexBuffer->lock(HardwareBuffer::HBL_DISCARD));
			char* baseBuf = static_cast<char*>(baseVertexBuffer->lock(HardwareBuffer::HBL_READ_ONLY));

			//Copy and repeat
			for( size_t j=0; j<mInstancesPerBatch; ++j )
			{
				const size_t sizeOfBuffer = baseVertexData->vertexCount *
											baseVertexData->vertexDeclaration->getVertexSize(i);
				memcpy( thisBuf + j * sizeOfBuffer, baseBuf, sizeOfBuffer );
			}

			baseVertexBuffer->unlock();
			vertexBuffer->unlock();
		}

		{
			//Now create the vertices "index ID" to individualize each instance
			const unsigned short lastSource = thisVertexData->vertexDeclaration->getMaxSource();
			HardwareVertexBufferSharedPtr vertexBuffer =
											HardwareBufferManager::getSingleton().createVertexBuffer(
											thisVertexData->vertexDeclaration->getVertexSize( lastSource ),
											thisVertexData->vertexCount,
											HardwareBuffer::HBU_STATIC_WRITE_ONLY );
			thisVertexData->vertexBufferBinding->setBinding( lastSource, vertexBuffer );

			char* thisBuf = static_cast<char*>(vertexBuffer->lock(HardwareBuffer::HBL_DISCARD));
			for( size_t j=0; j<mInstancesPerBatch; ++j )
			{
				for( size_t k=0; k<baseVertexData->vertexCount; ++k )
				{
					*thisBuf++ = j;
					*thisBuf++ = j;
					*thisBuf++ = j;
					*thisBuf++ = j;
				}
			}

			vertexBuffer->unlock();
		}
	}
	//-----------------------------------------------------------------------
	void InstanceBatchShader::setupIndices( const SubMesh* baseSubMesh )
	{
		mRenderOperation.indexData = OGRE_NEW IndexData();

		IndexData *thisIndexData = mRenderOperation.indexData;
		IndexData *baseIndexData = baseSubMesh->indexData;

		thisIndexData->indexStart = 0;
		thisIndexData->indexCount = baseIndexData->indexCount * mInstancesPerBatch;

		//TODO: Check numVertices is below max supported by GPU
		HardwareIndexBuffer::IndexType indexType = HardwareIndexBuffer::IT_16BIT;
		if( mRenderOperation.vertexData->vertexCount > 65535 )
			indexType = HardwareIndexBuffer::IT_32BIT;
		thisIndexData->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(
													indexType, thisIndexData->indexCount,
													HardwareBuffer::HBU_STATIC_WRITE_ONLY );

		void *buf			= thisIndexData->indexBuffer->lock( HardwareBuffer::HBL_DISCARD );
		void const *baseBuf	= baseIndexData->indexBuffer->lock( HardwareBuffer::HBL_READ_ONLY );

		uint16 *thisBuf16 = static_cast<uint16*>(buf);
		uint32 *thisBuf32 = static_cast<uint32*>(buf);

		for( size_t i=0; i<mInstancesPerBatch; ++i )
		{
			const size_t vertexOffset = i * mRenderOperation.vertexData->vertexCount / mInstancesPerBatch;

			uint16 const *initBuf16 = static_cast<uint16 const *>(baseBuf);
			uint32 const *initBuf32 = static_cast<uint32 const *>(baseBuf);

			for( size_t j=0; j<baseIndexData->indexCount; ++j )
			{
				uint32 originalVal;
				if( baseSubMesh->indexData->indexBuffer->getType() == HardwareIndexBuffer::IT_16BIT )
					originalVal = *initBuf16++;
				else
					originalVal = *initBuf32++;

				if( indexType == HardwareIndexBuffer::IT_16BIT )
					*thisBuf16++ = static_cast<uint16>(originalVal) + vertexOffset;
				else
					*thisBuf32++ = originalVal + vertexOffset;
			}
		}

		baseIndexData->indexBuffer->unlock();
		thisIndexData->indexBuffer->unlock();
	}
	//-----------------------------------------------------------------------
	void InstanceBatchShader::setupHardwareSkinned( const SubMesh* baseSubMesh, VertexData *thisVertexData,
													VertexData *baseVertexData )
	{
		const size_t numBones = baseSubMesh->blendIndexToBoneIndexMap.size();
		mNumWorldMatrices = mInstancesPerBatch * numBones;

		for( size_t i=0; i<=thisVertexData->vertexDeclaration->getMaxSource(); ++i )
		{
			//Create our own vertex buffer
			HardwareVertexBufferSharedPtr vertexBuffer =
											HardwareBufferManager::getSingleton().createVertexBuffer(
											thisVertexData->vertexDeclaration->getVertexSize(i),
											thisVertexData->vertexCount,
											HardwareBuffer::HBU_STATIC_WRITE_ONLY );
			thisVertexData->vertexBufferBinding->setBinding( i, vertexBuffer );

			VertexDeclaration::VertexElementList veList =
											thisVertexData->vertexDeclaration->findElementsBySource(i);

			//Grab the base submesh data
			HardwareVertexBufferSharedPtr baseVertexBuffer =
													baseVertexData->vertexBufferBinding->getBuffer(i);

			char* thisBuf = static_cast<char*>(vertexBuffer->lock(HardwareBuffer::HBL_DISCARD));
			char* baseBuf = static_cast<char*>(baseVertexBuffer->lock(HardwareBuffer::HBL_READ_ONLY));
			char *startBuf = baseBuf;

			//Copy and repeat
			for( size_t j=0; j<mInstancesPerBatch; ++j )
			{
				//Repeat source
				baseBuf = startBuf;

				for( size_t k=0; k<baseVertexData->vertexCount; ++k )
				{
					VertexDeclaration::VertexElementList::const_iterator it = veList.begin();
					VertexDeclaration::VertexElementList::const_iterator en = veList.end();

					while( it != en )
					{
						switch( it->getSemantic() )
						{
						case VES_BLEND_INDICES:
						*(thisBuf + it->getOffset() + 0) = *(baseBuf + it->getOffset() + 0) + j * numBones;
						*(thisBuf + it->getOffset() + 1) = *(baseBuf + it->getOffset() + 1) + j * numBones;
						*(thisBuf + it->getOffset() + 2) = *(baseBuf + it->getOffset() + 2) + j * numBones;
						*(thisBuf + it->getOffset() + 3) = *(baseBuf + it->getOffset() + 3) + j * numBones;
							break;
						default:
							memcpy( thisBuf + it->getOffset(), baseBuf + it->getOffset(), it->getSize() );
							break;
						}
						++it;
					}
					thisBuf += baseVertexData->vertexDeclaration->getVertexSize(i);
					baseBuf += baseVertexData->vertexDeclaration->getVertexSize(i);
				}
			}

			baseVertexBuffer->unlock();
			vertexBuffer->unlock();
		}
	}
	//-----------------------------------------------------------------------
	void InstanceBatchShader::getWorldTransforms( Matrix4* xform ) const
	{
		InstancedEntityVec::const_iterator itor = mInstancedEntities.begin();
		InstancedEntityVec::const_iterator end  = mInstancedEntities.end();

		while( itor != end )
		{
			xform += (*itor)->getTransforms( xform );
			++itor;
		}
	}
	//-----------------------------------------------------------------------
	unsigned short InstanceBatchShader::getNumWorldTransforms(void) const
	{
		return mNumWorldMatrices;
	}
}
<commit_msg>Improved handling of dual quaternions in InstanceBatchShader (no longer generates in-accurate error messages).<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2009 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#include "OgreStableHeaders.h"
#include "OgreInstanceBatchShader.h"
#include "OgreSubMesh.h"
#include "OgreRenderOperation.h"
#include "OgreHardwareBufferManager.h"
#include "OgreInstancedEntity.h"
#include "OgreMaterial.h"
#include "OgreTechnique.h"

namespace Ogre
{
	InstanceBatchShader::InstanceBatchShader( InstanceManager *creator, MeshPtr &meshReference,
										const MaterialPtr &material, size_t instancesPerBatch,
										const Mesh::IndexMap *indexToBoneMap, const String &batchName ) :
				InstanceBatch( creator, meshReference, material, instancesPerBatch,
								indexToBoneMap, batchName ),
				mNumWorldMatrices( instancesPerBatch )
	{
	}

	InstanceBatchShader::~InstanceBatchShader()
	{
	}

	//-----------------------------------------------------------------------
	size_t InstanceBatchShader::calculateMaxNumInstances( const SubMesh *baseSubMesh, uint16 flags ) const
	{
		const size_t numBones = std::max<size_t>( 1, baseSubMesh->blendIndexToBoneIndexMap.size() );

		mMaterial->load();
		Technique *technique = mMaterial->getBestTechnique();
		if( technique )
		{
			GpuProgramParametersSharedPtr vertexParam = technique->getPass(0)->getVertexProgramParameters();
			GpuConstantDefinitionIterator itor = vertexParam->getConstantDefinitionIterator();
			while( itor.hasMoreElements() )
			{
				const GpuConstantDefinition &constDef = itor.getNext();
				if( constDef.constType == GCT_MATRIX_3X4 ||
					constDef.constType == GCT_MATRIX_4X3 ||		//OGL GLSL bitches without this
					constDef.constType == GCT_MATRIX_2X4 ||
					constDef.constType == GCT_FLOAT4			//OGL GLSL bitches without this
					&& constDef.isFloat() )
				{
					const GpuProgramParameters::AutoConstantEntry *entry =
									vertexParam->_findRawAutoConstantEntryFloat( constDef.physicalIndex );
					if( entry && (entry->paramType == GpuProgramParameters::ACT_WORLD_MATRIX_ARRAY_3x4 || entry->paramType == GpuProgramParameters::ACT_WORLD_DUALQUATERNION_ARRAY_2x4))
					{
						//Material is correctly done!
						size_t arraySize = constDef.arraySize;

						//Deal with GL "hacky" way of doing 4x3 matrices
						if(entry->paramType == GpuProgramParameters::ACT_WORLD_MATRIX_ARRAY_3x4 && constDef.constType == GCT_FLOAT4)
							arraySize /= 3;
						else if(entry->paramType == GpuProgramParameters::ACT_WORLD_DUALQUATERNION_ARRAY_2x4 && constDef.constType == GCT_FLOAT4)
							arraySize /= 2;

						//Check the num of arrays
						size_t retVal = arraySize / numBones;

						if( flags & IM_USE16BIT )
						{
							if( baseSubMesh->vertexData->vertexCount * retVal > 0xFFFF )
								retVal = 0xFFFF / baseSubMesh->vertexData->vertexCount;
						}

						if((retVal < 3 && entry->paramType == GpuProgramParameters::ACT_WORLD_MATRIX_ARRAY_3x4) ||
							(retVal < 2 && entry->paramType == GpuProgramParameters::ACT_WORLD_DUALQUATERNION_ARRAY_2x4))
						{
							LogManager::getSingleton().logMessage( "InstanceBatchShader: Mesh " +
										mMeshReference->getName() + " using material " +
										mMaterial->getName() + " contains many bones. The amount of "
										"instances per batch is very low. Performance benefits will "
										"be minimal, if any. It might be even slower!",
										LML_NORMAL );
						}

						return retVal;
					}
				}
			}

			//Reaching here means material is supported, but malformed
			OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS,
			"Material '" + mMaterial->getName() + "' is malformed for this instancing technique",
			"InstanceBatchShader::calculateMaxNumInstances");
		}

		//Reaching here the material is just unsupported.

		return 0;
	}
	//-----------------------------------------------------------------------
	void InstanceBatchShader::buildFrom( const SubMesh *baseSubMesh, const RenderOperation &renderOperation )
	{
		if( mMeshReference->hasSkeleton() && !mMeshReference->getSkeleton().isNull() )
			mNumWorldMatrices = mInstancesPerBatch * baseSubMesh->blendIndexToBoneIndexMap.size();
		InstanceBatch::buildFrom( baseSubMesh, renderOperation );
	}
	//-----------------------------------------------------------------------
	void InstanceBatchShader::setupVertices( const SubMesh* baseSubMesh )
	{
		mRenderOperation.vertexData = OGRE_NEW VertexData();

		VertexData *thisVertexData = mRenderOperation.vertexData;
		VertexData *baseVertexData = baseSubMesh->vertexData;

		thisVertexData->vertexStart = 0;
		thisVertexData->vertexCount = baseVertexData->vertexCount * mInstancesPerBatch;

		HardwareBufferManager::getSingleton().destroyVertexDeclaration( thisVertexData->vertexDeclaration );
		thisVertexData->vertexDeclaration = baseVertexData->vertexDeclaration->clone();

		if( mMeshReference->hasSkeleton() && !mMeshReference->getSkeleton().isNull() )
		{
			//Building hw skinned batches follow a different path
			setupHardwareSkinned( baseSubMesh, thisVertexData, baseVertexData );
			return;
		}

		//TODO: Can't we, instead of using another source, put the index ID in the same source?
		thisVertexData->vertexDeclaration->addElement(
										thisVertexData->vertexDeclaration->getMaxSource() + 1, 0,
										VET_UBYTE4, VES_BLEND_INDICES );

		for( size_t i=0; i<thisVertexData->vertexDeclaration->getMaxSource(); ++i )
		{
			//Create our own vertex buffer
			HardwareVertexBufferSharedPtr vertexBuffer =
											HardwareBufferManager::getSingleton().createVertexBuffer(
											thisVertexData->vertexDeclaration->getVertexSize(i),
											thisVertexData->vertexCount,
											HardwareBuffer::HBU_STATIC_WRITE_ONLY );
			thisVertexData->vertexBufferBinding->setBinding( i, vertexBuffer );

			//Grab the base submesh data
			HardwareVertexBufferSharedPtr baseVertexBuffer =
													baseVertexData->vertexBufferBinding->getBuffer(i);

			char* thisBuf = static_cast<char*>(vertexBuffer->lock(HardwareBuffer::HBL_DISCARD));
			char* baseBuf = static_cast<char*>(baseVertexBuffer->lock(HardwareBuffer::HBL_READ_ONLY));

			//Copy and repeat
			for( size_t j=0; j<mInstancesPerBatch; ++j )
			{
				const size_t sizeOfBuffer = baseVertexData->vertexCount *
											baseVertexData->vertexDeclaration->getVertexSize(i);
				memcpy( thisBuf + j * sizeOfBuffer, baseBuf, sizeOfBuffer );
			}

			baseVertexBuffer->unlock();
			vertexBuffer->unlock();
		}

		{
			//Now create the vertices "index ID" to individualize each instance
			const unsigned short lastSource = thisVertexData->vertexDeclaration->getMaxSource();
			HardwareVertexBufferSharedPtr vertexBuffer =
											HardwareBufferManager::getSingleton().createVertexBuffer(
											thisVertexData->vertexDeclaration->getVertexSize( lastSource ),
											thisVertexData->vertexCount,
											HardwareBuffer::HBU_STATIC_WRITE_ONLY );
			thisVertexData->vertexBufferBinding->setBinding( lastSource, vertexBuffer );

			char* thisBuf = static_cast<char*>(vertexBuffer->lock(HardwareBuffer::HBL_DISCARD));
			for( size_t j=0; j<mInstancesPerBatch; ++j )
			{
				for( size_t k=0; k<baseVertexData->vertexCount; ++k )
				{
					*thisBuf++ = j;
					*thisBuf++ = j;
					*thisBuf++ = j;
					*thisBuf++ = j;
				}
			}

			vertexBuffer->unlock();
		}
	}
	//-----------------------------------------------------------------------
	void InstanceBatchShader::setupIndices( const SubMesh* baseSubMesh )
	{
		mRenderOperation.indexData = OGRE_NEW IndexData();

		IndexData *thisIndexData = mRenderOperation.indexData;
		IndexData *baseIndexData = baseSubMesh->indexData;

		thisIndexData->indexStart = 0;
		thisIndexData->indexCount = baseIndexData->indexCount * mInstancesPerBatch;

		//TODO: Check numVertices is below max supported by GPU
		HardwareIndexBuffer::IndexType indexType = HardwareIndexBuffer::IT_16BIT;
		if( mRenderOperation.vertexData->vertexCount > 65535 )
			indexType = HardwareIndexBuffer::IT_32BIT;
		thisIndexData->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(
													indexType, thisIndexData->indexCount,
													HardwareBuffer::HBU_STATIC_WRITE_ONLY );

		void *buf			= thisIndexData->indexBuffer->lock( HardwareBuffer::HBL_DISCARD );
		void const *baseBuf	= baseIndexData->indexBuffer->lock( HardwareBuffer::HBL_READ_ONLY );

		uint16 *thisBuf16 = static_cast<uint16*>(buf);
		uint32 *thisBuf32 = static_cast<uint32*>(buf);

		for( size_t i=0; i<mInstancesPerBatch; ++i )
		{
			const size_t vertexOffset = i * mRenderOperation.vertexData->vertexCount / mInstancesPerBatch;

			uint16 const *initBuf16 = static_cast<uint16 const *>(baseBuf);
			uint32 const *initBuf32 = static_cast<uint32 const *>(baseBuf);

			for( size_t j=0; j<baseIndexData->indexCount; ++j )
			{
				uint32 originalVal;
				if( baseSubMesh->indexData->indexBuffer->getType() == HardwareIndexBuffer::IT_16BIT )
					originalVal = *initBuf16++;
				else
					originalVal = *initBuf32++;

				if( indexType == HardwareIndexBuffer::IT_16BIT )
					*thisBuf16++ = static_cast<uint16>(originalVal) + vertexOffset;
				else
					*thisBuf32++ = originalVal + vertexOffset;
			}
		}

		baseIndexData->indexBuffer->unlock();
		thisIndexData->indexBuffer->unlock();
	}
	//-----------------------------------------------------------------------
	void InstanceBatchShader::setupHardwareSkinned( const SubMesh* baseSubMesh, VertexData *thisVertexData,
													VertexData *baseVertexData )
	{
		const size_t numBones = baseSubMesh->blendIndexToBoneIndexMap.size();
		mNumWorldMatrices = mInstancesPerBatch * numBones;

		for( size_t i=0; i<=thisVertexData->vertexDeclaration->getMaxSource(); ++i )
		{
			//Create our own vertex buffer
			HardwareVertexBufferSharedPtr vertexBuffer =
											HardwareBufferManager::getSingleton().createVertexBuffer(
											thisVertexData->vertexDeclaration->getVertexSize(i),
											thisVertexData->vertexCount,
											HardwareBuffer::HBU_STATIC_WRITE_ONLY );
			thisVertexData->vertexBufferBinding->setBinding( i, vertexBuffer );

			VertexDeclaration::VertexElementList veList =
											thisVertexData->vertexDeclaration->findElementsBySource(i);

			//Grab the base submesh data
			HardwareVertexBufferSharedPtr baseVertexBuffer =
													baseVertexData->vertexBufferBinding->getBuffer(i);

			char* thisBuf = static_cast<char*>(vertexBuffer->lock(HardwareBuffer::HBL_DISCARD));
			char* baseBuf = static_cast<char*>(baseVertexBuffer->lock(HardwareBuffer::HBL_READ_ONLY));
			char *startBuf = baseBuf;

			//Copy and repeat
			for( size_t j=0; j<mInstancesPerBatch; ++j )
			{
				//Repeat source
				baseBuf = startBuf;

				for( size_t k=0; k<baseVertexData->vertexCount; ++k )
				{
					VertexDeclaration::VertexElementList::const_iterator it = veList.begin();
					VertexDeclaration::VertexElementList::const_iterator en = veList.end();

					while( it != en )
					{
						switch( it->getSemantic() )
						{
						case VES_BLEND_INDICES:
						*(thisBuf + it->getOffset() + 0) = *(baseBuf + it->getOffset() + 0) + j * numBones;
						*(thisBuf + it->getOffset() + 1) = *(baseBuf + it->getOffset() + 1) + j * numBones;
						*(thisBuf + it->getOffset() + 2) = *(baseBuf + it->getOffset() + 2) + j * numBones;
						*(thisBuf + it->getOffset() + 3) = *(baseBuf + it->getOffset() + 3) + j * numBones;
							break;
						default:
							memcpy( thisBuf + it->getOffset(), baseBuf + it->getOffset(), it->getSize() );
							break;
						}
						++it;
					}
					thisBuf += baseVertexData->vertexDeclaration->getVertexSize(i);
					baseBuf += baseVertexData->vertexDeclaration->getVertexSize(i);
				}
			}

			baseVertexBuffer->unlock();
			vertexBuffer->unlock();
		}
	}
	//-----------------------------------------------------------------------
	void InstanceBatchShader::getWorldTransforms( Matrix4* xform ) const
	{
		InstancedEntityVec::const_iterator itor = mInstancedEntities.begin();
		InstancedEntityVec::const_iterator end  = mInstancedEntities.end();

		while( itor != end )
		{
			xform += (*itor)->getTransforms( xform );
			++itor;
		}
	}
	//-----------------------------------------------------------------------
	unsigned short InstanceBatchShader::getNumWorldTransforms(void) const
	{
		return mNumWorldMatrices;
	}
}
<|endoftext|>


<commit_before><commit_msg>actually try less unrolled kernels<commit_after><|endoftext|>


<commit_before>/*
 *  qicomplex.cpp
 *
 *  Copyright (c) 2015 Tobias Wood.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include <getopt.h>
#include <iostream>

#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkImageSliceConstIteratorWithIndex.h"
#include "itkImageSliceIteratorWithIndex.h"
#include "itkMultiplyImageFilter.h"
#include "itkComplexToPhaseImageFilter.h"
#include "itkComplexToModulusImageFilter.h"
#include "itkComplexToRealImageFilter.h"
#include "itkComplexToImaginaryImageFilter.h"
#include "itkComposeImageFilter.h"
#include "itkMagnitudeAndPhaseToComplexImageFilter.h"

#include "QI/Util.h"

using namespace std;

namespace itk {
template<typename TImage>
class FixGEFilter : public InPlaceImageFilter<TImage> {
public:
    typedef FixGEFilter                 Self;
    typedef InPlaceImageFilter<TImage>  Superclass;
    typedef SmartPointer<Self>          Pointer;
    typedef typename TImage::RegionType        TRegion;
    typedef typename TImage::InternalPixelType TPixel;

    itkNewMacro(Self);
    itkTypeMacro(FixGEFilter, InPlaceImageFilter);

private:
    FixGEFilter(const Self &); //purposely not implemented
    void operator=(const Self &);  //purposely not implemented

protected:
    FixGEFilter() {}
    ~FixGEFilter() {}

public:
    virtual void ThreadedGenerateData(const TRegion &region, ThreadIdType threadId) ITK_OVERRIDE {
        //std::cout <<  __PRETTY_FUNCTION__ << std::endl;
        typedef typename TImage::PixelType PixelType;
        ImageSliceConstIteratorWithIndex<TImage> inIt(this->GetInput(), region);
        ImageSliceIteratorWithIndex<TImage>      outIt(this->GetOutput(), region);

        inIt.SetFirstDirection(0);
        inIt.SetSecondDirection(1);
        outIt.SetFirstDirection(0);
        outIt.SetSecondDirection(1);
        inIt.GoToBegin();
        outIt.GoToBegin();
        PixelType mult(1, 0);
        while(!inIt.IsAtEnd()) {
            while (!inIt.IsAtEndOfSlice()) {
                while (!inIt.IsAtEndOfLine()) {
                    outIt.Set(mult * inIt.Get());
                    ++inIt;
                    ++outIt;
                }
                inIt.NextLine();
                outIt.NextLine();
            }
            mult = mult * PixelType(-1, 0);
            inIt.NextSlice();
            outIt.NextSlice();
        }
        // std::cout << "End " << __PRETTY_FUNCTION__ << std::endl;
    }
};

} // End namespace itk

const string usage {
"Usage is: qcomplex [input options] [output options] [other options] \n\
\n\
Input is specified with lower case letters. One of the following\n\
combinations must be specified:\n\
    -m mag_image -p phase_image\n\
    -r real_image -i imaginary_image\n\
    -x complex_image\n\
\n\
Output is specified with upper case letters. One or more of the\n\
following can be specified:\n\
    -M : Output a magnitude image\n\
    -P : Output a phase image\n\
    -R : Output a real image\n\
    -I : Output an imaginary image\n\
    -X : Output a complex image\n\
\n\
Other options:\n\
    --negate : Multiply everything by -1 before output.\n\
    --double : Use double precision instead of float\n\
    --fixge  : Fix alternate slice problem with GE data.\n\
\n\
Example:\n\
    qicomplex -m mag.nii -p phase.nii -R real.nii -I imag.nii\n"
};
int verbose = false, use_double = false, fixge = false, do_negate = false;
const struct option long_options[] =
{
    {"help", no_argument, 0, 'h'},
    {"verbose", no_argument, 0, 'v'},
    {"double", no_argument, &use_double, 1},
    {"fixge", no_argument, &fixge, 1},
    {"negate", no_argument, &do_negate, 1},
    {0, 0, 0, 0}
};
const char* short_options = "hvm:M:p:P:r:R:i:I:x:X:";
int c, index_ptr = 0;

template<typename TPixel> void Run(int argc, char **argv) {
    typedef itk::Image<TPixel, 4>          TImage;
    typedef itk::Image<complex<TPixel>, 4> TXImage;
    typedef itk::ImageFileReader<TImage>   TReader;
    typedef itk::ImageFileReader<TXImage>  TXReader;
    typedef itk::ImageFileWriter<TImage>   TWriter;
    typedef itk::ImageFileWriter<TXImage>  TXWriter;

    typename TImage::Pointer img1 = ITK_NULLPTR, img2 = ITK_NULLPTR;
    typename TXImage::Pointer imgX = ITK_NULLPTR;

    if (verbose) cout << "Reading input files" << endl;
    bool ri = false, x = false;
    optind = 1;
    while ((c = getopt_long(argc, argv, short_options,  long_options, &index_ptr)) != -1) {
        switch (c) {
            case 'r':
                ri = true;
            case 'm': {
                auto read = TReader::New();
                read->SetFileName(optarg);
                read->Update();
                img1 = read->GetOutput();
            } break;
            case 'i':
                ri = true;
            case 'p': {
                auto read = TReader::New();
                read->SetFileName(optarg);
                read->Update();
                img2 = read->GetOutput();
            } break;
            case 'x': {
                x = true;
                typename TXReader::Pointer readX = TXReader::New();
                readX->SetFileName(optarg);
                readX->Update();
                imgX = readX->GetOutput();
            } break;
            default: break;
        }
    }

    if (x) {
        // Nothing to see here
    } else if (ri) {
        if (!(img1 && img2)) {
            QI_EXCEPTION("Must set real and imaginary inputs");
        }
        if (verbose) cout << "Combining real and imaginary input" << endl;
        auto compose = itk::ComposeImageFilter<TImage, TXImage>::New();
        compose->SetInput(0, img1);
        compose->SetInput(1, img2);
        compose->Update();
        imgX = compose->GetOutput();
    } else {
        if (!(img1 && img2)) {
            QI_EXCEPTION("Must set magnitude and phase inputs");
        }
        if (verbose) cout << "Combining magnitude and phase input" << endl;
        auto compose = itk::MagnitudeAndPhaseToComplexImageFilter<TImage, TImage, TXImage>::New();
        compose->SetInput(0, img1);
        compose->SetInput(1, img2);
        compose->Update();
        imgX = compose->GetOutput();
    }

    if (fixge) {
        if (verbose) cout << "Fixing GE phase bug" << endl;
        auto fix = itk::FixGEFilter<TXImage>::New();
        fix->SetInput(imgX);
        fix->Update();
        imgX = fix->GetOutput();
    }

    if (do_negate) {
        if (verbose) cout << "Negating values" << endl;
        auto neg = itk::MultiplyImageFilter<TXImage, TXImage, TXImage>::New();
        neg->SetInput(imgX);
        neg->SetConstant(complex<TPixel>(-1.0, 0.0));
        neg->Update();
        imgX = neg->GetOutput();
    }
    if (verbose) cout << "Writing output files" << endl;
    typename TWriter::Pointer write = TWriter::New();
    optind = 1;
    while ((c = getopt_long(argc, argv, short_options, long_options, &index_ptr)) != -1) {
        switch (c) {
            case 'M': {
                auto o = itk::ComplexToModulusImageFilter<TXImage, TImage>::New();
                o->SetInput(imgX);
                write->SetFileName(optarg);
                write->SetInput(o->GetOutput());
                write->Update();
                if (verbose) cout << "Wrote magnitude image " + string(optarg) << endl;
            } break;
            case 'P': {
                auto o = itk::ComplexToPhaseImageFilter<TXImage, TImage>::New();
                o->SetInput(imgX);
                write->SetFileName(optarg);
                write->SetInput(o->GetOutput());
                write->Update();
                if (verbose) cout << "Wrote phase image " + string(optarg) << endl;
            } break;
            case 'R': {
                auto o = itk::ComplexToRealImageFilter<TXImage, TImage>::New();
                o->SetInput(imgX);
                write->SetFileName(optarg);
                write->SetInput(o->GetOutput());
                write->Update();
                if (verbose) cout << "Wrote real image " + string(optarg) << endl;
            } break;
            case 'I': {
                auto o = itk::ComplexToImaginaryImageFilter<TXImage, TImage>::New();
                o->SetInput(imgX);
                write->SetFileName(optarg);
                write->SetInput(o->GetOutput());
                write->Update();
                if (verbose) cout << "Wrote imaginary image " + string(optarg) << endl;
            } break;
            case 'X': {
                auto writeX = TXWriter::New();
                writeX->SetFileName(optarg);
                writeX->SetInput(imgX);
                writeX->Update();
                if (verbose) cout << "Wrote complex image " + string(optarg) << endl;
            } break;
            default: break;
        }
    }
}

int main(int argc, char **argv) {
    // Do one pass for the general options
    bool have_some_options = false;
    while ((c = getopt_long(argc, argv, short_options, long_options, &index_ptr)) != -1) {
        switch (c) {
            case 'v': verbose = true; break;
            case 'h':
                cout << QI::GetVersion() << endl << usage << endl;
                return EXIT_SUCCESS;
            case 0: break; // A flag
            case 'm': case 'M': case 'p': case 'P':
            case 'r': case 'R': case 'i': case 'I':
            case 'x': case 'X':
                have_some_options = true;
                break;
            case '?': // getopt will print an error message
                return EXIT_FAILURE;
            default:
            cout << "Unhandled option " << string(1, c) << endl;
            return EXIT_FAILURE;
        }
    }

    if (!have_some_options) {
        cout << QI::GetVersion() << endl << usage << endl;
        return EXIT_FAILURE;
    }

    if (use_double) {
        if (verbose) cout << "Using double precision" << endl;
        Run<double>(argc, argv);
    } else {
        if (verbose) cout << "Using float precision" << endl;
        Run<float>(argc, argv);
    }

    return EXIT_SUCCESS;
}
<commit_msg>ENH: Copes with Bruker real/imaginary files ENH: Updated to Args<commit_after>/*
 *  qicomplex.cpp
 *
 *  Copyright (c) 2015 Tobias Wood.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include <iostream>

#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkImageSliceConstIteratorWithIndex.h"
#include "itkImageSliceIteratorWithIndex.h"
#include "itkMultiplyImageFilter.h"
#include "itkComplexToPhaseImageFilter.h"
#include "itkComplexToModulusImageFilter.h"
#include "itkComplexToRealImageFilter.h"
#include "itkComplexToImaginaryImageFilter.h"
#include "itkComposeImageFilter.h"
#include "itkMagnitudeAndPhaseToComplexImageFilter.h"
#include "itkRegionOfInterestImageFilter.h"

#include "QI/Util.h"
#include "QI/IO.h"
#include "QI/Args.h"

namespace itk {
template<typename TImage>
class NegateFilter : public InPlaceImageFilter<TImage> {
public:
    typedef NegateFilter                Self;
    typedef InPlaceImageFilter<TImage>  Superclass;
    typedef SmartPointer<Self>          Pointer;
    typedef typename TImage::RegionType        TRegion;
    typedef typename TImage::InternalPixelType TPixel;

    itkNewMacro(Self);
    itkTypeMacro(NegateFilter, InPlaceImageFilter);

private:
    NegateFilter(const Self &); //purposely not implemented
    void operator=(const Self &);  //purposely not implemented
    bool m_all = false, m_alternate = false;
protected:
    NegateFilter() {}
    ~NegateFilter() {}

public:
    void SetNegate(const bool all, const bool alternate) {
        m_all = all;
        m_alternate = all;
    }
    virtual void ThreadedGenerateData(const TRegion &region, ThreadIdType threadId) ITK_OVERRIDE {
        typedef typename TImage::PixelType PixelType;
        ImageSliceConstIteratorWithIndex<TImage> inIt(this->GetInput(), region);
        ImageSliceIteratorWithIndex<TImage>      outIt(this->GetOutput(), region);

        inIt.SetFirstDirection(0);
        inIt.SetSecondDirection(1);
        outIt.SetFirstDirection(0);
        outIt.SetSecondDirection(1);
        inIt.GoToBegin();
        outIt.GoToBegin();
        PixelType mult(m_all ? -1 : 1, 0);
        while(!inIt.IsAtEnd()) {
            while (!inIt.IsAtEndOfSlice()) {
                while (!inIt.IsAtEndOfLine()) {
                    outIt.Set(mult * inIt.Get());
                    ++inIt;
                    ++outIt;
                }
                inIt.NextLine();
                outIt.NextLine();
            }
            if (m_alternate) {
                mult = mult * PixelType(-1, 0);
            }
            inIt.NextSlice();
            outIt.NextSlice();
        }
        // std::std::cout << "End " << __PRETTY_FUNCTION__ << std::std::endl;
    }
};

} // End namespace itk

/* Arguments defined here so they are available in the templated run function */
args::ArgumentParser parser(
    "Input is specified with lower case letters. A valid combination of inputs "
    " must be specified, e.g. real & imaginary or magnitude & phase.\n"
    "Output is specified with upper case letters. Any combination can be given\n"
    "http://github.com/spinicist/QUIT");

args::ValueFlag<std::string> in_mag(parser, "IN_MAG", "Input magnitude file", {'m', "mag"});
args::ValueFlag<std::string> in_pha(parser, "IN_PHA", "Input phase file", {'p', "pha"});
args::ValueFlag<std::string> in_real(parser, "IN_REAL", "Input real file", {'r', "real"});
args::ValueFlag<std::string> in_imag(parser, "IN_IMAG", "Input imaginary file", {'i', "imag"});
args::ValueFlag<std::string> in_complex(parser, "IN_CPLX", "Input complex file", {'x', "complex"});
args::ValueFlag<std::string> in_realimag(parser, "IN_REALIMAG", "Input real & imaginary file", {'l', "realimag"});

args::ValueFlag<std::string> out_mag(parser, "OUT_MAG", "Output magnitude file", {'M', "MAG"});
args::ValueFlag<std::string> out_pha(parser, "OUT_PHA", "Output phase file", {'P', "PHA"});
args::ValueFlag<std::string> out_real(parser, "OUT_REAL", "Output real file", {'R', "REAL"});
args::ValueFlag<std::string> out_imag(parser, "OUT_IMAG", "Output imaginary file", {'I', "IMAG"});
args::ValueFlag<std::string> out_complex(parser, "OUT_CPLX", "Output complex file", {'X', "COMPLEX"});

args::HelpFlag help(parser, "HELP", "Show this help menu", {'h', "help"});
args::Flag     verbose(parser, "VERBOSE", "Print more information", {'v', "verbose"});
args::Flag     use_double(parser, "DOUBLE", "Process & output at double precision", {'d', "double"});
args::Flag     fixge(parser, "FIX_GE", "Negate alternate slices (fixes lack of FFT shift)", {"fixge"});
args::Flag     negate(parser, "NEGATE", "Negate entire volume", {"negate"});

template<typename TPixel>
void Run() {
    typedef itk::Image<TPixel, 4>          TImage;
    typedef itk::Image<std::complex<TPixel>, 4> TXImage;
    typedef itk::ImageFileReader<TImage>   TReader;
    typedef itk::ImageFileReader<TXImage>  TXReader;
    typedef itk::ImageFileWriter<TImage>   TWriter;
    typedef itk::ImageFileWriter<TXImage>  TXWriter;

    typename TImage::Pointer img1 = ITK_NULLPTR, img2 = ITK_NULLPTR;
    typename TXImage::Pointer imgX = ITK_NULLPTR;

    if (in_real) {
        if (verbose) std::cout << "Reading real file: " << in_real.Get() << std::endl;
        auto img1 = QI::ReadImage<TImage>(in_real.Get());
        if (in_imag) {
            if (verbose) std::cout << "Reading imaginary file: " << in_imag.Get() << std::endl;
            auto img2 = QI::ReadImage<TImage>(in_imag.Get());
        } else {
            QI_FAIL("Must set real and imaginary inputs together");
        }
        auto compose = itk::ComposeImageFilter<TImage, TXImage>::New();
        compose->SetInput(0, img1);
        compose->SetInput(1, img2);
        compose->Update();
        imgX = compose->GetOutput();
        imgX->DisconnectPipeline();
    } else if (in_mag) {
        if (verbose) std::cout << "Reading magnitude file: " << in_mag.Get() << std::endl;
        img1 = QI::ReadImage<TImage>(in_mag.Get());
        if (in_pha) {
            if (verbose) std::cout << "Reading phase file: " << in_pha.Get() << std::endl;
            img2 = QI::ReadImage<TImage>(in_pha.Get());
        } else {
            QI_FAIL("Must set magnitude and phase inputs together");
        }
        auto compose = itk::MagnitudeAndPhaseToComplexImageFilter<TImage, TImage, TXImage>::New();
        compose->SetInput(0, img1);
        compose->SetInput(1, img2);
        compose->Update();
        imgX = compose->GetOutput();
        imgX->DisconnectPipeline();
    } else if (in_complex) {
        if (verbose) std::cout << "Reading complex file: " << in_complex.Get() << std::endl;
        imgX = QI::ReadImage<TXImage>(in_complex.Get());
    } else if (in_realimag) {
        if (verbose) std::cout << "Reading real/imaginary file: " << in_realimag.Get() << std::endl;
        auto img_both = QI::ReadImage<TImage>(in_realimag.Get());
        auto real_region = img_both->GetLargestPossibleRegion();
        auto imag_region = img_both->GetLargestPossibleRegion();
        real_region.GetModifiableSize()[3] = real_region.GetSize()[3] / 2;
        imag_region.GetModifiableSize()[3] = real_region.GetSize()[3];
        imag_region.GetModifiableIndex()[3] = real_region.GetSize()[3];
        auto extract_real = itk::RegionOfInterestImageFilter<TImage, TImage>::New();
        extract_real->SetRegionOfInterest(real_region);
        extract_real->SetInput(img_both);
        extract_real->Update();
        auto extract_imag = itk::RegionOfInterestImageFilter<TImage, TImage>::New();
        extract_imag->SetRegionOfInterest(imag_region);
        extract_imag->SetInput(img_both);
        extract_imag->Update();
        /* Hack round ITK changing the origin */
        extract_imag->GetOutput()->SetOrigin(extract_real->GetOutput()->GetOrigin());
        auto compose = itk::ComposeImageFilter<TImage, TXImage>::New();
        compose->SetInput(0, extract_real->GetOutput());
        compose->SetInput(1, extract_imag->GetOutput());
        compose->Update();
        imgX = compose->GetOutput();
        imgX->DisconnectPipeline();
    } else {
        QI_FAIL("No input files specified, use --help to see usage");
    }

    if (fixge || negate) {
        if (verbose) std::cout << "Negating values" << std::endl;
        auto fix = itk::NegateFilter<TXImage>::New();
        fix->SetInput(imgX);
        fix->SetNegate(negate, fixge);
        fix->Update();
        imgX = fix->GetOutput();
    }

    if (verbose) std::cout << "Writing output files" << std::endl;
    typename TWriter::Pointer write = TWriter::New();

    if (out_mag) {
        auto o = itk::ComplexToModulusImageFilter<TXImage, TImage>::New();
        o->SetInput(imgX);
        o->Update();
        QI::WriteImage(o->GetOutput(), out_mag.Get());
        if (verbose) std::cout << "Wrote magnitude image " << out_mag.Get() << std::endl;
    }
    if (out_pha) {
        auto o = itk::ComplexToPhaseImageFilter<TXImage, TImage>::New();
        o->SetInput(imgX);
        o->Update();
        QI::WriteImage(o->GetOutput(), out_pha.Get());
        if (verbose) std::cout << "Wrote phase image " << out_pha.Get() << std::endl;
    }
    if (out_real) {
        auto o = itk::ComplexToRealImageFilter<TXImage, TImage>::New();
        o->SetInput(imgX);
        o->Update();
        QI::WriteImage(o->GetOutput(), out_real.Get());
        if (verbose) std::cout << "Wrote real image " << out_real.Get() << std::endl;
    }
    if (out_imag) {
        auto o = itk::ComplexToImaginaryImageFilter<TXImage, TImage>::New();
        o->SetInput(imgX);
        o->Update();
        QI::WriteImage(o->GetOutput(), out_imag.Get());
        if (verbose) std::cout << "Wrote imaginary image " << out_imag.Get() << std::endl;
    }
    if (out_complex) {
        QI::WriteImage(imgX, out_complex.Get());
        if (verbose) std::cout << "Wrote complex image " << out_complex.Get() << std::endl;
    }
}

int main(int argc, char **argv) {
    QI::ParseArgs(parser, argc, argv);
    if (use_double) {
        if (verbose) std::cout << "Using double precision" << std::endl;
        Run<double>();
    } else {
        if (verbose) std::cout << "Using float precision" << std::endl;
        Run<float>();
    }
    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*
 *  qikfilter.cpp
 *
 *  Copyright (c) 2015 Tobias Wood.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include <time.h>
#include <getopt.h>
#include <iostream>
#include <atomic>
#include <sstream>
#include "Eigen/Dense"

#include "itkImageSource.h"
#include "itkConstNeighborhoodIterator.h"
#include "itkImageRegionIteratorWithIndex.h"
#include "itkMultiplyImageFilter.h"
#include "itkDivideImageFilter.h"
#include "itkForwardFFTImageFilter.h"
#include "itkInverseFFTImageFilter.h"
#include "itkFFTShiftImageFilter.h"
#include "itkComplexToModulusImageFilter.h"
#include "itkFFTPadImageFilter.h"
#include "itkExtractImageFilter.h"
#include "itkPasteImageFilter.h"
#include "itkCastImageFilter.h"

#include "QI/Types.h"
#include "QI/Util.h"

using namespace std;
using namespace Eigen;

class FilterKernel {

};

class TukeyKernel : FilterKernel {
protected:
    double m_a = 0.75;
    double m_q = 0.25;
    int m_hx = 0, m_hy = 0, m_hz = 0;

public:
    void setSize(const int sx, const int sy, const int sz) {
        m_hx = sx / 2;  m_hy = sy / 2;  m_hz = sz / 2;
    }
    void setAQ(const double a, const double q) {
        m_a = a;
        m_q = q;
    }

    double operator() (const int x, const int y, const int z) const {
            const double rx = static_cast<double>(x - m_hx)/m_hx;
            const double ry = static_cast<double>(y - m_hy)/m_hy;
            const double rz = static_cast<double>(z - m_hz)/m_hz;
            const double r = sqrt((rx*rx + ry*ry + rz*rz) / 3);
            const double v = (r <= (1 - m_a)) ? 1 : 0.5*((1+m_q)+(1-m_q)*cos((M_PI/m_a)*(r - 1 + m_a)));
            return v;
    }
};

namespace itk {

template<typename ImageType>
class KSpaceFilter : public ImageToImageFilter<ImageType, ImageType> {
public:
    typedef ImageType                          TImage;
    typedef KSpaceFilter                       Self;
    typedef ImageToImageFilter<TImage, TImage> Superclass;
    typedef SmartPointer<Self>                 Pointer;

protected:
    typedef typename TImage::RegionType::SizeType SizeType;
    typename TImage::RegionType    m_region;
    typename TImage::SpacingType   m_spacing;
    typename TImage::DirectionType m_direction;
    typename TImage::PointType     m_origin;

    TukeyKernel m_kernel;

    KSpaceFilter(){}
    ~KSpaceFilter(){}

public:
    itkNewMacro(Self);
    itkTypeMacro(KSpaceFilter, ImageSource);

    virtual void GenerateOutputInformation() override {
        Superclass::GenerateOutputInformation();
        SizeType size = this->GetOutput()->GetLargestPossibleRegion().GetSize();
        m_kernel.setSize(size[0], size[1], size[2]);
    }

    void SetKernel(const TukeyKernel &k) { m_kernel = k; }

protected:
    virtual void ThreadedGenerateData(const typename TImage::RegionType &region, ThreadIdType threadId) override {
        itk::ImageRegionIterator<TImage> outIt(this->GetOutput(),region);
        itk::ImageRegionConstIteratorWithIndex<TImage> inIt(this->GetInput(),region);
        inIt.GoToBegin();
        outIt.GoToBegin();
        while(!inIt.IsAtEnd()) {
            const auto index = inIt.GetIndex() - m_region.GetIndex(); // Might be padded to a negative start
            const typename TImage::PixelType::value_type k = m_kernel(index[0], index[1], index[2]);
            const typename TImage::PixelType v = inIt.Get();
            outIt.Set(v * k);
            ++inIt;
            ++outIt;
        }
    }

private:
    KSpaceFilter(const Self &);
    void operator=(const Self &);
};

} // End namespace itk

QI::ImageF::Pointer FilterVolume(const QI::ImageF::Pointer invol, const itk::KSpaceFilter<QI::ImageXF>::Pointer k_filter, const bool verbose, const bool debug, const string &prefix) {
    if (verbose) cout << "Padding image to valid FFT size." << endl;
    typedef itk::FFTPadImageFilter<QI::ImageF> PadFFTType;
    auto padFFT = PadFFTType::New();
    padFFT->SetInput(invol);
    padFFT->Update();
    if (debug) QI::WriteImage(padFFT->GetOutput(), prefix + "_step1_padFFT" + QI::OutExt());
    if (verbose) {
        cout << "Padded image size: " << padFFT->GetOutput()->GetLargestPossibleRegion().GetSize() << endl;
        cout << "Calculating Forward FFT." << endl;
    }
    typedef itk::ForwardFFTImageFilter<QI::ImageF> FFFTType;
    auto forwardFFT = FFFTType::New();
    forwardFFT->SetInput(padFFT->GetOutput());
    forwardFFT->Update();

    typedef itk::FFTShiftImageFilter<QI::ImageXF, QI::ImageXF> ShiftType;
    auto shiftFFT = ShiftType::New();
    shiftFFT->SetInput(forwardFFT->GetOutput());
    shiftFFT->Update();
    if (debug) QI::WriteImage(shiftFFT->GetOutput(), prefix + "_step2_forwardFFT" + QI::OutExt());

    if (verbose) cout << "Filtering." << endl;
    k_filter->SetInput(shiftFFT->GetOutput());
    if (debug) QI::WriteImage   (k_filter->GetOutput(), prefix + "_step3_multFFT" + QI::OutExt());

    auto unshiftFFT = ShiftType::New();
    unshiftFFT->SetInput(k_filter->GetOutput());
    unshiftFFT->Update();

    if (verbose) cout << "Inverse FFT." << endl;
    auto inverseFFT = itk::InverseFFTImageFilter<QI::ImageXF, QI::ImageF>::New();
    inverseFFT->SetInput(unshiftFFT->GetOutput());
    inverseFFT->Update();
    if (debug) QI::WriteImage(inverseFFT->GetOutput(), prefix + "_step4_inverseFFT" + QI::OutExt());
    if (verbose) cout << "Extracting original size image" << endl;
    auto extract = itk::ExtractImageFilter<QI::ImageF, QI::ImageF>::New();
    extract->SetInput(inverseFFT->GetOutput());
    extract->SetDirectionCollapseToSubmatrix();
    extract->SetExtractionRegion(invol->GetLargestPossibleRegion());
    extract->Update();
    QI::ImageF::Pointer outvol = extract->GetOutput();
    outvol->DisconnectPipeline();
    return outvol;
}

//******************************************************************************
// Arguments / Usage
//******************************************************************************
const string usage {
"Usage is: qikfilter [options] input \n\
\n\
Filter images in k-Space\n\
\n\
Options:\n\
    --help, -h           : Print this message.\n\
    --verbose, -v        : Print more information.\n\
    --out, -o path       : Specify an output filename (default image base).\n\
    --filter, -f \"a q\" : Set Filter a and q values (default 0.75 0.25).\n\
    --debug, -d          : Save all pipeline steps.\n\
    --threads, -T N      : Use N threads (default=hardware limit).\n"
};

const struct option long_options[] = {
    {"help", no_argument, 0, 'h'},
    {"verbose", no_argument, 0, 'v'},
    {"out", required_argument, 0, 'o'},
    {"filter", required_argument, 0, 'f'},
    {"debug", no_argument, 0, 'd'},
    {"threads", required_argument, 0, 'T'},
    {0, 0, 0, 0}
};
const char *short_options = "hvo:m:e:dT:";

//******************************************************************************
// Main
//******************************************************************************
int main(int argc, char **argv) {
    Eigen::initParallel();

    bool verbose = false, debug = false;
    double filter_a = 0.75, filter_q = 0.25;
    string prefix;
    int indexptr = 0, c;
    while ((c = getopt_long(argc, argv, short_options, long_options, &indexptr)) != -1) {
        switch (c) {
            case 'v': verbose = true; break;
            case 'o':
                prefix = optarg;
                cout << "Output prefix will be: " << prefix << endl;
                break;
            case 'f': {
                stringstream f(optarg);
                f >> filter_a >> filter_q;
            } break;
            case 'd': debug = true; break;
            case 'T': itk::MultiThreader::SetGlobalMaximumNumberOfThreads(atoi(optarg)); break;
            case 'h':
                cout << QI::GetVersion() << endl << usage << endl;
                return EXIT_SUCCESS;
            case '?': // getopt will print an error message
                return EXIT_FAILURE;
            default:
                cout << "Unhandled option " << string(1, c) << endl;
                return EXIT_FAILURE;
        }
    }
    if ((argc - optind) != 1) {
        cout << "Incorrect number of arguments." << endl << usage << endl;
        return EXIT_FAILURE;
    }

    string fname(argv[optind++]);
    if (prefix == "")
        prefix = fname.substr(0, fname.find(".nii"));
    string outname = prefix + "_filtered" + QI::OutExt();

    if (verbose) cout << "Opening input file: " << fname << endl;
    QI::TimeseriesF::Pointer vols = QI::ReadImage<QI::TimeseriesF>(fname);
    auto region = vols->GetLargestPossibleRegion();
    const size_t nvols = region.GetSize()[3]; // Save for the loop
    region.GetModifiableSize()[3] = 0;
    auto extract = itk::ExtractImageFilter<QI::TimeseriesF, QI::ImageF>::New();
    extract->SetInput(vols);
    extract->SetDirectionCollapseToSubmatrix();
    itk::PasteImageFilter<QI::TimeseriesF>::Pointer paster = itk::PasteImageFilter<QI::TimeseriesF>::New();
    itk::CastImageFilter<QI::ImageF, QI::TimeseriesF>::Pointer caster = itk::CastImageFilter<QI::ImageF, QI::TimeseriesF>::New();
    paster->SetDestinationImage(vols);
    //paster->SetInPlace(true);
    auto k_filter = itk::KSpaceFilter<QI::ImageXF>::New();
    TukeyKernel tukey;
    tukey.setAQ(filter_a, filter_q);
    k_filter->SetKernel(tukey);
    for (int i = 0; i < nvols; i++) {
        region.GetModifiableIndex()[3] = i;
        extract->SetExtractionRegion(region);
        extract->Update();
        QI::ImageF::Pointer outvol = FilterVolume(extract->GetOutput(), k_filter, verbose, debug, prefix);
        caster->SetInput(outvol);
        caster->Update();
        paster->SetSourceImage(caster->GetOutput());
        paster->SetSourceRegion(caster->GetOutput()->GetLargestPossibleRegion());
        paster->SetDestinationImage(vols);
        paster->SetDestinationIndex(region.GetIndex());
        paster->Update();
        vols = paster->GetOutput();
    }
    cout << "paster in place " << paster->GetInPlace() << endl;
    if (verbose) cout << "Writing output:" << outname << endl;
    QI::WriteImage(vols, outname);
    if (verbose) cout << "Finished." << endl;
    return EXIT_SUCCESS;
}
<commit_msg>WIP: Refactored pipeline to support complex input<commit_after>/*
 *  qikfilter.cpp
 *
 *  Copyright (c) 2015 Tobias Wood.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include <time.h>
#include <getopt.h>
#include <iostream>
#include <atomic>
#include <sstream>
#include "Eigen/Dense"

#include "itkImageSource.h"
#include "itkConstNeighborhoodIterator.h"
#include "itkImageRegionIteratorWithIndex.h"
#include "itkMultiplyImageFilter.h"
#include "itkDivideImageFilter.h"
#include "itkComplexToComplexFFTImageFilter.h"
#include "itkInverseFFTImageFilter.h"
#include "itkFFTShiftImageFilter.h"
#include "itkComplexToModulusImageFilter.h"
#include "itkFFTPadImageFilter.h"
#include "itkExtractImageFilter.h"
#include "itkPasteImageFilter.h"
#include "itkCastImageFilter.h"

#include "QI/Types.h"
#include "QI/Util.h"

using namespace std;
using namespace Eigen;

class FilterKernel {

};

class TukeyKernel : FilterKernel {
protected:
    double m_a = 0.75;
    double m_q = 0.25;
    int m_hx = 0, m_hy = 0, m_hz = 0;

public:
    void setSize(const int sx, const int sy, const int sz) {
        m_hx = sx / 2;  m_hy = sy / 2;  m_hz = sz / 2;
    }
    void setAQ(const double a, const double q) {
        m_a = a;
        m_q = q;
    }

    double operator() (const int x, const int y, const int z) const {
            const double rx = static_cast<double>(x - m_hx)/m_hx;
            const double ry = static_cast<double>(y - m_hy)/m_hy;
            const double rz = static_cast<double>(z - m_hz)/m_hz;
            const double r = sqrt((rx*rx + ry*ry + rz*rz) / 3);
            const double v = (r <= (1 - m_a)) ? 1 : 0.5*((1+m_q)+(1-m_q)*cos((M_PI/m_a)*(r - 1 + m_a)));
            return v;
    }
};

namespace itk {

template<typename ImageType>
class KSpaceFilter : public ImageToImageFilter<ImageType, ImageType> {
public:
    typedef ImageType                          TImage;
    typedef KSpaceFilter                       Self;
    typedef ImageToImageFilter<TImage, TImage> Superclass;
    typedef SmartPointer<Self>                 Pointer;

protected:
    typedef typename TImage::RegionType::SizeType SizeType;
    typename TImage::RegionType    m_region;
    typename TImage::SpacingType   m_spacing;
    typename TImage::DirectionType m_direction;
    typename TImage::PointType     m_origin;

    TukeyKernel m_kernel;

    KSpaceFilter(){}
    ~KSpaceFilter(){}

public:
    itkNewMacro(Self);
    itkTypeMacro(KSpaceFilter, ImageSource);

    virtual void GenerateOutputInformation() override {
        Superclass::GenerateOutputInformation();
        SizeType size = this->GetOutput()->GetLargestPossibleRegion().GetSize();
        m_kernel.setSize(size[0], size[1], size[2]);
    }

    void SetKernel(const TukeyKernel &k) { m_kernel = k; }

protected:
    virtual void ThreadedGenerateData(const typename TImage::RegionType &region, ThreadIdType threadId) override {
        itk::ImageRegionIterator<TImage> outIt(this->GetOutput(),region);
        itk::ImageRegionConstIteratorWithIndex<TImage> inIt(this->GetInput(),region);
        inIt.GoToBegin();
        outIt.GoToBegin();
        while(!inIt.IsAtEnd()) {
            const auto index = inIt.GetIndex() - m_region.GetIndex(); // Might be padded to a negative start
            const typename TImage::PixelType::value_type k = m_kernel(index[0], index[1], index[2]);
            const typename TImage::PixelType v = inIt.Get();
            outIt.Set(v * k);
            ++inIt;
            ++outIt;
        }
    }

private:
    KSpaceFilter(const Self &);
    void operator=(const Self &);
};

} // End namespace itk

template<typename TImage> typename TImage::Pointer FilterVolume(const typename TImage::Pointer invol, const TukeyKernel &kernel, const bool verbose, const bool debug, const string &out_name);

template<> QI::ImageXD::Pointer FilterVolume<QI::ImageXD>(const typename QI::ImageXD::Pointer invol, const TukeyKernel &kernel, const bool verbose, const bool debug, const string &out_name) {
    if (verbose) cout << "Padding image to valid FFT size." << endl;
    typedef itk::FFTPadImageFilter<QI::ImageXD> TPad;
    typename TPad::Pointer padFFT = TPad::New();
    padFFT->SetInput(invol);
    padFFT->Update();
    if (debug) QI::WriteImage(padFFT->GetOutput(), out_name + "_step1_padFFT" + QI::OutExt());
    if (verbose) {
        cout << "Padded image size: " << padFFT->GetOutput()->GetLargestPossibleRegion().GetSize() << endl;
        cout << "Calculating Forward FFT." << endl;
    }

    typedef itk::ComplexToComplexFFTImageFilter<QI::ImageXD> FFTType;
    auto forwardFFT = FFTType::New();
    forwardFFT->SetInput(padFFT->GetOutput());
    forwardFFT->Update();

    typedef itk::FFTShiftImageFilter<QI::ImageXD, QI::ImageXD> TShift;
    TShift::Pointer shiftFFT = TShift::New();
    shiftFFT->SetInput(forwardFFT->GetOutput());
    shiftFFT->Update();
    if (debug) QI::WriteImage(shiftFFT->GetOutput(), out_name + "_step2_forwardFFT" + QI::OutExt());

    if (verbose) cout << "Filtering." << endl;
    typedef itk::KSpaceFilter<QI::ImageXD> TFilter;
    TFilter::Pointer k_filter = TFilter::New();
    k_filter->SetKernel(kernel);
    k_filter->SetInput(shiftFFT->GetOutput());
    if (debug) QI::WriteImage   (k_filter->GetOutput(), out_name + "_step3_multFFT" + QI::OutExt());

    auto unshiftFFT = TShift::New();
    unshiftFFT->SetInput(k_filter->GetOutput());
    unshiftFFT->Update();

    if (verbose) cout << "Inverse FFT." << endl;
    auto inverseFFT = FFTType::New();
    inverseFFT->SetTransformDirection(FFTType::INVERSE);
    inverseFFT->SetInput(unshiftFFT->GetOutput());
    inverseFFT->Update();

    if (debug) QI::WriteImage(inverseFFT->GetOutput(), out_name + "_step4_inverseFFT" + QI::OutExt());
    if (verbose) cout << "Extracting original size image" << endl;
    auto extract = itk::ExtractImageFilter<QI::ImageXD, QI::ImageXD>::New();
    extract->SetInput(inverseFFT->GetOutput());
    extract->SetDirectionCollapseToSubmatrix();
    extract->SetExtractionRegion(invol->GetLargestPossibleRegion());
    extract->Update();
    typename QI::ImageXD::Pointer outvol = extract->GetOutput();
    outvol->DisconnectPipeline();
    return outvol;
}

template<> QI::ImageD::Pointer FilterVolume<QI::ImageD>(const typename QI::ImageD::Pointer invol, const TukeyKernel &kernel, const bool verbose, const bool debug, const string &out_name) {
    typedef itk::CastImageFilter<QI::ImageD, QI::ImageXD> TCast;
    auto caster = TCast::New();
    caster->SetInput(invol);
    caster->Update();
    QI::ImageXD::Pointer filtered = FilterVolume<QI::ImageXD>(caster->GetOutput(), kernel, verbose, debug, out_name);
    if (verbose) cout << "Taking complex modulus" << endl;
    typedef itk::ComplexToModulusImageFilter<QI::ImageXD, QI::ImageD> TMod;
    auto mod = TMod::New();
    mod->SetInput(filtered);
    mod->Update();
    QI::ImageD::Pointer final = mod->GetOutput();
    final->DisconnectPipeline();
    return final;
}

template<typename TPixel>
void run_pipeline(const std::string &in_name, const std::string &out_name, const bool verbose, const bool debug, const TukeyKernel &kernel) {
    typedef itk::Image<TPixel, 4> TSeries;
    typedef itk::Image<TPixel, 3> TVolume;

    if (verbose) cout << "Opening input file: " << in_name << endl;
    typename TSeries::Pointer vols = QI::ReadImage<TSeries>(in_name);
    auto region = vols->GetLargestPossibleRegion();
    const size_t nvols = region.GetSize()[3]; // Save for the loop
    region.GetModifiableSize()[3] = 0;
    auto extract = itk::ExtractImageFilter<TSeries, TVolume>::New();
    extract->SetInput(vols);
    extract->SetDirectionCollapseToSubmatrix();
    typename itk::PasteImageFilter<TSeries>::Pointer paster = itk::PasteImageFilter<TSeries>::New();
    typename itk::CastImageFilter<TVolume, TSeries>::Pointer caster = itk::CastImageFilter<TVolume, TSeries>::New();
    paster->SetDestinationImage(vols);
    //paster->InPlaceOn();
    for (int i = 0; i < nvols; i++) {
        region.GetModifiableIndex()[3] = i;
        extract->SetExtractionRegion(region);
        if (verbose) cout << "Extracting volume " << i << endl;
        cout << extract->GetInPlace() << endl;
        extract->Update();
        if (verbose) cout << "Launching filter pipeline" << endl;
        typename TVolume::Pointer outvol = FilterVolume<TVolume>(extract->GetOutput(), kernel, verbose, debug, out_name);
        if (verbose) cout << "Casting to 4D" << endl;
        caster->SetInput(outvol);
        caster->Update();
        if (verbose) cout << "Pasting" << endl;
        paster->SetSourceImage(caster->GetOutput());
        paster->SetSourceRegion(caster->GetOutput()->GetLargestPossibleRegion());
        paster->SetDestinationImage(vols);
        paster->SetDestinationIndex(region.GetIndex());
        paster->Update();
        vols = paster->GetOutput();
    }
    cout << "paster in place " << paster->GetInPlace() << endl;
    if (verbose) cout << "Writing output:" << out_name + QI::OutExt() << endl;
    QI::WriteImage(vols, out_name + QI::OutExt());
    if (verbose) cout << "Finished." << endl;
}

//******************************************************************************
// Arguments / Usage
//******************************************************************************
const string usage {
"Usage is: qikfilter [options] input \n\
\n\
Filter images in k-Space\n\
\n\
Options:\n\
    --help, -h           : Print this message.\n\
    --verbose, -v        : Print more information.\n\
    --out, -o path       : Specify an output filename (default image base).\n\
    --filter, -f \"a q\" : Set Filter a and q values (default 0.75 0.25).\n\
    --debug, -d          : Save all pipeline steps.\n\
    --complex, -x        : Input/output data is complex.\n\
    --threads, -T N      : Use N threads (default=hardware limit).\n"
};

const struct option long_options[] = {
    {"help", no_argument, 0, 'h'},
    {"verbose", no_argument, 0, 'v'},
    {"out", required_argument, 0, 'o'},
    {"filter", required_argument, 0, 'f'},
    {"debug", no_argument, 0, 'd'},
    {"complex", no_argument, 0, 'x'},
    {"threads", required_argument, 0, 'T'},
    {0, 0, 0, 0}
};
const char *short_options = "hvo:m:e:dxT:";

//******************************************************************************
// Main
//******************************************************************************
int main(int argc, char **argv) {
    Eigen::initParallel();

    bool verbose = false, debug = false, is_complex = false;
    double filter_a = 0.75, filter_q = 0.25;
    string out_name;
    int indexptr = 0, c;
    while ((c = getopt_long(argc, argv, short_options, long_options, &indexptr)) != -1) {
        switch (c) {
            case 'v': verbose = true; break;
            case 'o':
                out_name = optarg;
                cout << "Output filename will be: " << out_name << endl;
                break;
            case 'f': {
                stringstream f(optarg);
                f >> filter_a >> filter_q;
            } break;
            case 'd': debug = true; break;
            case 'x': is_complex = true; break;
            case 'T': itk::MultiThreader::SetGlobalMaximumNumberOfThreads(atoi(optarg)); break;
            case 'h':
                cout << QI::GetVersion() << endl << usage << endl;
                return EXIT_SUCCESS;
            case '?': // getopt will print an error message
                return EXIT_FAILURE;
            default:
                cout << "Unhandled option " << string(1, c) << endl;
                return EXIT_FAILURE;
        }
    }
    if ((argc - optind) != 1) {
        cout << "Incorrect number of arguments." << endl << usage << endl;
        return EXIT_FAILURE;
    }

    string in_name(argv[optind++]);
    if (out_name == "")
        out_name = in_name.substr(0, in_name.find(".")) + "_filtered";

    TukeyKernel filter_kernel;
    filter_kernel.setAQ(filter_a, filter_q);
    if (is_complex) {
        if (verbose) cout << "Data is complex." << endl;
        run_pipeline<complex<double>>(in_name, out_name, verbose, debug, filter_kernel);
    } else {
        if (verbose) cout << "Data is real." << endl;
        run_pipeline<double>(in_name, out_name, verbose, debug, filter_kernel);
    }

    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>#include <boost/foreach.hpp>
#include <event.h>

#include "libcage/src/cage.hpp"
#include "ipc.h"

extern "C" {
#include "safe_assert.h"
}

#ifndef MAX
#define MAX(a,b) a>b ? a : b
#endif

static int sock;

static void
dht_on_joined(bool res) {
	int len;
	struct ipc_message msg = {};

	msg.type = JOINED;
	msg.joined.result = res;

	len = send(sock, &msg, sizeof(msg), 0);
	safe_assert_io(len, sizeof(msg), size_t);
}

class dht_get_callback
{
public:
	dht_get_callback(void *user_data) : m_user_data(user_data) {}

	void operator() (bool result, libcage::dht::value_set_ptr vset) {
		struct ipc_message msg = {};
		ssize_t len;
		char *buf;
		libcage::dht::value_set::const_iterator it;

		msg.type = RESULT;
		msg.result.user_data = this->m_user_data;
		msg.result.length = (vset && result) ? vset->size() : 0;

		len = send(sock, &msg, sizeof(msg), 0);
		safe_assert_io(len, sizeof(msg), size_t);

		if (msg.result.length == 0)
			return;

		BOOST_FOREACH(const libcage::dht::value_t &val, *vset) {
			size_t length;

			buf = val.value.get();

			length = val.len;
			safe_assert(val.len > 0);

			len = send(sock, &length, sizeof(length), 0);
			safe_assert_io(len, sizeof(length), size_t);

			len = send(sock, buf, val.len, 0);
			safe_assert_io(len, val.len, int);
		}
	}

protected:
	void *m_user_data;
};

static size_t
construct_lookup_key(unsigned int app_id, char *key, size_t keylen,
	unsigned int **buf)
{
	size_t len;

	len = sizeof(app_id) + keylen;
	safe_assert(len > sizeof(app_id) && len > keylen);

	*buf = (unsigned int *) safe_malloc(len);

	(*buf)[0] = htonl(app_id);
	memcpy(&((*buf)[1]), key, keylen);

	return len;
}

static void
dht_get(libcage::cage *cage, unsigned int app_id, char *key, size_t keylen,
	void *user_data)
{
	size_t len;
	unsigned int *buf;
	dht_get_callback on_get_finished(user_data);

	len = construct_lookup_key(app_id, key, keylen, &buf);
	cage->get(buf, len, on_get_finished);

	free(buf);
}

static void
dht_put(libcage::cage *cage, unsigned int app_id, char *key, size_t keylen,
	char *value, int valuelen, int unsigned ttl)
{
	int len;
	unsigned int *buf;

	len = construct_lookup_key(app_id, key, keylen, &buf);
	cage->put(buf, len, value, valuelen, ttl);

	free(buf);
}

static void
dht_send_node_list(std::list<libcage::cageaddr> const nodes) {
	unsigned int max_host_len = MAX(INET6_ADDRSTRLEN, INET_ADDRSTRLEN);
	char host[max_host_len];
	std::list<libcage::cageaddr>::const_iterator it;
	struct ipc_message msg = {};
	unsigned short port;
	libcage::in6_ptr in6;
	libcage::in_ptr in4;
	const char *res;
	size_t length;
	int len;

	msg.type = NODE_LIST;
	msg.node_list.length = nodes.size();

	len = send(sock, &msg, sizeof(msg), 0);
	safe_assert_io(len, sizeof(msg), size_t);

	for (it = nodes.begin(); it != nodes.end(); it++) {
		if (it->domain == PF_INET6) {
			in6 = boost::get<libcage::in6_ptr>(it->saddr);
			res = inet_ntop(it->domain, &(*in6), host, sizeof(host));
			port = ntohs(in6->sin6_port);
		}
		else if (it->domain == PF_INET) {
			in4 = boost::get<libcage::in_ptr>(it->saddr);
			res = inet_ntop(it->domain, &(*in4), host, sizeof(host));
			port = ntohs(in4->sin_port);
		}
		else
			safe_assert(0==1 && "unknown addr domain");
		safe_assert(res != NULL);

		len = send(sock, &port, sizeof(port), 0);
		safe_assert_io(len, sizeof(port), size_t);

		length = strlen(host)+1;
		len = send(sock, &length, sizeof(length), 0);
		safe_assert_io(len, sizeof(length), size_t);

		len = send(sock, host, length, 0);
		safe_assert_io(len, sizeof(length), size_t);
	}
}

static void
dht_on_ipc(int fd, short ev_type, void *user_data)
{
	libcage::cage *cage = (libcage::cage *) user_data;
	std::list<libcage::cageaddr> nodes;
	struct ipc_message msg = {};
	std::string str;
	ssize_t len;
	char *key;
	char *host;
	char *value;
	char *id;

	len = recv(fd, &msg, sizeof(msg), MSG_WAITALL);
	safe_assert_io(len, sizeof(msg), size_t);

	switch(msg.type) {
	case JOIN:
		// TODO: timer that retries to join every 60 sec if not connected.
		host = (char *) safe_malloc(msg.join.hostlen);
		len = recv(fd, host, msg.join.hostlen, MSG_WAITALL);
		safe_assert_io(len, msg.join.hostlen, size_t);

		cage->join(host, msg.join.port, dht_on_joined);

		free(host);
		break;

	case GET:
		key = (char *) safe_malloc(msg.get.keylen);

		len = recv(fd, key, msg.get.keylen, MSG_WAITALL);
		safe_assert_io(len, msg.get.keylen, size_t);

		dht_get(cage, msg.get.app_id, key, msg.get.keylen, msg.get.user_data);
		free(key);
		break;

	case PUT:
		key = (char *) safe_malloc(msg.put.keylen);
		value = (char *) safe_malloc(msg.put.valuelen);

		len = recv(fd, key, msg.put.keylen, MSG_WAITALL);
		safe_assert_io(len, msg.put.keylen, size_t);

		len = recv(fd, value, msg.put.valuelen, MSG_WAITALL);
		safe_assert_io(len, msg.put.valuelen, size_t);

		dht_put(cage, msg.put.app_id,
			key, msg.put.keylen,
			value, msg.put.valuelen,
			msg.put.ttl);

		free(key);
		free(value);
		break;

	case NODE_LIST:
		nodes = cage->get_table();
		dht_send_node_list(nodes);
		// TODO: free nodes?
		break;

	case GET_NODE_ID:
		id = (char *) cage->get_id_str().c_str();
		msg.type = GET_NODE_ID;
		msg.node_id.length = strlen(id)+1;

		len = send(sock, &msg, sizeof(msg), 0);
		safe_assert_io(len, sizeof(msg), size_t);

		len = send(sock, id, msg.node_id.length, 0);
		safe_assert_io(len, sizeof(msg.node_id.length), size_t);
		break;

	case SET_NODE_ID:
		id = (char *) safe_malloc(msg.node_id.length);

		len = recv(sock, id, msg.node_id.length, MSG_WAITALL);
		safe_assert_io(len, sizeof(msg.node_id.length), size_t);

		str = std::string(id, len);
		cage->set_id_str(str);

		free(id);
		break;

	case QUIT:
		event_loopbreak();
		break;

	default:
		safe_assert("should not be reached" && (1!=1));
		break;
	}
}

extern "C" int
dht_run(int socket, int port) {
	sock = socket;
	event_init();

	/* setup dht */
	libcage::cage *cage = new libcage::cage();
	cage->set_global();
	cage->open(AF_INET6, port);

	/* setup ipc */
	struct event ev = {};
	event_set(&ev, sock, EV_READ | EV_PERSIST, dht_on_ipc, cage);
	event_add(&ev, NULL);

	event_dispatch();

	return 0;
}
<commit_msg>Close ipc socket when finished<commit_after>#include <boost/foreach.hpp>
#include <event.h>

#include "libcage/src/cage.hpp"
#include "ipc.h"

extern "C" {
#include "safe_assert.h"
}

#ifndef MAX
#define MAX(a,b) a>b ? a : b
#endif

static int sock;

static void
dht_on_joined(bool res) {
	int len;
	struct ipc_message msg = {};

	msg.type = JOINED;
	msg.joined.result = res;

	len = send(sock, &msg, sizeof(msg), 0);
	safe_assert_io(len, sizeof(msg), size_t);
}

class dht_get_callback
{
public:
	dht_get_callback(void *user_data) : m_user_data(user_data) {}

	void operator() (bool result, libcage::dht::value_set_ptr vset) {
		struct ipc_message msg = {};
		ssize_t len;
		char *buf;
		libcage::dht::value_set::const_iterator it;

		msg.type = RESULT;
		msg.result.user_data = this->m_user_data;
		msg.result.length = (vset && result) ? vset->size() : 0;

		len = send(sock, &msg, sizeof(msg), 0);
		safe_assert_io(len, sizeof(msg), size_t);

		if (msg.result.length == 0)
			return;

		BOOST_FOREACH(const libcage::dht::value_t &val, *vset) {
			size_t length;

			buf = val.value.get();

			length = val.len;
			safe_assert(val.len > 0);

			len = send(sock, &length, sizeof(length), 0);
			safe_assert_io(len, sizeof(length), size_t);

			len = send(sock, buf, val.len, 0);
			safe_assert_io(len, val.len, int);
		}
	}

protected:
	void *m_user_data;
};

static size_t
construct_lookup_key(unsigned int app_id, char *key, size_t keylen,
	unsigned int **buf)
{
	size_t len;

	len = sizeof(app_id) + keylen;
	safe_assert(len > sizeof(app_id) && len > keylen);

	*buf = (unsigned int *) safe_malloc(len);

	(*buf)[0] = htonl(app_id);
	memcpy(&((*buf)[1]), key, keylen);

	return len;
}

static void
dht_get(libcage::cage *cage, unsigned int app_id, char *key, size_t keylen,
	void *user_data)
{
	size_t len;
	unsigned int *buf;
	dht_get_callback on_get_finished(user_data);

	len = construct_lookup_key(app_id, key, keylen, &buf);
	cage->get(buf, len, on_get_finished);

	free(buf);
}

static void
dht_put(libcage::cage *cage, unsigned int app_id, char *key, size_t keylen,
	char *value, int valuelen, int unsigned ttl)
{
	int len;
	unsigned int *buf;

	len = construct_lookup_key(app_id, key, keylen, &buf);
	cage->put(buf, len, value, valuelen, ttl);

	free(buf);
}

static void
dht_send_node_list(std::list<libcage::cageaddr> const nodes) {
	unsigned int max_host_len = MAX(INET6_ADDRSTRLEN, INET_ADDRSTRLEN);
	char host[max_host_len];
	std::list<libcage::cageaddr>::const_iterator it;
	struct ipc_message msg = {};
	unsigned short port;
	libcage::in6_ptr in6;
	libcage::in_ptr in4;
	const char *res;
	size_t length;
	int len;

	msg.type = NODE_LIST;
	msg.node_list.length = nodes.size();

	len = send(sock, &msg, sizeof(msg), 0);
	safe_assert_io(len, sizeof(msg), size_t);

	for (it = nodes.begin(); it != nodes.end(); it++) {
		if (it->domain == PF_INET6) {
			in6 = boost::get<libcage::in6_ptr>(it->saddr);
			res = inet_ntop(it->domain, &(*in6), host, sizeof(host));
			port = ntohs(in6->sin6_port);
		}
		else if (it->domain == PF_INET) {
			in4 = boost::get<libcage::in_ptr>(it->saddr);
			res = inet_ntop(it->domain, &(*in4), host, sizeof(host));
			port = ntohs(in4->sin_port);
		}
		else
			safe_assert(0==1 && "unknown addr domain");
		safe_assert(res != NULL);

		len = send(sock, &port, sizeof(port), 0);
		safe_assert_io(len, sizeof(port), size_t);

		length = strlen(host)+1;
		len = send(sock, &length, sizeof(length), 0);
		safe_assert_io(len, sizeof(length), size_t);

		len = send(sock, host, length, 0);
		safe_assert_io(len, sizeof(length), size_t);
	}
}

static void
dht_on_ipc(int fd, short ev_type, void *user_data)
{
	libcage::cage *cage = (libcage::cage *) user_data;
	std::list<libcage::cageaddr> nodes;
	struct ipc_message msg = {};
	std::string str;
	ssize_t len;
	char *key;
	char *host;
	char *value;
	char *id;

	len = recv(fd, &msg, sizeof(msg), MSG_WAITALL);
	safe_assert_io(len, sizeof(msg), size_t);

	switch(msg.type) {
	case JOIN:
		// TODO: timer that retries to join every 60 sec if not connected.
		host = (char *) safe_malloc(msg.join.hostlen);
		len = recv(fd, host, msg.join.hostlen, MSG_WAITALL);
		safe_assert_io(len, msg.join.hostlen, size_t);

		cage->join(host, msg.join.port, dht_on_joined);

		free(host);
		break;

	case GET:
		key = (char *) safe_malloc(msg.get.keylen);

		len = recv(fd, key, msg.get.keylen, MSG_WAITALL);
		safe_assert_io(len, msg.get.keylen, size_t);

		dht_get(cage, msg.get.app_id, key, msg.get.keylen, msg.get.user_data);
		free(key);
		break;

	case PUT:
		key = (char *) safe_malloc(msg.put.keylen);
		value = (char *) safe_malloc(msg.put.valuelen);

		len = recv(fd, key, msg.put.keylen, MSG_WAITALL);
		safe_assert_io(len, msg.put.keylen, size_t);

		len = recv(fd, value, msg.put.valuelen, MSG_WAITALL);
		safe_assert_io(len, msg.put.valuelen, size_t);

		dht_put(cage, msg.put.app_id,
			key, msg.put.keylen,
			value, msg.put.valuelen,
			msg.put.ttl);

		free(key);
		free(value);
		break;

	case NODE_LIST:
		nodes = cage->get_table();
		dht_send_node_list(nodes);
		// TODO: free nodes?
		break;

	case GET_NODE_ID:
		id = (char *) cage->get_id_str().c_str();
		msg.type = GET_NODE_ID;
		msg.node_id.length = strlen(id)+1;

		len = send(sock, &msg, sizeof(msg), 0);
		safe_assert_io(len, sizeof(msg), size_t);

		len = send(sock, id, msg.node_id.length, 0);
		safe_assert_io(len, sizeof(msg.node_id.length), size_t);
		break;

	case SET_NODE_ID:
		id = (char *) safe_malloc(msg.node_id.length);

		len = recv(sock, id, msg.node_id.length, MSG_WAITALL);
		safe_assert_io(len, sizeof(msg.node_id.length), size_t);

		str = std::string(id, len);
		cage->set_id_str(str);

		free(id);
		break;

	case QUIT:
		event_loopbreak();
		break;

	default:
		safe_assert("should not be reached" && (1!=1));
		break;
	}
}

extern "C" int
dht_run(int socket, int port) {
	sock = socket;
	event_init();

	/* setup dht */
	libcage::cage *cage = new libcage::cage();
	cage->set_global();
	cage->open(AF_INET6, port);

	/* setup ipc */
	struct event ev = {};
	event_set(&ev, sock, EV_READ | EV_PERSIST, dht_on_ipc, cage);
	event_add(&ev, NULL);

	event_dispatch();

	close(sock);

	return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014, Ford Motor Company
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following
 * disclaimer in the documentation and/or other materials provided with the
 * distribution.
 *
 * Neither the name of the Ford Motor Company nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "utils/logger.h"
#include "utils/log_message_loop_thread.h"
#include <apr_time.h>

void deinit_logger () {
  CREATE_LOGGERPTR_LOCAL (logger_, "Logger");
  LOG4CXX_DEBUG(logger_, "Logger deinitialization");
  logger::LogMessageLoopThread::destroy();
  log4cxx::LoggerPtr rootLogger = log4cxx::Logger::getRootLogger();
  log4cxx::spi::LoggerRepositoryPtr repository = rootLogger->getLoggerRepository();
  log4cxx::LoggerList loggers = repository->getCurrentLoggers();
  for (log4cxx::LoggerList::iterator i = loggers.begin(); i != loggers.end(); ++i) {
    log4cxx::LoggerPtr logger = *i;
    logger->removeAllAppenders();
  }
  rootLogger->removeAllAppenders();
}

log4cxx_time_t time_now() {
  return apr_time_now();
}
<commit_msg>Remove unneeded log from DEINIT_LOGGER<commit_after>/*
 * Copyright (c) 2014, Ford Motor Company
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following
 * disclaimer in the documentation and/or other materials provided with the
 * distribution.
 *
 * Neither the name of the Ford Motor Company nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "utils/logger.h"
#include "utils/log_message_loop_thread.h"
#include <apr_time.h>

void deinit_logger () {
  logger::LogMessageLoopThread::destroy();
  log4cxx::LoggerPtr rootLogger = log4cxx::Logger::getRootLogger();
  log4cxx::spi::LoggerRepositoryPtr repository = rootLogger->getLoggerRepository();
  log4cxx::LoggerList loggers = repository->getCurrentLoggers();
  for (log4cxx::LoggerList::iterator i = loggers.begin(); i != loggers.end(); ++i) {
    log4cxx::LoggerPtr logger = *i;
    logger->removeAllAppenders();
  }
  rootLogger->removeAllAppenders();
}

log4cxx_time_t time_now() {
  return apr_time_now();
}
<|endoftext|>


<commit_before>#ifndef __CONCURRENCY_ONE_PER_THREAD_HPP__
#define __CONCURRENCY_ONE_PER_THREAD_HPP__

#include "errors.hpp"
#include <boost/bind.hpp>
#include <boost/scoped_array.hpp>
#include <boost/scoped_ptr.hpp>

#include "arch/runtime/runtime.hpp"

template<class inner_t>
class one_per_thread_t {
public:
    one_per_thread_t() : array(new boost::scoped_ptr<inner_t>[get_num_threads()]) {
        pmap(get_num_threads(), boost::bind(&one_per_thread_t::construct_on_thread, this, _1));
    }
    ~one_per_thread_t() {
        pmap(get_num_threads(), boost::bind(&one_per_thread_t::destruct_on_thread, this, _1));
    }
    inner_t *get() {
        return array[get_thread_id()].get();
    }
private:
    void construct_on_thread(int thread) {
        on_thread_t thread_switcher(thread);
        array[thread].reset(new inner_t);
    }
    void destruct_on_thread(int thread) {
        on_thread_t thread_switcher(thread);
        array[thread].reset();
    }
    boost::scoped_array<boost::scoped_ptr<inner_t> > array;
};

#endif /* __CONCURRENCY_ONE_PER_THREAD_HPP__ */
<commit_msg>Made one_per_thread_t allow arguments to constructor.<commit_after>#ifndef __CONCURRENCY_ONE_PER_THREAD_HPP__
#define __CONCURRENCY_ONE_PER_THREAD_HPP__

#include "errors.hpp"
#include <boost/bind.hpp>
#include <boost/scoped_array.hpp>
#include <boost/scoped_ptr.hpp>

#include "arch/runtime/runtime.hpp"

template<class inner_t>
class one_per_thread_t {
public:
    one_per_thread_t() : array(new boost::scoped_ptr<inner_t>[get_num_threads()]) {
        pmap(get_num_threads(), boost::bind(&one_per_thread_t::construct_on_thread_0, this, _1));
    }
    template<class arg1_t>
    explicit one_per_thread_t(const arg1_t &arg1) : array(new boost::scoped_ptr<inner_t>[get_num_threads()]) {
        pmap(get_num_threads(), boost::bind(&one_per_thread_t::construct_on_thread_1<arg1_t>, this, _1, arg1));
    }
    template<class arg1_t, class arg2_t>
    one_per_thread_t(const arg1_t &arg1, const arg2_t &arg2) : array(new boost::scoped_ptr<inner_t>[get_num_threads()]) {
        pmap(get_num_threads(), boost::bind(&one_per_thread_t::construct_on_thread_2<arg1_t, arg2_t>, this, _1, arg1, arg2));
    }
    ~one_per_thread_t() {
        pmap(get_num_threads(), boost::bind(&one_per_thread_t::destruct_on_thread, this, _1));
    }
    inner_t *get() {
        return array[get_thread_id()].get();
    }
private:
    void construct_on_thread_0(int thread) {
        on_thread_t thread_switcher(thread);
        array[thread].reset(new inner_t);
    }
    template<class arg1_t>
    void construct_on_thread_1(int thread, const arg1_t &arg1) {
        on_thread_t thread_switcher(thread);
        array[thread].reset(new inner_t(arg1));
    }
    template<class arg1_t, class arg2_t>
    void construct_on_thread_2(int thread, const arg1_t &arg1, const arg2_t &arg2) {
        on_thread_t thread_switcher(thread);
        array[thread].reset(new inner_t(arg1, arg2));
    }
    void destruct_on_thread(int thread) {
        on_thread_t thread_switcher(thread);
        array[thread].reset();
    }
    boost::scoped_array<boost::scoped_ptr<inner_t> > array;
};

#endif /* __CONCURRENCY_ONE_PER_THREAD_HPP__ */
<|endoftext|>


<commit_before>#include "condor_common.h"
#include "ad_printmask.h"

static char *new_strdup (const char *);

AttrListPrintMask::
AttrListPrintMask ()
{
}

AttrListPrintMask::
AttrListPrintMask (const AttrListPrintMask &pm)
{
	copyList (formats, (List<char> &) pm.formats);
	copyList (attributes, (List<char> &) pm.attributes);
	copyList (alternates, (List<char> &) pm.alternates);
}

AttrListPrintMask::
~AttrListPrintMask ()
{
	clearFormats ();
}

void AttrListPrintMask::
registerFormat (char *fmt, const char *attr, char *alternate)
{
	formats.Append   (new_strdup (fmt));
	attributes.Append(new_strdup (attr));
	alternates.Append(new_strdup(alternate));
}

void AttrListPrintMask::
clearFormats (void)
{
	clearList (formats);
	clearList (attributes);
	clearList (alternates);
}

int AttrListPrintMask::
display (FILE *file, AttrList *al)
{
	char *fmt, *attr, *alt;
	ExprTree *tree;
	EvalResult result;
	int retval = 1;

	formats.Rewind();
	attributes.Rewind();
	alternates.Rewind();

	// for each item registered in the print mask
	while ((fmt=formats.Next()) && (attr=attributes.Next()) &&
				(alt=alternates.Next()))
	{
		// get the expression tree of the attribute
		if (!(tree = al->Lookup (attr)))
		{
			if (alt) printf ("%s", alt);
			continue;
		}

		// print the result
		if (tree->EvalTree (al, NULL, &result))
		{
			switch (result.type)
			{
			  case LX_STRING:
				fprintf (file, fmt, result.s);
				break;

			  case LX_FLOAT:
				fprintf (file, fmt, result.f);
				break;

			  case LX_INTEGER:
				fprintf (file, fmt, result.i);
				break;

			  case LX_BOOL:
				fprintf (file, fmt, result.b);
				break;

			  default:
				fprintf (file, "(Unknown type)");
				retval = 0;
				continue;
			}
		}
		else
		{
			fprintf (file, "(Not found)");
			retval = 0;
		}
	}

	return retval;
}

int AttrListPrintMask::
display (FILE *file, AttrListList *list)
{
	int retval = 1;
	AttrList *al;

	list->Open();
    while (al = (AttrList *) list->Next())
    {
		if (!display (file, al))
			retval = 0;
    }
    list->Close ();

	return retval;
}

void AttrListPrintMask::
clearList (List<char> &l)
{
    char *x;
    l.Rewind ();
    while (x = l.Next ())
    {
        delete [] x;
        l.DeleteCurrent ();
    }
}

void AttrListPrintMask::
copyList (List<char> &to, List<char> &from)
{
	char *item;

	clearList (to);
	from.Rewind ();
	while (item = from.Next ())
		to.Append (new_strdup (item));
}

// strdup() which uses new
static char *new_strdup (const char *str)
{
    char *x = new char [strlen (str) + 1];
    if (!x)
    {
		return 0;
    }
    strcpy (x, str);
    return x;
}
<commit_msg>Fixed output to go to a FILE * instead of stdout<commit_after>#include "condor_common.h"
#include "ad_printmask.h"

static char *new_strdup (const char *);

AttrListPrintMask::
AttrListPrintMask ()
{
}

AttrListPrintMask::
AttrListPrintMask (const AttrListPrintMask &pm)
{
	copyList (formats, (List<char> &) pm.formats);
	copyList (attributes, (List<char> &) pm.attributes);
	copyList (alternates, (List<char> &) pm.alternates);
}

AttrListPrintMask::
~AttrListPrintMask ()
{
	clearFormats ();
}

void AttrListPrintMask::
registerFormat (char *fmt, const char *attr, char *alternate)
{
	formats.Append   (new_strdup (fmt));
	attributes.Append(new_strdup (attr));
	alternates.Append(new_strdup(alternate));
}

void AttrListPrintMask::
clearFormats (void)
{
	clearList (formats);
	clearList (attributes);
	clearList (alternates);
}

int AttrListPrintMask::
display (FILE *file, AttrList *al)
{
	char *fmt, *attr, *alt;
	ExprTree *tree;
	EvalResult result;
	int retval = 1;

	formats.Rewind();
	attributes.Rewind();
	alternates.Rewind();

	// for each item registered in the print mask
	while ((fmt=formats.Next()) && (attr=attributes.Next()) &&
				(alt=alternates.Next()))
	{
		// get the expression tree of the attribute
		if (!(tree = al->Lookup (attr)))
		{
			if (alt) fprintf (file, "%s", alt);
			continue;
		}

		// print the result
		if (tree->EvalTree (al, NULL, &result))
		{
			switch (result.type)
			{
			  case LX_STRING:
				fprintf (file, fmt, result.s);
				break;

			  case LX_FLOAT:
				fprintf (file, fmt, result.f);
				break;

			  case LX_INTEGER:
				fprintf (file, fmt, result.i);
				break;

			  case LX_BOOL:
				fprintf (file, fmt, result.b);
				break;

			  default:
				fprintf (file, "%s", alt);
				retval = 0;
				continue;
			}
		}
		else
		{
			fprintf (file, "(Not found)");
			retval = 0;
		}
	}

	return retval;
}

int AttrListPrintMask::
display (FILE *file, AttrListList *list)
{
	int retval = 1;
	AttrList *al;

	list->Open();
    while (al = (AttrList *) list->Next())
    {
		if (!display (file, al))
			retval = 0;
    }
    list->Close ();

	return retval;
}

void AttrListPrintMask::
clearList (List<char> &l)
{
    char *x;
    l.Rewind ();
    while (x = l.Next ())
    {
        delete [] x;
        l.DeleteCurrent ();
    }
}

void AttrListPrintMask::
copyList (List<char> &to, List<char> &from)
{
	char *item;

	clearList (to);
	from.Rewind ();
	while (item = from.Next ())
		to.Append (new_strdup (item));
}

// strdup() which uses new
static char *new_strdup (const char *str)
{
    char *x = new char [strlen (str) + 1];
    if (!x)
    {
		return 0;
    }
    strcpy (x, str);
    return x;
}
<|endoftext|>