/// <summary>
        /// Load
        /// </summary>
        /// <param name="inputPoints">Input points</param>
        /// <param name="widthHelpers">Width helpers</param>
        /// <param name="roadHelpers">Road helpers</param>
        /// <param name="neutralObjects">Neutral objects</param>
        /// <param name="landscape">Landscape</param>
        protected void Load(Vector3[] inputPoints,
			List<TrackData.WidthHelper> widthHelpers,
			List<TrackData.RoadHelper> roadHelpers,
			List<TrackData.NeutralObject> neutralObjects,
			Landscape landscape)
        {
            #region Kill all previously loaded data
            points.Clear();
            helperPositions.Clear();

            // Kill all loaded objects
            if (landscape != null)
                landscape.KillAllLoadedObjects();
            #endregion

            #region Make sure we got valid data
            if (inputPoints == null ||
                inputPoints.Length < 3)
                throw new ArgumentException("inputPoints is invalid, we need at "+
                    "least 3 valid input points to generate a TrackLine.");
            #endregion

            #region Check if all points are ABOVE the landscape
            if (landscape != null)
            {
                // Go through all spline points
                for (int num = 0; num < inputPoints.Length; num++)
                {
                    // Get landscape height here
                    float landscapeHeight = landscape.GetMapHeight(
                        inputPoints[num].X, inputPoints[num].Y) +
                        // add little to fix ground errors
                        MinimumLandscapeDistance * 2.25f;

                    // And make sure we are always above it!
                    if (inputPoints[num].Z < landscapeHeight)
                        inputPoints[num].Z = landscapeHeight;
                } // for (num)

                // Second pass, check 24 interpolation points between all inputPoints
                for (int num = 0; num < inputPoints.Length; num++)
                    for (int iter = 1; iter < 25; iter++)
              {
                        float iterPercent = iter / 25.0f;

                        float iterHeight = inputPoints[num].Z * (1 - iterPercent) +
                            inputPoints[(num + 1) % inputPoints.Length].Z * iterPercent;

                        // Check 2x2 points (in all directions) to make sure
                        // we don't go through the landscape at the sides
                        for (int x = 0; x < 2; x++)
                            for (int y = 0; y < 2; y++)
                            {
                                // Also get height at middle to next pos
                                float landscapeHeight = landscape.GetMapHeight(
                                    -5.0f + 10.0f * x +
                                    inputPoints[num].X * (1 - iterPercent) +
                                    inputPoints[(num + 1) % inputPoints.Length].X * iterPercent,
                                    -5.0f + 10.0f * y +
                                    inputPoints[num].Y * (1 - iterPercent) +
                                    inputPoints[(num + 1) % inputPoints.Length].Y * iterPercent)+
                                    // add little to fix ground errors
                                    MinimumLandscapeDistance * 1.6f;// 1.5f;//1.25f;

                                // Increase both positions if this point is under the landscape
                                if (iterHeight < landscapeHeight)
                                {
                                    float increaseHeight = landscapeHeight - iterHeight;
                                    inputPoints[num].Z += increaseHeight;
                                    inputPoints[(num + 1) % inputPoints.Length].Z +=
                                        increaseHeight;
                                } // if (iterHeight)
                            } // for
              } // for for (iter)
            } // if (landscape)
            //Log.Write("Input points: " + StringHelper.WriteArrayData(inputPoints));
            #endregion

            #region Search for any loopings indicated by 2 points above each other
            // Go through all spline points (ignore first and last 3, this
            // makes it easier to remove points and add new ones).
            for (int num = 1; num < inputPoints.Length-3; num++)
            {
                // X/Y distance has to be 4 times smaller than Z distance
                Vector3 distVec = inputPoints[num + 1] - inputPoints[num];
                float xyDist = (float)Math.Sqrt(
                    distVec.X*distVec.X+distVec.Y*distVec.Y);
                float zDist = Math.Abs(distVec.Z);
                // Also check if next point is down again.
                Vector3 distVec2 = inputPoints[num + 2] - inputPoints[num + 1];
                if (zDist / 2 > xyDist &&
                    Math.Abs(distVec.Z + distVec2.Z) < zDist / 2)
                {
                    // Find out which direction we are going
                    Vector3 dir = inputPoints[num] - inputPoints[num - 1];
                    dir.Normalize();
                    Vector3 upVec = new Vector3(0, 0, 1);
                    Vector3 rightVec = Vector3.Cross(dir, upVec);
                    // Matrix build helper matrix to rotate our looping points
                    Matrix rotMatrix = new Matrix(
                        rightVec.X, rightVec.Y, rightVec.Z, 0,
                        dir.X, dir.Y, dir.Z, 0,
                        upVec.X, upVec.Y, upVec.Z, 0,
                        0, 0, 0, 1);

                    // Ok do a looping with zDist as height.
                    // Start with the current point, loop around and end with the
                    // point after the looping. We will remove the current and the
                    // next 2 points, but add 9 new points instead for our smooth loop.
                    // See LoopingPoints for the looping itself.
                    Vector3 startLoopPos = inputPoints[num];
                    Vector3 endLoopPos = inputPoints[num + 2];

                    // Insert 7 new points (9 new points, but we reuse
                    // start, middle and end points which are num, num+1 and num+2,
                    // plus an additional point after the looping to keep the road
                    // straight!)
                    Vector3[] remInputPoints = (Vector3[])inputPoints.Clone();
                    inputPoints = new Vector3[inputPoints.Length + 7];
                    // Copy everything over
                    for (int copyNum = 0; copyNum < remInputPoints.Length; copyNum++)
                        if (copyNum < num)
                            inputPoints[copyNum] = remInputPoints[copyNum];
                        else
                            inputPoints[copyNum + 7] = remInputPoints[copyNum];

                    // Ok, now we can add our loop
                    for (int loopNum = 0; loopNum < LoopingPoints.Length; loopNum++)
                    {
                        // Interpolate between start and end pos to land at the end pos!
                        float loopPercent = loopNum / (float)(LoopingPoints.Length - 1);
                        inputPoints[num + loopNum] =
                            startLoopPos * (1 - loopPercent) +
                            endLoopPos * loopPercent +
                            zDist * Vector3.Transform(LoopingPoints[loopNum], rotMatrix);
                    } // for (loopNum)

                    // Add extra point to keep the road straight
                    Vector3 newRoadDir =
                        inputPoints[num + 10] - inputPoints[num + 8];
                    // Don't go more than zDist * 2 units away!
                    if (newRoadDir.Length() > zDist * 2)
                    {
                        newRoadDir.Normalize();
                        newRoadDir = newRoadDir * zDist;
                        inputPoints[num + 9] = inputPoints[num + 8] + newRoadDir;
                    } // if (newRoadDir.Length)
                    else
                        // Just add an interpolation point
                        inputPoints[num + 9] =
                            (inputPoints[num + 8] + inputPoints[num + 10])/2.0f;

                    // Advance 10 points until we check for the next loop
                    num += 10;

                    // That's it, good work everyone ^^
                } // if (zDist)
            } // for (num)
            #endregion

            #region Generate all points with help of catmull rom splines
            // Generate all points with help of catmull rom splines
            for (int num = 0; num < inputPoints.Length; num++)
            {
                // Get the 4 required points for the catmull rom spline
                Vector3 p1 = inputPoints[num-1 < 0 ? inputPoints.Length-1 : num-1];
                Vector3 p2 = inputPoints[num];
                Vector3 p3 = inputPoints[(num + 1) % inputPoints.Length];
                Vector3 p4 = inputPoints[(num + 2) % inputPoints.Length];

                // Calculate number of iterations we use here based
                // on the distance of the 2 points we generate new points from.
                float distance = Vector3.Distance(p2, p3);
                int numberOfIterations =
                    (int)(NumberOfIterationsPer100Meters * (distance / 100.0f));
                if (numberOfIterations <= 0)
                    numberOfIterations = 1;

                Vector3 lastPos = p1;
                for (int iter = 0; iter < numberOfIterations; iter++)
                {
                    TrackVertex newVertex = new TrackVertex(
                        Vector3.CatmullRom(p1, p2, p3, p4,
                        iter / (float)numberOfIterations));

                    lastPos = newVertex.pos;

                    points.Add(newVertex);
                } // for (iter)
            } // for (num)
            #endregion

            #region Generate up vectors, very important for our road building
            // Pre up vectors are used to first generate all optimal up vectors
            // for the track, but this is not useful for driving because we need
            // the road to point up always except for loopings.
            List<Vector3> preUpVectors = new List<Vector3>();

            // Now generate all up vectors, first pass does optimal up vectors.
            Vector3 defaultUpVec = new Vector3(0, 0, 1);
            Vector3 lastUpVec = defaultUpVec;
            for (int num = 0; num < points.Count; num++)
            {
                // Get direction we are driving in at this point,
                // interpolate with help of last and next points.
                Vector3 dir = points[(num + 1) % points.Count].pos -
                    points[num - 1 < 0 ? points.Count - 1 : num - 1].pos;
                dir.Normalize();

                // Now calculate the optimal up vector for this point
                Vector3 middlePoint = (points[(num + 1) % points.Count].pos +
                    points[num - 1 < 0 ? points.Count - 1 : num - 1].pos) / 2.0f;
                Vector3 optimalUpVector = middlePoint - points[num].pos;
                if (optimalUpVector.Length() < 0.0001f)
                    optimalUpVector = lastUpVec;
                optimalUpVector.Normalize();

                // Store the optimalUpVectors in the preUpVectors list
                preUpVectors.Add(optimalUpVector);

                // Also save dir vector
                points[num].dir = dir;

                // And remember the last upVec in case the road is going straight ahead
                lastUpVec = optimalUpVector;
            } // for (num)

            // Interpolate the first up vector for a smoother road at the start pos
            preUpVectors[0] = preUpVectors[preUpVectors.Count - 1] + preUpVectors[1];
            preUpVectors[0].Normalize();
            #endregion

            #region Interpolate the up vectors and also add the dir and right vectors
            // Second pass, interpolated precalced values and apply our logic :)
            //preUpVectors[0] =
            lastUpVec = Vector3.Lerp(defaultUpVec, preUpVectors[0],
                1.5f * CurveFactor * UpFactorCorrector);
            //lastUpVec = preUpVectors[0];
            Vector3 lastUpVecUnmodified = lastUpVec;// defaultUpVec;
            Vector3 lastRightVec = Vector3.Zero;
            for (int num = 0; num < points.Count; num++)
            {
                // Grab dir vector (could be calculated here too)
                Vector3 dir = points[num].dir;

                // First of all interpolate the preUpVectors
                Vector3 upVec =
                    //single input: preUpVectors[num];
                    Vector3.Zero;
                for (int smoothNum = -NumberOfUpSmoothValues / 2;
                    smoothNum <= NumberOfUpSmoothValues / 2; smoothNum++)
                    upVec +=
                        preUpVectors[(num + points.Count + smoothNum) % points.Count];
                upVec.Normalize();

                // Find out if this road piece is upside down and if we are
                // moving up or down. This is VERY important for catching loopings.
                bool upsideDown = upVec.Z < -0.25f &&
                    lastUpVecUnmodified.Z < -0.05f;
                bool movingUp = dir.Z > 0.75f;
                bool movingDown = dir.Z < -0.75f;

                //float changeAngle2 =
                //  GetAngleBetweenVectors(lastUpVec, upVec);
                //if (num < 100)
                //  Log.Write("changeAngel2=" + changeAngle2);

                // Mix in the last vector to make curves weaker
                upVec = Vector3.Lerp(lastUpVec, upVec, CurveFactor);
                upVec.Normalize();
                // Store the last value to check for loopings.
                lastUpVecUnmodified = upVec;

                // Don't mix in default up if we head up or are upside down!
                // Its very useful to know if we move up or down to fix the
                // problematic areas at loopings by pointing stuff correct right away.
                if (movingUp)
                    lastUpVec = Vector3.Lerp(upVec, -defaultUpVec, UpFactorCorrector);
                else if (movingDown)
                    lastUpVec = Vector3.Lerp(upVec, defaultUpVec, UpFactorCorrector);
                else if (upsideDown)
                    lastUpVec = Vector3.Lerp(upVec, -defaultUpVec, UpFactorCorrector);
                else
                    lastUpVec = Vector3.Lerp(upVec, defaultUpVec, UpFactorCorrector);

                // If we are very close to the ground, make the road point up more!
                if (//upsideDown == false &&
                    landscape != null)
                {
                    // Get landscape height here
                    float landscapeHeight = landscape.GetMapHeight(
                        points[num].pos.X, points[num].pos.Y);

                    // If point is close to the landscape, let everything point up more
                    if (points[num].pos.Z - landscapeHeight <
                        MinimumLandscapeDistance * 4)
                        lastUpVec = Vector3.Lerp(upVec, defaultUpVec,
                            1.75f * UpFactorCorrector);
                } // if (upsideDown == false &&)

                // And finally calculate rightVectors with just a cross product.
                // Used to render the track later.
                Vector3 rightVec = Vector3.Cross(dir, upVec);
                rightVec.Normalize();
                points[num].right = rightVec;

                //*tst
                // Recalculate up vector with help of right and dir.
                // This makes the up vector to always point up 90 degrees.
                upVec = Vector3.Cross(rightVec, dir);
                upVec.Normalize();
                points[num].up = upVec;
                //*/

                //// Make sure we never rotate the road more than a few degrees
                //if (lastRightVec.Length() > 0)
                //{
                //  float changeAngle =
                //    GetAngleBetweenVectors(lastRightVec, rightVec);
                //  if (num < 100)
                //    Log.Write("changeAngel=" + changeAngle);
                //} // if (lastRightVec.Length)

                //// Remember right vec for comparison in the next frame.
                //lastRightVec = rightVec;
            } // for (num)
            #endregion

            #region Smooth up vectors!
            lastUpVec = points[0].up;
            for (int num = 0; num < points.Count; num++)
                preUpVectors[num] = points[num].up;
            for (int num = 0; num < points.Count; num++)
            {
                // Interpolate up vectors again
                Vector3 upVec = Vector3.Zero;
                for (int smoothNum = -NumberOfUpSmoothValues;
                    smoothNum <= NumberOfUpSmoothValues; smoothNum++)
                {
                    upVec +=
                        preUpVectors[(num + points.Count + smoothNum) % points.Count];
                } // for (smoothNum)
                upVec.Normalize();
                points[num].up = upVec;

                // Also rebuild right vector
                Vector3 dir = points[num].dir;
                points[num].right = Vector3.Cross(dir, upVec);

                /*suxx
                // Grab dir and up vector
                Vector3 dir = points[num].dir;
                Vector3 upVec = points[num].up;
                /*suxx
                // Compare with previous up vector
                float changeAngle =
                    GetAngleBetweenVectors(lastUpVec, upVec);
                /*tst
                bool upsideDown = upVec.Z < -0.25f &&
                    lastUpVecUnmodified.Z < -0.05f;
                bool movingUp = dir.Z > 0.75f;
                bool movingDown = dir.Z < -0.75f;
                lastUpVecUnmodified = upVec;
                if (Math.Abs(changeAngle) > 0.02f &&
                    upsideDown == false &&
                    movingUp == false &&
                    movingDown == false)
                {
                    points[num].up = Vector3.SmoothStep(lastUpVec, upVec, 0.33f);//.25f);
                    // Also rebuild right vector
                    points[num].right = Vector3.Cross(dir, points[num].up);
                } // if (Math.Abs)
                 */
                /*suxx
                //if (Math.Abs(changeAngle) > 0.02f)
                {
                    points[num].up = Vector3.SmoothStep(lastUpVec, upVec, 0.05f);//.25f);
                    // Also rebuild right vector
                    points[num].right = Vector3.Cross(dir, points[num].up);
                } // if (Math.Abs)
                lastUpVec = upVec;
                 */
                //if (num < 100)
                //  Log.Write("changeAngel=" + changeAngle);
            } // for (num)
            #endregion

            AdjustRoadWidths(widthHelpers);

            GenerateUTextureCoordinates();

            GenerateTunnelsAndLandscapeObjects(
                roadHelpers, neutralObjects, landscape);
        }
