I was recently trying to get my Windows 7 Home Premium 64bit laptop to see the network drive on my Asus RT-N56U router with no success. It was a bit frustrating because my Windows 8 Pro desktop could see the drive on the router without any issues. Some search results talked about changing registry settings or changing values under the Group Policy Editor but these did not apply to Windows 7 Home Premium.

Ultimately I came across this one post here that suggested to add an entry to the hosts file. After adding “192.168.1.1  RT-N56U” to the bottom of the list poof I could now see a network place called “RT-N56U” inside file explorer. Wooty Woot !


The code below can be used to log performance of your code.

    using System.Collections.Generic;
    using System.Diagnostics;

    /// <summary>
    /// Provides a simple performance testing class that utilizes <see cref="Stopwatch"/>.
    /// </summary>
    /// <typeparam name="T">The type that will be used as the indexer.</typeparam>
    public class PerformanceTesting<T>
    {
        /// <summary>
        /// Provides a model that contains timer information.
        /// </summary>
        private class TimerModel
        {
            /// <summary>
            /// Used to record performance timings.
            /// </summary>
            public readonly Stopwatch Timer;

            /// <summary>
            /// Used to record how many times the <see cref="Timer"/> has been started.
            /// </summary>
            public int Count;

            /// <summary>
            /// Used to store the enabled state.
            /// </summary>
            private bool enabled;

            /// <summary>
            /// Gets or sets a value whether or not this timer if enabled.
            /// </summary>
            /// <remarks>If <see cref="Timer"/> has been started and Enabled is set to false the timer will be stopped.</remarks>
            public bool Enabled
            {
                get
                {
                    return this.enabled;
                }

                set
                {
                    this.enabled = value;

                    // be sure to stop the timer if disabled
                    if (!value && this.Timer.IsRunning)
                    {
                        this.Timer.Stop();
                    }
                }
            }

            /// <summary>
            /// Default constructor.
            /// </summary>
            public TimerModel()
            {
                this.Timer = new Stopwatch();
                this.enabled = true;
            }
        }

        /// <summary>
        /// Holds a reference to a singleton instance.
        /// </summary>
        private static PerformanceTesting<T> singleton;

        /// <summary>
        /// Used to store various timer information.
        /// </summary>
        private readonly Dictionary<T, TimerModel> timers;

        /// <summary>
        /// Default constructor.
        /// </summary>
        public PerformanceTesting()
        {
            this.timers = new Dictionary<T, TimerModel>();
        }

        /// <summary>
        /// Creates a new timer.
        /// </summary>
        /// <param name="key">The unique key for the timer.</param>
        /// <remarks>It is best to create the timer at the start of the application getting it ready for use.</remarks>
        public void Create(T key)
        {
            this.timers.Add(key, new TimerModel());
        }

        /// <summary>
        /// Creates a new timer for each key.
        /// </summary>
        /// <param name="keys">The unique keys for the timers.</param>
        /// <remarks>It is best to create the timer at the start of the application getting it ready for use.</remarks>
        public void Create(T[] keys)
        {
            foreach (var key in keys)
            {
                this.timers.Add(key, new TimerModel());
            }
        }

        /// <summary>
        /// Returns the total ticks that this timer has observed.
        /// </summary>
        /// <param name="key">The key to the timer information.</param>
        /// <returns>Returns a time value in ticks.</returns>
        public long TotalTicks(T key)
        {
            var model = this.timers[key];
            return model.Timer.ElapsedTicks;
        }

        /// <summary>
        /// Returns the total ticks that this timer has observed.
        /// </summary>
        /// <param name="keys">The keys to the timers information.</param>
        /// <returns>Returns the sum of the time values in ticks.</returns>
        public long TotalTicks(T[] keys)
        {
            long total = 0;
            foreach (var key in keys)
            {
                var model = this.timers[key];
                total += model.Timer.ElapsedTicks;
            }

            return total;
        }

        /// <summary>
        /// Gets the start count.
        /// </summary>
        /// <param name="key">The key to the timer information.</param>
        /// <returns>The number of times the timer has started.</returns>
        public int GetStartCount(T key)
        {
            var model = this.timers[key];
            return model.Count;
        }

        /// <summary>
        /// Gets the start count for specified timers.
        /// </summary>
        /// <param name="keys">The keys to the timer information.</param>
        /// <returns>The sum total of times all specified the timers have started.</returns>
        public int GetStartCount(T[] keys)
        {
            int total = 0;
            foreach (var key in keys)
            {
                var model = this.timers[key];
                total += model.Count;
            }

            return total;
        }

        /// <summary>
        /// Returns the total ticks that this timer has observed.
        /// </summary>
        /// <param name="key">The key to the timer information.</param>
        /// <returns>Returns a time value in milliseconds.</returns>
        public long TotalMilliseconds(T key)
        {
            var model = this.timers[key];
            return model.Timer.ElapsedMilliseconds;
        }

        /// <summary>
        /// Returns the total ticks that this timer has observed.
        /// </summary>
        /// <param name="keys">The keys to the timers information.</param>
        /// <returns>Returns the sum of the time values in milliseconds.</returns>
        public long TotalMilliseconds(T[] keys)
        {
            long total = 0;
            foreach (var key in keys)
            {
                var model = this.timers[key];
                total += model.Timer.ElapsedMilliseconds;
            }

            return total;
        }

        /// <summary>
        /// Calculates the average time in ticks that elapsed while this timer was recording.
        /// </summary>
        /// <param name="key">The key to the timer information.</param>
        /// <returns>Returns the average time in ticks that elapsed between each start and stop.</returns>
        public long AverageTicks(T key)
        {
            var model = this.timers[key];
            return model.Timer.ElapsedTicks / model.Count;
        }

        /// <summary>
        /// Calculates the total average time in ticks that elapsed while the specified timers were recording.
        /// </summary>
        /// <param name="keys">The keys to the timer information.</param>
        /// <returns>Returns the total average time in ticks that elapsed between each start and stop for all the specified timers.</returns>
        public long AverageTicks(T[] keys)
        {
            long total = 0;
            var count = 0;
            foreach (var key in keys)
            {
                var model = this.timers[key];
                total += model.Timer.ElapsedTicks;
                count += model.Count;
            }

            return total / count;
        }

        /// <summary>
        /// Calculates the average time in milliseconds that elapsed while this timer was recording.
        /// </summary>
        /// <param name="key">The key to the timer information.</param>
        /// <returns>Returns the average time in milliseconds that elapsed between each start and stop.</returns>
        public long AverageMilliseconds(T key)
        {
            var model = this.timers[key];
            if (model.Count == 0)
            {
                return 0;
            }

            return model.Timer.ElapsedMilliseconds / model.Count;
        }

        /// <summary>
        /// Calculates the total average time in milliseconds that elapsed while the specified timers were recording.
        /// </summary>
        /// <param name="keys">The keys to the timer information.</param>
        /// <returns>Returns the total average time in milliseconds that elapsed between each start and stop for all the specified timers.</returns>
        public long AverageMilliseconds(T[] keys)
        {
            long total = 0;
            var count = 0;
            foreach (var key in keys)
            {
                var model = this.timers[key];
                total += model.Timer.ElapsedMilliseconds;
                count += model.Count;
            }

            if (count == 0)
            {
                return 0;
            }

            return total / count;
        }

        /// <summary>
        /// Removes the specified timers.
        /// </summary>
        /// <param name="keys">The keys to the timers that will be removed.</param>
        public void Remove(T[] keys)
        {
            foreach (var key in keys)
            {
                this.timers.Remove(key);
            }
        }

        /// <summary>
        /// Removes a timer.
        /// </summary>
        /// <param name="key">The key to the timer information.</param>
        public void Remove(T key)
        {
            this.timers.Remove(key);
        }

        /// <summary>
        /// Resets all the timers.
        /// </summary>
        public void ResetAll()
        {
            foreach (var pair in this.timers)
            {
                pair.Value.Timer.Reset();
            }
        }

        /// <summary>
        /// Resets all the timers.
        /// </summary>
        /// <param name="resetCounts">If true will set each timer start count to 0.</param>
        public void ResetAll(bool resetCounts)
        {
            foreach (var pair in this.timers)
            {
                pair.Value.Timer.Reset();
                if (resetCounts)
                {
                    pair.Value.Count = 0;
                }
            }
        }

        /// <summary>
        /// Gets an array of timer keys.
        /// </summary>
        /// <returns>Returns an array of timer keys.</returns>
        public T[] GetKeys()
        {
            var keys = new T[this.timers.Count];
            this.timers.Keys.CopyTo(keys, 0);
            return keys;
        }

        /// <summary>
        /// Sets the enabled state of the timer.
        /// </summary>
        /// <param name="key">The key to the timer information.</param>
        /// <param name="enabled">If true the timer will be enabled. If false the timer will be stopped if it is running.</param>
        public void SetEnabled(T key, bool enabled)
        {
            var model = this.timers[key];
            model.Enabled = enabled;
        }

        /// <summary>
        /// Sets the enabled state of the specified timers.
        /// </summary>
        /// <param name="keys">The keys to the timer information.</param>
        /// <param name="enabled">If true the timers will be enabled. If false the timers will be stopped if they are running.</param>
        public void SetEnabled(T[] keys, bool enabled)
        {
            foreach (var key in keys)
            {
                var model = this.timers[key];
                model.Enabled = enabled;
            }
        }

        /// <summary>
        /// Gets the enabled state of the timer.
        /// </summary>
        /// <param name="key">The key to the timer information.</param>
        public bool IsEnabled(T key)
        {
            var model = this.timers[key];
            return model.Enabled;
        }

        /// <summary>
        /// Gets the enabled state of the specified timers.
        /// </summary>
        /// <param name="keys">The keys to the timer information.</param>
        /// <param name="enabled">Will contain the enabled state for each specified key.</param>
        public void IsEnabled(T[] keys, out bool[] enabled)
        {
            var enabledStates = new bool[keys.Length];
            for (int i = 0; i < keys.Length; i++)
            {
                var model = this.timers[keys[i]];
                enabledStates[i] = model.Enabled;
            }

            enabled = enabledStates;
        }

        /// <summary>
        /// Starts the timer.
        /// </summary>
        /// <param name="key">The key to the timer information.</param>
        /// <remarks>Will not start if the enabled state is false.</remarks>
        public void Start(T key)
        {
            var model = this.timers[key];
            if (!model.Enabled)
            {
                return;
            }
            model.Count++;
            model.Timer.Start();
        }

        /// <summary>
        /// Starts the timers.
        /// </summary>
        /// <param name="keys">The keys to the timer information.</param>
        /// <remarks>Will not start if the timers enabled state is false.</remarks>
        public void Start(T[] keys)
        {
            foreach (var key in keys)
            {
                var model = this.timers[key];
                if (!model.Enabled)
                {
                    continue;
                }
                model.Count++;
                model.Timer.Start();
            }
        }

        /// <summary>
        /// Stops the timer.
        /// </summary>
        /// <param name="key">The key to the timer information.</param>
        public void Stop(T key)
        {
            var model = this.timers[key];
            if (!model.Enabled)
            {
                return;
            }
            model.Timer.Stop();
        }

        /// <summary>
        /// Stops the timers.
        /// </summary>
        /// <param name="keys">The keys to the timer information.</param>
        public void Stop(T[] keys)
        {
            foreach (var key in keys)
            {
                var model = this.timers[key];
                if (!model.Enabled)
                {
                    continue;
                }
                model.Timer.Stop();
            }
        }

        /// <summary>
        /// Resets the timer.
        /// </summary>
        /// <param name="key">The key to the timer information.</param>
        public void Reset(T key)
        {
            this.Reset(key, false);
        }

        /// <summary>
        /// Resets the timers.
        /// </summary>
        /// <param name="keys">The keys to the timer information.</param>
        public void Reset(T[] keys)
        {
            this.Reset(keys, false);
        }

        /// <summary>
        /// Resets the timer.
        /// </summary>
        /// <param name="key">The key to the timer information.</param>
        /// <param name="resetCount">If true the start count for the timer will be set to 0.</param>
        public void Reset(T key, bool resetCount)
        {
            var model = this.timers[key];
            model.Timer.Reset();
            if (resetCount)
            {
                model.Count = 0;
            }
        }

        /// <summary>
        /// Resets the timers.
        /// </summary>
        /// <param name="keys">The keys to the timer information.</param>
        /// <param name="resetCounts">If true the start count for the timers will be set to 0.</param>
        public void Reset(T[] keys, bool resetCounts)
        {
            foreach (var key in keys)
            {
                var model = this.timers[key];
                model.Timer.Reset();
                if (resetCounts)
                {
                    model.Count = 0;
                }
            }
        }

        /// <summary>
        /// Resets the timer start count to 0.
        /// </summary>
        /// <param name="key">The key to the timer information.</param>
        public void ResetCount(T key)
        {
            var model = this.timers[key];
            model.Count = 0;
        }

        /// <summary>
        /// Resets each timer start count to 0.
        /// </summary>
        /// <param name="keys">The keys to the timer information.</param>
        public void ResetCount(T[] keys)
        {
            foreach (var key in keys)
            {
                var model = this.timers[key];
                model.Count = 0;
            }
        }

        /// <summary>
        /// Restarts the timer.
        /// </summary>
        /// <param name="key">The key to the timer information.</param>
        /// <param name="resetCount">If true the start count for the timer will be set to 0.</param>
        /// <remarks>The timer will be reset then started again.</remarks>
        public void Restart(T key, bool resetCount)
        {
            var model = this.timers[key];
            model.Timer.Reset();
            if (resetCount)
            {
                model.Count = 0;
            }

            this.Start(key);
        }

        /// <summary>
        /// Restarts the specified timers.
        /// </summary>
        /// <param name="keys">The keys to the timer information.</param>
        /// <param name="resetCounts">If true the start count for the timers will be set to 0.</param>
        /// <remarks>Each timer will be reset then started again.</remarks>
        public void Restart(T[] keys, bool resetCounts)
        {
            foreach (var key in keys)
            {
                var model = this.timers[key];
                model.Timer.Reset();
                if (resetCounts)
                {
                    model.Count = 0;
                }
            }

            this.Start(keys);
        }

        /// <summary>
        /// Gets a singleton instance of the <see cref="PerformanceTesting{T}"/> class.
        /// </summary>
        public static PerformanceTesting<T> Instance
        {
            get
            {
                return singleton ?? (singleton = new PerformanceTesting<T>());
            }
        }
    }

