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 }
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 ); } } }
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 ); } } }
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 ); } }
// 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"); }
/** 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 ); }
/** * 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()); }
/** 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 ) ); }
//--------------------------------------------------------------------- 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 ); } } } }
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 ); }