Beispiel #1
0
CqLightsource::CqLightsource( const boost::shared_ptr<IqShader>& pShader, bool fActive ) :
		m_pShader( pShader ),
		m_pAttributes(),
		m_pTransform(),
		m_pShaderExecEnv(IqShaderExecEnv::create(QGetRenderContextI()))
{
	// Set a reference with the current attributes.
	m_pAttributes = QGetRenderContext() ->pattrCurrent();

	m_pShader->SetType(Type_Lightsource);
	m_pTransform = QGetRenderContext() ->ptransCurrent();
}
void CqImageBuffer::RenderImage()
{
	////////// Create a new dump file  //////////
#if ENABLE_MPDUMP
	const TqInt* poptDump = QGetRenderContext() ->poptCurrent()->GetIntegerOption( "mpdump", "enabled" );
	if(poptDump && (*poptDump != 0))
	{
		m_mpdump.open();
		m_mpdump.dumpImageInfo();
	}
#endif
	/////////////////////////////////////////////

	STATS_SETF( MPG_min_area, FLT_MAX );
	STATS_SETF( MPG_max_area, FLT_MIN );

	if ( bucketmodulo == -1 )
	{
		// Small change which allows full control of virtual memory on NT swapping
		bucketmodulo = m_cXBuckets;
		TqInt *poptModulo = ( TqInt * ) QGetRenderContext() ->poptCurrent()->GetIntegerOption( "limits", "bucketmodulo" );
		if ( poptModulo != 0 )
		{
			bucketmodulo = poptModulo[ 0 ];
		}
		if ( bucketmodulo <= 0 )
			bucketmodulo = m_cXBuckets;
	}

	// Render the surface at the front of the list.
	RtProgressFunc pProgressHandler = NULL;
	pProgressHandler = QGetRenderContext()->pProgressHandler();

	const CqString* pstrBucketOrder = QGetRenderContext() ->poptCurrent()->GetStringOption( "render", "bucketorder" );
	enum EqBucketOrder order = Bucket_Horizontal;
	if ( NULL != pstrBucketOrder )
	{
	if( !pstrBucketOrder[ 0 ].compare( "vertical" ) )
		order = Bucket_Vertical;
	else if ( !pstrBucketOrder[ 0 ].compare( "horizontal" ) )
		order = Bucket_Horizontal;
	else {
		Aqsis::log() << warning << "Not supported \"" << pstrBucketOrder[ 0 ] << "\" " << std::endl;
	}
#ifdef NOTREADY
	else if ( !pstrBucketOrder[ 0 ].compare( "zigzag" ) )
		order = Bucket_ZigZag;
	else if ( !pstrBucketOrder[ 0 ].compare( "circle" ) )
		order = Bucket_Circle;
	else if ( !pstrBucketOrder[ 0 ].compare( "random" ) )
		order = Bucket_Random;
#endif
	}
Beispiel #3
0
void CqTransform::SetCurrentTransform( TqFloat time, const CqMatrix& matTrans )
{
	TqFloat det = matTrans.Determinant();
	bool flip = ( !matTrans.fIdentity() && det < 0 );

	SqTransformation ct;
	ct.m_matTransform = matTrans;
	ct.m_Handedness = !flip;

	if ( QGetRenderContext() ->pconCurrent() ->fMotionBlock() )
	{
		AddTimeSlot( time, ct );
		m_IsMoving = true;
	}
	else
	{
		if( m_IsMoving )
		{
			AddTimeSlot( time, ct );
		}
		else
		{
			m_StaticMatrix = matTrans;
			m_Handedness = (flip)? !m_Handedness : m_Handedness;
			//m_Handedness = flip;
			ct.m_Handedness = flip;
			SetDefaultObject( ct );
		}
	}
}
Beispiel #4
0
void CqTransform::ConcatCurrentTransform( TqFloat time, const CqMatrix& matTrans )
{
	TqFloat det = matTrans.Determinant();
	bool flip = ( !matTrans.fIdentity() && det < 0 );

	SqTransformation ct;
	ct.m_matTransform = matTrans;
	ct.m_Handedness = (flip)? !m_Handedness : m_Handedness;

	// If we are actually in a motion block, and we already describe a moving transform,
	// concatenate this transform with the existing one at that time slot,
	// ConcatTimeSlot will take care of making sure that the matrix is initially set to the
	// static matrix, as long as we ensure that the default is kept up to date.
	if ( QGetRenderContext() ->pconCurrent() ->fMotionBlock() )
	{
		ConcatTimeSlot( time, ct );
		m_IsMoving = true;
	}
	else
		// else, if we are moving, apply this transform at all time slots, otherwise apply to static matrix.
	{
		if( m_IsMoving )
			ConcatAllTimeSlots( ct );
		else
		{
			m_StaticMatrix = m_StaticMatrix * matTrans;
			m_Handedness = (flip)? !m_Handedness : m_Handedness;
			ct.m_Handedness = m_Handedness;
			SetDefaultObject( ct );
		}
	}
}
Beispiel #5
0
void CqTransform::SetTransform( TqFloat time, const CqMatrix& matTrans )
{
	TqFloat det = matTrans.Determinant();
	bool flip = ( !matTrans.fIdentity() && det < 0 );
	CqMatrix matCtoW;
	QGetRenderContext()->matSpaceToSpace("world", "camera", NULL, NULL, QGetRenderContext()->Time(), matCtoW);
	TqFloat camdet = matCtoW.Determinant();
	bool camhand = ( !matCtoW.fIdentity() && camdet < 0 );

	if ( QGetRenderContext() ->pconCurrent() ->fMotionBlock() )
	{
		SqTransformation ct;
		ct.m_Handedness = (flip)? !camhand : camhand;
		ct.m_matTransform = matTrans;
		AddTimeSlot( time, ct );
		m_IsMoving = true;
	}
	else
	{
		// If not in a motion block, but we are moving, apply the transform to all keys.
		if( m_IsMoving )
		{
			CqMatrix mat0 = matObjectToWorld(Time(0));

			SqTransformation ct;
			ct.m_Handedness = (flip)? !camhand : camhand;
			bool hand0 = ct.m_Handedness;
			ct.m_matTransform = matTrans;

			AddTimeSlot( Time(0), ct );
			TqInt i;
			for(i=1; i<cTimes(); i++)
			{
				CqMatrix matOffset = mat0 * matObjectToWorld(Time(i)).Inverse();
				ct.m_matTransform = matOffset * matTrans;
				bool flip2 = ( matOffset.Determinant() < 0 );
				ct.m_Handedness = (flip2)? !hand0 : hand0;
				AddTimeSlot( Time(i), ct);
			}
		}
		else
		{
			m_StaticMatrix = matTrans;
			m_Handedness = (flip)? !camhand : camhand;
		}
	}
}
IqTextureMapOld* CqTextureMapOld::GetLatLongMap( const CqString& strName )
{
	QGetRenderContext() ->Stats().IncTextureMisses( 2 );

	TqUlong hash = CqString::hash(strName.c_str());

	// First search the texture map cache
	for ( std::vector<CqTextureMapOld*>::iterator i = m_TextureMap_Cache.begin(); i != m_TextureMap_Cache.end(); i++ )
	{
		if ( ( *i ) ->m_hash == hash )
		{
			if ( ( *i ) ->Type() == MapType_LatLong )
			{
				QGetRenderContext() ->Stats().IncTextureHits( 1, 2 );
				return ( *i );
			} else
			{
				return NULL;
			}
		}
	}

	QGetRenderContext() ->Stats().IncTextureHits( 0, 2 );

	// If we got here, it doesn't exist yet, so we must create and load it.
	CqTextureMapOld* pNew = new CqLatLongMapOld( strName );
	m_TextureMap_Cache.push_back( pNew );
	pNew->Open();

	TqPchar ptexfmt;

	// Invalid only if this is not a LatLong Env. map file
	if ( pNew->m_pImage == 0 ||
	        TIFFGetField( pNew->m_pImage, TIFFTAG_PIXAR_TEXTUREFORMAT, &ptexfmt ) != 1 ||
	        strcmp( ptexfmt, LATLONG_HEADER ) != 0 )
	{
		static bool done = false;
		if (!done)
		{
			Aqsis::log() << error << "Map \"" << strName.c_str() << "\" is not an environment map, use RiMakeLatLongEnvironment" << std::endl;
			done = true;
		}

		pNew->SetInvalid();
   	}
	return ( pNew );
}
CqImagersource::CqImagersource( const boost::shared_ptr<IqShader>& pShader, bool fActive ) :
		m_pShader( pShader ),
		m_pAttributes(), 
		m_pShaderExecEnv(IqShaderExecEnv::create(QGetRenderContextI()))
{
	m_pAttributes = QGetRenderContext()->pattrCurrent();
	m_pShader->SetType(Type_Imager);
}
/** Delete the object context.
 * \attention This is the only valid context deletion from within this block.
 */
void CqMotionModeBlock::EndMotionModeBlock()
{
	if( m_pDeformingSurface )
	{
		QGetRenderContext()->StorePrimitive( m_pDeformingSurface );
		STATS_INC( GPR_created );
	}
}
Beispiel #9
0
// Dump global information about the image
void CqMPDump::dumpImageInfo()
{
	short id = 3;

	if (m_outFile==NULL)
	{
		Aqsis::log() << error << "Attempted to write to unopened mpdump file." << std::endl;
		return;
	}

	int width = QGetRenderContext() ->poptCurrent()->GetIntegerOption( "System", "Resolution" ) [ 0 ];
	int height = QGetRenderContext() ->poptCurrent()->GetIntegerOption( "System", "Resolution" ) [ 1 ];
	size_t len_written = fwrite((void*)&id, sizeof(short), 1, m_outFile);
	len_written += fwrite((void*)&width, sizeof(int), 1, m_outFile);
	len_written += fwrite((void*)&height, sizeof(int), 1, m_outFile);
	if(len_written != 3)
		AQSIS_THROW_XQERROR(XqInvalidFile, EqE_System,
				"Error writing mpdump file");
}
Beispiel #10
0
/** Initialise the default object.
 */
void	CqTransform::InitialiseDefaultObject( const CqTransformPtr& From )
{
	// Get the state of the transformation at the last stack entry, and use this as the default value for new timeslots.
	// if the previous level has motion specification, the value will be interpolated.
	TqFloat time = QGetRenderContext()->Time();
	CqMatrix matOtoWLast =  From->matObjectToWorld( time );
	bool handLast =  From->GetHandedness( time );

	SqTransformation ct;
	ct.m_Handedness = handLast;
	ct.m_matTransform = matOtoWLast;
	SetDefaultObject( ct );
}
Beispiel #11
0
/**
 * Returns the approximate "length" of an edge of a grid in raster space.
 *
 * @return Approximate grid length.
 */
TqFloat CqCurve::GetGridLength() const
{
	// we want to find the number of micropolygons per grid - the default
	//  is 256 (16x16 micropolygon grid).
	TqFloat micropolysPerGrid = 256;
	const TqInt* poptGridSize =
	    QGetRenderContext() ->poptCurrent()->GetIntegerOption(
	        "limits", "gridsize"
	    );
	if ( poptGridSize != NULL )
		micropolysPerGrid = poptGridSize[0];

	// Assuming the grid is square, the side length of the grid in raster space
	// is the following.
	// TODO: this assumption may be pretty bad for RiCurves!
	return sqrt(micropolysPerGrid * AdjustedShadingRate());
}
Beispiel #12
0
/** Initialise the environment for the specified grid size.
 * \param iGridRes Integer grid resolution.
 * \param iGridRes Integer grid resolution.
 */
void CqLightsource::Initialise( TqInt uGridRes, TqInt vGridRes, TqInt microPolygonCount, TqInt shadingPointCount, bool hasValidDerivatives )
{
	TqInt Uses = gDefLightUses;
	if ( m_pShader )
	{
		Uses |= m_pShader->Uses();
		m_pShaderExecEnv->Initialise( uGridRes, vGridRes, microPolygonCount, shadingPointCount, hasValidDerivatives, m_pAttributes, boost::shared_ptr<IqTransform>(), m_pShader.get(), Uses );
	}

	if ( m_pShader )
		m_pShader->Initialise( uGridRes, vGridRes, shadingPointCount, m_pShaderExecEnv.get() );

	if ( USES( Uses, EnvVars_L ) )
		L() ->Initialise( shadingPointCount );
	if ( USES( Uses, EnvVars_Cl ) )
		Cl() ->Initialise( shadingPointCount );

	// Initialise the geometric parameters in the shader exec env.
	if ( USES( Uses, EnvVars_P ) )
	{
		CqMatrix mat;
		QGetRenderContext() ->matSpaceToSpace( "shader", "current", m_pShader->getTransform(), NULL, QGetRenderContextI()->Time(), mat );
		P() ->SetPoint( mat * CqVector3D( 0.0f, 0.0f, 0.0f ) );
	}
	if ( USES( Uses, EnvVars_u ) )
		u() ->SetFloat( 0.0f );
	if ( USES( Uses, EnvVars_v ) )
		v() ->SetFloat( 0.0f );
	if ( USES( Uses, EnvVars_du ) )
		du() ->SetFloat( 0.0f );
	if ( USES( Uses, EnvVars_dv ) )
		dv() ->SetFloat( 0.0f );
	if ( USES( Uses, EnvVars_s ) )
		s() ->SetFloat( 0.0f );
	if ( USES( Uses, EnvVars_t ) )
		t() ->SetFloat( 0.0f );
	if ( USES( Uses, EnvVars_N ) )
		N() ->SetNormal( CqVector3D( 0.0f, 0.0f, 0.0f ) );
}
Beispiel #13
0
//---------------------------------------------------------------------
void CqImagersource::Initialise( const CqRegion& DRegion, IqChannelBuffer* buffer )
{
	AQSIS_TIME_SCOPE(Imager_shading);

	// We use one less than the bucket width and height here, since these
	// resolutions really represent one less than the number of shaded points
	// in each direction.  (Usually they describe the number of micropolygons
	// on a grid which is one less than the number of shaded vertices.  This
	// concept has no real analogue in context of an imager shader.)
	TqInt uGridRes = DRegion.width()-1;
	TqInt vGridRes = DRegion.height()-1;
	TqInt x = DRegion.xMin();
	TqInt y = DRegion.yMin();

	m_uYOrigin = static_cast<TqInt>( y );
	m_uXOrigin = static_cast<TqInt>( x );
	m_uGridRes = uGridRes;
	m_vGridRes = vGridRes;

	TqInt mode = QGetRenderContext() ->poptCurrent()->GetIntegerOption( "System", "DisplayMode" ) [ 0 ];
	TqFloat components;
	TqInt j, i;
	TqFloat shuttertime = QGetRenderContext() ->poptCurrent()->GetFloatOption( "System", "Shutter" ) [ 0 ];

	components = mode & DMode_RGB ? 3 : 0;
	components += mode & DMode_A ? 1 : 0;
	components = mode & DMode_Z ? 1 : components;

	TqInt Uses = ( 1 << EnvVars_P ) | ( 1 << EnvVars_Ci ) | ( 1 << EnvVars_Oi | ( 1 << EnvVars_ncomps ) | ( 1 << EnvVars_time ) | ( 1 << EnvVars_alpha ) | ( 1 << EnvVars_s ) | ( 1 << EnvVars_t ) );

	m_pShaderExecEnv->Initialise( uGridRes, vGridRes, uGridRes * vGridRes, (uGridRes+1)*(vGridRes+1), true, IqAttributesPtr(), IqTransformPtr(), m_pShader.get(), Uses );

	// Initialise the geometric parameters in the shader exec env.

	TqInt numShadingPoints = (uGridRes+1) * (vGridRes+1);
	P() ->Initialise( numShadingPoints );
	Ci() ->Initialise( numShadingPoints );
	Oi() ->Initialise( numShadingPoints );
	alpha() ->Initialise( numShadingPoints );
	s() ->Initialise( numShadingPoints );
	t() ->Initialise( numShadingPoints );

	//TODO dtime is not initialised yet
	//dtime().Initialise(uGridRes, vGridRes, i);

	ncomps() ->SetFloat( components );
	time() ->SetFloat( shuttertime );

	m_pShader->Initialise( uGridRes, vGridRes, (uGridRes+1)*(vGridRes+1), m_pShaderExecEnv.get() );

	TqUint CiIndex = buffer->getChannelIndex("Ci");
	TqUint OiIndex = buffer->getChannelIndex("Oi");
	TqUint coverageIndex = buffer->getChannelIndex("coverage");
	for ( j = 0; j < vGridRes+1; j++ )
	{
		for ( i = 0; i < uGridRes+1; i++ )
		{
			TqInt off = j * ( uGridRes + 1 ) + i;
			P() ->SetPoint( CqVector3D( x + i, y + j, 0.0 ), off );
			Ci() ->SetColor( CqColor((*buffer)(i, j, CiIndex)[0], (*buffer)(i, j, CiIndex)[1], (*buffer)(i, j, CiIndex)[2]), off );
			CqColor opa((*buffer)(i, j, OiIndex)[0], (*buffer)(i, j, OiIndex)[1], (*buffer)(i, j, OiIndex)[2]);
			Oi() ->SetColor( opa, off );
			TqFloat avopa = ( opa.r() + opa.g() + opa.b() ) /3.0f;
			alpha() ->SetFloat( (*buffer)(i, j, coverageIndex)[0] * avopa, off );
			s() ->SetFloat( x + i + 0.5, off );
			t() ->SetFloat( y + j + 0.5, off );
		}
	}
	// Execute the Shader VM
	if ( m_pShader )
	{
		m_pShader->Evaluate( m_pShaderExecEnv.get() );
		alpha() ->SetFloat( 1.0f ); /* by default 3delight/bmrt set it to 1.0 */
	}
}
IqTextureMapOld* CqTextureMapOld::GetEnvironmentMap( const CqString& strName )
{
	QGetRenderContext() ->Stats().IncTextureMisses( 1 );

	TqUlong hash = CqString::hash(strName.c_str());

	// First search the texture map cache
	for ( std::vector<CqTextureMapOld*>::iterator i = m_TextureMap_Cache.begin(); i != m_TextureMap_Cache.end(); i++ )
	{
		if ( ( *i ) ->m_hash == hash )
		{
			if ( ( *i ) ->Type() == MapType_Environment )
			{
				QGetRenderContext() ->Stats().IncTextureHits( 1, 1 );
				return ( *i );
			} else
			{
				return NULL;
			}
		}
	}

	QGetRenderContext() ->Stats().IncTextureHits( 0, 1 );

	// If we got here, it doesn't exist yet, so we must create and load it.
	CqTextureMapOld* pNew = new CqEnvironmentMapOld( strName );
	m_TextureMap_Cache.push_back( pNew );
	pNew->Open();

	TqPchar ptexfmt = 0;

	// Invalid if the m_pImage is not there or it is not cube or latlong env. map file
	if ( pNew->m_pImage == 0 ||
	        TIFFGetField( pNew->m_pImage, TIFFTAG_PIXAR_TEXTUREFORMAT, &ptexfmt ) != 1 ||
	        ( strcmp( ptexfmt, CUBEENVMAP_HEADER ) != 0 ) && ( strcmp( ptexfmt, LATLONG_HEADER ) != 0 ) )
	{
		static bool done = false;
		if (!done)
		{
			Aqsis::log() << error << "Map \"" << strName.c_str() << "\" is not an environment map, use RiMakeCubeFaceEnvironment" << std::endl;
			done = true;
		}
		pNew->SetInvalid();
		delete pNew;
		pNew = NULL;

	}
	else
	{
		TqFloat fov;
		if (TIFFGetField( pNew->m_pImage, TIFFTAG_PIXAR_FOVCOT, &fov) == 1)
			((CqEnvironmentMapOld *)pNew)->SetFov(fov);
		else
			((CqEnvironmentMapOld *)pNew)->SetFov(1.0);
	}

	// remove from the list a LatLong env. map since in shadeops.cpp we will cope with it.
	if ( ptexfmt && strcmp( ptexfmt, LATLONG_HEADER ) == 0 )
	{
		pNew->SetInvalid();
		delete pNew;
		pNew = NULL;
   	} 
   
	return ( pNew );
}
void CqImageBuffer::PostSurface( const boost::shared_ptr<CqSurface>& pSurface )
{
	AQSIS_TIME_SCOPE(Post_surface);
	// Count the number of total gprims
	STATS_INC( GPR_created_total );

	// Bound the primitive in its current space (camera) space taking into account any motion specification.
	CqBound Bound;
	pSurface->Bound(&Bound);

	// Take into account the displacement bound extension.
	TqFloat db = 0.0f;
	CqString strCoordinateSystem( "object" );
	const TqFloat* pattrDispclacementBound = pSurface->pAttributes() ->GetFloatAttribute( "displacementbound", "sphere" );
	const CqString* pattrCoordinateSystem = pSurface->pAttributes() ->GetStringAttribute( "displacementbound", "coordinatesystem" );
	if ( pattrDispclacementBound != 0 )
		db = pattrDispclacementBound[ 0 ];
	if ( pattrCoordinateSystem != 0 )
		strCoordinateSystem = pattrCoordinateSystem[ 0 ];

	if ( db != 0.0f )
	{
		CqVector3D	vecDB( db, 0, 0 );
		const IqTransform* transShaderToWorld = NULL;
		// Default "shader" space to the displacement shader, unless there isn't one, in which
		// case use the surface shader.
		if ( pSurface->pAttributes() ->pshadDisplacement(QGetRenderContextI()->Time()) )
			transShaderToWorld = pSurface->pAttributes() ->pshadDisplacement(QGetRenderContextI()->Time()) ->getTransform();
		else if ( pSurface->pAttributes() ->pshadSurface(QGetRenderContextI()->Time()) )
			transShaderToWorld = pSurface->pAttributes() ->pshadSurface(QGetRenderContextI()->Time()) ->getTransform();
		CqMatrix mat;
		QGetRenderContext() ->matVSpaceToSpace( strCoordinateSystem.c_str(), "camera", transShaderToWorld, pSurface->pTransform().get(), QGetRenderContextI()->Time(), mat );
		vecDB = mat * vecDB;
		db = vecDB.Magnitude();

		Bound.vecMax() += db;
		Bound.vecMin() -= db;
	}

	// Check if the surface can be culled. (also adjusts for DOF and converts Bound to raster space).
	if ( CullSurface( Bound, pSurface ) )
	{
		STATS_INC( GPR_culled );
		return ;
	}

	// If the primitive has been marked as undiceable by the eyeplane check, then we cannot get a valid
	// bucket index from it as the projection of the bound would cross the camera plane and therefore give a false
	// result, so just put it back in the current bucket for further splitting.
	TqInt XMinb = 0;
	TqInt YMinb = 0;
	TqInt XMaxb = 0;
	TqInt YMaxb = 0;
	if (! pSurface->IsUndiceable() )
	{
		XMinb = static_cast<TqInt>( Bound.vecMin().x() ) / m_optCache.xBucketSize;
		YMinb = static_cast<TqInt>( Bound.vecMin().y() ) / m_optCache.yBucketSize;
		XMaxb = static_cast<TqInt>( Bound.vecMax().x() ) / m_optCache.xBucketSize;
		YMaxb = static_cast<TqInt>( Bound.vecMax().y() ) / m_optCache.yBucketSize;
	}
	XMinb = clamp( XMinb, m_bucketRegion.xMin(), m_bucketRegion.xMax()-1 );
	YMinb = clamp( YMinb, m_bucketRegion.yMin(), m_bucketRegion.yMax()-1 );
	XMaxb = clamp( XMaxb, m_bucketRegion.xMin(), m_bucketRegion.xMax()-1 );
	YMaxb = clamp( YMaxb, m_bucketRegion.yMin(), m_bucketRegion.yMax()-1 );

	// Sanity check we are not putting into a bucket that has already been processed.
	CqBucket* bucket = &Bucket( XMinb, YMinb );
	if ( bucket->IsProcessed() )
	{
		// Scan over the buckets that the bound touches, looking for the first one that isn't processed.
		TqInt yb = YMinb;
		TqInt xb = XMinb + 1;
		bool done = false;
		while(!done && yb <= YMaxb)
		{
			while(!done && xb <= XMaxb)
			{
				CqBucket& availBucket = Bucket(xb, yb);
				if(!availBucket.IsProcessed())
				{
					availBucket.AddGPrim(pSurface);
					done = true;
				}
				++xb;
			}
			xb = XMinb;
			++yb;
		}
	}
	else
	{
		bucket->AddGPrim( pSurface );
	}
}
void CqImageBuffer::AddMPG( boost::shared_ptr<CqMicroPolygon>& pmpgNew )
{
	CqRenderer* renderContext = QGetRenderContext();
	CqBound B = pmpgNew->GetBound();

	// Expand the micropolygon bound for DoF if necessary.
	if(renderContext->UsingDepthOfField())
	{
		// Get the maximum CoC multiplier for the micropolygon depth.
		const CqVector2D maxCoC = max(
			renderContext->GetCircleOfConfusion(B.vecMin().z()),
			renderContext->GetCircleOfConfusion(B.vecMax().z())
		);
		// Expand the bound by the CoC radius
		B.vecMin() -= vectorCast<CqVector3D>(maxCoC);
		B.vecMax() += vectorCast<CqVector3D>(maxCoC);
	}

	// Discard when outside the crop window.
	if ( B.vecMax().x() < renderContext->cropWindowXMin() - m_optCache.xFiltSize / 2.0f ||
	     B.vecMax().y() < renderContext->cropWindowYMin() - m_optCache.yFiltSize / 2.0f ||
	     B.vecMin().x() > renderContext->cropWindowXMax() + m_optCache.xFiltSize / 2.0f ||
	     B.vecMin().y() > renderContext->cropWindowYMax() + m_optCache.yFiltSize / 2.0f )
	{
		return;
	}

	////////// Dump the micro polygon into a dump file //////////
#if ENABLE_MPDUMP
	if(m_mpdump.IsOpen())
		m_mpdump.dump(*pmpgNew);
#endif
	/////////////////////////////////////////////////////////////


	// Find out the minimum bucket touched by the micropoly bound.

	B.vecMin().x( B.vecMin().x() - (lfloor(m_optCache.xFiltSize / 2.0f)) );
	B.vecMin().y( B.vecMin().y() - (lfloor(m_optCache.yFiltSize / 2.0f)) );
	B.vecMax().x( B.vecMax().x() + (lfloor(m_optCache.xFiltSize / 2.0f)) );
	B.vecMax().y( B.vecMax().y() + (lfloor(m_optCache.yFiltSize / 2.0f)) );

	TqInt iXBa = static_cast<TqInt>( B.vecMin().x() / m_optCache.xBucketSize );
	TqInt iYBa = static_cast<TqInt>( B.vecMin().y() / m_optCache.yBucketSize );
	TqInt iXBb = static_cast<TqInt>( B.vecMax().x() / m_optCache.xBucketSize );
	TqInt iYBb = static_cast<TqInt>( B.vecMax().y() / m_optCache.yBucketSize );

	if ( ( iXBb < m_bucketRegion.xMin() ) || ( iYBb < m_bucketRegion.yMin() ) ||
	        ( iXBa >= m_bucketRegion.xMax() ) || ( iYBa >= m_bucketRegion.yMax() ) )
	{
		return ;
	}

	// Use sane values -- otherwise sometimes crashes, probably
	// due to precision problems
	if ( iXBa < m_bucketRegion.xMin() )  iXBa = m_bucketRegion.xMin();
	if ( iYBa < m_bucketRegion.yMin() )  iYBa = m_bucketRegion.yMin();
	if ( iXBb >= m_bucketRegion.xMax() )  iXBb = m_bucketRegion.xMax() - 1;
	if ( iYBb >= m_bucketRegion.yMax() )  iYBb = m_bucketRegion.yMax() - 1;

	// Add the MP to all the Buckets that it touches
	for ( TqInt i = iXBa; i <= iXBb; i++ )
	{
		for ( TqInt j = iYBa; j <= iYBb; j++ )
		{
			CqBucket* bucket = &Bucket( i, j );
			// Only add the MPG if the bucket isn't processed.
			// \note It is possible for this to happen validly, if a primitive is occlusion culled in a 
			// previous bucket, and not in a subsequent one. When it gets processed in the later bucket
			// the MPGs can leak into the previous one, shouldn't be a problem, as the occlusion culling 
			// means the MPGs shouldn't be rendered in that bucket anyway.
			if ( !bucket->IsProcessed() )
			{
				bucket->AddMP( pmpgNew );
			}
		}
	}
}
Beispiel #17
0
bool CqCurve::Diceable()
{
	// OK, here the CqCubicCurveSegment line has two options:
	//  1. split into two more lines
	//  2. turn into a bilinear patch for rendering
	// We don't want to go turning into a patch unless absolutely
	// necessary, since patches cost more.  We only want to become a patch
	// if the current curve is "best handled" as a patch.  For now, I'm
	// choosing to define that the curve is best handled as a patch under
	// one or more of the following two conditions:
	//  1. If the maximum width is a significant fraction of the length of
	//      the line (width greater than 0.75 x length; ignoring normals).
	//  2. If the length of the line (ignoring the width; cos' it's
	//      covered by point 1) is such that it's likely a bilinear
	//      patch would be diced immediately if we created one (so that
	//      patches don't have to get split!).
	//  3. If the curve crosses the eye plane (m_fDiceable == false).

	// find the length of the CqLinearCurveSegment line in raster space
	if( m_splitDecision == Split_Undecided )
	{
		// AGG - 31/07/04
		// well, if we follow the above statagy we end up splitting into
		// far too many grids (with roughly 1 mpg per grid). so after
		// profiling a few scenes, the fastest method seems to be just
		// to convert to a patch immediatly.
		// we really need a native dice for curves but until that time
		// i reckon this is best.
		//m_splitDecision = Split_Patch;

		CqMatrix matCtoR;
		QGetRenderContext() ->matSpaceToSpace(
									"camera", "raster",
									NULL, NULL,
									QGetRenderContextI()->Time(),
									matCtoR
									);
		// control hull
		CqVector2D hull[2] = {
			vectorCast<CqVector2D>(matCtoR * P()->pValue(0)[0]),
			vectorCast<CqVector2D>(matCtoR * P()->pValue(1)[0])
		};
		CqVector2D lengthVector = hull[ 1 ] - hull[ 0 ];
		TqFloat lengthraster = lengthVector.Magnitude();

		// find the approximate "length" of a diced patch in raster space
		TqFloat gridlength = GetGridLength();

		// decide whether to split into more curve segments or a patch
		if(( lengthraster < gridlength ) || ( !m_fDiceable ))
		{
			// split into a patch
			m_splitDecision = Split_Patch;
		}
		else
		{
			// split into smaller curves
			m_splitDecision = Split_Curve;
		}
	}

	return false;
}
bool CqImageBuffer::CullSurface( CqBound& Bound, const boost::shared_ptr<CqSurface>& pSurface )
{
	// If the primitive is completely outside of the hither-yon z range, cull it.
	if ( Bound.vecMin().z() >= m_optCache.clipFar ||
	     Bound.vecMax().z() <= m_optCache.clipNear )
		return true;

	// This needs to be re-enabled when the RiClippingPlane code is wired up.
#if 0
	if(QGetRenderContext()->clippingVolume().whereIs(Bound) == CqBound::Side_Outside)
	{
		return(true);
	}
#endif

	// If the primitive spans the epsilon plane and the hither plane and can be split,
	if ( Bound.vecMin().z() <= FLT_EPSILON )
	{
		// Mark the primitive as not dicable.
		pSurface->ForceUndiceable();

		CqString objname( "unnamed" );
		const CqString* pattrName = pSurface->pAttributes() ->GetStringAttribute( "identifier", "name" );
		if ( pattrName != 0 )
			objname = pattrName[ 0 ];
		Aqsis::log() << info << "Object \"" << objname.c_str() << "\" spans the epsilon plane" << std::endl;

		if ( pSurface->SplitCount() > m_optCache.maxEyeSplits )
		{
			Aqsis::log() << warning << "Max eyesplits for object \"" << objname.c_str() << "\" exceeded" << std::endl;
			return( true );
		}
		return ( false );
	}

	TqFloat minz = Bound.vecMin().z();
	TqFloat maxz = Bound.vecMax().z();


	// Convert the bounds to raster space.
	CqMatrix mat;
	QGetRenderContext() ->matSpaceToSpace( "camera", "raster", NULL, NULL, QGetRenderContext()->Time(), mat );
	Bound.Transform( mat );

	// Take into account depth-of-field
	if ( QGetRenderContext() ->UsingDepthOfField() )
	{
		const CqVector2D minZCoc = QGetRenderContext()->GetCircleOfConfusion( minz );
		const CqVector2D maxZCoc = QGetRenderContext()->GetCircleOfConfusion( maxz );
		TqFloat cocX = max( minZCoc.x(), maxZCoc.x() );
		TqFloat cocY = max( minZCoc.y(), maxZCoc.y() );
		Bound.vecMin().x( Bound.vecMin().x() - cocX );
		Bound.vecMin().y( Bound.vecMin().y() - cocY );
		Bound.vecMax().x( Bound.vecMax().x() + cocX );
		Bound.vecMax().y( Bound.vecMax().y() + cocY );
	}

	// And expand to account for filter size.
	Bound.vecMin().x( Bound.vecMin().x() - m_optCache.xFiltSize / 2.0f );
	Bound.vecMin().y( Bound.vecMin().y() - m_optCache.yFiltSize / 2.0f );
	Bound.vecMax().x( Bound.vecMax().x() + m_optCache.xFiltSize / 2.0f );
	Bound.vecMax().y( Bound.vecMax().y() + m_optCache.yFiltSize / 2.0f );

	// If the bounds are completely outside the viewing frustum, cull the primitive.
	if( Bound.vecMin().x() > QGetRenderContext()->cropWindowXMax() ||
		Bound.vecMin().y() > QGetRenderContext()->cropWindowYMax() ||
		Bound.vecMax().x() < QGetRenderContext()->cropWindowXMin() ||
		Bound.vecMax().y() < QGetRenderContext()->cropWindowYMin() )
		return ( true );

	// Restore Z-Values to camera space.
	Bound.vecMin().z( minz );
	Bound.vecMax().z( maxz );

	// Cache the Bound.
	pSurface->CacheRasterBound( Bound );
	return ( false );
}