Exemple #1
0
Imath::Box3f StandardNodeGadget::bound() const
{
	Box3f b = IndividualContainer::bound();
	
	LinearContainer::Orientation orientation = inputNoduleContainer()->getOrientation();

	if( orientation == LinearContainer::X )
	{
		// enforce a minimum width
		float width = std::max( b.size().x, g_minWidth );
		float c = b.center().x;
		b.min.x = c - width / 2.0f;
		b.max.x = c + width / 2.0f;
	}
	
	// add the missing spacing to the border if we have no nodules on a given side
			
	Box3f inputContainerBound = inputNoduleContainer()->transformedBound( this );
	Box3f outputContainerBound = outputNoduleContainer()->transformedBound( this );
	if( inputContainerBound.isEmpty() )
	{
		if( orientation == LinearContainer::X )
		{
			b.max.y += g_spacing + g_borderWidth;
		}
		else
		{
			b.min.x -= g_spacing + g_borderWidth;		
		}
	}
	
	if( outputContainerBound.isEmpty() )
	{
		if( orientation == LinearContainer::X )
		{
			b.min.y -= g_spacing + g_borderWidth;
		}
		else
		{
			b.max.x += g_spacing + g_borderWidth;
		}
	}
	
	// add on a little bit in the major axis, so that the nodules don't get drawn in the frame corner
	
	if( orientation == LinearContainer::X )
	{
		b.min.x -= g_borderWidth;
		b.max.x += g_borderWidth;
	}
	else
	{
		b.min.y -= g_borderWidth;
		b.max.y += g_borderWidth;
	}
	
	return b;
}
Exemple #2
0
void StandardNodeGadget::doRender( const Style *style ) const
{
	// decide what state we're rendering in
	Gaffer::ConstScriptNodePtr script = node()->scriptNode();
	
	Style::State state = Style::NormalState;
	if( script && script->selection()->contains( node() ) )
	{
		state = Style::HighlightedState;
	}
	
	// draw 
	Box3f b = bound();

	LinearContainer::Orientation orientation = inputNoduleContainer()->getOrientation();
	
	Box3f inputContainerBound = inputNoduleContainer()->transformedBound( this );
	Box3f outputContainerBound = outputNoduleContainer()->transformedBound( this );
	
	if( !inputContainerBound.isEmpty() )
	{
		if( orientation == LinearContainer::X )
		{
			b.max.y -= inputContainerBound.size().y / 2.0f;
		}
		else
		{
			b.min.x += inputContainerBound.size().x / 2.0f;
		}
	}
	if( !outputContainerBound.isEmpty() )
	{
		if( orientation == LinearContainer::X )
		{
			b.min.y += outputContainerBound.size().y / 2.0f;
		}
		else
		{
			b.max.x -= outputContainerBound.size().x / 2.0f;		
		}
	}

	style->renderFrame( Box2f( V2f( b.min.x, b.min.y ) + V2f( g_borderWidth ), V2f( b.max.x, b.max.y ) - V2f( g_borderWidth ) ), g_borderWidth, state );
	
	NodeGadget::doRender( style );
	
	if( !m_nodeEnabled && !IECoreGL::Selector::currentSelector() )
	{
		/// \todo Replace renderLine() with a specific method (renderNodeStrikeThrough?) on the Style class
		/// so that styles can do customised drawing based on knowledge of what is being drawn.
		style->renderLine( IECore::LineSegment3f( V3f( b.min.x, b.min.y, 0 ), V3f( b.max.x, b.max.y, 0 ) ) );	
	}
}
void BackdropNodeGadget::frame( const std::vector<Gaffer::Node *> &nodes )
{
	GraphGadget *graph = ancestor<GraphGadget>();
	if( !graph )
	{
		return;
	}
	
	Box3f b;
	for( std::vector<Node *>::const_iterator it = nodes.begin(), eIt = nodes.end(); it != eIt; ++it )
	{
		NodeGadget *nodeGadget = graph->nodeGadget( *it );
		if( nodeGadget )
		{
			b.extendBy( nodeGadget->transformedBound( NULL ) );
		}
	}
	
	if( b.isEmpty() )
	{
		return;
	}
	
	graph->setNodePosition( node(), V2f( b.center().x, b.center().y ) );
	
	V2f s( b.size().x / 2.0f, b.size().y / 2.0f );
	
	boundPlug()->setValue(
		Box2f( 
			V2f( -s ) - V2f( g_margin ),
			V2f( s ) + V2f( g_margin + 2.0f * g_margin )
		)
	);
}
Exemple #4
0
bool intersectLine( const Box3f& box,
    const Vector3f& rayOrigin, const Vector3f& rayDirection,
    float& tNear, float& tFar )
{
    assert( box.isStandard() );
    assert( !box.isEmpty() );

    // Compute t to each face.
    Vector3f rcpDir = 1.0f / rayDirection;

    // Three "bottom" faces (min of the box).
    Vector3f tBottom = rcpDir * ( box.origin - rayOrigin );
    // three "top" faces (max of the box)
    Vector3f tTop = rcpDir * ( box.rightTopFront() - rayOrigin );

    // find the smallest and largest distances along each axis
    Vector3f tMin = libcgt::core::math::minimum( tBottom, tTop );
    Vector3f tMax = libcgt::core::math::maximum( tBottom, tTop );

    // tNear is the largest tMin
    tNear = libcgt::core::math::maximum( tMin );

    // tFar is the smallest tMax
    tFar = libcgt::core::math::minimum( tMax );

    return tFar > tNear;
}
Exemple #5
0
bool intersectRay( const Box3f& box,
    const Vector3f& rayOrigin, const Vector3f& rayDirection,
    float& tIntersect, float tMin )
{
    assert( box.isStandard() );
    assert( !box.isEmpty() );

    float tNear;
    float tFar;
    bool intersect = intersectLine( box, rayOrigin, rayDirection,
        tNear, tFar );
    if( intersect )
    {
        if( tNear >= tMin )
        {
            tIntersect = tNear;
        }
        else if( tFar >= tMin )
        {
            tIntersect = tFar;
        }
        else
        {
            intersect = false;
        }
    }
    return intersect;
}
Exemple #6
0
bool carefulIntersectBoxRay( const Box3f& box,
    const Vector3f& rayOrigin, const Vector3f& rayDirection,
    float& t0, float& t1, int& t0Face, int& t1Face,
    float rayTMin, float rayTMax )
{
    assert( box.isStandard() );
    assert( !box.isEmpty() );

    t0 = rayTMin;
    t1 = rayTMax;
    t0Face = -1;
    t1Face = -1;

    // Compute t to each face.
    Vector3f rcpDir = 1.0f / rayDirection;

    Vector3f boxMax = box.rightTopFront();

    for( int i = 0; i < 3; ++i )
    {
        // Compute the intersection between the line and the slabs along the
        // i-th axis, parameterized as [tNear, tFar].
        float rcpDir = 1.0f / rayDirection[ i ];
        float tNear = rcpDir * ( box.origin[ i ] - rayOrigin[ i ] );
        float tFar = rcpDir * ( boxMax[ i ] - rayOrigin[ i ] );

        // Which face we're testing against.
        int nearFace = 2 * i;
        int farFace = 2 * i + 1;

        // Swap such that tNear < tFAr.
        if( tNear > tFar )
        {
            std::swap( tNear, tFar );
            std::swap( nearFace, farFace );
        }

        // Compute the set intersection between [tNear, tFar] and [t0, t1].
        if( tNear > t0 )
        {
            t0 = tNear;
            t0Face = nearFace;
        }
        if( tFar < t1 )
        {
            t1 = tFar;
            t1Face = farFace;
        }

        // Early abort if the range is empty.
        if( t0 > t1 )
        {
            return false;
        }
    }

    return true;
}
void IECoreArnold::RendererImplementation::procedural( IECore::Renderer::ProceduralPtr proc )
{
	Box3f bound = proc->bound();
	if( bound.isEmpty() )
	{
		return;
	}

	AtNode *procedural = AiNode( "procedural" );

	if( ExternalProcedural *externalProc = dynamic_cast<ExternalProcedural *>( proc.get() ) )
	{
		AiNodeSetStr( procedural, "dso", externalProc->fileName().c_str() );
		ParameterAlgo::setParameters( procedural, externalProc->parameters() );
		applyTransformToNode( procedural );
	}
	else
	{

		// we have to transform the bound, as we're not applying the current transform to the
		// procedural node, but instead applying absolute transforms to the shapes the procedural
		// generates.
		if( bound != Procedural::noBound )
		{
			Box3f transformedBound;
			for( size_t i = 0, e = m_transformStack.numSamples(); i < e; ++i )
			{
				transformedBound.extendBy( transform( bound, m_transformStack.sample( i ) ) );
			}
			bound = transformedBound;
		}

		AiNodeSetPtr( procedural, "funcptr", (void *)procLoader );

		ProceduralData *data = new ProceduralData;
		data->procedural = proc;
		data->renderer = new IECoreArnold::Renderer( new RendererImplementation( *this ) );

		AiNodeSetPtr( procedural, "userptr", data );
	}

	if( bound != Procedural::noBound )
	{
		AiNodeSetPnt( procedural, "min", bound.min.x, bound.min.y, bound.min.z );
		AiNodeSetPnt( procedural, "max", bound.max.x, bound.max.y, bound.max.z );
	}
	else
	{
		// No bound available - expand procedural immediately.
		AiNodeSetBool( procedural, "load_at_init", true );
	}

	// we call addNode() rather than addShape() as we don't want to apply transforms and
	// shaders and attributes to procedurals. if we do, they override the things we set
	// on the nodes generated by the procedurals, which is frankly useless.
	addNode( procedural );
}
Exemple #8
0
Imath::Box3f Seeds::computeBranchBound( const ScenePath &parentPath, const ScenePath &branchPath, const Gaffer::Context *context ) const
{
	Box3f b =  inPlug()->bound( parentPath );
	if( !b.isEmpty() )
	{
		// The PointsPrimitive we make has a default point width of 1,
		// so we must expand our bounding box to take that into account.
		b.min -= V3f( 0.5 );
		b.max += V3f( 0.5 );
	}
	return b;
}
Exemple #9
0
void ImageView::preRender()
{
	if( m_framed )
	{
		return;
	}

	const Box3f b = m_imageGadget->bound();
	if( b.isEmpty() )
	{
		return;
	}

	viewportGadget()->frame( b );
	m_framed = true;
}
Exemple #10
0
bool Line::intersect( float angle, const Box3f& box ) const
{
	if (box.isEmpty())		return false;

	const Vec3f	&max = box.getMax(), &min = box.getMin();
	float		fuzz = 0.0;
	int			i;

	if (angle < 0.0)
	{
		fuzz = - angle;
	}
	else 
	{
		// Find the farthest point on the bounding box (where the pick
		// cone will be largest).  The amount of fuzz at this point will
		// be the minimum we can use.  Expand the box by that amount and
		// do an intersection.
		double tanA = tan(angle);
		for(i = 0; i < 8; i++) 
		{
			Vec3f point(i & 01 ? min[0] : max[0],
				  i & 02 ? min[1] : max[1],
				  i & 04 ? min[2] : max[2]);
			// how far is point from line origin??
			Vec3f	diff(point - getPosition());
			double	thisFuzz = sqrt(diff.dot(diff)) * tanA;

			if (thisFuzz > fuzz)
				fuzz = float(thisFuzz);
		}
	}

	Box3f fuzzBox = box;

	fuzzBox.extendBy(Vec3f(min[0] - fuzz, min[1] - fuzz, min[2] - fuzz));
	fuzzBox.extendBy(Vec3f(max[0] + fuzz, max[1] + fuzz, max[2] + fuzz));

	Vec3f scratch1, scratch2;
	return intersect(fuzzBox, scratch1, scratch2);
}
ConnectionCreator *StandardNodeGadget::closestDragDestination( const DragDropEvent &event ) const
{
	if( event.buttons != DragDropEvent::Left )
	{
		// See comments in StandardNodule::dragEnter()
		return nullptr;
	}

	ConnectionCreator *result = nullptr;
	float maxDist = Imath::limits<float>::max();

	for( RecursiveConnectionCreatorIterator it( this ); !it.done(); it++ )
	{
		if( !(*it)->getVisible() )
		{
			it.prune();
			continue;
		}
		if( !canConnect( event, it->get() ) )
		{
			continue;
		}

		const Box3f bound = (*it)->transformedBound( this );
		if( bound.isEmpty() )
		{
			continue;
		}

		const V3f closestPoint = closestPointOnBox( event.line.p0, bound );
		const float dist = ( closestPoint - event.line.p0 ).length2();
		if( dist < maxDist )
		{
			result = it->get();
			maxDist = dist;
		}
	}

	return result;
}
Exemple #12
0
bool Line::intersect( const Box3f& box, Vec3f& enter, Vec3f& exit ) const
{
	if (box.isEmpty())
	{
		return false;
	}

	const Vec3f	&pos = getPosition(), &dir = getDirection();
	const Vec3f	&max = box.getMax(), &min = box.getMin();
	Vec3f		points[8], inter, bary;
	Plane		plane;
	int		i, v0, v1, v2;
	bool		front = false, valid, validIntersection = false;

	//
	// First, check the distance from the ray to the center
	// of the box.  If that distance is greater than 1/2
	// the diagonal distance, there is no intersection
	// diff is the vector from the closest point on the ray to the center
	// dist2 is the square of the distance from the ray to the center
	// radi2 is the square of 1/2 the diagonal length of the bounding box
	//
	float	t = (box.getCenter() - pos).dot(dir);
	Vec3f	diff(pos + dir * t - box.getCenter());
	float	dist2 = diff.dot(diff);
	float	radi2 = (max - min).dot(max - min) * 0.25f;

	if (dist2 > radi2)
	{
		return false;
	}

	// set up the eight coords of the corners of the box
	for(i = 0; i < 8; i++)
	{
		points[i].setValue(i & 01 ? min[0] : max[0],
				   i & 02 ? min[1] : max[1],
				   i & 04 ? min[2] : max[2]);
	}

	// intersect the 12 triangles.
	for(i = 0; i < 12; i++) 
	{
		switch(i) 
		{
		case  0: v0 = 2; v1 = 1; v2 = 0; break;		// +z
		case  1: v0 = 2; v1 = 3; v2 = 1; break;

		case  2: v0 = 4; v1 = 5; v2 = 6; break;		// -z
		case  3: v0 = 6; v1 = 5; v2 = 7; break;

		case  4: v0 = 0; v1 = 6; v2 = 2; break;		// -x
		case  5: v0 = 0; v1 = 4; v2 = 6; break;

		case  6: v0 = 1; v1 = 3; v2 = 7; break;		// +x
		case  7: v0 = 1; v1 = 7; v2 = 5; break;

		case  8: v0 = 1; v1 = 4; v2 = 0; break;		// -y
		case  9: v0 = 1; v1 = 5; v2 = 4; break;

		case 10: v0 = 2; v1 = 7; v2 = 3; break;		// +y
		case 11: v0 = 2; v1 = 6; v2 = 7; break;

		default:
			assert(false && "Must never happened");
			v0 = v1 = v2 = 0; // to remove a warning.
		}

		valid = intersect(	points[v0], points[v1], points[v2],
									inter, bary, front);

		if ( valid )
		{
			if	(front) 
			{
				enter = inter;
				validIntersection = valid;
			}
			else
			{
				exit = inter;
				validIntersection = valid;
			}
		}
	}

	return validIntersection;
}
void IECoreArnold::RendererImplementation::procedural( IECore::Renderer::ProceduralPtr proc )
{
	Box3f bound = proc->bound();
	if( bound.isEmpty() )
	{
		return;
	}

	AtNode *node = NULL;
	std::string nodeType = "procedural";

	if( const ExternalProcedural *externalProc = dynamic_cast<ExternalProcedural *>( proc.get() ) )
	{
		// Allow a parameter "ai:nodeType" == "volume" to create a volume shape rather
		// than a procedural shape. Volume shapes provide "dso", "min" and "max" parameters
		// just as procedural shapes do, so the mapping is a fairly natural one.
		CompoundDataMap::const_iterator nodeTypeIt = externalProc->parameters().find( "ai:nodeType" );
		if( nodeTypeIt != externalProc->parameters().end() && nodeTypeIt->second->isInstanceOf( StringData::staticTypeId() ) )
		{
			nodeType = static_cast<const StringData *>( nodeTypeIt->second.get() )->readable();
		}
		node = AiNode( nodeType.c_str() );

		AiNodeSetStr( node, "dso", externalProc->fileName().c_str() );
		ParameterAlgo::setParameters( node, externalProc->parameters() );
		applyTransformToNode( node );
	}
	else
	{
		node = AiNode( nodeType.c_str() );

		// we have to transform the bound, as we're not applying the current transform to the
		// procedural node, but instead applying absolute transforms to the shapes the procedural
		// generates.
		if( bound != Procedural::noBound )
		{
			Box3f transformedBound;
			for( size_t i = 0, e = m_transformStack.numSamples(); i < e; ++i )
			{
				transformedBound.extendBy( transform( bound, m_transformStack.sample( i ) ) );
			}
			bound = transformedBound;
		}

		AiNodeSetPtr( node, "funcptr", (void *)procLoader );

		ProceduralData *data = new ProceduralData;
		data->procedural = proc;
		data->renderer = new IECoreArnold::Renderer( new RendererImplementation( *this ) );

		AiNodeSetPtr( node, "userptr", data );
	}

	if( bound != Procedural::noBound )
	{
		AiNodeSetPnt( node, "min", bound.min.x, bound.min.y, bound.min.z );
		AiNodeSetPnt( node, "max", bound.max.x, bound.max.y, bound.max.z );
	}
	else
	{
		// No bound available - expand procedural immediately.
		AiNodeSetBool( node, "load_at_init", true );
	}

	if( nodeType == "procedural" )
	{
		// We call addNode() rather than addShape() as we don't want to apply transforms and
		// shaders and attributes to procedurals. If we do, they override the things we set
		// on the nodes generated by the procedurals, which is frankly useless.
		addNode( node );
	}
	else
	{
		addShape( node );
	}
}
void LinearContainer::calculateChildTransforms() const
{
	if( m_clean )
	{
		return;
	}

	int axis = m_orientation - 1;
	V3f size( 0 );
	vector<Box3f> bounds;
	for( ChildContainer::const_iterator it=children().begin(); it!=children().end(); it++ )
	{
		const Gadget *child = static_cast<const Gadget *>( it->get() );
		if( !child->getVisible() )
		{
			continue;
		}

		Box3f b = child->bound();
		if( !b.isEmpty() )
		{
			for( int a=0; a<3; a++ )
			{
				if( a==axis )
				{
					size[a] += b.size()[a];
				}
				else
				{
					size[a] = max( size[a], b.size()[a] );
				}
			}
		}
		bounds.push_back( b );
	}
	size[axis] += (bounds.size() - 1) * m_spacing;

	float offset = size[axis] / 2.0f  * ( m_direction==Increasing ? -1.0f : 1.0f );

	int i = 0;
	for( ChildContainer::const_iterator it=children().begin(); it!=children().end(); it++ )
	{
		Gadget *child = static_cast<Gadget *>( it->get() );
		if( !child->getVisible() )
		{
			continue;
		}

		const Box3f &b = bounds[i++];

		V3f childOffset( 0 );
		if( !b.isEmpty() )
		{
			for( int a=0; a<3; a++ )
			{
				if( a==axis )
				{
					childOffset[a] = offset - ( m_direction==Increasing ? b.min[a] : b.max[a] );
				}
				else
				{
					switch( m_alignment )
					{
						case Min :
							childOffset[a] = -size[a]/2.0f - b.min[a];
							break;
						case Centre :
							childOffset[a] = -b.center()[a];
							break;
						default :
							// max
							childOffset[a] = size[a]/2.0f - b.max[a];
					}
				}
			}
			offset += b.size()[axis] * ( m_direction==Increasing ? 1.0f : -1.0f );
		}
		offset += m_spacing * ( m_direction==Increasing ? 1.0f : -1.0f );

		M44f m; m.translate( childOffset );
		child->setTransform( m );
	}

	m_clean = true;
}