Esempio n. 2
0
        }         // TrackLine(inputPointsFromColladaTrack)

        #endregion

        #region Load
        /// <summary>
        /// Load
        /// </summary>
        /// <param name="inputPoints">Input points</param>
        /// <param name="widthHelpers">Width helpers</param>
        /// <param name="roadHelpers">Road helpers</param>
        /// <param name="neutralObjects">Neutral objects</param>
        /// <param name="landscape">Landscape</param>
        protected void Load(Vector3[] inputPoints,
                            List <TrackData.WidthHelper> widthHelpers,
                            List <TrackData.RoadHelper> roadHelpers,
                            List <TrackData.NeutralObject> neutralObjects,
                            Landscape landscape)
        {
            #region Kill all previously loaded data
            points.Clear();
            helperPositions.Clear();

            // Kill all loaded objects
            if (landscape != null)
            {
                landscape.KillAllLoadedObjects();
            }
            #endregion

            #region Make sure we got valid data
            if (inputPoints == null ||
                inputPoints.Length < 3)
            {
                throw new ArgumentException("inputPoints is invalid, we need at " +
                                            "least 3 valid input points to generate a TrackLine.");
            }
            #endregion

            #region Check if all points are ABOVE the landscape
            if (landscape != null)
            {
                // Go through all spline points
                for (int num = 0; num < inputPoints.Length; num++)
                {
                    // Get landscape height here
                    float landscapeHeight = landscape.GetMapHeight(
                        inputPoints[num].X, inputPoints[num].Y) +
                                            // add little to fix ground errors
                                            MinimumLandscapeDistance * 2.25f;

                    // And make sure we are always above it!
                    if (inputPoints[num].Z < landscapeHeight)
                    {
                        inputPoints[num].Z = landscapeHeight;
                    }
                }                 // for (num)

                // Second pass, check 24 interpolation points between all inputPoints
                for (int num = 0; num < inputPoints.Length; num++)
                {
                    for (int iter = 1; iter < 25; iter++)
                    {
                        float iterPercent = iter / 25.0f;

                        float iterHeight = inputPoints[num].Z * (1 - iterPercent) +
                                           inputPoints[(num + 1) % inputPoints.Length].Z * iterPercent;

                        // Check 2x2 points (in all directions) to make sure
                        // we don't go through the landscape at the sides
                        for (int x = 0; x < 2; x++)
                        {
                            for (int y = 0; y < 2; y++)
                            {
                                // Also get height at middle to next pos
                                float landscapeHeight = landscape.GetMapHeight(
                                    -5.0f + 10.0f * x +
                                    inputPoints[num].X * (1 - iterPercent) +
                                    inputPoints[(num + 1) % inputPoints.Length].X * iterPercent,
                                    -5.0f + 10.0f * y +
                                    inputPoints[num].Y * (1 - iterPercent) +
                                    inputPoints[(num + 1) % inputPoints.Length].Y * iterPercent) +
                                                                                         // add little to fix ground errors
                                                        MinimumLandscapeDistance * 1.6f; // 1.5f;//1.25f;

                                // Increase both positions if this point is under the landscape
                                if (iterHeight < landscapeHeight)
                                {
                                    float increaseHeight = landscapeHeight - iterHeight;
                                    inputPoints[num].Z += increaseHeight;
                                    inputPoints[(num + 1) % inputPoints.Length].Z +=
                                        increaseHeight;
                                }                         // if (iterHeight)
                            }                             // for
                        }
                    } // for for (iter)
                }
            }             // if (landscape)
            //Log.Write("Input points: " + StringHelper.WriteArrayData(inputPoints));
            #endregion

            #region Search for any loopings indicated by 2 points above each other
            // Go through all spline points (ignore first and last 3, this
            // makes it easier to remove points and add new ones).
            for (int num = 1; num < inputPoints.Length - 3; num++)
            {
                // X/Y distance has to be 4 times smaller than Z distance
                Vector3 distVec = inputPoints[num + 1] - inputPoints[num];
                float   xyDist  = (float)Math.Sqrt(
                    distVec.X * distVec.X + distVec.Y * distVec.Y);
                float zDist = Math.Abs(distVec.Z);
                // Also check if next point is down again.
                Vector3 distVec2 = inputPoints[num + 2] - inputPoints[num + 1];
                if (zDist / 2 > xyDist &&
                    Math.Abs(distVec.Z + distVec2.Z) < zDist / 2)
                {
                    // Find out which direction we are going
                    Vector3 dir = inputPoints[num] - inputPoints[num - 1];
                    dir.Normalize();
                    Vector3 upVec    = new Vector3(0, 0, 1);
                    Vector3 rightVec = Vector3.Cross(dir, upVec);
                    // Matrix build helper matrix to rotate our looping points
                    Matrix rotMatrix = new Matrix(
                        rightVec.X, rightVec.Y, rightVec.Z, 0,
                        dir.X, dir.Y, dir.Z, 0,
                        upVec.X, upVec.Y, upVec.Z, 0,
                        0, 0, 0, 1);

                    // Ok do a looping with zDist as height.
                    // Start with the current point, loop around and end with the
                    // point after the looping. We will remove the current and the
                    // next 2 points, but add 9 new points instead for our smooth loop.
                    // See LoopingPoints for the looping itself.
                    Vector3 startLoopPos = inputPoints[num];
                    Vector3 endLoopPos   = inputPoints[num + 2];

                    // Insert 7 new points (9 new points, but we reuse
                    // start, middle and end points which are num, num+1 and num+2,
                    // plus an additional point after the looping to keep the road
                    // straight!)
                    Vector3[] remInputPoints = (Vector3[])inputPoints.Clone();
                    inputPoints = new Vector3[inputPoints.Length + 7];
                    // Copy everything over
                    for (int copyNum = 0; copyNum < remInputPoints.Length; copyNum++)
                    {
                        if (copyNum < num)
                        {
                            inputPoints[copyNum] = remInputPoints[copyNum];
                        }
                        else
                        {
                            inputPoints[copyNum + 7] = remInputPoints[copyNum];
                        }
                    }

                    // Ok, now we can add our loop
                    for (int loopNum = 0; loopNum < LoopingPoints.Length; loopNum++)
                    {
                        // Interpolate between start and end pos to land at the end pos!
                        float loopPercent = loopNum / (float)(LoopingPoints.Length - 1);
                        inputPoints[num + loopNum] =
                            startLoopPos * (1 - loopPercent) +
                            endLoopPos * loopPercent +
                            zDist * Vector3.Transform(LoopingPoints[loopNum], rotMatrix);
                    }                     // for (loopNum)

                    // Add extra point to keep the road straight
                    Vector3 newRoadDir =
                        inputPoints[num + 10] - inputPoints[num + 8];
                    // Don't go more than zDist * 2 units away!
                    if (newRoadDir.Length() > zDist * 2)
                    {
                        newRoadDir.Normalize();
                        newRoadDir           = newRoadDir * zDist;
                        inputPoints[num + 9] = inputPoints[num + 8] + newRoadDir;
                    }                     // if (newRoadDir.Length)
                    else
                    {
                        // Just add an interpolation point
                        inputPoints[num + 9] =
                            (inputPoints[num + 8] + inputPoints[num + 10]) / 2.0f;
                    }

                    // Advance 10 points until we check for the next loop
                    num += 10;

                    // That's it, good work everyone ^^
                }         // if (zDist)
            }             // for (num)
            #endregion

            #region Generate all points with help of catmull rom splines
            // Generate all points with help of catmull rom splines
            for (int num = 0; num < inputPoints.Length; num++)
            {
                // Get the 4 required points for the catmull rom spline
                Vector3 p1 = inputPoints[num - 1 < 0 ? inputPoints.Length - 1 : num - 1];
                Vector3 p2 = inputPoints[num];
                Vector3 p3 = inputPoints[(num + 1) % inputPoints.Length];
                Vector3 p4 = inputPoints[(num + 2) % inputPoints.Length];

                // Calculate number of iterations we use here based
                // on the distance of the 2 points we generate new points from.
                float distance           = Vector3.Distance(p2, p3);
                int   numberOfIterations =
                    (int)(NumberOfIterationsPer100Meters * (distance / 100.0f));
                if (numberOfIterations <= 0)
                {
                    numberOfIterations = 1;
                }

                Vector3 lastPos = p1;
                for (int iter = 0; iter < numberOfIterations; iter++)
                {
                    TrackVertex newVertex = new TrackVertex(
                        Vector3.CatmullRom(p1, p2, p3, p4,
                                           iter / (float)numberOfIterations));

                    lastPos = newVertex.pos;

                    points.Add(newVertex);
                }         // for (iter)
            }             // for (num)
            #endregion

            #region Generate up vectors, very important for our road building
            // Pre up vectors are used to first generate all optimal up vectors
            // for the track, but this is not useful for driving because we need
            // the road to point up always except for loopings.
            List <Vector3> preUpVectors = new List <Vector3>();

            // Now generate all up vectors, first pass does optimal up vectors.
            Vector3 defaultUpVec = new Vector3(0, 0, 1);
            Vector3 lastUpVec    = defaultUpVec;
            for (int num = 0; num < points.Count; num++)
            {
                // Get direction we are driving in at this point,
                // interpolate with help of last and next points.
                Vector3 dir = points[(num + 1) % points.Count].pos -
                              points[num - 1 < 0 ? points.Count - 1 : num - 1].pos;
                dir.Normalize();

                // Now calculate the optimal up vector for this point
                Vector3 middlePoint = (points[(num + 1) % points.Count].pos +
                                       points[num - 1 < 0 ? points.Count - 1 : num - 1].pos) / 2.0f;
                Vector3 optimalUpVector = middlePoint - points[num].pos;
                if (optimalUpVector.Length() < 0.0001f)
                {
                    optimalUpVector = lastUpVec;
                }
                optimalUpVector.Normalize();

                // Store the optimalUpVectors in the preUpVectors list
                preUpVectors.Add(optimalUpVector);

                // Also save dir vector
                points[num].dir = dir;

                // And remember the last upVec in case the road is going straight ahead
                lastUpVec = optimalUpVector;
            }             // for (num)

            // Interpolate the first up vector for a smoother road at the start pos
            preUpVectors[0] = preUpVectors[preUpVectors.Count - 1] + preUpVectors[1];
            preUpVectors[0].Normalize();
            #endregion

            #region Interpolate the up vectors and also add the dir and right vectors
            // Second pass, interpolated precalced values and apply our logic :)
            //preUpVectors[0] =
            lastUpVec = Vector3.Lerp(defaultUpVec, preUpVectors[0],
                                     1.5f * CurveFactor * UpFactorCorrector);
            //lastUpVec = preUpVectors[0];
            Vector3 lastUpVecUnmodified = lastUpVec;            // defaultUpVec;
            Vector3 lastRightVec        = Vector3.Zero;
            for (int num = 0; num < points.Count; num++)
            {
                // Grab dir vector (could be calculated here too)
                Vector3 dir = points[num].dir;

                // First of all interpolate the preUpVectors
                Vector3 upVec =
                    //single input: preUpVectors[num];
                    Vector3.Zero;
                for (int smoothNum = -NumberOfUpSmoothValues / 2;
                     smoothNum <= NumberOfUpSmoothValues / 2; smoothNum++)
                {
                    upVec +=
                        preUpVectors[(num + points.Count + smoothNum) % points.Count];
                }
                upVec.Normalize();

                // Find out if this road piece is upside down and if we are
                // moving up or down. This is VERY important for catching loopings.
                bool upsideDown = upVec.Z < -0.25f &&
                                  lastUpVecUnmodified.Z < -0.05f;
                bool movingUp   = dir.Z > 0.75f;
                bool movingDown = dir.Z < -0.75f;

                //float changeAngle2 =
                //  GetAngleBetweenVectors(lastUpVec, upVec);
                //if (num < 100)
                //  Log.Write("changeAngel2=" + changeAngle2);

                // Mix in the last vector to make curves weaker
                upVec = Vector3.Lerp(lastUpVec, upVec, CurveFactor);
                upVec.Normalize();
                // Store the last value to check for loopings.
                lastUpVecUnmodified = upVec;

                // Don't mix in default up if we head up or are upside down!
                // Its very useful to know if we move up or down to fix the
                // problematic areas at loopings by pointing stuff correct right away.
                if (movingUp)
                {
                    lastUpVec = Vector3.Lerp(upVec, -defaultUpVec, UpFactorCorrector);
                }
                else if (movingDown)
                {
                    lastUpVec = Vector3.Lerp(upVec, defaultUpVec, UpFactorCorrector);
                }
                else if (upsideDown)
                {
                    lastUpVec = Vector3.Lerp(upVec, -defaultUpVec, UpFactorCorrector);
                }
                else
                {
                    lastUpVec = Vector3.Lerp(upVec, defaultUpVec, UpFactorCorrector);
                }

                // If we are very close to the ground, make the road point up more!
                if (                //upsideDown == false &&
                    landscape != null)
                {
                    // Get landscape height here
                    float landscapeHeight = landscape.GetMapHeight(
                        points[num].pos.X, points[num].pos.Y);

                    // If point is close to the landscape, let everything point up more
                    if (points[num].pos.Z - landscapeHeight <
                        MinimumLandscapeDistance * 4)
                    {
                        lastUpVec = Vector3.Lerp(upVec, defaultUpVec,
                                                 1.75f * UpFactorCorrector);
                    }
                }                 // if (upsideDown == false &&)

                // And finally calculate rightVectors with just a cross product.
                // Used to render the track later.
                Vector3 rightVec = Vector3.Cross(dir, upVec);
                rightVec.Normalize();
                points[num].right = rightVec;

                //*tst
                // Recalculate up vector with help of right and dir.
                // This makes the up vector to always point up 90 degrees.
                upVec = Vector3.Cross(rightVec, dir);
                upVec.Normalize();
                points[num].up = upVec;
                //*/

                //// Make sure we never rotate the road more than a few degrees
                //if (lastRightVec.Length() > 0)
                //{
                //  float changeAngle =
                //    GetAngleBetweenVectors(lastRightVec, rightVec);
                //  if (num < 100)
                //    Log.Write("changeAngel=" + changeAngle);
                //} // if (lastRightVec.Length)

                //// Remember right vec for comparison in the next frame.
                //lastRightVec = rightVec;
            }             // for (num)
            #endregion

            #region Smooth up vectors!
            lastUpVec = points[0].up;
            for (int num = 0; num < points.Count; num++)
            {
                preUpVectors[num] = points[num].up;
            }
            for (int num = 0; num < points.Count; num++)
            {
                // Interpolate up vectors again
                Vector3 upVec = Vector3.Zero;
                for (int smoothNum = -NumberOfUpSmoothValues;
                     smoothNum <= NumberOfUpSmoothValues; smoothNum++)
                {
                    upVec +=
                        preUpVectors[(num + points.Count + smoothNum) % points.Count];
                }                 // for (smoothNum)
                upVec.Normalize();
                points[num].up = upVec;

                // Also rebuild right vector
                Vector3 dir = points[num].dir;
                points[num].right = Vector3.Cross(dir, upVec);

                /*suxx
                 * // Grab dir and up vector
                 * Vector3 dir = points[num].dir;
                 * Vector3 upVec = points[num].up;
                 * /*suxx
                 * // Compare with previous up vector
                 * float changeAngle =
                 *      GetAngleBetweenVectors(lastUpVec, upVec);
                 * /*tst
                 * bool upsideDown = upVec.Z < -0.25f &&
                 *      lastUpVecUnmodified.Z < -0.05f;
                 * bool movingUp = dir.Z > 0.75f;
                 * bool movingDown = dir.Z < -0.75f;
                 * lastUpVecUnmodified = upVec;
                 * if (Math.Abs(changeAngle) > 0.02f &&
                 *      upsideDown == false &&
                 *      movingUp == false &&
                 *      movingDown == false)
                 * {
                 *      points[num].up = Vector3.SmoothStep(lastUpVec, upVec, 0.33f);//.25f);
                 *      // Also rebuild right vector
                 *      points[num].right = Vector3.Cross(dir, points[num].up);
                 * } // if (Math.Abs)
                 */
                /*suxx
                 * //if (Math.Abs(changeAngle) > 0.02f)
                 * {
                 *      points[num].up = Vector3.SmoothStep(lastUpVec, upVec, 0.05f);//.25f);
                 *      // Also rebuild right vector
                 *      points[num].right = Vector3.Cross(dir, points[num].up);
                 * } // if (Math.Abs)
                 * lastUpVec = upVec;
                 */
                //if (num < 100)
                //  Log.Write("changeAngel=" + changeAngle);
            }             // for (num)
            #endregion

            AdjustRoadWidths(widthHelpers);

            GenerateUTextureCoordinates();

            GenerateTunnelsAndLandscapeObjects(
                roadHelpers, neutralObjects, landscape);
        }         // Load(inputPoints, widthHelpers, roadHelpers)