void DisplayDriverServer::Session::handleReadDataParameters( const boost::system::error_code& error )
{
	if (error)
	{
		msg( Msg::Error, "DisplayDriverServer::Session::handleReadDataParameters", error.message().c_str() );
		m_socket.close();
		return;
	}

	// sanity check: check DisplayDriver object
	if (! m_displayDriver )
	{
		msg( Msg::Error, "DisplayDriverServer::Session::handleReadDataParameters", "No display drivers!" );
		m_socket.close();
		return;
	}

	// get imageData parameters
	Box2iDataPtr box;
	FloatVectorDataPtr data;

	try
	{
		MemoryIndexedIOPtr io = new MemoryIndexedIO( m_buffer, IndexedIO::rootPath, IndexedIO::Exclusive | IndexedIO::Read );
		box = staticPointerCast<Box2iData>( Object::load( io, "box" ) );
		data = staticPointerCast<FloatVectorData>( Object::load( io, "data" ) );

		// call imageData passing the data
		m_displayDriver->imageData( box->readable(), &(data->readable()[0]), data->readable().size() );

		// prepare for getting more imageData packages or a imageClose.
		boost::asio::async_read( m_socket,
			boost::asio::buffer( m_header.buffer(), m_header.headerLength),
			boost::bind(
				&DisplayDriverServer::Session::handleReadHeader, SessionPtr(this),
				boost::asio::placeholders::error
			)
		);
	}
	catch( std::exception &e )
	{
		msg( Msg::Error, "DisplayDriverServer::Session::handleReadDataParameters", e.what() );
		m_socket.close();
		return;
	}
}
void ToMayaImageConverter::writeDepth( MImage &image, FloatVectorDataPtr channelData ) const
{
	assert( channelData );
	ConstImagePrimitivePtr toConvert = runTimeCast<const ImagePrimitive>( srcParameter()->getValidatedValue() );
	assert( toConvert );

	unsigned width, height;
	MStatus s = image.getSize( width, height );
	assert( s );

	const Imath::Box2i &dataWindow = toConvert->getDataWindow();
	const Imath::Box2i &displayWindow = toConvert->getDisplayWindow();

	unsigned int dataWidth = dataWindow.size().x + 1;
	unsigned int dataHeight = dataWindow.size().y + 1;

	Imath::V2i dataOffset = dataWindow.min - displayWindow.min ;

	boost::multi_array_ref< const float, 2 > src( &channelData->readable()[0], boost::extents[dataHeight][dataWidth] );

	std::vector<float> depth;
	depth.resize( height * width, 0 );
	boost::multi_array_ref< float, 2 > dst( &depth[0], boost::extents[ height ][ width ] );

	for ( unsigned x = 0; x < dataWidth; x++ )
	{
		for ( unsigned y = 0; y < dataHeight; y++ )
		{
			/// Vertical flip, to match Maya
			dst[ ( height - 1 ) - ( y + dataOffset.y ) ][ x + dataOffset.x ] = src[y][x];
		}
	}

	s = image.setDepthMap( &depth[0], width, height );
	assert( s );
	assert( image.depth() );
#ifndef NDEBUG
	unsigned depthWidth = 0, depthHeight = 0;
	s = image.getDepthMapSize( depthWidth, depthHeight );
	assert( s );
	assert( depthWidth == width );
	assert( depthHeight == height );
#endif
}
static void displayDriverImageData( DisplayDriverPtr dd, const Imath::Box2i &box, FloatVectorDataPtr data )
{
	dd->imageData( box, &(data->readable()[0]), data->readable().size() );
}
void ImageCompositeOp::composite( CompositeFn fn, DataWindowResult dwr, ImagePrimitive * imageB, const CompoundObject * operands )
{
	assert( fn );
	assert( imageB );
	assert( operands );

	const StringVectorParameter::ValueType &channelNames = channelNamesParameter()->getTypedValue();
	if ( !channelNames.size() )
	{
		throw InvalidArgumentException( "ImageCompositeOp: No channels specified" );
	}

	ImagePrimitivePtr imageA = runTimeCast< ImagePrimitive > ( imageAParameter()->getValue() );
	assert( imageA );

	const std::string &alphaChannel = alphaChannelNameParameter()->getTypedValue();
	if ( !imageA->arePrimitiveVariablesValid() )
	{
		throw InvalidArgumentException( "ImageCompositeOp: Input image has invalid channels" );
	}

	const int inputMode = m_inputModeParameter->getNumericValue();
	if ( inputMode == Unpremultiplied )
	{
		ImagePremultiplyOpPtr premultOp = new ImagePremultiplyOp();
		premultOp->alphaChannelNameParameter()->setTypedValue( alphaChannel );
		premultOp->channelNamesParameter()->setTypedValue( channelNames );

		if ( imageA->variables.find( alphaChannel ) != imageA->variables.end() )
		{
			/// Make a new imageA, premultiplied
			premultOp->copyParameter()->setTypedValue( true );
			premultOp->inputParameter()->setValue( imageA );

			imageA = assertedStaticCast< ImagePrimitive >( premultOp->operate() );
			assert( imageA->arePrimitiveVariablesValid() );
		}

		if ( imageB->variables.find( alphaChannel ) != imageB->variables.end() )
		{
			/// Premultiply imageB in-place
			premultOp->copyParameter()->setTypedValue( false );
			premultOp->inputParameter()->setValue( imageB );
			premultOp->operate();
		}
	}
	else
	{
		assert( inputMode == Premultiplied );
	}


	const Imath::Box2i displayWindow = imageB->getDisplayWindow();

	Imath::Box2i newDataWindow = imageB->getDataWindow();

	if ( dwr == Union )
	{
		newDataWindow.extendBy( imageA->getDataWindow() );
	}
	else
	{
		assert( dwr == Intersection );
		newDataWindow = boxIntersection( newDataWindow, imageA->getDataWindow() );
	}

	newDataWindow = boxIntersection( newDataWindow, displayWindow );

	ImageCropOpPtr cropOp = new ImageCropOp();

	/// Need to make sure that we don't create a new image here - we want to modify the current one in-place. So,
	/// we turn off the "copy" parameter of ModifyOp.
	cropOp->copyParameter()->setTypedValue( false );
	cropOp->inputParameter()->setValue( imageB );
	cropOp->cropBoxParameter()->setTypedValue( newDataWindow );
	cropOp->matchDataWindowParameter()->setTypedValue( true );
	cropOp->resetOriginParameter()->setTypedValue( false );

	cropOp->operate();

	assert( imageB->arePrimitiveVariablesValid() );
	assert( imageB->getDataWindow() == newDataWindow );

	/// \todo Use the "reformat" parameter of the ImageCropOp to do this, when it's implemented
	imageB->setDisplayWindow( displayWindow );

	FloatVectorDataPtr aAlphaData = getChannelData( imageA.get(), alphaChannel, false );
	FloatVectorDataPtr bAlphaData = getChannelData( imageB, alphaChannel, false );

	const int newWidth = newDataWindow.size().x + 1;
	const int newHeight = newDataWindow.size().y + 1;
	const int newArea = newWidth * newHeight;

	assert( newArea == (int)imageB->variableSize( PrimitiveVariable::Vertex ) );

	for( unsigned i=0; i<channelNames.size(); i++ )
	{
		const StringVectorParameter::ValueType::value_type &channelName = channelNames[i];

		FloatVectorDataPtr aData = getChannelData( imageA.get(), channelName );
		assert( aData->readable().size() == imageA->variableSize( PrimitiveVariable::Vertex ) );
		FloatVectorDataPtr bData = getChannelData( imageB, channelName );
		assert( bData->readable().size() == imageB->variableSize( PrimitiveVariable::Vertex ) );
		FloatVectorDataPtr newBData = new FloatVectorData();

		newBData->writable().resize( newArea );
		imageB->variables[ channelName ].data = newBData;

		for ( int y = newDataWindow.min.y; y <= newDataWindow.max.y; y++ )
		{
			int offset = (y - newDataWindow.min.y ) * newWidth;
			for ( int x = newDataWindow.min.x; x <= newDataWindow.max.x; x++, offset++ )
			{
				float aVal = readChannelData( imageA.get(), aData.get(), V2i( x, y ) );
				float bVal = readChannelData( imageB, bData.get(), V2i( x, y ) );

				float aAlpha = aAlphaData ? readChannelData( imageA.get(), aAlphaData.get(), V2i( x, y ) ) : 1.0f;
				float bAlpha = bAlphaData ? readChannelData( imageB, bAlphaData.get(), V2i( x, y ) ) : 1.0f;

				assert( offset >= 0 );
				assert( offset < (int)newBData->readable().size() );
				newBData->writable()[ offset  ] = fn( aVal, aAlpha, bVal, bAlpha );
			}
		}
	}

	/// displayWindow should be unchanged
	assert( imageB->getDisplayWindow() == displayWindow );
	assert( imageB->arePrimitiveVariablesValid() );

	/// If input images were unpremultiplied, then ensure that the output is also
	if ( inputMode == Unpremultiplied && imageB->variables.find( alphaChannel ) != imageB->variables.end() )
	{
		ImageUnpremultiplyOpPtr unpremultOp = new ImageUnpremultiplyOp();
		/// Unpremultiply imageB in-place
		unpremultOp->copyParameter()->setTypedValue( false );
		unpremultOp->channelNamesParameter()->setTypedValue( channelNames );
		unpremultOp->alphaChannelNameParameter()->setTypedValue( alphaChannel );
		unpremultOp->inputParameter()->setValue( imageB );
		unpremultOp->operate();
		assert( imageB->arePrimitiveVariablesValid() );
	}
	else
	{
		assert( inputMode == Premultiplied );
	}
}
void MeshTangentsOp::modifyTypedPrimitive( MeshPrimitive * mesh, const CompoundObject * operands )
{
	if( !mesh->arePrimitiveVariablesValid( ) )
	{
		throw InvalidArgumentException( "MeshTangentsOp : MeshPrimitive variables are invalid." );
	}
	
	const std::string &pPrimVarName = pPrimVarNameParameter()->getTypedValue();
	Data * pData = mesh->variableData<Data>( pPrimVarName, PrimitiveVariable::Vertex );
	if( !pData )
	{
		string e = boost::str( boost::format( "MeshTangentsOp : MeshPrimitive has no Vertex \"%s\" primitive variable." ) % pPrimVarName );
		throw InvalidArgumentException( e );
	}

	const IntVectorData * vertsPerFace = mesh->verticesPerFace();
	for ( IntVectorData::ValueType::const_iterator it = vertsPerFace->readable().begin(); it != vertsPerFace->readable().end(); ++it )
	{
		if ( *it != 3 )
		{
			throw InvalidArgumentException( "MeshTangentsOp : MeshPrimitive has non-triangular faces." );
		}
	}

	const std::string &uPrimVarName = uPrimVarNameParameter()->getTypedValue();
	const std::string &vPrimVarName = vPrimVarNameParameter()->getTypedValue();
	const std::string &uvIndicesPrimVarName = uvIndicesPrimVarNameParameter()->getTypedValue();

	FloatVectorDataPtr uData = mesh->variableData<FloatVectorData>( uPrimVarName, PrimitiveVariable::FaceVarying );
	if( !uData )
	{
		throw InvalidArgumentException( ( boost::format( "MeshTangentsOp : MeshPrimitive has no FaceVarying FloatVectorData primitive variable named \"%s\"."  ) % ( uPrimVarName ) ).str() );
	}

	FloatVectorDataPtr vData = mesh->variableData<FloatVectorData>( vPrimVarName, PrimitiveVariable::FaceVarying );
	if( !vData )
	{
		throw InvalidArgumentException( ( boost::format( "MeshTangentsOp : MeshPrimitive has no FaceVarying FloatVectorData primitive variable named \"%s\"."  ) % ( vPrimVarName ) ).str() );
	}

	ConstIntVectorDataPtr uvIndicesData = 0;
	if( uvIndicesPrimVarName=="" )
	{
		uvIndicesData = mesh->vertexIds();
	}
	else
	{
		uvIndicesData = mesh->variableData<IntVectorData>( uvIndicesPrimVarName, PrimitiveVariable::FaceVarying );
		if( !uvIndicesData )
		{
			throw InvalidArgumentException( ( boost::format( "MeshTangentsOp : MeshPrimitive has no FaceVarying IntVectorData primitive variable named \"%s\"."  ) % ( uvIndicesPrimVarName ) ).str() );
		}
	}
	
	DataCastOpPtr dco = new DataCastOp();
	dco->targetTypeParameter()->setNumericValue( FloatVectorDataTypeId );

	bool orthoTangents = orthogonalizeTangentsParameter()->getTypedValue();

	CalculateTangents f( vertsPerFace->readable(), mesh->vertexIds()->readable(), uData->readable(), vData->readable(), uvIndicesData->readable(), orthoTangents );

	despatchTypedData<CalculateTangents, TypeTraits::IsFloatVec3VectorTypedData, HandleErrors>( pData, f );

	mesh->variables[ uTangentPrimVarNameParameter()->getTypedValue() ] = PrimitiveVariable( PrimitiveVariable::FaceVarying, f.fvUTangentsData );
	mesh->variables[ vTangentPrimVarNameParameter()->getTypedValue() ] = PrimitiveVariable( PrimitiveVariable::FaceVarying, f.fvVTangentsData );

	assert( mesh->arePrimitiveVariablesValid() );
}