Setting up a performance counter

#if PERFORMANCE
            var perf = PerformanceTesting<string>.Instance;
            perf.Create("ScanLines");
#endif

A sample usage

#if PERFORMANCE
                var perf = PerformanceTesting<string>.Instance;
                perf.Reset("ScanLines");
                perf.Start("ScanLines");
#endif
                this.scanner.Calculate(this.points);
#if PERFORMANCE
                perf.Stop("ScanLines");
#endif

How to report the results

#if PERFORMANCE
        public static void ReportPerformanceTimes()
        {
            var perf = PerformanceTesting<string>.Instance;
            foreach (var value in perf.GetKeys())
            {
                Debug.Log(string.Format("{0} - Total: {1}ms Average: {2} Count: {3}", value, perf.TotalMilliseconds(value), perf.AverageMilliseconds(value), perf.GetStartCount(value)));
            }

            Debug.Log(string.Format("Total Performance Times - Total: {0}ms", perf.TotalMilliseconds("ScanLines")));
        }
#endif

Unity 101 Tip #59 – PingObject

Published 3/25/2013 by createdbyx in Unity | News
Tags: ,

Ever wonder how unity makes assets in the project window pop out when you select a link to them in the inspector? See the EditorGUIUtility.PingObject method.

PingObject

[MenuItem("Examples/Ping Selected")]
static void Ping()
{
    if (!Selection.activeObject)
    {
        Debug.LogError("Select an object to ping");
        return;
    }
    EditorGUIUtility.PingObject(Selection.activeObject);
}

