void matrix4_assign_rotation_for_pivot(Matrix4& matrix, const scene::INodePtr& node) {
    EditablePtr editable = Node_getEditable(node);
    // If the instance is editable, take the localpivot point into account, otherwise just apply the rotation
    if (editable != 0) {
        matrix4_assign_rotation(matrix, node->localToWorld().getMultipliedBy(editable->getLocalPivot()));
    }
    else {
        matrix4_assign_rotation(matrix, node->localToWorld());
    }
}
void ScaleSelected::visit(const scene::INodePtr& node) const {
    ITransformNodePtr transformNode = Node_getTransformNode(node);
    if(transformNode != 0)
    {
      ITransformablePtr transform = Node_getTransformable(node);
      if(transform != 0)
      {
        transform->setType(TRANSFORM_PRIMITIVE);
        transform->setScale(c_scale_identity);
        transform->setTranslation(c_translation_identity);

        transform->setType(TRANSFORM_PRIMITIVE);
        transform->setScale(m_scale);
        {
          EditablePtr editable = Node_getEditable(node);
          const Matrix4& localPivot = editable != 0 ? editable->getLocalPivot() : Matrix4::getIdentity();

          Vector3 parent_translation;
          translation_for_pivoted_scale(
            parent_translation,
            m_scale,
            m_world_pivot,
			node->localToWorld().getMultipliedBy(localPivot),
			transformNode->localToParent().getMultipliedBy(localPivot)
          );

          transform->setTranslation(parent_translation);
        }
      }
    }
}
void RotateSelected::visit(const scene::INodePtr& node) const
{
    ITransformNodePtr transformNode = Node_getTransformNode(node);

    if (transformNode) 
    {
        // Upcast the instance onto a Transformable
        ITransformablePtr transformable = Node_getTransformable(node);

        if (transformable)
        {
            // The object is not scaled or translated explicitly
            // A translation might occur due to the rotation around a pivot point
            transformable->setType(TRANSFORM_PRIMITIVE);
            transformable->setScale(c_scale_identity);
            transformable->setTranslation(c_translation_identity);

            // Pass the rotation quaternion and the world pivot, 
            // unless we're rotating each object around their own center
            transformable->setRotation(_rotation, 
                _freeObjectRotation ? transformable->getUntransformedOrigin() : _worldPivot, 
                node->localToWorld());
        }
    }
}
void ModelExporter::processLight(const scene::INodePtr& node)
{
	// Export lights as small polyhedron
	static const double EXTENTS = 8.0;
	std::vector<model::ModelPolygon> polys;

	Vertex3f up(0, 0, EXTENTS);
	Vertex3f down(0, 0, -EXTENTS);
	Vertex3f north(0, EXTENTS, 0);
	Vertex3f south(0, -EXTENTS, 0);
	Vertex3f east(EXTENTS, 0, 0);
	Vertex3f west(-EXTENTS, 0, 0);

	// Upper semi-diamond
	polys.push_back(createPolyCCW(up, south, east));
	polys.push_back(createPolyCCW(up, east, north));
	polys.push_back(createPolyCCW(up, north, west));
	polys.push_back(createPolyCCW(up, west, south));

	// Lower semi-diamond
	polys.push_back(createPolyCCW(down, south, west));
	polys.push_back(createPolyCCW(down, west, north));
	polys.push_back(createPolyCCW(down, north, east));
	polys.push_back(createPolyCCW(down, east, south));

	Matrix4 exportTransform = node->localToWorld().getPremultipliedBy(_centerTransform);

	_exporter->addPolygons("lights/default", polys, exportTransform);
}
void ScaleComponentSelected::visit(const scene::INodePtr& node) const {
    ITransformablePtr transform = Node_getTransformable(node);
    if(transform != 0) {
      Vector3 parent_translation;
	  translation_for_pivoted_scale(parent_translation, m_scale, m_world_pivot, node->localToWorld(), Node_getTransformNode(node)->localToParent());

      transform->setType(TRANSFORM_COMPONENT);
      transform->setScale(m_scale);
      transform->setTranslation(parent_translation);
    }
}
void ModelExporter::processBrush(const scene::INodePtr& node)
{
	IBrush* brush = Node_getIBrush(node);

	if (brush == nullptr) return;

	Matrix4 exportTransform = node->localToWorld().getPremultipliedBy(_centerTransform);

	for (std::size_t b = 0; b < brush->getNumFaces(); ++b)
	{
		const IFace& face = brush->getFace(b);

		const std::string& materialName = face.getShader();

		if (!isExportableMaterial(materialName)) continue;

		const IWinding& winding = face.getWinding();

		std::vector<model::ModelPolygon> polys;

		if (winding.size() < 3)
		{
			rWarning() << "Skipping face with less than 3 winding verts" << std::endl;
			continue;
		}

		// Create triangles for this winding 
		for (std::size_t i = 1; i < winding.size() - 1; ++i)
		{
			model::ModelPolygon poly;

			poly.a = convertWindingVertex(winding[i + 1]);
			poly.b = convertWindingVertex(winding[i]);
			poly.c = convertWindingVertex(winding[0]);

			polys.push_back(poly);
		}

		_exporter->addPolygons(materialName, polys, exportTransform);
	}
}
void ModelExporter::processPatch(const scene::INodePtr& node)
{
	IPatch* patch = Node_getIPatch(node);

	if (patch == nullptr) return;

	const std::string& materialName = patch->getShader();

	if (!isExportableMaterial(materialName)) return;

	PatchMesh mesh = patch->getTesselatedPatchMesh();

	std::vector<model::ModelPolygon> polys;

	for (std::size_t h = 0; h < mesh.height - 1; ++h)
	{
		for (std::size_t w = 0; w < mesh.width - 1; ++w)
		{
			model::ModelPolygon poly;

			poly.a = convertPatchVertex(mesh.vertices[w + (h*mesh.width)]);
			poly.b = convertPatchVertex(mesh.vertices[w + 1 + (h*mesh.width)]);
			poly.c = convertPatchVertex(mesh.vertices[w + mesh.width + (h*mesh.width)]);

			polys.push_back(poly);
				
			poly.a = convertPatchVertex(mesh.vertices[w + 1 + (h*mesh.width)]);
			poly.b = convertPatchVertex(mesh.vertices[w + 1 + mesh.width + (h*mesh.width)]);
			poly.c = convertPatchVertex(mesh.vertices[w + mesh.width + (h*mesh.width)]);

			polys.push_back(poly);
		}
	}

	Matrix4 exportTransform = node->localToWorld().getPremultipliedBy(_centerTransform);

	_exporter->addPolygons(materialName, polys, exportTransform);
}