//-----------------------------------------------------------------------
        public static void _extrudeShape(ref TriangleBuffer buffer, Shape shape, Vector3 position, Quaternion orientationLeft, Quaternion orientationRight, float scale, float scaleCorrectionLeft, float scaleCorrectionRight, float totalShapeLength, float uTexCoord, bool joinToTheNextSection, Track shapeTextureTrack)
        {
            float lineicShapePos = 0.0f;
            int   numSegShape    = shape.getSegCount();

            // Insert new points
            for (uint j = 0; j <= numSegShape; ++j)
            {
                Vector2    vp2         = shape.getPoint((int)j);
                Quaternion orientation = (vp2.x > 0) ? orientationRight : orientationLeft;
                Vector2    vp2normal   = shape.getAvgNormal(j);
                Vector3    vp          = new Vector3();
                if (vp2.x > 0)
                {
                    vp = new Vector3(scaleCorrectionRight * vp2.x, vp2.y, 0);
                }
                else
                {
                    vp = new Vector3(scaleCorrectionLeft * vp2.x, vp2.y, 0);
                }
                Vector3 normal = new Vector3(vp2normal.x, vp2normal.y, 0);
                buffer.rebaseOffset();
                Vector3 newPoint = position + orientation * (scale * vp);
                if (j > 0)
                {
                    lineicShapePos += (vp2 - shape.getPoint((int)j - 1)).Length;
                }
                float vTexCoord = 0f;
                if (shapeTextureTrack != null)
                {
                    vTexCoord = shapeTextureTrack.getValue(lineicShapePos, lineicShapePos / totalShapeLength, j);
                }
                else
                {
                    vTexCoord = lineicShapePos / totalShapeLength;
                }

                buffer.vertex(newPoint, orientation * normal, new Vector2(uTexCoord, vTexCoord));

                if (j < numSegShape && joinToTheNextSection)
                {
                    if (shape.getOutSide() == Side.SIDE_LEFT)
                    {
                        buffer.triangle(numSegShape + 1, numSegShape + 2, 0);
                        buffer.triangle(0, numSegShape + 2, 1);
                    }
                    else
                    {
                        buffer.triangle(numSegShape + 2, numSegShape + 1, 0);
                        buffer.triangle(numSegShape + 2, 0, 1);
                    }
                }
            }
        }
        //-----------------------------------------------------------------------
        public static void _extrudeBodyImpl(ref TriangleBuffer buffer, Shape shapeToExtrude, Path pathToExtrude, int pathBeginIndex, int pathEndIndex, Track shapeTextureTrack, Track rotationTrack, Track scaleTrack, Track pathTextureTrack)
        {
            if (pathToExtrude == null || shapeToExtrude == null)
            {
                OGRE_EXCEPT("Ogre::Exception::ERR_INVALID_STATE", "Shape and Path must not be null!", "Procedural::Extruder::_extrudeBodyImpl(Procedural::TriangleBuffer&, const Procedural::Shape*)");
            }
            ;

            uint numSegPath  = (uint)(pathEndIndex - pathBeginIndex);
            uint numSegShape = (uint)shapeToExtrude.getSegCount();

            if (numSegPath == 0 || numSegShape == 0)
            {
                OGRE_EXCEPT("Ogre::Exception::ERR_INVALID_STATE", "Shape and path must contain at least two points", "Procedural::Extruder::_extrudeBodyImpl(Procedural::TriangleBuffer&, const Procedural::Shape*)");
            }
            ;

            float totalPathLength  = pathToExtrude.getTotalLength();
            float totalShapeLength = shapeToExtrude.getTotalLength();

            // Merge shape and path with tracks
            float lineicPos = pathToExtrude.getLengthAtPoint(pathBeginIndex);
            Path  path      = pathToExtrude;

            numSegPath  = (uint)(pathEndIndex - pathBeginIndex);
            numSegShape = (uint)shapeToExtrude.getSegCount();

            // Estimate vertex and index count
            buffer.rebaseOffset();
            buffer.estimateIndexCount(numSegShape * numSegPath * 6);
            buffer.estimateVertexCount((numSegShape + 1) * (numSegPath + 1));

            Vector3 oldup = new Vector3();

            for (int i = pathBeginIndex; i <= pathEndIndex; ++i)
            {
                Vector3 v0        = path.getPoint(i);
                Vector3 direction = path.getAvgDirection(i);

                Quaternion q = Utils._computeQuaternion(direction);

                Radian angle = Utils.angleBetween((q * Vector3.UNIT_Y), (oldup));
                if (i > pathBeginIndex && angle > (Radian)Math.HALF_PI / 2.0f)
                {
                    q = Utils._computeQuaternion(direction, oldup);
                }
                oldup = q * Vector3.UNIT_Y;

                float scale = 1.0f;

                if (i > pathBeginIndex)
                {
                    lineicPos += (v0 - path.getPoint(i - 1)).Length;
                }

                // Get the values of angle and scale
                if (rotationTrack != null)
                {
                    float angle_2 = 0f;
                    angle_2 = rotationTrack.getValue(lineicPos, lineicPos / totalPathLength, (uint)i);

                    q = q * new Quaternion((Radian)angle_2, Vector3.UNIT_Z);
                }
                if (scaleTrack != null)
                {
                    scale = scaleTrack.getValue(lineicPos, lineicPos / totalPathLength, (uint)i);
                }
                float uTexCoord = 0f;
                if (pathTextureTrack != null)
                {
                    uTexCoord = pathTextureTrack.getValue(lineicPos, lineicPos / totalPathLength, (uint)i);
                }
                else
                {
                    uTexCoord = lineicPos / totalPathLength;
                }

                _extrudeShape(ref buffer, shapeToExtrude, v0, q, q, scale, 1.0f, 1.0f, totalShapeLength, uTexCoord, i < pathEndIndex, shapeTextureTrack);
            }
        }