I have been wondering how my Compaq nx9420 holds up to the Microsoft Surface Pro as I have been contemplating purchasing one. Even though it’s pushing 6 or 7 years old now my nx9420 is still a decent machine to work with Unity3D, Visual Studio, and to play older games on but the battery no longer holds a charge, the 5200 rpm 100Gb hard drive slows it down a lot compared to the 256Gb Samsung 830 SSD (replaced by the 840 series) I recently purchased for my desktop.

It’s at a point where given it’s age I feel it’s too old to sell, especially when you can get a decent machine for like $600 now a days. And I am hesitant to put any more money into it like a new battery and a ssd to try and extend it’s life a little more.

So I started to crunch some numbers and look around for performance comparisons I could do and I have documented the few comparisons I have done below.

Based off the Window Experience Index numbers alone it seems comparable to a Surface Pro, but after running the peacemaker browser benchmark there started to be a noticeable performance gap. Running PCMark7 there was a huge performance gap. I know the surface pro is more powerful but I am still trying to get a sense of just how much more powerful it actually is compared to my nx9420.

My laptop used to be my main machine for a number of years until I bought my desktop, And even though I hardly ever use my laptop anymore it sure is nice to have a mobile computer to pack around on long trips and when I am away from home.

The single biggest reason I am holding off getting a Surface Pro is the fact I cannot replace the battery. Even after 6+ years I can still buy a new $40 battery for my nx9420 off eBay. Given that I rarely have a use for a portable machine I will undoubtedly have the Surface Pro for a good 6+ years and if I can’t replace the battery, it no longer becomes a portable device seeing as how it will need to be plugged in all the time. Thus defeating the purpose of a mobile computer.

