Website may be up and down over next few months. I'm currently doing a complete overhaul of everything. Going back to simple individual .htm pages, new overall site theme, sanitizing and cleaning up html of all pages and blog posts, attempting to implement a new tooling and publishing system etc etc.

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.


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 
        }
    }

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;
}

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

/// <summary>
/// Builds an array of folders & sub folders.
/// </summary>
/// <param name="path">The path to search.</param>
/// <param name="pattern">The search string to match against the names of files in path. The parameter cannot end in two periods 
/// ("..") or contain two periods ("..") followed by System.IO.Path.DirectorySeparatorChar or System.IO.Path.AltDirectorySeparatorChar,
/// nor can it contain any of the characters in System.IO.Path.InvalidPathChars.
///</param>
/// <param name="searchOptions">One of the System.IO.SearchOption values that specifies whether the search operation should include 
/// all subdirectories or only the current directory.
///</param>
/// <returns>A String array of directories that match the search pattern.</returns>
public static string[] GetDirectories(string path, string pattern, SearchOption searchOptions)
{
    // check if searching for all directories
    if (searchOptions == SearchOption.AllDirectories)
    {
        // add start paths to list
        var list = Directory.GetDirectories(path, pattern);
        var index = 0;
        var count = list.Length;

        // process list and add folders to end of list
        while (index < count)
        {
            var directories = Directory.GetDirectories(list[index++], pattern);
            if (directories.Length > 0)
            {
                // check if we need more space to store the directories
                if (count + directories.Length > list.Length - 1)
                {
                    Array.Resize(ref list, list.Length + directories.Length + 1000);
                }

                // add directories to end of the list
                foreach (var directory in directories)
                {
                    list[count++] = directory;
                }
            }

            // trim unused index from end of the array
            if (list.Length > count)
            {
                Array.Resize(ref list, count);
            }
        }

        return list;
    }

    // just return initial list of folder with no sub folders
    return Directory.GetDirectories(path, pattern);
}

/// <summary>
/// Provides a game object that automatically self terminates.
/// </summary>
[ExecuteInEditMode]
public class SelfTerminatingObject : MonoBehaviour
{
    /// <summary>
    /// Holds a reference to a callback that will be called just before termination.
    /// </summary>
    public Action Callback;

    /// <summary>
    /// Holds the time delay in seconds before object self terminates.
    /// </summary>
    public float Delay;

    /// <summary>
    /// Holds a time value used to determine whether it's time to self terminate.
    /// </summary>
    private DateTime lastTime;

    /// <summary>
    /// Called by Unity to update the object.
    /// </summary>
    public void Update()
    {
        this.PerformCheck();
    }

    /// <summary>
    /// Called by Unity to draw the object's GUI.
    /// </summary>
    public void OnGui()
    {
        this.PerformCheck();
    }

    /// <summary>
    /// Determines whether it's time to terminate.
    /// </summary>
    private void PerformCheck()
    {
        // check if specified time span has elapsed
        if (DateTime.Now > this.lastTime + TimeSpan.FromSeconds(this.Delay))
        {
            // run callback is specified
            if (this.Callback != null)
            {
                this.Callback();
            }

            // destroy object
#if UNITY_EDITOR
        DestroyImmediate(this.gameObject, true);
#else
            Destroy(this.gameObject);
#endif
        }
    }

    /// <summary>
    /// Creates a self terminating game object.
    /// </summary>
    /// <param name="callback">The method to be called before the object terminates.</param>
    /// <returns>Returns a reference to the game object that will self terminate.</returns>
    public static GameObject CreateUpdateCallback(Action callback)
    {
        return CreateUpdateCallback(callback, 0);
    }

    /// <summary>
    /// Creates a self terminating game object.
    /// </summary>
    /// <param name="callback">The method to be called before the object terminates.</param>
    /// <param name="delay">Specifies a delay value in seconds before the object will self terminate.</param>
    /// <returns>Returns a reference to the game object that will self terminate.</returns>
    public static GameObject CreateUpdateCallback(Action callback, float delay)
    {
        var obj = new GameObject();
        var com = obj.AddComponent<SelfTerminatingObject>();
        com.lastTime = DateTime.Now;
        com.Delay = delay;
        com.Callback = callback;

        return obj;
    }
}

File Backup Solutions

Published 3/1/2013 by createdbyx in News
Tags:

I have been procrastinating whether or not to write my own open source Google Drive / DropBox clone in C# for some time now. I’ve been looking for a cloud based backup solution but am to cheap to pay and have only used the free storage that DropBox, Google Drive & SkyDrive offer. Google Drive & DropBox work awesome and seamlessly but I have had various “issues” with SkyDrive.

The reason I wanted to write my own clone of these cloud based storage solutions is because I am already paying for “Unlimited” storage with my web hosting account that this site and all my other web sites are hosted from. So for me to pay extra for storage on SkyDrive, DropBox etc doesn't make much sense.

I used to use SyncBack for a while but stopped using it. I started looking around for free alternatives and came across Duplicati. Duplicati is almost what I had planed on making myself. it’s open source, written in C# and can back up files to a multitude of storage destinations like SkyDrive, Google Drive, FTP etc. It’s multi platform (Mac, Win, Linux) & it supports encryption, compression & incremental backups! It’s pretty much everything I could have hoped for and a little bit more.

Although I have not used it for very long I think I may have found a backup solution I can live with.


There is no Unity specific API for getting the project folder, but you can use System.IO.Directory.GetCurrentDirectory. The unity editor expects the current folder to be set to the project folder at all times.

If you are changing the current directory in your editor scripts using System.IO.Directory.SetCurrentDirectory you need to restore the directory back to the project folder when you are done. Otherwise the next time unity compiles your scripts it will prompt you with a dialog box and a message stating you need to restore the current directory back to the project directory and only gives you a “Quit” button to click on that will quit unity.

    // save project folder
    var projectFolder = System.IO.Directory.GetCurrentDirectory();
                   
    // set current directory to a folder of your choosing
    System.IO.Directory.SetCurrentDirectory("c:\\some folder name");
                  
    // do what you need to do
    // ...

    // restore current folder back the the project folder 
    System.IO.Directory.SetCurrentDirectory(projectFolder);

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