virtual void createVertexStream(
        const MDagPath &dagPath, 
              MVertexBuffer &vertexBuffer,
        const MComponentDataIndexing &targetIndexing,
        const MComponentDataIndexing &,
        const MVertexBufferArray &) const
    {
#else
    virtual void createVertexStream(
        const MDagPath &dagPath, MVertexBuffer &vertexBuffer,
        const MComponentDataIndexing &targetIndexing) const
    {
#endif
        const MVertexBufferDescriptor &desc = vertexBuffer.descriptor();

        MFnMesh meshFn(dagPath);
        int nVertices = meshFn.numVertices();

#if MAYA_API_VERSION >= 201350
        float *buffer = static_cast<float*>(vertexBuffer.acquire(nVertices, true));
#else
        float *buffer = static_cast<float*>(vertexBuffer.acquire(nVertices));
#endif
        float *dst = buffer;
        if (_normal) {
            MFloatVectorArray normals;
            meshFn.getVertexNormals(true, normals);
            for (int i = 0; i < nVertices; ++i) {
                *dst++ = normals[i].x;
                *dst++ = normals[i].y;
                *dst++ = normals[i].z;
            }
        } else {
            MFloatPointArray points;
            meshFn.getPoints(points);
            for (int i = 0; i < nVertices; ++i) {
                *dst++ = points[i].x;
                *dst++ = points[i].y;
                *dst++ = points[i].z;
            }
        }
        vertexBuffer.commit(buffer);
    }

    static MPxVertexBufferGenerator *positionBufferCreator()
    {
        return new OsdBufferGenerator(/*normal = */false);
    }
    static MPxVertexBufferGenerator *normalBufferCreator()
    {
        return new OsdBufferGenerator(/*normal = */true);
    }
private:
    virtual void createVertexStream(
#if MAYA_API_VERSION >= 201400
        const MObject &object, 
#else
        const MDagPath &dagPath, 
#endif        
              MVertexBuffer &vertexBuffer,
        const MComponentDataIndexing &targetIndexing,
        const MComponentDataIndexing &,
        const MVertexBufferArray &) const
    {
#else
    virtual void createVertexStream(
        const MDagPath &dagPath, MVertexBuffer &vertexBuffer,
        const MComponentDataIndexing &targetIndexing) const
    {
#endif

#if MAYA_API_VERSION >= 201400
        MFnMesh meshFn(object);
#else
        MFnMesh meshFn(dagPath);
#endif
        int nVertices = meshFn.numVertices();

#if MAYA_API_VERSION >= 201350
        float *buffer = static_cast<float*>(vertexBuffer.acquire(nVertices, true));
#else
        float *buffer = static_cast<float*>(vertexBuffer.acquire(nVertices));
#endif
        float *dst = buffer;
        if (_normal) {
            MFloatVectorArray normals;
            meshFn.getVertexNormals(true, normals);
            for (int i = 0; i < nVertices; ++i) {
                *dst++ = normals[i].x;
                *dst++ = normals[i].y;
                *dst++ = normals[i].z;
            }
        } else {
            MFloatPointArray points;
            meshFn.getPoints(points);
            for (int i = 0; i < nVertices; ++i) {
                *dst++ = points[i].x;
                *dst++ = points[i].y;
                *dst++ = points[i].z;
            }
        }
        vertexBuffer.commit(buffer);
    }
    virtual void createVertexStream(const MObject& object,
        MVertexBuffer& vertexBuffer, const MComponentDataIndexing& targetIndexing, const MComponentDataIndexing& /*sharedIndexing*/, const MVertexBufferArray& /*sourceStreams*/) const
    {
        // get the descriptor from the vertex buffer.  
        // It describes the format and layout of the stream.
        const MVertexBufferDescriptor& descriptor = vertexBuffer.descriptor();
        
        // we are expecting a float stream.
        if (descriptor.dataType() != MGeometry::kFloat) 
            return;

        // we are expecting a float2
        if (descriptor.dimension() != 2)
            return;

        // we are expecting a texture channel
        if (descriptor.semantic() != MGeometry::kTexture)
            return;

        // get the mesh from the current path
        // if it is not a mesh we do nothing.
        MStatus status;
        MFnMesh mesh(object, &status);
        if (!status) return; // failed

        const MUintArray& indices = targetIndexing.indices();

        unsigned int vertexCount = indices.length();
        if (vertexCount <= 0)
            return;

        // acquire the buffer to fill with data.
        float* buffer = (float*)vertexBuffer.acquire(vertexCount, true /*writeOnly - we don't need the current buffer values*/);
        float* start = buffer;

        for(unsigned int i = 0; i < vertexCount; ++i)
        {
            // Here we are embedding some custom data into the stream.
            // The included effects (vertexBufferGeneratorGL.cgfx and
            // vertexBufferGeneratorDX11.fx) will alternate 
            // red, green, and blue vertex colored triangles based on this input.
            *(buffer++) = 1.0f;
            *(buffer++) = (float)indices[i]; // color index
        }

        // commit the buffer to signal completion.
        vertexBuffer.commit(start);
    }
                                    const MVertexBufferArray &) const 
#else
    virtual void createVertexStream(const MDagPath &dagPath, MVertexBuffer &vertexBuffer,
                                    const MComponentDataIndexing &targetIndexing) const 
#endif
        {
            const MVertexBufferDescriptor &desc = vertexBuffer.descriptor();

            MFnMesh meshFn(dagPath);
            int nVertices = meshFn.numVertices();
            if (!_normal) {
                MFloatPointArray points;
                meshFn.getPoints(points);
                
#ifdef MAYA2013_PREVIEW
                float *buffer = (float*)vertexBuffer.acquire(nVertices, true);
#else
                float *buffer = (float*)vertexBuffer.acquire(nVertices);
#endif
                float *dst = buffer;
                for(int i=0; i < nVertices; ++i){
                    *dst++ = points[i].x;
                    *dst++ = points[i].y;
                    *dst++ = points[i].z;
                }
                vertexBuffer.commit(buffer);
            } else {
                MFloatVectorArray normals;
                meshFn.getVertexNormals(true, normals);

#ifdef MAYA2013_PREVIEW
                float *buffer = (float*)vertexBuffer.acquire(nVertices, true);
#else
                float *buffer = (float*)vertexBuffer.acquire(nVertices);
#endif
                float *dst = buffer;
                for(int i=0; i < nVertices; ++i){
                    *dst++ = normals[i].x;
                    *dst++ = normals[i].y;
                    *dst++ = normals[i].z;
                }
                vertexBuffer.commit(buffer);
            }
        }
void geometryReplicatorGeometryOverride::populateGeometry(
	const MGeometryRequirements& requirements,
	const MRenderItemList& renderItems,
	MGeometry& data)
{
	if (!fPath.isValid())
		return;

	// MGeometryExtractor::MGeometryExtractor.
	// here, fPath is the path of the linked object instead of the plugin node; it
	// is used to determine the right type of the geometry shape, e.g., polygon
	// or NURBS surface.
	// The sharing flag (true here) is just for the polygon shape.
	MStatus status;
	MPolyGeomOptions options = kPolyGeom_Normal;
	if( isBaseMesh() ) options = options|kPolyGeom_BaseMesh;
	MGeometryExtractor extractor(requirements, fPath, options, &status);
	if (MS::kFailure == status)
		return;

	// fill vertex buffer
	const MVertexBufferDescriptorList& descList = requirements.vertexRequirements();
	for (int reqNum = 0; reqNum < descList.length(); ++reqNum)
	{
		MVertexBufferDescriptor desc;
		if (!descList.getDescriptor(reqNum, desc))
		{
			continue;
		}

		switch (desc.semantic())
		{
		case MGeometry::kPosition:
		case MGeometry::kNormal:
		case MGeometry::kTexture:
		case MGeometry::kTangent:
		case MGeometry::kBitangent:
		case MGeometry::kColor:
			{
				MVertexBuffer* vertexBuffer = data.createVertexBuffer(desc);
				if (vertexBuffer) {
					// MGeometryExtractor::vertexCount and MGeometryExtractor::populateVertexBuffer.
					// since the plugin node has the same vertex data as its linked scene object,
					// call vertexCount to allocate vertex buffer of the same size, and then call
					// populateVertexBuffer to copy the data.
					unsigned int vertexCount = extractor.vertexCount();
					float* data = (float*)vertexBuffer->acquire(vertexCount, true /*writeOnly - we don't need the current buffer values*/);
					if (data) {
						status = extractor.populateVertexBuffer(data, vertexCount, desc);
						if (MS::kFailure == status)
							return;
						vertexBuffer->commit(data);
					}
				}
			}
			break;

		default:
			// do nothing for stuff we don't understand
			break;
		}
	}

	// fill index buffer
	for (int i = 0; i < renderItems.length(); ++i)
	{
		const MRenderItem* item = renderItems.itemAt(i);
		if (!item) continue;

		MIndexBuffer* indexBuffer = data.createIndexBuffer(MGeometry::kUnsignedInt32);
		if (!indexBuffer) continue;

		// MGeometryExtractor::primitiveCount and MGeometryExtractor::populateIndexBuffer.
		// since the plugin node has the same index data as its linked scene object,
		// call primitiveCount to allocate index buffer of the same size, and then call
		// populateIndexBuffer to copy the data.
		if (item->primitive() == MGeometry::kTriangles)
		{
			MIndexBufferDescriptor triangleDesc(MIndexBufferDescriptor::kTriangle, MString(), MGeometry::kTriangles, 3);
			unsigned int numTriangles = extractor.primitiveCount(triangleDesc);

			unsigned int* indices = (unsigned int*)indexBuffer->acquire(3 * numTriangles, true /*writeOnly - we don't need the current buffer values*/);
			status = extractor.populateIndexBuffer(indices, numTriangles, triangleDesc);
			if (MS::kFailure == status)
				return;
			indexBuffer->commit(indices);
		}
		else if (item->primitive() == MGeometry::kLines)
		{
			MIndexBufferDescriptor edgeDesc(MIndexBufferDescriptor::kEdgeLine, MString(), MGeometry::kLines, 2);
			unsigned int numEdges = extractor.primitiveCount(edgeDesc);

			unsigned int* indices = (unsigned int*)indexBuffer->acquire(2 * numEdges, true /*writeOnly - we don't need the current buffer values*/);
			status = extractor.populateIndexBuffer(indices, numEdges, edgeDesc);
			if (MS::kFailure == status)
				return;
			indexBuffer->commit(indices);
		}

		item->associateWithIndexBuffer(indexBuffer);
	}
}
	virtual void createVertexStream(const MObject& object,
        MVertexBuffer& vertexBuffer, const MComponentDataIndexing& targetIndexing, const MComponentDataIndexing& /*sourceIndexing*/, const MVertexBufferArray& sourceStreams) const
	{
		// get the descriptor from the vertex buffer.  
		// It describes the format and layout of the stream.
		const MVertexBufferDescriptor& descriptor = vertexBuffer.descriptor();
        
		// we are expecting a float or int stream.
		MGeometry::DataType dataType = descriptor.dataType();
		if (dataType != MGeometry::kFloat && dataType != MGeometry::kInt32) 
			return;

		// we are expecting a dimension of 3 or 4
		int dimension = descriptor.dimension();
		if (dimension != 4 && dimension != 3)
			return;

		// we are expecting a texture channel
		if (descriptor.semantic() != MGeometry::kTexture)
			return;

		// get the mesh from the current path
		// if it is not a mesh we do nothing.
		MStatus status;
		MFnMesh mesh(object, &status);
		if (!status) return; // failed

        const MUintArray& indices = targetIndexing.indices();

        unsigned int vertexCount = indices.length();
        if (vertexCount <= 0)
            return;

		MVertexBuffer *positionStream = sourceStreams.getBuffer( "Position" );
		if(positionStream == NULL || positionStream->descriptor().dataType() != MGeometry::kFloat)
			return;
		int positionDimension = positionStream->descriptor().dimension();
		if(positionDimension != 3 && positionDimension != 4)
			return;

		MVertexBuffer *normalStream = sourceStreams.getBuffer( "Normal" );
		if(normalStream == NULL || normalStream->descriptor().dataType() != MGeometry::kFloat)
			return;
		int normalDimension = normalStream->descriptor().dimension();
		if(normalDimension != 3 && normalDimension != 4)
			return;

		float* positionBuffer = (float*)positionStream->map();
		if(positionBuffer)
		{
			float* normalBuffer = (float*)normalStream->map();
			if(normalBuffer)
			{
				void* compositeBuffer = vertexBuffer.acquire(vertexCount, true /*writeOnly - we don't need the current buffer values*/);
				if(compositeBuffer)
				{
					void* compositeBufferStart = compositeBuffer;
					float* compositeBufferAsFloat = (float*)compositeBuffer;
					int* compositeBufferAsInt = (int*)compositeBuffer;

					for(unsigned int i = 0; i < vertexCount; ++i)
					{
						if(dataType == MGeometry::kFloat)
						{
							*(compositeBufferAsFloat++) = *(positionBuffer + 1);	// store position.y 
							*(compositeBufferAsFloat++) = *(positionBuffer + 2);	// store position.z 
							*(compositeBufferAsFloat++) = *(normalBuffer);			// store normal.x
							if(dimension == 4)
								*(compositeBufferAsFloat++) = *(normalBuffer + 2);	// store normal.z
						}
						else if(dataType == MGeometry::kInt32)
						{
							*(compositeBufferAsInt++) = (int)(*(positionBuffer + 1) * 255);		// store position.y 
							*(compositeBufferAsInt++) = (int)(*(positionBuffer + 2) * 255);		// store position.z 
							*(compositeBufferAsInt++) = (int)(*(normalBuffer) * 255);			// store normal.x
							if(dimension == 4)
								*(compositeBufferAsInt++) = (int)(*(normalBuffer + 2) * 255);	// store normal.z
						}
		
						positionBuffer += positionDimension;
						normalBuffer += normalDimension;
					}

					vertexBuffer.commit(compositeBufferStart);
				}

				normalStream->unmap();
			}

			positionStream->unmap();
		}
	}