So without further adieu lets compare numbers shall we !

Windows Experience Index numbers are as follows. Keep in mind the math play below is simply a numerical comparison on the windows experience index numbers alone and does not reflect actual hardware features like the nx9420’s x1600 graphics with DX9 v2 vertex & pixel shader support compared to the HD4000’s (I’m guessing) DX11 v3 or v4 vertex & pixel shader support.

Win 7 experience index 1.0 to 7.9
Win 8 experience index 1.0 to 9.9
7.9 / 9.9 * 100 - 100 = 20.20% diff

Microsoft Surface Pro
Processor: 6.9 / 9.9 * 100 = 69.9% (core i5 third gen)
Memory: 5.9 / 9.9 * 100 = 59.59% (4gb)
Graphics: 5.6 / 9.9 * 100 = 56.56%
Gaming: 6.4 / 9.9 * 100 = 64.64% (HD4000 integrated)
Hard Disk: 8.1 / 9.9 * 100 = 81.81% (ssd)

Compaq nx9420
Processor: 3.7 / 7.9 * 100 = 46.83% (Core i2 dual core T7200 2.0Ghz)
Memory: 4.4 / 7.9 * 100 = 55.69% (4gb but intel chipset only recognizes 3gb)
Graphics: 4.2 / 7.9 * 100 = 51.16%
Gaming: 4.3 / 7.9 * 100 = 54.43% (ati x1600 discrete)
Hard Disk: 4.4 / 7.9 * 100 = 55.69% (hdd 5200rpm)

