void Grade::processChannelData( const Gaffer::Context *context, const ImagePlug *parent, const std::string &channel, FloatVectorDataPtr outData ) const { // Calculate the valid data window that we are to merge. const int dataWidth = ImagePlug::tileSize()*ImagePlug::tileSize(); // Do some pre-processing. float A, B, gamma; bool whiteClamp, blackClamp; { GradeParametersScope s( context ); parameters( std::max( 0, ImageAlgo::colorIndex( channel ) ), A, B, gamma ); whiteClamp = whiteClampPlug()->getValue(); blackClamp = blackClampPlug()->getValue(); } const float invGamma = 1. / gamma; // Get some useful pointers. float *outPtr = &(outData->writable()[0]); const float *END = outPtr + dataWidth; while (outPtr != END) { // Calculate the colour of the graded pixel. float colour = *outPtr; // As the input has been copied to outData, grab the input colour from there. const float c = A * colour + B; colour = ( c >= 0.f && invGamma != 1.f ? (float)pow( c, invGamma ) : c ); // Clamp the white and blacks if necessary. if ( blackClamp && colour < 0.f ) colour = 0.f; if ( whiteClamp && colour > 1.f ) colour = 1.f; // Write back the result. *outPtr++ = colour; } }
IECore::ImagePrimitivePtr ImagePlug::image() const { Format format = formatPlug()->getValue(); Box2i dataWindow = dataWindowPlug()->getValue(); Box2i newDataWindow( Imath::V2i(0) ); if( dataWindow.isEmpty() ) { dataWindow = Box2i( Imath::V2i(0) ); } else { newDataWindow = format.yDownToFormatSpace( dataWindow ); } ImagePrimitivePtr result = new ImagePrimitive( newDataWindow, format.getDisplayWindow() ); ConstStringVectorDataPtr channelNamesData = channelNamesPlug()->getValue(); const vector<string> &channelNames = channelNamesData->readable(); vector<float *> imageChannelData; for( vector<string>::const_iterator it = channelNames.begin(), eIt = channelNames.end(); it!=eIt; it++ ) { FloatVectorDataPtr cd = new FloatVectorData; vector<float> &c = cd->writable(); c.resize( result->variableSize( PrimitiveVariable::Vertex ), 0.0f ); result->variables[*it] = PrimitiveVariable( PrimitiveVariable::Vertex, cd ); imageChannelData.push_back( &(c[0]) ); } parallel_for( blocked_range2d<size_t>( 0, dataWindow.size().x+1, tileSize(), 0, dataWindow.size().y+1, tileSize() ), GafferImage::Detail::CopyTiles( imageChannelData, channelNames, channelDataPlug(), dataWindow, Context::current(), tileSize()) ); return result; }
IECore::ImagePrimitivePtr DepthTexture::imagePrimitive() const { ScopedBinding binding( *this ); GLint width = 0; GLint height = 0; glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width ); glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height ); vector<float> data( width * height ); glGetTexImage( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, GL_FLOAT, &data[0] ); FloatVectorDataPtr zd = new FloatVectorData(); vector<float> &z = zd->writable(); z.resize( width * height ); unsigned int i = 0; for( int y=height-1; y>=0; y-- ) { float *rz = &z[y*width]; for( int x=0; x<width; x++ ) { rz[x] = data[i++]; } } Box2i imageExtents( V2i( 0, 0 ), V2i( width-1, height-1 ) ); ImagePrimitivePtr image = new ImagePrimitive( imageExtents, imageExtents ); image->variables["Z"] = PrimitiveVariable( PrimitiveVariable::Vertex, zd ); return image; }
IECore::ConstFloatVectorDataPtr Shape::computeChannelData( const std::string &channelName, const Imath::V2i &tileOrigin, const Gaffer::Context *context, const ImagePlug *parent ) const { assert( parent == shapePlug() ); if( channelName == g_shapeChannelName ) { // Private channel we use for caching the shape but don't advertise via channelNames. return computeShapeChannelData( tileOrigin, context ); } else { ConstFloatVectorDataPtr shape = parent->channelData( g_shapeChannelName, context->get<V2i>( ImagePlug::tileOriginContextName ) ); const float c = channelValue( parent, channelName ); if( c == 1 ) { return shape; } else { FloatVectorDataPtr resultData = shape->copy(); vector<float> &result = resultData->writable(); for( vector<float>::iterator it = result.begin(), eIt = result.end(); it != eIt; ++it ) { *it *= c; } return resultData; } } }
static IECore::FloatVectorDataPtr parseFloats( const std::string &value ) { FloatVectorDataPtr result = new FloatVectorData; string::const_iterator first = value.begin(); bool r = qi::phrase_parse( first, value.end(), ///////////////// qi::omit[ -qi::char_( '{' ) ] >> ( qi::float_ % ',' ) >> qi::omit[ -qi::char_( '}' ) ] , ///////////////// ascii::space, result->writable() ); if( !r || first != value.end() ) { return 0; } return result; }
IECore::CompoundDataPtr IECoreRI::SXRendererImplementation::shadePlane( const V2i &resolution ) const { IECore::CompoundDataPtr points = new IECore::CompoundData(); V3fVectorDataPtr pData = new IECore::V3fVectorData(); V3fVectorDataPtr nData = new IECore::V3fVectorData(); FloatVectorDataPtr sData = new IECore::FloatVectorData(); FloatVectorDataPtr tData = new IECore::FloatVectorData(); std::vector<V3f> &p = pData->writable(); std::vector<V3f> &n = nData->writable(); std::vector<float> &s = sData->writable(); std::vector<float> &t = tData->writable(); unsigned numPoints = resolution[0] * resolution[1]; p.resize( numPoints ); n.resize( numPoints ); s.resize( numPoints ); t.resize( numPoints ); unsigned xResMinus1 = resolution[0] - 1; unsigned yResMinus1 = resolution[1] - 1; unsigned i = 0; for( int y = 0; y < resolution[1]; y++ ) { for( int x = 0; x < resolution[0]; x++ ) { p[i] = V3f( float(x) / xResMinus1 , float(y) / yResMinus1, 0.0 ); s[i] = p[i][0]; t[i] = p[i][1]; n[i] = V3f( 0.0f, 0.0f, 1.0f ); i++; } } points->writable()[ "P" ] = pData; points->writable()[ "N" ] = nData; points->writable()[ "s" ] = sData; points->writable()[ "t" ] = tData; return shade( points, resolution ); }
IECore::ConstFloatVectorDataPtr Constant::computeChannelData( const std::string &channelName, const Imath::V2i &tileOrigin, const Gaffer::Context *context, const ImagePlug *parent ) const { const int channelIndex = colorIndex( context->get<std::string>( ImagePlug::channelNameContextName ) ); const float value = colorPlug()->getChild( channelIndex )->getValue(); FloatVectorDataPtr result = new FloatVectorData; result->writable().resize( ImagePlug::tileSize() * ImagePlug::tileSize(), value ); return result; }
IECore::CompoundDataPtr GXEvaluator::evaluate( const IECore::FloatVectorData *s, const IECore::FloatVectorData *t, const std::vector<std::string> &primVarNames ) const { size_t numPoints = s->readable().size(); if( t->readable().size() != numPoints ) { throw InvalidArgumentException( "s and t must have the same length" ); } buildSTEvaluator(); MeshPrimitiveEvaluator::ResultPtr evaluatorResult = staticPointerCast<MeshPrimitiveEvaluator::Result>( m_stEvaluator->createResult() ); IntVectorDataPtr fData = new IntVectorData; FloatVectorDataPtr uData = new FloatVectorData; FloatVectorDataPtr vData = new FloatVectorData; BoolVectorDataPtr statusData = new BoolVectorData; std::vector<int> &fWritable = fData->writable(); fWritable.resize( numPoints ); std::vector<float> &uWritable = uData->writable(); uWritable.resize( numPoints ); std::vector<float> &vWritable = vData->writable(); vWritable.resize( numPoints ); std::vector<bool> &statusWritable = statusData->writable(); statusWritable.resize( numPoints ); const std::vector<float> &sReadable = s->readable(); const std::vector<float> &tReadable = t->readable(); const PrimitiveVariable &uPrimVar = m_stEvaluator->primitive()->variables.find( "u" )->second; const PrimitiveVariable &vPrimVar = m_stEvaluator->primitive()->variables.find( "v" )->second; for( size_t i=0; i<numPoints; i++ ) { bool success = m_stEvaluator->pointAtUV( Imath::V2f( sReadable[i], tReadable[i] ), evaluatorResult ); // dividing by 2 maps from the triangle index to the original face index of the mesh before it // was triangulated - we can guarantee this because the original mesh was all quads. fWritable[i] = success ? evaluatorResult->triangleIndex() / 2 : 0; uWritable[i] = success ? evaluatorResult->floatPrimVar( uPrimVar ) : 0; vWritable[i] = success ? evaluatorResult->floatPrimVar( vPrimVar ) : 0; statusWritable[i] = success; } CompoundDataPtr result = evaluate( fData, uData, vData, primVarNames ); result->writable()["gxStatus"] = statusData; return result; }
void Clamp::processChannelData( const Gaffer::Context *context, const ImagePlug *parent, const std::string &channelName, FloatVectorDataPtr outData ) const { const int channelIndex = std::max( 0, ImageAlgo::colorIndex( channelName ) ); const float minimum = minPlug()->getChild( channelIndex )->getValue(); const float maximum = maxPlug()->getChild( channelIndex )->getValue(); const float minClampTo = minClampToPlug()->getChild( channelIndex )->getValue(); const float maxClampTo = maxClampToPlug()->getChild( channelIndex )->getValue(); const bool minimumEnabled = minEnabledPlug()->getValue(); const bool maximumEnabled = maxEnabledPlug()->getValue(); const bool minClampToEnabled = minClampToEnabledPlug()->getValue(); const bool maxClampToEnabled = maxClampToEnabledPlug()->getValue(); std::vector<float> &out = outData->writable(); std::vector<float>::iterator outDataIterator; for (outDataIterator = out.begin(); outDataIterator != out.end(); ++outDataIterator) { if (minimumEnabled) { if (*outDataIterator < minimum) { if (minClampToEnabled) { *outDataIterator = minClampTo; } else { *outDataIterator = minimum; } } } if (maximumEnabled) { if (*outDataIterator > maximum) { if (maxClampToEnabled) { *outDataIterator = maxClampTo; } else { *outDataIterator = maximum; } } } } }
void ToArnoldShapeConverter::convertRadius( const IECore::Primitive *primitive, AtNode *shape ) const { ConstFloatVectorDataPtr radius = primitive->variableData<FloatVectorData>( "radius" ); if( !radius ) { FloatVectorDataPtr calculatedRadius = new FloatVectorData(); if( const FloatData *constantRadius = primitive->variableData<FloatData>( "radius", PrimitiveVariable::Constant ) ) { calculatedRadius->writable().push_back( constantRadius->readable() ); } else if( const FloatVectorData *width = primitive->variableData<FloatVectorData>( "width" ) ) { calculatedRadius->writable().resize( width->readable().size() ); const std::vector<float>::iterator end = calculatedRadius->writable().end(); std::vector<float>::const_iterator wIt = width->readable().begin(); for( std::vector<float>::iterator it = calculatedRadius->writable().begin(); it != end; it++, wIt++ ) { *it = *wIt / 2.0f; } } else { const FloatData *constantWidth = primitive->variableData<FloatData>( "width", PrimitiveVariable::Constant ); if( !constantWidth ) { constantWidth = primitive->variableData<FloatData>( "constantwidth", PrimitiveVariable::Constant ); } float r = constantWidth ? constantWidth->readable() / 2.0f : 0.5f; calculatedRadius->writable().push_back( r ); } radius = calculatedRadius; } AiNodeSetArray( shape, "radius", AiArrayConvert( radius->readable().size(), 1, AI_TYPE_FLOAT, (void *)&( radius->readable()[0] ) ) ); }
virtual void imageData( const Imath::Box2i &box, const float *data, size_t dataSize ) { Box2i yUpBox = m_gafferFormat.yDownToFormatSpace( box ); const V2i boxMinTileOrigin = ImagePlug::tileOrigin( yUpBox.min ); const V2i boxMaxTileOrigin = ImagePlug::tileOrigin( yUpBox.max ); for( int tileOriginY = boxMinTileOrigin.y; tileOriginY <= boxMaxTileOrigin.y; tileOriginY += ImagePlug::tileSize() ) { for( int tileOriginX = boxMinTileOrigin.x; tileOriginX <= boxMaxTileOrigin.x; tileOriginX += ImagePlug::tileSize() ) { for( int channelIndex = 0, numChannels = channelNames().size(); channelIndex < numChannels; ++channelIndex ) { const V2i tileOrigin( tileOriginX, tileOriginY ); ConstFloatVectorDataPtr tileData = getTile( tileOrigin, channelIndex ); if( !tileData ) { // we've been sent data outside of the data window continue; } // we must create a new object to hold the updated tile data, // because the old one might well have been returned from // computeChannelData and be being held in the cache. FloatVectorDataPtr updatedTileData = tileData->copy(); vector<float> &updatedTile = updatedTileData->writable(); const Box2i tileBound( tileOrigin, tileOrigin + Imath::V2i( GafferImage::ImagePlug::tileSize() - 1 ) ); const Box2i transferBound = IECore::boxIntersection( tileBound, yUpBox ); for( int y = transferBound.min.y; y<=transferBound.max.y; ++y ) { int srcY = m_gafferFormat.formatToYDownSpace( y ); size_t srcIndex = ( ( srcY - box.min.y ) * ( box.size().x + 1 ) * numChannels ) + ( transferBound.min.x - box.min.x ) + channelIndex; size_t dstIndex = ( y - tileBound.min.y ) * ImagePlug::tileSize() + transferBound.min.x - tileBound.min.x; const size_t srcEndIndex = srcIndex + transferBound.size().x * numChannels; while( srcIndex <= srcEndIndex ) { updatedTile[dstIndex] = data[srcIndex]; srcIndex += numChannels; dstIndex++; } } setTile( tileOrigin, channelIndex, updatedTileData ); } } } dataReceivedSignal()( this, box ); }
IECore::ConstFloatVectorDataPtr CopyChannels::computeChannelData( const std::string &channelName, const Imath::V2i &tileOrigin, const Gaffer::Context *context, const ImagePlug *parent ) const { ConstCompoundObjectPtr mapping; { ImagePlug::GlobalScope c( context ); mapping = mappingPlug()->getValue(); } if( const IntData *i = mapping->member<const IntData>( channelName ) ) { const ImagePlug *inputImage = inPlugs()->getChild<ImagePlug>( i->readable() ); const V2i tileOrigin = context->get<V2i>( ImagePlug::tileOriginContextName ); const Box2i tileBound( tileOrigin, tileOrigin + V2i( ImagePlug::tileSize() ) ); Box2i inputDataWindow; { ImagePlug::GlobalScope c( context ); inputDataWindow = inputImage->dataWindowPlug()->getValue(); } const Box2i validBound = BufferAlgo::intersection( tileBound, inputDataWindow ); if( validBound == tileBound ) { return inputImage->channelDataPlug()->getValue(); } else { FloatVectorDataPtr resultData = new FloatVectorData; vector<float> &result = resultData->writable(); result.resize( ImagePlug::tileSize() * ImagePlug::tileSize(), 0.0f ); if( !BufferAlgo::empty( validBound ) ) { ConstFloatVectorDataPtr inputData = inputImage->channelDataPlug()->getValue(); copyRegion( &inputData->readable().front(), tileBound, validBound, &result.front(), tileBound, validBound.min ); } return resultData; } } else { return ImagePlug::blackTile(); } }
IECore::ConstFloatVectorDataPtr Constant::computeChannelData( const std::string &channelName, const Imath::V2i &tileOrigin, const Gaffer::Context *context, const ImagePlug *parent ) const { FloatVectorDataPtr resultData = new FloatVectorData; vector<float> &result = resultData->writable(); result.resize( ImagePlug::tileSize() * ImagePlug::tileSize() ); int idx = channelName == "R" ? 0 : channelName == "G" ? 1 : channelName == "B" ? 2 : 3; const float v = colorPlug()->getValue()[idx]; float *ptr = &result[0]; for( int i = 0; i < ImagePlug::tileSize() * ImagePlug::tileSize(); i++ ) { *ptr++ = v; } return resultData; }
IECore::ImagePrimitivePtr ImagePlug::image() const { Format format = formatPlug()->getValue(); Box2i dataWindow = dataWindowPlug()->getValue(); Box2i newDataWindow( Imath::V2i(0) ); if( dataWindow.isEmpty() ) { dataWindow = Box2i( Imath::V2i(0) ); } else { newDataWindow = format.yDownToFormatSpace( dataWindow ); } // use the default format if we don't have an explicit one. /// \todo: remove this once FormatPlug is handling it for /// us during ExecutableNode::execute (see issue #887). if( format.getDisplayWindow().isEmpty() ) { format = Context::current()->get<Format>( Format::defaultFormatContextName, Format() ); } ImagePrimitivePtr result = new ImagePrimitive( newDataWindow, format.getDisplayWindow() ); ConstCompoundObjectPtr metadata = metadataPlug()->getValue(); compoundObjectToCompoundData( metadata.get(), result->blindData() ); ConstStringVectorDataPtr channelNamesData = channelNamesPlug()->getValue(); const vector<string> &channelNames = channelNamesData->readable(); vector<float *> imageChannelData; for( vector<string>::const_iterator it = channelNames.begin(), eIt = channelNames.end(); it!=eIt; it++ ) { FloatVectorDataPtr cd = new FloatVectorData; vector<float> &c = cd->writable(); c.resize( result->variableSize( PrimitiveVariable::Vertex ), 0.0f ); result->variables[*it] = PrimitiveVariable( PrimitiveVariable::Vertex, cd ); imageChannelData.push_back( &(c[0]) ); } parallel_for( blocked_range3d<size_t>( 0, imageChannelData.size(), 1, 0, dataWindow.size().x+1, tileSize(), 0, dataWindow.size().y+1, tileSize() ), GafferImage::Detail::CopyTiles( imageChannelData, channelNames, channelDataPlug(), dataWindow, Context::current(), tileSize()) ); return result; }
IECore::ConstFloatVectorDataPtr ImageReader::computeChannelData( const std::string &channelName, const Imath::V2i &tileOrigin, const Gaffer::Context *context, const ImagePlug *parent ) const { std::string fileName = fileNamePlug()->getValue(); ustring uFileName( fileName.c_str() ); const ImageSpec *spec = imageCache()->imagespec( uFileName ); vector<string>::const_iterator channelIt = find( spec->channelnames.begin(), spec->channelnames.end(), channelName ); if( channelIt == spec->channelnames.end() ) { { return parent->channelDataPlug()->defaultValue(); } } Format format( Imath::Box2i( Imath::V2i( spec->full_x, spec->full_y ), Imath::V2i( spec->full_width + spec->full_x - 1, spec->full_height + spec->full_y - 1 ) ) ); const int newY = format.formatToYDownSpace( tileOrigin.y + ImagePlug::tileSize() - 1 ); std::vector<float> channelData( ImagePlug::tileSize() * ImagePlug::tileSize() ); size_t channelIndex = channelIt - spec->channelnames.begin(); imageCache()->get_pixels( uFileName, 0, 0, // subimage, miplevel tileOrigin.x, tileOrigin.x + ImagePlug::tileSize(), newY, newY + ImagePlug::tileSize(), 0, 1, channelIndex, channelIndex + 1, TypeDesc::FLOAT, &(channelData[0]) ); // Create the output data buffer. FloatVectorDataPtr resultData = new FloatVectorData; vector<float> &result = resultData->writable(); result.resize( ImagePlug::tileSize() * ImagePlug::tileSize() ); // Flip the tile in the Y axis to convert it to our internal image data representation. for( int y = 0; y < ImagePlug::tileSize(); ++y ) { memcpy( &(result[ ( ImagePlug::tileSize() - y - 1 ) * ImagePlug::tileSize() ]), &(channelData[ y * ImagePlug::tileSize() ]), sizeof(float)*ImagePlug::tileSize() ); } return resultData; }
IECore::ConstFloatVectorDataPtr Mirror::computeChannelData( const std::string &channelName, const Imath::V2i &tileOrigin, const Gaffer::Context *context, const ImagePlug *parent ) const { const bool horizontal = horizontalPlug()->getValue(); const bool vertical = verticalPlug()->getValue(); if( !horizontal && !vertical ) { return inPlug()->channelDataPlug()->getValue(); } const Box2i displayWindow = inPlug()->formatPlug()->getValue().getDisplayWindow(); const Box2i tileBound( tileOrigin, tileOrigin + V2i( ImagePlug::tileSize() ) ); const Box2i sampleWindow = mirror( tileBound, horizontal, vertical, displayWindow ); Sampler sampler( inPlug(), channelName, sampleWindow ); FloatVectorDataPtr outData = new FloatVectorData; vector<float> &out = outData->writable(); out.reserve( ImagePlug::tileSize() * ImagePlug::tileSize() ); V2i pIn; V2i pOut; for( pOut.y = tileBound.min.y; pOut.y < tileBound.max.y; ++pOut.y ) { pOut.x = tileBound.min.x; pIn = mirror( pOut, horizontal, vertical, displayWindow ); const int xStep = horizontal ? -1 : 1; for( ; pOut.x < tileBound.max.x; ++pOut.x ) { out.push_back( sampler.sample( pIn.x, pIn.y ) ); pIn.x += xStep; } } return outData; }
IECoreImage::ImagePrimitivePtr ImagePlug::image() const { Format format = formatPlug()->getValue(); Box2i dataWindow = dataWindowPlug()->getValue(); Box2i newDataWindow( Imath::V2i( 0 ) ); if( !BufferAlgo::empty( dataWindow ) ) { newDataWindow = format.toEXRSpace( dataWindow ); } else { dataWindow = newDataWindow; } Box2i newDisplayWindow = format.toEXRSpace( format.getDisplayWindow() ); IECoreImage::ImagePrimitivePtr result = new IECoreImage::ImagePrimitive( newDataWindow, newDisplayWindow ); ConstCompoundDataPtr metadata = metadataPlug()->getValue(); result->blindData()->Object::copyFrom( metadata.get() ); ConstStringVectorDataPtr channelNamesData = channelNamesPlug()->getValue(); const vector<string> &channelNames = channelNamesData->readable(); vector<float *> imageChannelData; for( vector<string>::const_iterator it = channelNames.begin(), eIt = channelNames.end(); it!=eIt; it++ ) { FloatVectorDataPtr cd = new FloatVectorData; vector<float> &c = cd->writable(); c.resize( result->channelSize(), 0.0f ); result->channels[*it] = cd; imageChannelData.push_back( &(c[0]) ); } CopyTile copyTile( imageChannelData, channelNames, dataWindow ); ImageAlgo::parallelProcessTiles( this, channelNames, copyTile, dataWindow ); return result; }
void Unpremultiply::processChannelData( const Gaffer::Context *context, const ImagePlug *parent, const std::string &channel, FloatVectorDataPtr outData ) const { std::string alphaChannel = alphaChannelPlug()->getValue(); if ( channel == alphaChannel ) { return; } ConstStringVectorDataPtr inChannelNamesPtr; { ImagePlug::GlobalScope c( context ); inChannelNamesPtr = inPlug()->channelNamesPlug()->getValue(); } const std::vector<std::string> &inChannelNames = inChannelNamesPtr->readable(); if ( std::find( inChannelNames.begin(), inChannelNames.end(), alphaChannel ) == inChannelNames.end() ) { std::ostringstream channelError; channelError << "Channel '" << alphaChannel << "' does not exist"; throw( IECore::Exception( channelError.str() ) ); } ImagePlug::ChannelDataScope channelDataScope( context ); channelDataScope.setChannelName( alphaChannel ); ConstFloatVectorDataPtr aData = inPlug()->channelDataPlug()->getValue(); const std::vector<float> &a = aData->readable(); std::vector<float> &out = outData->writable(); std::vector<float>::const_iterator aIt = a.begin(); for ( std::vector<float>::iterator outIt = out.begin(), outItEnd = out.end(); outIt != outItEnd; ++outIt, ++aIt ) { if ( *aIt != 0.0f ) { *outIt /= *aIt; } } }
ObjectPtr SLOReader::doOperation( const CompoundObject * operands ) { tbb::mutex::scoped_lock lock( g_mutex ); if( Slo_SetShader( (char *)fileName().c_str() ) ) { throw Exception( boost::str( boost::format( "Unable to set shader to \"%s\"" ) % fileName() ) ); } string name = Slo_GetName(); string type = Slo_TypetoStr( Slo_GetType() ); ShaderPtr result = new Shader( name, type ); CompoundDataPtr typeHints = new CompoundData; result->blindData()->writable().insert( pair<string, DataPtr>( "ri:parameterTypeHints", typeHints ) ); // we lose the ordering of parameter names when we put them in result->parameters(), // so we stick the correct order in the blind data as a workaround for anyone interested // in the true ordering. StringVectorDataPtr orderedParameterNames = new StringVectorData; result->blindData()->writable().insert( pair<string, DataPtr>( "ri:orderedParameterNames", orderedParameterNames ) ); // we don't have a way of communicating which parameters are outputs in the Shader::parametersData(), // so we work around that using the blind data too. StringVectorDataPtr outputParameterNames = new StringVectorData; result->blindData()->writable().insert( pair<string, DataPtr>( "ri:outputParameterNames", outputParameterNames ) ); int numArgs = Slo_GetNArgs(); for( int i=1; i<=numArgs; i++ ) { DataPtr data = 0; SLO_VISSYMDEF *arg = Slo_GetArgById( i ); switch( arg->svd_type ) { case SLO_TYPE_POINT : case SLO_TYPE_VECTOR : case SLO_TYPE_NORMAL : { if( arg->svd_arraylen==0 ) { const SLO_POINT *p = arg->svd_default.pointval; if( p ) { data = new V3fData( V3f( p->xval, p->yval, p->zval ) ); } else { // 0 length and null value signifies a variable length array data = new V3fVectorData(); } } else { V3fVectorDataPtr vData = new V3fVectorData(); data = vData; for( int j=0; j<arg->svd_arraylen; j++ ) { SLO_VISSYMDEF *a = Slo_GetArrayArgElement( arg, j ); const SLO_POINT *p = a->svd_default.pointval; vData->writable().push_back( V3f( p->xval, p->yval, p->zval ) ); } } typeHints->writable().insert( pair<string, DataPtr>( arg->svd_name, new StringData( Slo_TypetoStr( arg->svd_type ) ) ) ); break; } case SLO_TYPE_COLOR : { if( arg->svd_arraylen==0 ) { const SLO_POINT *p = arg->svd_default.pointval; if( p ) { data = new Color3fData( Color3f( p->xval, p->yval, p->zval ) ); } else { // 0 length and null value signifies a variable length array data = new Color3fVectorData(); } } else { Color3fVectorDataPtr vData = new Color3fVectorData(); data = vData; for( int j=0; j<arg->svd_arraylen; j++ ) { SLO_VISSYMDEF *a = Slo_GetArrayArgElement( arg, j ); const SLO_POINT *p = a->svd_default.pointval; vData->writable().push_back( Color3f( p->xval, p->yval, p->zval ) ); } } } break; case SLO_TYPE_SCALAR : { if( arg->svd_arraylen==0 ) { const float *value = arg->svd_default.scalarval; if( value ) { data = new FloatData( *value ); } else { // 0 length and null value signifies a variable length array data = new FloatVectorData(); } } else { FloatVectorDataPtr vData = new FloatVectorData(); data = vData; for( int j=0; j<arg->svd_arraylen; j++ ) { SLO_VISSYMDEF *a = Slo_GetArrayArgElement( arg, j ); vData->writable().push_back( *(a->svd_default.scalarval) ); } if( arg->svd_arraylen==3 ) { // allow V3fData and V3fVectorData to be mapped to float[3] parameters. typeHints->writable().insert( pair<string, DataPtr>( arg->svd_name, new StringData( "float[3]" ) ) ); } } } break; case SLO_TYPE_STRING : { if( arg->svd_arraylen==0 ) { const char *defaultValue = arg->svd_default.stringval; if( defaultValue ) { data = new StringData( defaultValue ); } else { // 0 length and null value signifies a variable length array data = new StringVectorData(); } } else { StringVectorDataPtr vData = new StringVectorData(); data = vData; for( int j=0; j<arg->svd_arraylen; j++ ) { SLO_VISSYMDEF *a = Slo_GetArrayArgElement( arg, j ); // sometimes the default value for an element of a string array can be a null pointer. // i'm not sure what the meaning of this is. the 3delight shaderinfo utility reports such values // as "(null)", so that's what we do too. const char *defaultValue = a->svd_default.stringval; vData->writable().push_back( defaultValue ? defaultValue : "(null)" ); } } } break; case SLO_TYPE_MATRIX : { if( arg->svd_arraylen==0 ) { const float *m = arg->svd_default.matrixval; if( m ) { M44f mm( m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], m[11], m[12], m[13], m[14], m[15] ); data = new M44fData( mm ); } else { // 0 length and null value signifies a variable length array data = new M44fVectorData(); } } else { M44fVectorDataPtr vData = new M44fVectorData(); data = vData; for( int j=0; j<arg->svd_arraylen; j++ ) { SLO_VISSYMDEF *a = Slo_GetArrayArgElement( arg, j ); const float *m = a->svd_default.matrixval; M44f mm( m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], m[11], m[12], m[13], m[14], m[15] ); vData->writable().push_back( mm ); } } } break; case SLO_TYPE_SHADER : { if( arg->svd_arraylen==0 ) { if( !arg->svd_valisvalid ) { // variable length array data = new StringVectorData(); } else { data = new StringData(); } } else { StringVectorDataPtr sData = new StringVectorData(); data = sData; sData->writable().resize( arg->svd_arraylen ); } typeHints->writable().insert( pair<string, DataPtr>( arg->svd_name, new StringData( Slo_TypetoStr( arg->svd_type ) ) ) ); } break; default : msg( Msg::Warning, "SLOReader::read", format( "Parameter \"%s\" has unsupported type." ) % arg->svd_name ); } if( data ) { orderedParameterNames->writable().push_back( arg->svd_name ); result->parameters().insert( CompoundDataMap::value_type( arg->svd_name, data ) ); if( arg->svd_storage == SLO_STOR_OUTPUTPARAMETER ) { outputParameterNames->writable().push_back( arg->svd_name ); } } } // shader annotations CompoundDataPtr annotations = new CompoundData; result->blindData()->writable().insert( pair<string, DataPtr>( "ri:annotations", annotations ) ); #ifndef PRMANEXPORT for( int i=1, n=Slo_GetNAnnotations(); i <= n; i++ ) { const char *key = Slo_GetAnnotationKeyById( i ); annotations->writable()[key] = new StringData( Slo_GetAnnotationByKey( key ) ); } #endif Slo_EndShader(); return result; }
void LuminanceOp::modifyPrimitive( Primitive * primitive, const CompoundObject * operands ) { DataPtr luminanceData = 0; PrimitiveVariable::Interpolation interpolation = PrimitiveVariable::Invalid; int steps[3] = { 1, 1, 1 }; PrimitiveVariableMap::iterator colorIt = primitive->variables.find( m_colorPrimVarParameter->getTypedValue() ); if( colorIt!=primitive->variables.end() && colorIt->second.data ) { // RGB in a single channel switch( colorIt->second.data->typeId() ) { case Color3fDataTypeId : { FloatDataPtr l = new FloatData; const float *d = staticPointerCast<Color3fData>( colorIt->second.data )->baseReadable(); calculate( d, d + 1, d + 2, steps, 1, l->baseWritable() ); luminanceData = l; } break; case Color3fVectorDataTypeId : { FloatVectorDataPtr l = new FloatVectorData; Color3fVectorDataPtr d = staticPointerCast<Color3fVectorData>( colorIt->second.data ); l->writable().resize( d->readable().size() ); const float *dd = d->baseReadable(); steps[0] = steps[1] = steps[2] = 3; calculate( dd, dd + 1, dd + 2, steps, d->readable().size(), l->baseWritable() ); luminanceData = l; } break; default : throw Exception( "PrimitiveVariable has unsupported type." ); break; } interpolation = colorIt->second.interpolation; } else { // separate RGB channels? PrimitiveVariableMap::iterator rIt = primitive->variables.find( m_redPrimVarParameter->getTypedValue() ); PrimitiveVariableMap::iterator gIt = primitive->variables.find( m_greenPrimVarParameter->getTypedValue() ); PrimitiveVariableMap::iterator bIt = primitive->variables.find( m_bluePrimVarParameter->getTypedValue() ); if( rIt==primitive->variables.end() || gIt==primitive->variables.end() || bIt==primitive->variables.end() ) { throw Exception( "Primitive does not have appropriately named PrimitiveVariables." ); } TypeId type = rIt->second.data->typeId(); if( gIt->second.data->typeId() != type || bIt->second.data->typeId() != type ) { throw Exception( "PrimitiveVariable types do not match." ); } size_t rSize = despatchTypedData<TypedDataSize>( rIt->second.data ); size_t gSize = despatchTypedData<TypedDataSize>( gIt->second.data ); size_t bSize = despatchTypedData<TypedDataSize>( bIt->second.data ); if( rSize!=gSize || rSize!=bSize ) { throw Exception( "PrimitiveVariable sizes do not match." ); } switch( type ) { case HalfDataTypeId : { HalfDataPtr l = new HalfData; calculate( staticPointerCast<HalfData>( rIt->second.data )->baseReadable(), staticPointerCast<HalfData>( gIt->second.data )->baseReadable(), staticPointerCast<HalfData>( bIt->second.data )->baseReadable(), steps, rSize, l->baseWritable() ); luminanceData = l; } break; case HalfVectorDataTypeId : { HalfVectorDataPtr l = new HalfVectorData; l->writable().resize( rSize ); calculate( staticPointerCast<HalfVectorData>( rIt->second.data )->baseReadable(), staticPointerCast<HalfVectorData>( gIt->second.data )->baseReadable(), staticPointerCast<HalfVectorData>( bIt->second.data )->baseReadable(), steps, rSize, l->baseWritable() ); luminanceData = l; } break; case FloatDataTypeId : { FloatDataPtr l = new FloatData; calculate( staticPointerCast<FloatData>( rIt->second.data )->baseReadable(), staticPointerCast<FloatData>( gIt->second.data )->baseReadable(), staticPointerCast<FloatData>( bIt->second.data )->baseReadable(), steps, rSize, l->baseWritable() ); luminanceData = l; } break; case FloatVectorDataTypeId : { FloatVectorDataPtr l = new FloatVectorData; l->writable().resize( rSize ); calculate( staticPointerCast<FloatVectorData>( rIt->second.data )->baseReadable(), staticPointerCast<FloatVectorData>( gIt->second.data )->baseReadable(), staticPointerCast<FloatVectorData>( bIt->second.data )->baseReadable(), steps, rSize, l->baseWritable() ); luminanceData = l; } break; default : throw Exception( "PrimitiveVariables have unsupported type." ); break; } interpolation = rIt->second.interpolation; } assert( interpolation != PrimitiveVariable::Invalid ); assert( luminanceData ); primitive->variables[luminancePrimVarParameter()->getTypedValue()] = PrimitiveVariable( interpolation, luminanceData ); if( removeColorPrimVarsParameter()->getTypedValue() ) { primitive->variables.erase( colorPrimVarParameter()->getTypedValue() ); primitive->variables.erase( redPrimVarParameter()->getTypedValue() ); primitive->variables.erase( greenPrimVarParameter()->getTypedValue() ); primitive->variables.erase( bluePrimVarParameter()->getTypedValue() ); } }
ImagePrimitivePtr ColorTexture::imagePrimitive() const { ScopedBinding binding( *this ); GLint width = 0; GLint height = 0; glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width ); glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height ); GLint internalFormat = 0; glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &internalFormat ); unsigned int numChannels = 4; vector<float> data( width * height * numChannels ); glGetTexImage( GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, &data[0] ); FloatVectorDataPtr rd = new FloatVectorData(); vector<float> &r = rd->writable(); r.resize( width * height ); FloatVectorDataPtr gd = new FloatVectorData(); vector<float> &g = gd->writable(); g.resize( width * height ); FloatVectorDataPtr bd = new FloatVectorData(); vector<float> &b = bd->writable(); b.resize( width * height ); FloatVectorDataPtr ad = 0; vector<float> *a = 0; // there are potentially loads of different internal formats which denote alpha. // these are the only ones encountered so far, but it's not a great way of testing // and i can't find another way of doing it. if( internalFormat==GL_RGBA || internalFormat==GL_RGBA8_EXT || internalFormat==GL_RGBA16 ) { ad = new FloatVectorData(); a = &ad->writable(); a->resize( width * height ); } unsigned int i = 0; for( int y=height-1; y>=0; y-- ) { float *rr = &r[y*width]; float *rg = &g[y*width]; float *rb = &b[y*width]; float *ra = a ? &(*a)[y*width] : 0; for( int x=0; x<width; x++ ) { rr[x] = data[i++]; rg[x] = data[i++]; rb[x] = data[i++]; if( ra ) { ra[x] = data[i++]; } } } Box2i imageExtents( V2i( 0, 0 ), V2i( width-1, height-1 ) ); ImagePrimitivePtr image = new ImagePrimitive( imageExtents, imageExtents ); image->variables["R"] = PrimitiveVariable( PrimitiveVariable::Vertex, rd ); image->variables["G"] = PrimitiveVariable( PrimitiveVariable::Vertex, gd ); image->variables["B"] = PrimitiveVariable( PrimitiveVariable::Vertex, bd ); if( a ) { image->variables["A"] = PrimitiveVariable( PrimitiveVariable::Vertex, ad ); } Exception::throwIfError(); return image; }
MeshPrimitivePtr MeshPrimitive::createSphere( float radius, float zMin, float zMax, float thetaMax, const Imath::V2i &divisions ) { IntVectorDataPtr vertexIds = new IntVectorData; IntVectorDataPtr verticesPerFace = new IntVectorData; std::vector<int> &vpf = verticesPerFace->writable(); std::vector<int> &vIds = vertexIds->writable(); V3fVectorDataPtr pData = new V3fVectorData; V3fVectorDataPtr nData = new V3fVectorData; std::vector<V3f> &pVector = pData->writable(); std::vector<V3f> &nVector = nData->writable(); FloatVectorDataPtr sData = new FloatVectorData; FloatVectorDataPtr tData = new FloatVectorData; std::vector<float> &sVector = sData->writable(); std::vector<float> &tVector = tData->writable(); float oMin = Math<float>::asin( zMin ); float oMax = Math<float>::asin( zMax ); const unsigned int nO = max( 4u, (unsigned int)( ( divisions.x + 1 ) * (oMax - oMin) / M_PI ) ); float thetaMaxRad = thetaMax / 180.0f * M_PI; const unsigned int nT = max( 7u, (unsigned int)( ( divisions.y + 1 ) * thetaMaxRad / (M_PI*2) ) ); for ( unsigned int i=0; i<nO; i++ ) { float v = (float)i/(float)(nO-1); float o = lerp( oMin, oMax, v ); float z = radius * Math<float>::sin( o ); float r = radius * Math<float>::cos( o ); for ( unsigned int j=0; j<nT; j++ ) { float u = (float)j/(float)(nT-1); float theta = thetaMaxRad * u; V3f p( r * Math<float>::cos( theta ), r * Math<float>::sin( theta ), z ); sVector.push_back( u ); tVector.push_back( v ); pVector.push_back( p ); nVector.push_back( p ); if( i < nO - 1 && j < nT - 1 ) { unsigned int i0 = i * nT + j; unsigned int i1 = i0 + 1; unsigned int i2 = i0 + nT; unsigned int i3 = i2 + 1; vpf.push_back( 3 ); vIds.push_back( i0 ); vIds.push_back( i1 ); vIds.push_back( i2 ); vpf.push_back( 3 ); vIds.push_back( i1 ); vIds.push_back( i3 ); vIds.push_back( i2 ); } } } MeshPrimitivePtr result = new MeshPrimitive( verticesPerFace, vertexIds, "linear", pData ); result->variables["N"] = PrimitiveVariable( PrimitiveVariable::Vertex, nData ); result->variables["s"] = PrimitiveVariable( PrimitiveVariable::Vertex, sData ); result->variables["t"] = PrimitiveVariable( PrimitiveVariable::Vertex, tData ); return result; }
CompoundDataPtr BGEOParticleReader::readAttributes( const std::vector<std::string> &names ) { if( !open() ) { return 0; } CompoundDataPtr result = new CompoundData(); std::vector< struct AttrInfo > attrInfo; int intAttribBuffer[ 3 ]; int *intAttributePtr = &intAttribBuffer[0]; float floatAttribBuffer[ 4 ]; float *floatAttributePtr = &floatAttribBuffer[0]; vector<Record>::const_iterator it; for( it=m_header.attributes.begin(); it!=m_header.attributes.end(); it++ ) { V3fVectorDataPtr v3fVector = 0; V2fVectorDataPtr v2fVector = 0; FloatVectorDataPtr floatVector = 0; IntVectorDataPtr intVector = 0; StringVectorDataPtr stringVector = 0; DataPtr dataVector = 0; if ( it->size == 1 ) { if ( it->type == Float ) { floatVector = new FloatVectorData(); floatVector->writable().resize( numParticles() ); dataVector = floatVector; } else if ( it->type == Integer ) { intVector = new IntVectorData(); intVector->writable().resize( numParticles() ); dataVector = intVector; } else if ( it->type == Index ) { stringVector = new StringVectorData(); stringVector->writable().resize( numParticles() ); dataVector = stringVector; } } else if ( it->size == 2 ) { v2fVector = new V2fVectorData(); v2fVector->writable().resize( numParticles() ); dataVector = v2fVector; } else if ( it->size == 3 || it->size == 4 ) { v3fVector = new V3fVectorData(); v3fVector->writable().resize( numParticles() ); dataVector = v3fVector; } else { msg( Msg::Error, "BGEOParticleReader::readAttributes()", format( "Internal error. Unrecognized type '%d' of size '%d' while loading attribute %s." ) % it->type % it->size % it->name ); return 0; } AttrInfo info = { *it, dataVector, }; attrInfo.push_back( info ); } // read all of the data at once std::vector<char> dataBuffer; dataBuffer.resize( m_header.numPoints * m_header.dataSize ); char *dataBufferPtr = &dataBuffer[0]; m_iStream->seekg( ios_base::beg + m_header.firstPointPosition ); m_iStream->read( dataBufferPtr, m_header.numPoints * m_header.dataSize ); for ( int i = 0; i < m_header.numPoints; i++) { std::vector< struct AttrInfo >::iterator it; for (it = attrInfo.begin(); it != attrInfo.end(); it++) { // P contains an additional byte in the BGEO if ( it->info.type == Integer || it->info.type == Index ) { readAttributeData( &dataBufferPtr, intAttributePtr, it->info.size ); } else { readAttributeData( &dataBufferPtr, floatAttributePtr, it->info.size ); } switch (it->targetData->typeId()) { case V3fVectorDataTypeId: { V3f &p = staticPointerCast<V3fVectorData>(it->targetData)->writable()[ i ]; p[0] = floatAttributePtr[0]; p[1] = floatAttributePtr[1]; p[2] = floatAttributePtr[2]; break; } case V2fVectorDataTypeId: { V2f &p = staticPointerCast<V2fVectorData>(it->targetData)->writable()[ i ]; p[0] = floatAttributePtr[0]; p[1] = floatAttributePtr[1]; break; } case FloatVectorDataTypeId: staticPointerCast<FloatVectorData>(it->targetData)->writable()[ i ] = floatAttributePtr[0]; break; case IntVectorDataTypeId: staticPointerCast<IntVectorData>(it->targetData)->writable()[ i ] = intAttributePtr[0]; break; case StringVectorDataTypeId: { std::string value = it->info.indexableValues.at( intAttributePtr[0] ); staticPointerCast<StringVectorData>(it->targetData)->writable()[ i ] = value; break; } default: msg( Msg::Error, "BGEOParticleReader::readAttributes()", format( "Internal error. Unrecognized typeId '%d'." ) % it->targetData->typeId() ); return 0; } } } /// \todo Use particle ids for filtering. const Data *ids = 0; DataPtr filteredData = 0; // filter and convert each attribute individually. std::vector< struct AttrInfo >::const_iterator attrIt; for( attrIt=attrInfo.begin(); attrIt!=attrInfo.end(); attrIt++ ) { // The data had to be read, but we don't need to filter or store it if( find( names.begin(), names.end(), attrIt->info.name ) == names.end() ) { continue; } if ( attrIt->info.size == 1 ) { if ( attrIt->info.type == Float ) { switch( realType() ) { case ParticleReader::Native : case ParticleReader::Float : filteredData = filterAttr<FloatVectorData, FloatVectorData>( staticPointerCast<FloatVectorData>(attrIt->targetData), particlePercentage(), ids ); break; case ParticleReader::Double : filteredData = filterAttr<DoubleVectorData, FloatVectorData>( staticPointerCast<FloatVectorData>(attrIt->targetData), particlePercentage(), ids ); break; } } else if ( attrIt->info.type == Integer ) { filteredData = filterAttr<IntVectorData, IntVectorData>( staticPointerCast<IntVectorData>(attrIt->targetData), particlePercentage(), ids ); } else if ( attrIt->info.type == Index ) { filteredData = filterAttr<StringVectorData, StringVectorData>( staticPointerCast<StringVectorData>(attrIt->targetData), particlePercentage(), ids ); } } else if ( attrIt->info.size == 2 ) { if ( attrIt->info.type == Float ) { switch( realType() ) { case ParticleReader::Native : case ParticleReader::Float : filteredData = filterAttr<V2fVectorData, V2fVectorData>( staticPointerCast<V2fVectorData>(attrIt->targetData), particlePercentage(), ids ); break; case ParticleReader::Double : filteredData = filterAttr<V2dVectorData, V2fVectorData>( staticPointerCast<V2fVectorData>(attrIt->targetData), particlePercentage(), ids ); break; } } } else if ( attrIt->info.size == 3 || attrIt->info.size == 4 ) { if ( ( attrIt->info.type == Float ) || ( attrIt->info.type == Vector ) ) { switch( realType() ) { case ParticleReader::Native : case ParticleReader::Float : filteredData = filterAttr<V3fVectorData, V3fVectorData>( staticPointerCast<V3fVectorData>(attrIt->targetData), particlePercentage(), ids ); break; case ParticleReader::Double : filteredData = filterAttr<V3dVectorData, V3fVectorData>( staticPointerCast<V3fVectorData>(attrIt->targetData), particlePercentage(), ids ); break; } } } else { msg( Msg::Error, "BGEOParticleReader::readAttributes()", format( "Internal error. Unrecognized type '%d' of size '%d' while converting attribute %s." ) % attrIt->info.type % attrIt->info.size % attrIt->info.name ); return 0; } result->writable()[attrIt->info.name] = filteredData; } return result; }
IECore::ConstCompoundDataPtr OSLImage::computeShading( const Gaffer::Context *context ) const { OSLRenderer::ConstShadingEnginePtr shadingEngine; if( const OSLShader *shader = runTimeCast<const OSLShader>( shaderPlug()->source<Plug>()->node() ) ) { shadingEngine = shader->shadingEngine(); } if( !shadingEngine ) { return static_cast<const CompoundData *>( shadingPlug()->defaultValue() ); } const V2i tileOrigin = context->get<V2i>( ImagePlug::tileOriginContextName ); const Format format = inPlug()->formatPlug()->getValue(); CompoundDataPtr shadingPoints = new CompoundData(); V3fVectorDataPtr pData = new V3fVectorData; FloatVectorDataPtr uData = new FloatVectorData; FloatVectorDataPtr vData = new FloatVectorData; vector<V3f> &pWritable = pData->writable(); vector<float> &uWritable = uData->writable(); vector<float> &vWritable = vData->writable(); const size_t tileSize = ImagePlug::tileSize(); pWritable.reserve( tileSize * tileSize ); uWritable.reserve( tileSize * tileSize ); vWritable.reserve( tileSize * tileSize ); /// \todo Non-zero display window origins - do we have those? const float uStep = 1.0f / format.width(); const float uMin = 0.5f * uStep; const float vStep = 1.0f / format.height(); const float vMin = 0.5f * vStep; const size_t xMax = tileOrigin.x + tileSize; const size_t yMax = tileOrigin.y + tileSize; for( size_t y = tileOrigin.y; y < yMax; ++y ) { const float v = vMin + y * vStep; for( size_t x = tileOrigin.x; x < xMax; ++x ) { uWritable.push_back( uMin + x * uStep ); vWritable.push_back( v ); pWritable.push_back( V3f( x, y, 0.0f ) ); } } shadingPoints->writable()["P"] = pData; shadingPoints->writable()["u"] = uData; shadingPoints->writable()["v"] = vData; ConstStringVectorDataPtr channelNamesData = inPlug()->channelNamesPlug()->getValue(); const vector<string> &channelNames = channelNamesData->readable(); for( vector<string>::const_iterator it = channelNames.begin(), eIt = channelNames.end(); it != eIt; ++it ) { shadingPoints->writable()[*it] = boost::const_pointer_cast<FloatVectorData>( inPlug()->channelData( *it, tileOrigin ) ); } CompoundDataPtr result = shadingEngine->shade( shadingPoints.get() ); // remove results that aren't suitable to become channels for( CompoundDataMap::iterator it = result->writable().begin(); it != result->writable().end(); ) { CompoundDataMap::iterator nextIt = it; nextIt++; if( !runTimeCast<FloatVectorData>( it->second ) ) { result->writable().erase( it ); } it = nextIt; } return result; }
void FaceAreaOp::modifyTypedPrimitive( MeshPrimitive * mesh, const CompoundObject * operands ) { string areaPrimVarName = parameters()->parameter<StringParameter>( "areaPrimVar" )->getTypedValue(); if( areaPrimVarName!="" ) { const string &pName = parameters()->parameter<StringParameter>( "pointPrimVar" )->getTypedValue(); ConstV3fVectorDataPtr pData = mesh->variableData<V3fVectorData>( pName, PrimitiveVariable::Vertex ); if( !pData ) { throw InvalidArgumentException( boost::str( boost::format( "FaceAreaOp : MeshPrimitive has no \"%s\" primitive variable." ) % pName ) ); } const vector<V3f> &p = pData->readable(); FloatVectorDataPtr areasData = new FloatVectorData; vector<float> &areas = areasData->writable(); areas.reserve( mesh->variableSize( PrimitiveVariable::Uniform ) ); PolygonIterator faceEnd = mesh->faceEnd(); for( PolygonIterator pIt = mesh->faceBegin(); pIt!=faceEnd; pIt++ ) { typedef vector<V3f> PointVector; areas.push_back( polygonArea( pIt.vertexBegin( p.begin() ), pIt.vertexEnd( p.begin() ) ) ); } mesh->variables[areaPrimVarName] = PrimitiveVariable( PrimitiveVariable::Uniform, areasData ); } string textureAreaPrimVarName = parameters()->parameter<StringParameter>( "textureAreaPrimVar" )->getTypedValue(); if( textureAreaPrimVarName!="" ) { const string &sName = parameters()->parameter<StringParameter>( "sPrimVar" )->getTypedValue(); PrimitiveVariable::Interpolation sInterpolation = PrimitiveVariable::Vertex; ConstFloatVectorDataPtr sData = mesh->variableData<FloatVectorData>( sName, PrimitiveVariable::Vertex ); if( !sData ) { sData = mesh->variableData<FloatVectorData>( sName, PrimitiveVariable::FaceVarying ); if( !sData ) { throw InvalidArgumentException( boost::str( boost::format( "FaceAreaOp : MeshPrimitive has no suitable \"%s\" primitive variable." ) % sName ) ); } sInterpolation = PrimitiveVariable::FaceVarying; } const vector<float> &s = sData->readable(); const string &tName = parameters()->parameter<StringParameter>( "tPrimVar" )->getTypedValue(); PrimitiveVariable::Interpolation tInterpolation = PrimitiveVariable::Vertex; ConstFloatVectorDataPtr tData = mesh->variableData<FloatVectorData>( tName, PrimitiveVariable::Vertex ); if( !tData ) { tData = mesh->variableData<FloatVectorData>( tName, PrimitiveVariable::FaceVarying ); if( !tData ) { throw InvalidArgumentException( boost::str( boost::format( "FaceAreaOp : MeshPrimitive has no suitable \"%s\" primitive variable." ) % tName ) ); } tInterpolation = PrimitiveVariable::FaceVarying; } const vector<float> &t = tData->readable(); if( sInterpolation!=tInterpolation ) { throw InvalidArgumentException( boost::str( boost::format( "FaceAreaOp : interpolation for \"%s\" and \"%s\" primitive variables don't match." ) % sName % tName ) ); } FloatVectorDataPtr textureAreasData = new FloatVectorData; vector<float> &textureAreas = textureAreasData->writable(); textureAreas.reserve( mesh->variableSize( PrimitiveVariable::Uniform ) ); PolygonIterator faceEnd = mesh->faceEnd(); for( PolygonIterator pIt = mesh->faceBegin(); pIt!=faceEnd; pIt++ ) { if( sInterpolation==PrimitiveVariable::Vertex ) { typedef PolygonVertexIterator<vector<float>::const_iterator> VertexIterator; typedef boost::tuple<VertexIterator, VertexIterator> IteratorTuple; typedef boost::zip_iterator<IteratorTuple> ZipIterator; typedef boost::transform_iterator<STTupleToV3f, ZipIterator> STIterator; STIterator begin( ZipIterator( IteratorTuple( pIt.vertexBegin( s.begin() ), pIt.vertexBegin( t.begin() ) ) ) ); STIterator end( ZipIterator( IteratorTuple( pIt.vertexEnd( s.begin() ), pIt.vertexEnd( t.begin() ) ) ) ); textureAreas.push_back( polygonArea( begin, end ) ); } else { assert( sInterpolation==PrimitiveVariable::FaceVarying ); typedef boost::tuple<vector<float>::const_iterator, vector<float>::const_iterator> IteratorTuple; typedef boost::zip_iterator<IteratorTuple> ZipIterator; typedef boost::transform_iterator<STTupleToV3f, ZipIterator> STIterator; STIterator begin( ZipIterator( IteratorTuple( pIt.faceVaryingBegin( s.begin() ), pIt.faceVaryingBegin( t.begin() ) ) ) ); STIterator end( ZipIterator( IteratorTuple( pIt.faceVaryingEnd( s.begin() ), pIt.faceVaryingEnd( t.begin() ) ) ) ); textureAreas.push_back( polygonArea( begin, end ) ); } } mesh->variables[textureAreaPrimVarName] = PrimitiveVariable( PrimitiveVariable::Uniform, textureAreasData ); } }
void FromHoudiniPolygonsConverter::convertCreases( MeshPrimitive *mesh, const std::vector<int> &vertIds, size_t numEdges ) const { // Houdini stores creases via a Vertex Attrib (which has been converted to a FaceVarying PrimitiveVariable), // with the first face-vert of each creased face-edge containing the sharpness, and all other face-verts set to 0. const auto *creaseWeightData = mesh->variableData<FloatVectorData>( g_creaseWeightAttrib, PrimitiveVariable::FaceVarying ); if( !creaseWeightData ) { return; } IntVectorDataPtr creaseLengthsData = new IntVectorData(); auto &creaseLengths = creaseLengthsData->writable(); IntVectorDataPtr creaseIdsData = new IntVectorData(); auto &creaseIds = creaseIdsData->writable(); FloatVectorDataPtr creaseSharpnessesData = new FloatVectorData(); auto &creaseSharpnesses = creaseSharpnessesData->writable(); // Calculate face-edge offsets based on winding order in Houdini, // which is opposite to that of Cortex. We need these to map from // single face-vert crease weights and find both verts of the edge. size_t faceOffset = 0; std::vector<int> windingOffsets; // most face-vert offsets will be to use the previous face-vert windingOffsets.resize( mesh->variableSize( PrimitiveVariable::FaceVarying ), -1 ); for( auto numFaceVerts : mesh->verticesPerFace()->readable() ) { // but we need to mark a wraparound vert for each face windingOffsets[faceOffset] = (numFaceVerts - 1); faceOffset += numFaceVerts; } const auto &creaseWeights = creaseWeightData->readable(); for( int i = 0; i < creaseWeights.size(); ++i ) { // there is a crease at this face-edge if( creaseWeights[i] > 0.0f ) { // locate the 2nd vert of this face-edge int nextFaceVert = i + windingOffsets[i]; // Since Houdini will have stored the crease in both directions // (once for each face-edge), we need to make sure we only record // it once, so we enforce that the vertIds are increasing. if( vertIds[i] < vertIds[nextFaceVert] ) { creaseLengths.push_back( 2 ); creaseIds.push_back( vertIds[i] ); creaseIds.push_back( vertIds[nextFaceVert] ); creaseSharpnesses.push_back( creaseWeights[i] ); } } } if( !creaseLengths.empty() ) { mesh->setCreases( creaseLengthsData.get(), creaseIdsData.get(), creaseSharpnessesData.get() ); mesh->variables.erase( g_creaseWeightAttrib ); } }
MeshPrimitivePtr MeshPrimitive::createPlane( const Box2f &b, const Imath::V2i &divisions ) { V3fVectorDataPtr pData = new V3fVectorData; std::vector<V3f> &p = pData->writable(); // add vertices float xStep = b.size().x / (float)divisions.x; float yStep = b.size().y / (float)divisions.y; for ( int i = 0; i <= divisions.y; ++i ) { for ( int j = 0; j <= divisions.x; ++j ) { p.push_back( V3f( b.min.x + j * xStep, b.min.y + i * yStep, 0 ) ); } } IntVectorDataPtr vertexIds = new IntVectorData; IntVectorDataPtr verticesPerFace = new IntVectorData; std::vector<int> &vpf = verticesPerFace->writable(); std::vector<int> &vIds = vertexIds->writable(); FloatVectorDataPtr sData = new FloatVectorData; FloatVectorDataPtr tData = new FloatVectorData; std::vector<float> &s = sData->writable(); std::vector<float> &t = tData->writable(); float sStep = 1.0f / (float)divisions.x; float tStep = 1.0f / (float)divisions.y; // add faces int v0, v1, v2, v3; for ( int i = 0; i < divisions.y; ++i ) { for ( int j = 0; j < divisions.x; ++j ) { v0 = j + (divisions.x+1) * i; v1 = j + 1 + (divisions.x+1) * i;; v2 = j + 1 + (divisions.x+1) * (i+1); v3 = j + (divisions.x+1) * (i+1); vpf.push_back( 4 ); vIds.push_back( v0 ); vIds.push_back( v1 ); vIds.push_back( v2 ); vIds.push_back( v3 ); s.push_back( j * sStep ); s.push_back( (j+1) * sStep ); s.push_back( (j+1) * sStep ); s.push_back( j * sStep ); t.push_back( 1 - i * tStep ); t.push_back( 1 - i * tStep ); t.push_back( 1 - (i+1) * tStep ); t.push_back( 1 - (i+1) * tStep ); } } MeshPrimitivePtr result = new MeshPrimitive( verticesPerFace, vertexIds, "linear", pData ); result->variables["s"] = PrimitiveVariable( PrimitiveVariable::FaceVarying, sData ); result->variables["t"] = PrimitiveVariable( PrimitiveVariable::FaceVarying, tData ); return result; }
IECore::ConstFloatVectorDataPtr Merge::merge( F f, const std::string &channelName, const Imath::V2i &tileOrigin ) const { FloatVectorDataPtr resultData = NULL; // Temporary buffer for computing the alpha of intermediate composited layers. FloatVectorDataPtr resultAlphaData = NULL; const Box2i tileBound( tileOrigin, tileOrigin + V2i( ImagePlug::tileSize() ) ); for( ImagePlugIterator it( inPlugs() ); !it.done(); ++it ) { if( !(*it)->getInput<ValuePlug>() ) { continue; } IECore::ConstStringVectorDataPtr channelNamesData = (*it)->channelNamesPlug()->getValue(); const std::vector<std::string> &channelNames = channelNamesData->readable(); ConstFloatVectorDataPtr channelData; ConstFloatVectorDataPtr alphaData; if( channelExists( channelNames, channelName ) ) { channelData = (*it)->channelDataPlug()->getValue(); } else { channelData = ImagePlug::blackTile(); } if( channelExists( channelNames, "A" ) ) { alphaData = (*it)->channelData( "A", tileOrigin ); } else { alphaData = ImagePlug::blackTile(); } const Box2i validBound = boxIntersection( tileBound, (*it)->dataWindowPlug()->getValue() ); if( !resultData ) { // The first connected layer, with which we must initialise our result. // There's no guarantee that this layer actually covers the full data // window though (the data window could have been expanded by the upper // layers) so we must take care to mask out any invalid areas of the input. /// \todo I'm not convinced this is correct - if we have no connection /// to in[0] then should that not be treated as being a black image, so /// we should unconditionally initaliase with in[0] and then always use /// the operation for in[1:], even if in[0] is disconnected. In other /// words, shouldn't multiplying a white constant over an unconnected /// in[0] produce black? resultData = channelData->copy(); resultAlphaData = alphaData->copy(); float *B = &resultData->writable().front(); float *b = &resultAlphaData->writable().front(); for( int y = tileBound.min.y; y < tileBound.max.y; ++y ) { const bool yValid = y >= validBound.min.y && y < validBound.max.y; for( int x = tileBound.min.x; x < tileBound.max.x; ++x ) { if( !yValid || x < validBound.min.x || x >= validBound.max.x ) { *B = *b = 0.0f; } ++B; ++b; } } } else { // A higher layer (A) which must be composited over the result (B). const float *A = &channelData->readable().front(); float *B = &resultData->writable().front(); const float *a = &alphaData->readable().front(); float *b = &resultAlphaData->writable().front(); for( int y = tileBound.min.y; y < tileBound.max.y; ++y ) { const bool yValid = y >= validBound.min.y && y < validBound.max.y; for( int x = tileBound.min.x; x < tileBound.max.x; ++x ) { const bool valid = yValid && x >= validBound.min.x && x < validBound.max.x; *B = f( valid ? *A : 0.0f, *B, valid ? *a : 0.0f, *b ); *b = f( valid ? *a : 0.0f, *b, valid ? *a : 0.0f, *b ); ++A; ++B; ++a; ++b; } } } } return resultData; }
IECore::ConstFloatVectorDataPtr Mix::computeChannelData( const std::string &channelName, const Imath::V2i &tileOrigin, const Gaffer::Context *context, const ImagePlug *parent ) const { const float mix = mixPlug()->getValue(); if( mix == 0.0f ) { return inPlugs()->getChild< ImagePlug>( 0 )->channelDataPlug()->getValue(); } else if( mix == 1.0f && !maskPlug()->getInput<ValuePlug>() ) { return inPlugs()->getChild< ImagePlug >( 1 )->channelDataPlug()->getValue(); } const Box2i tileBound( tileOrigin, tileOrigin + V2i( ImagePlug::tileSize() ) ); IECore::ConstStringVectorDataPtr maskChannelNamesData; Box2i maskDataWindow; { ImagePlug::GlobalScope c( Context::current() ); maskChannelNamesData = maskPlug()->channelNamesPlug()->getValue(); maskDataWindow = maskPlug()->dataWindowPlug()->getValue(); } const std::string &maskChannel = maskChannelPlug()->getValue(); ConstFloatVectorDataPtr maskData = NULL; Box2i maskValidBound; if( maskPlug()->getInput<ValuePlug>() && ImageAlgo::channelExists( maskChannelNamesData->readable(), maskChannel ) ) { maskData = maskPlug()->channelData( maskChannel, tileOrigin ); maskValidBound = boxIntersection( tileBound, maskDataWindow ); } ConstFloatVectorDataPtr channelData[2]; Box2i validBound[2]; int i = 0; for( ImagePlugIterator it( inPlugs() ); !it.done(); ++it,++i ) { IECore::ConstStringVectorDataPtr channelNamesData; Box2i dataWindow; { ImagePlug::GlobalScope c( Context::current() ); channelNamesData = (*it)->channelNamesPlug()->getValue(); dataWindow = (*it)->dataWindowPlug()->getValue(); } const std::vector<std::string> &channelNames = channelNamesData->readable(); if( ImageAlgo::channelExists( channelNames, channelName ) ) { channelData[i] = (*it)->channelDataPlug()->getValue(); validBound[i] = boxIntersection( tileBound, dataWindow ); } else { channelData[i] = NULL; validBound[i] = Box2i(); } } FloatVectorDataPtr resultData = ImagePlug::blackTile()->copy(); float *R = &resultData->writable().front(); const float *A = channelData[0] ? &channelData[0]->readable().front() : NULL; const float *B = channelData[1] ? &channelData[1]->readable().front() : NULL; const float *M = maskData ? &maskData->readable().front() : NULL; for( int y = tileBound.min.y; y < tileBound.max.y; ++y ) { const bool yValidIn0 = y >= validBound[0].min.y && y < validBound[0].max.y; const bool yValidIn1 = y >= validBound[1].min.y && y < validBound[1].max.y; const bool yValidMask = y >= maskValidBound.min.y && y < maskValidBound.max.y; for( int x = tileBound.min.x; x < tileBound.max.x; ++x ) { float a = 0; if( yValidIn0 && x >= validBound[0].min.x && x < validBound[0].max.x ) { a = *A; } float b = 0; if( yValidIn1 && x >= validBound[1].min.x && x < validBound[1].max.x ) { b = *B; } float m = mix; if( yValidMask && x >= maskValidBound.min.x && x < maskValidBound.max.x ) { m *= std::max( 0.0f, std::min( 1.0f, *M ) ); } *R = a * ( 1 - m ) + b * m; ++R; ++A; ++B; ++M; } } return resultData; }
IECore::ConstFloatVectorDataPtr Resample::computeChannelData( const std::string &channelName, const Imath::V2i &tileOrigin, const Gaffer::Context *context, const ImagePlug *parent ) const { V2f ratio, offset; ratioAndOffset( matrixPlug()->getValue(), ratio, offset ); Filter2DPtr filter = createFilter( filterPlug()->getValue(), filterWidthPlug()->getValue(), ratio ); const unsigned passes = requiredPasses( this, parent, filter.get() ); Sampler sampler( passes == Vertical ? horizontalPassPlug() : inPlug(), channelName, inputRegion( tileOrigin, passes, ratio, offset, filter.get() ), (Sampler::BoundingMode)boundingModePlug()->getValue() ); const V2i filterRadius = inputFilterRadius( filter.get(), ratio ); const Box2i tileBound( tileOrigin, tileOrigin + V2i( ImagePlug::tileSize() ) ); FloatVectorDataPtr resultData = new FloatVectorData; resultData->writable().resize( ImagePlug::tileSize() * ImagePlug::tileSize() ); std::vector<float>::iterator pIt = resultData->writable().begin(); if( passes == Both ) { // When the filter isn't separable we must perform all the // filtering in a single pass. This version also provides // a reference implementation against which the two-pass // version can be validated - use the SinglePass debug mode // to force the use of this code path. V2i oP; // output pixel position V2f iP; // input pixel position (floating point) V2i iPI; // input pixel position (floored to int) V2f iPF; // fractional part of input pixel position after flooring for( oP.y = tileBound.min.y; oP.y < tileBound.max.y; ++oP.y ) { iP.y = ( oP.y + 0.5 ) / ratio.y + offset.y; iPF.y = OIIO::floorfrac( iP.y, &iPI.y ); for( oP.x = tileBound.min.x; oP.x < tileBound.max.x; ++oP.x ) { iP.x = ( oP.x + 0.5 ) / ratio.x + offset.x; iPF.x = OIIO::floorfrac( iP.x, &iPI.x ); V2i fP; // relative filter position float v = 0.0f; float totalW = 0.0f; for( fP.y = -filterRadius.y; fP.y<= filterRadius.y; ++fP.y ) { for( fP.x = -filterRadius.x; fP.x<= filterRadius.x; ++fP.x ) { /// \todo version of sample taking V2i. const float w = (*filter)( ratio.x * (fP.x - ( iPF.x - 0.5f )), ratio.y * (fP.y - ( iPF.y - 0.5f )) ); if( w == 0.0f ) { continue; } v += w * sampler.sample( iPI.x + fP.x, iPI.y + fP.y ); totalW += w; } } if( totalW != 0.0f ) { *pIt = v / totalW; } ++pIt; } } } else if( passes == Horizontal ) { // When the filter is separable we can perform filtering in two // passes, one for the horizontal and one for the vertical. We // output the horizontal pass on the horizontalPassPlug() so that // it is cached for use in the vertical pass. The HorizontalPass // debug mode causes this pass to be output directly for inspection. // Pixels in the same column share the same filter weights, so // we precompute the weights now to avoid repeating work later. std::vector<float> weights; filterWeights( filter.get(), filterRadius.x, tileBound.min.x, ratio.x, offset.x, Horizontal, weights ); V2i oP; // output pixel position float iX; // input pixel x coordinate (floating point) int iXI; // input pixel position (floored to int) for( oP.y = tileBound.min.y; oP.y < tileBound.max.y; ++oP.y ) { std::vector<float>::const_iterator wIt = weights.begin(); for( oP.x = tileBound.min.x; oP.x < tileBound.max.x; ++oP.x ) { iX = ( oP.x + 0.5 ) / ratio.x + offset.x; OIIO::floorfrac( iX, &iXI ); int fX; // relative filter position float v = 0.0f; float totalW = 0.0f; for( fX = -filterRadius.x; fX<= filterRadius.x; ++fX ) { const float w = *wIt++; if( w == 0.0f ) { continue; } v += w * sampler.sample( iXI + fX, oP.y ); totalW += w; } if( totalW != 0.0f ) { *pIt = v / totalW; } ++pIt; } } } else if( passes == Vertical ) { V2i oP; // output pixel position float iY; // input pixel position (floating point) int iYI; // input pixel position (floored to int) // Pixels in the same row share the same filter weights, so // we precompute the weights now to avoid repeating work later. std::vector<float> weights; filterWeights( filter.get(), filterRadius.y, tileBound.min.y, ratio.y, offset.y, Vertical, weights ); for( oP.y = tileBound.min.y; oP.y < tileBound.max.y; ++oP.y ) { iY = ( oP.y + 0.5 ) / ratio.y + offset.y; OIIO::floorfrac( iY, &iYI ); for( oP.x = tileBound.min.x; oP.x < tileBound.max.x; ++oP.x ) { int fY; // relative filter position float v = 0.0f; float totalW = 0.0f; std::vector<float>::const_iterator wIt = weights.begin() + ( oP.y - tileBound.min.y ) * ( filterRadius.y * 2 + 1); for( fY = -filterRadius.y; fY<= filterRadius.y; ++fY ) { const float w = *wIt++; if( w == 0.0f ) { continue; } v += w * sampler.sample( oP.x, iYI + fY ); totalW += w; } if( totalW != 0.0f ) { *pIt = v / totalW; } ++pIt; } } } return resultData; }