nx9420 Win7 Experience Index scaled values to Win8 Experience Index (0.202 = 20.20%)
Processor: 46.83% * 0.202 = 9.45%  adjusted result is 56.28%
Memory: 55.69% * 0.202 = 11.24% adjusted result is 66.93%
Graphics: 51.16% * 0.202 = 10.33% adjusted result is 61.49%
Gaming: 54.43% * 0.202 = 10.99% adjusted result is 65.42%
Hard Disk: 55.69% * 0.202 = 11.24% adjusted result is 66.93%

nx9420 verses Surface Pro relative windows experience index
Processor: 56.28% -> 69.9%  = -13.2% slower
Memory: 66.93% -> 59.59% = +7.34% faster
Graphics: 61.49% -> 56.56% = +4.93% faster
Gaming: 65.42% -> 64.64% = +0.78% faster 
Hard Disk: 66.93% -> 81.81% = -14.88% slower

Compared the the performance numbers from the other tests listed below if I was to compare my nx9420 to the Surface Pro based on the windows experience index numbers alone one could get the false impression that the Surface Pro is not that much of a upgrade. Memory, Graphics and Gaming numbers are almost identical when comparing the Win 7 Experience index numbers relative to Win 8’s Experience index numbers.

Peacemaker browser benchmark test results

Microsoft Surface Pro IE10

surface pro on youtube small

nx9420 Laptop Chrome v24.0

chrome small

nx9420 Laptop IE9 64bit

IE9 64bit small

nx9420 Laptop IE9 32bit

IE9 32bit small

nx9420 Laptop Firefox 19

fiewfox small

My desktop win 8 pro (IE10 desktop mode 32bit)

desktop ie10 32bit

My desktop win 8 pro Firefox 19

desktop firefox

PCMark 7 results

Microsoft Surface Pro Score: 4657 (paid version)

Source –> MobleTechReview website

pcmark07 small

Compaq nx9420 Score 844 (free version)

Link to the results are here –> http://www.3dmark.com/pcm7/569200

DOTA 2 results

The Youtube channel SurfaceProGaming has a number of games that show the gaming performance of the Surface Pro.

Dota 2 on Surface Pro runs at about an average of say 30 fps at resolution of 1280x720 (921,600 pixels) while recording fraps.

Using the same graphics settings with the closest resolution my nx9420 lets me select 1024x768 (786,432 pixels) I can run DOTA 2 at an average of 15 to 25 fps without recording fraps. Because of the 5200 rpm HDD is 80% full I only get 5 to 8 fps when fraps is recording.

In Conclusion

When comparing the Surface Pro to my nx9420 running DOTA 2 the Surface Pro has a noticeable increase in capability but in my opinion not enough to justify getting one. The fact that my nx9420 is 6+ years old and still “somewhat” keeps up with the Surface Pro in DOTA 2 is a strong indicator that my nx9420 is still a fairly decent system for what I use it for.

I don’t play too many games on my laptop other then simple games like Angry Birds, The Binding of Issac and older games like the legacy of kain series of games that I recently played on my laptop. For larger games like Starcraft 2, World of Warcraft, Skyrim, Crysis etc I will always play on my desktop.

If the Surface Pro showed a more drastic performance in DOTA 2 AND had a removable battery I would have given some serious thought into getting a Surface Pro but that’s not goanna happen after running these comparisons. Investing in a 128Gb SSD and a new battery for my nx9420 is a far more viable solution economically and strategically because after I decide to sell or retire my laptop I can always add the SDD to my desktop and a new battery is cheap at around $40.

I had also looked into the Razer Edge Pro but although it’s more graphically capable then the Surface Pro again it too has no removable battery, and a lower resolution the then Surface Pro, and no stylus pen.

My next portable computer will be a tablet but only if it has a discrete graphics chip, pen input, and a removable battery. I think I may be waiting quite a few years for that to happen.

Hope this gives some people a sense of how much of an upgrade buying a Surface Pro would be compared to using a older laptop.


This code uses a Point type that contains X/Y as integers similar to System.Drawing.Point. This class is used to calculate vertical scan lines for a polygon. It has been tested with 3 points but beyond that I am unsure if it will work.

using System;

/// <summary>
/// Helper class used to calculate scan lines of a triangle
/// </summary>
public class TriangleScanLineCalculator
{
    /// <summary>
    /// Provides a high low type for storing min & max values for scan lines.
    /// </summary>
    public struct HiLoTYPE
    {
        public int High;
        public int Low;
    }

    /// <summary>
    /// Holds scan line information.
    /// </summary>
    protected internal HiLoTYPE[] scanLines;

    /// <summary>
    /// Holds the calculated scan line count.
    /// </summary>
    protected internal int scanLineCount;

    /// <summary>
    /// Gets the right most side of the triangle.
    /// </summary>
    public int MaximumX { get; private set; }

    /// <summary>
    /// Gets the left most side of the triangle.
    /// </summary>
    public int MinimumX { get; private set; }

    /// <summary>
    /// Gets the number of scan lines.
    /// </summary>
    public int Count
    {
        get { return scanLineCount; }
    }

    /// <summary>
    /// Calculates the min & max y values for each scan line.
    /// </summary>
    /// <param name="points">The points that make up the triangle</param>
    public void Calculate(Point[] points)
    {
        var xMax = 0;
        var xMin = 0;
        float XDelta = 0;
        float YDelta = 0;
        // X/Y distance between 2 vertexes
        float YPos = 0;
        float YSlope = 0;
        var VertIndex1 = 0;
        var VertIndex2 = 0;
        var tempIndex = 0;

        // Step 1: Find the min and max 'X' dimensions of the polygon
        xMax = int.MinValue;
        xMin = int.MaxValue;
        for (var i = 0; i <= points.Length - 1; i++)
        {
            if (xMax < points[i].X)
            {
                xMax = points[i].X;
            }

            if (xMin > points[i].X)
            {
                xMin = points[i].X;
            }
        }
        this.MinimumX = xMin;
        this.MaximumX = xMax;
        this.scanLineCount = xMax - xMin;

        // Step 2: Resize scan line array to hold all the high and low x values
        if (this.scanLines == null || this.scanLines.Length < xMax - xMin)
        {
            // allocate 
            Array.Resize(ref this.scanLines, (xMax - xMin) + 100);
        }

        // Step3: Set the height value of all scan lines to there min or max value(s)
        for (var i = 0; i <= this.scanLines.Length - 1; i++)
        {
            this.scanLines[i].High = int.MinValue;
            this.scanLines[i].Low = int.MaxValue;
        }

        // Step 4: Set up the Y highs and lows for each X scan line between the min X and Max X points
        for (var i = 0; i < points.Length; i++)
        {
            // Step4a: Determine witch sides of the polygon we will be setting up
            VertIndex1 = i;
            VertIndex2 = i + 1;
            if (VertIndex2 == points.Length) VertIndex2 = 0;

            // Step4b: check if the first vertex if farther right then the second vertex
            // and if so swap vertex indexes
            if (points[VertIndex1].X > points[VertIndex2].X)
            {
                tempIndex = VertIndex1;
                VertIndex1 = VertIndex2;
                VertIndex2 = tempIndex;
            }

            // Step4c: Find the X/Y dist between vert1 and vert2
            XDelta = points[VertIndex2].X - points[VertIndex1].X;
            YDelta = points[VertIndex2].Y - points[VertIndex1].Y;

            // Step4d: Determine the Y slope to use.
            // YSlope determines how much to move down for every move we make to the right
            if (XDelta != 0)
            {
                YSlope = YDelta / XDelta;
            }
            else
            {
                YSlope = 0;
            }

            // Save the starting y position in YPos
            YPos = points[VertIndex1].Y;

            // Step4e: Process all of scan lines between vert1 and vert2
            for (var idy = points[VertIndex1].X; idy < points[VertIndex2].X; idy++)
            {
                // If the scan lines higher value has already been set then set the lower value
                // we use the formula 'idy - XMin' to determine what index into the scan line
                // array to use. (ScanLineIndex = AnyPositionBetweenVert1AndVert2 - LeftMostPartOfPoly)

                // Store the scan line index in the TmpIndex variable so we don't
                // have the overhead of doing 5 subtractions
                tempIndex = idy - xMin;

                var item = this.scanLines[tempIndex];

                // Check if Scan(TmpIndex).High has been set already
                if (item.High == int.MinValue)
                {
                    // High has not been set yet
                    item.High = (int)YPos;
                }
                else
                {
                    // High has been set yet so we set the low point
                    item.Low = (int)YPos;

                    // Ensure that the High is actually a higher value then low
                    if (item.High < item.Low)
                    {
                        var tempValue = item.High;
                        item.High = item.Low;
                        item.Low = tempValue;
                    }
                }
                this.scanLines[tempIndex] = item;

                // update the Y position
                YPos += YSlope;
            }
        }
    }

    /// <summary>
    /// Retrieves a scan line.
    /// </summary>
    /// <param name="index">The index of the scan line.</param>
    /// <returns>Returns information about the scan line.</returns>
    public HiLoTYPE ScanLine(int index)
    {
        return this.scanLines[index];
    }

    /// <summary>
    /// Gets all the scan lines.
    /// </summary>
    /// <returns>Returns all the scan line information.</returns>
    public HiLoTYPE[] GetScanLines()
    {
        // if there are no scan lines return null.
        if (this.scanLineCount == 0)
        {
            return null;
        }

        // resize the array 
        Array.Resize(ref this.scanLines, this.scanLineCount);
        return this.scanLines;
    }

    /// <summary>
    /// Calculates the scan lines for a triangle.
    /// </summary>
    /// <param name="points">The triangle points.</param>
    /// <param name="minXValue">Will return the minimum x value that the triangle starts at.</param>
    /// <returns>Returns the min max y values of the scanline.</returns>
    public static HiLoTYPE[] Calculate(Point[] points, out int minXValue)
    {
        // create scan line calculator and get values from it
        var scanner = new TriangleScanLineCalculator();
        scanner.Calculate(points);
        var items = scanner.GetScanLines();
        minXValue = scanner.MinimumX;
        return items;
    }
}

If you are writing UI code and you want the controls you are drawing to appear as if they are labels until they are in focus you can use  the EditorGUIUtility.LookLikeInspector & EditorGUIUtility.LookLikeControls methods.

LookLikeControls

public class LookLikeControlsInspector : EditorWindow
{
    private int integer1;
    float float1 = 5.5f;

    [MenuItem("Examples/Look Like Controls - Inspector")]
    static void Init()
    {
        var window = GetWindow<LookLikeControlsInspector>();
        window.Show();
    }

    void OnGUI()
    {
        EditorGUIUtility.LookLikeInspector();
        EditorGUILayout.TextField("Text Field:", "Hello There");
        EditorGUILayout.IntField("Int Field:", integer1);
        EditorGUILayout.FloatField("Float Field:", float1);
        EditorGUILayout.Space();
        EditorGUIUtility.LookLikeControls();
        EditorGUILayout.TextField("Text Field", "Hello There");
        EditorGUILayout.IntField("Int Field:", integer1);
        EditorGUILayout.FloatField("Float Field:", float1);
    }
}

I recently came across a strange behavior while loading text resource assets. In particular the Resources.LoadAll method does not accept Path.DirectorySeparatorChar characters in a path. In fact it only accepts Path.AltDirectorySeparatorChar characters. This behavior is different then standard .net file/folder methods that accept either Path.AltDirectorySeparatorChar or Path.DirectorySeparatorChar without distinction. What this means is that you can’t directly use Path.Combine to build a path and pass it to the Resources.LoadAll method you first have to replace any Path.DirectorySeparatorChar characters with Path.AltDirectorySeparatorChar characters.

The documentation for Resources.Load also does not mention this behavior.

I have submitted a bug report here –> https://fogbugz.unity3d.com/default.asp?533268_jgvrk2lbu1qm398e

    using System.IO;

    using UnityEditor;

    using UnityEngine;

    /// <summary>
    /// Handles settings registration.
    /// </summary>
    [InitializeOnLoad]
    public class EditorInitialization
    {
        /// <summary>
        /// Holds a value indicating whether the RunCallbacks method has been called at least once before.
        /// </summary>
        private static bool ranOnce;

        /// <summary>
        /// Initializes static members of the <see cref="EditorInitialization"/> class.
        /// </summary>
        static EditorInitialization()
        {
            EditorApplication.update += RunCallbacks;
        }

        private static void RunCallbacks()
        {
            if (!ranOnce)
            {
                // try to load resource
                var path = Path.Combine("Test/SubFolder", "testfile"); // result is Test/SubFolder\testfile

                // var data = Resources.LoadAll("Test/SubFolder/testfile", typeof(TextAsset)); // this line is successful
                var data = Resources.LoadAll(path, typeof(TextAsset));  // this line fails

                if (data != null && data.Length != 0)
                {
                    Debug.Log("found it");
                }
                else
                {
                    Debug.Log("not found! " + path);
                }

                ranOnce = true;
                return;
            }

            // do stuff 
        }
    }

Source - http://stackoverflow.com/questions/11518935/mvc-redirect-to-default-route/11520787#11520787

Redirect route handler

public class RedirectRouteHandler : IRouteHandler
{
    private string _redirectUrl;

    public RedirectRouteHandler(string redirectUrl)
    {
        _redirectUrl = redirectUrl;
    }

    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        if (_redirectUrl.StartsWith("~/"))
        {
            string virtualPath = _redirectUrl.Substring(2);
            Route route = new Route(virtualPath, null);
            var vpd = route.GetVirtualPath(requestContext,
                requestContext.RouteData.Values);
            if (vpd != null)
            {
                _redirectUrl = "~/" + vpd.VirtualPath;
            }
        }

        return new RedirectHandler(_redirectUrl, false);
    } 
}

Redirect http handler

public class RedirectHandler : IHttpHandler
{
    private readonly string _redirectUrl;

    public RedirectHandler(string redirectUrl, bool isReusable)
    {
        _redirectUrl = redirectUrl;
        IsReusable = isReusable;
    }

    public bool IsReusable { get; private set; }

    public void ProcessRequest(HttpContext context)
    {
        context.Response.Status = "301 Moved Permanently";
        context.Response.StatusCode = 301;
        context.Response.AddHeader("Location", _redirectUrl);
    }
}

Extension methods

public static class RouteExtensions
{
    public static void Redirect(this RouteCollection routes, string url, string redirectUrl)
    {
        routes.Add(new Route(url, new RedirectRouteHandler(redirectUrl)));
    }
}

The code below allows you to copy a directory structure with or without sub folders including files. Also includes a callback that can be used to filter out files or folders and reports the copy progress.

/// <summary>
/// Copies a directory structure to the destination.
/// </summary>
/// <param name="source">The directory structure to be copied.</param>
/// <param name="destination">The destination where the directory structure will be copied to.</param>
/// <param name="copySubDirectories">true to copy all subdirectories.</param>
/// <param name="overwriteFiles">true if the destination files can be overwritten; otherwise, false.</param>
/// <param name="callback">Provides a callback function for reporting progress. </param>
/// <remarks><p>The callback invoked just before a file copy occurs providing a way of being notified.</p>
/// <p>The callback parameter order is source file, destination file, progress.</p>
/// <p>If the callback is specified it should return true to allow the file copy to occur.</p> 
/// <p>The progress parameter reports progress from 0 to 100. Values to the left of the decimal represent folder copy progress and values to the
/// right of the decimal from 0.000 to 0.99 represent the current file copy progress for the folder that is being copied.</p>
/// <p>To get the current file copy progress as a value from 0 to 100 use the formula fileProgress = progress - 100 * 100.</p></remarks>
public static void CopyDirectories(string source, string destination, bool copySubDirectories, bool overwriteFiles, Func<string, string, float, bool> callback)
{
    // ensure source folder exists
    if (!Directory.Exists(source))
    {
        throw new DirectoryNotFoundException("The path specified in source is invalid (for example, it is on an unmapped drive).");
    }

    // create destination folder
    Directory.CreateDirectory(destination);

    // get all files in source and copy them to destination folder
    var files = Directory.GetFiles(source);
    var progress = 0f; // used to report the progress from 0 to 100

    // set up action to copy files
    var fileProcessor = new Action<float, string[], string>((folderProgress, filesToCopy, folder) =>
        {
            // copy files
            for (var i = 0; i < filesToCopy.Length; i++)
            {
                // get file
                var file = filesToCopy[i];

                // set default result
                var result = true;

                // build destination filename
                var fileName = Path.GetFileName(file);
                if (fileName == null) // should never happen
                {
                    return;
                }

                fileName = Path.Combine(folder, fileName);

                // check if callback specified
                if (callback != null)
                {
                    // store result from callback
                    result = callback(file, fileName, progress);
                }

                // if result is true we are allowed to copy the file
                if (result)
                {
                    File.Copy(file, fileName, overwriteFiles);
                }

                // (folder progress * 100) + file progress
                progress = folderProgress + ((float)i / filesToCopy.Length);
            }
        });

    // copy initial files
    fileProcessor(0, files, destination);

    // check to copy sub directories
    if (!copySubDirectories)
    {
        return;
    }

    // get the folder tree for the source folder
    var folders = Directory.GetDirectories(source, "*.*", SearchOption.AllDirectories);

    // process each sub folder
    for (var index = 0; index < folders.Length; index++)
    {
        // get folder and increment index
        var folder = folders[index];

        // get files
        files = Directory.GetFiles(folder);

        // crop source root from destination and build destination folder path
        folder = folder.Remove(0, source.Length);
        folder = Path.Combine(destination, folder);

        // create destination folder
        Directory.CreateDirectory(folder);

        // process file copying
        fileProcessor((index / folders.Length) * 100, files, folder);
    }
}

Some .net/mono frameworks do not support the IsNullOrWhiteSpace method. The code below provides a simple replacement.

/// <summary>
/// Indicates whether a specified string is null, empty, or consists only of white-space characters.
/// </summary>
/// <param name="value">value: The string to test.</param>
/// <returns>true if the value parameter is null or System.String.Empty, or if value consists exclusively of white-space characters.</returns>
public static bool IsNullOrWhiteSpace(this string value)
{
    if (value == null)
    {
        return true;
    }

    var index = 0;
    while (index < value.Length)
    {
        if (char.IsWhiteSpace(value[index]))
        {
            index++;
        }
        else
        {
            return false;
        }
    }

    return true;
}

Created by: X

Just another personal website in this crazy online world

Name of author Dean Lunz (aka Created by: X)
Computer programming nerd, and tech geek.
About Me -- Resume