<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3527266406367929266</id><updated>2012-02-16T10:55:22.167-07:00</updated><category term='C#'/><category term='OTD'/><category term='css'/><category term='MVC'/><category term='Linq'/><category term='Javascript'/><category term='php'/><category term='asp.net'/><category term='Entity Systems'/><category term='XNA'/><category term='MooTools'/><category term='Entity Framework'/><category term='Icons'/><category term='science'/><category term='Web'/><category term='kohana'/><title type='text'>chronoclast</title><subtitle type='html'>&lt;a href="http://www.chronoclast.com"&gt;Home&lt;/a&gt;
&lt;a href="http://blog.chronoclast.com"&gt;Blog&lt;/a&gt;
&lt;a href="http://www.chronoclast.com/albums/"&gt;Photos&lt;/a&gt;</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://blog.chronoclast.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default'/><link rel='alternate' type='text/html' href='http://blog.chronoclast.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default?start-index=26&amp;max-results=25'/><author><name>his leniency</name><uri>http://www.blogger.com/profile/08563846927500523919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_5PU69EU356k/S2IRaPkvuTI/AAAAAAAAAUQ/iwH8AkkCVyc/S220/Profile.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>34</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3527266406367929266.post-4363301013685502099</id><published>2011-09-23T15:59:00.001-06:00</published><updated>2011-09-23T16:01:11.489-06:00</updated><title type='text'>Recursion in Linq</title><content type='html'>&lt;p&gt;Being able to traverse a tree structure can be very handy, or flatten a tree to a list.  Linq doesn't offer this out of the box, but it's a fairly straightforward extension to add.&lt;/p&gt;&lt;br /&gt;
&lt;pre style="brush:csharp"&gt;/// &amp;lt;summary&amp;gt;
/// Recusively traverse a tree structure
/// &amp;lt;/summary&amp;gt;
/// &amp;lt;typeparam name="T"&amp;gt;&amp;lt;/typeparam&amp;gt;
/// &amp;lt;param name="collection"&amp;gt;&amp;lt;/param&amp;gt;
/// &amp;lt;param name="childrenSelector"&amp;gt;Child navigation property on T&amp;lt;/param&amp;gt;
/// &amp;lt;returns&gt;Flattened collection&amp;lt;/returns&amp;gt;
public static IEnumerable&amp;lt;T&amp;gt; Traverse&amp;lt;T&amp;gt;(this IEnumerable&amp;lt;T&amp;gt; collection, Func&amp;lt;T, IEnumerable&amp;lt;T&amp;gt;&amp;gt; childrenSelector)
{
    foreach (var item in collection)
    {
        yield return item;

        var children = childrenSelector(item);

        if (children != null)
        {
            foreach (var child in Traverse(children, childrenSelector))
            {
                yield return child;
            }
        }
    }
}
&lt;/pre&gt;&lt;br /&gt;
&lt;p&gt;The source is pretty much &lt;a href="http://stackoverflow.com/questions/732281/expressing-recursion-in-linq/793531#793531"&gt;straight from here&lt;/a&gt;, with an extra check against null children collections.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3527266406367929266-4363301013685502099?l=blog.chronoclast.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chronoclast.com/feeds/4363301013685502099/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chronoclast.com/2011/09/recursion-in-linq.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/4363301013685502099'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/4363301013685502099'/><link rel='alternate' type='text/html' href='http://blog.chronoclast.com/2011/09/recursion-in-linq.html' title='Recursion in Linq'/><author><name>his leniency</name><uri>http://www.blogger.com/profile/08563846927500523919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_5PU69EU356k/S2IRaPkvuTI/AAAAAAAAAUQ/iwH8AkkCVyc/S220/Profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3527266406367929266.post-5363748167982853075</id><published>2011-07-07T14:14:00.000-06:00</published><updated>2011-07-07T14:14:43.479-06:00</updated><title type='text'>Entry Extensions</title><content type='html'>&lt;p&gt;Entity Framework 4.1 CodeFirst is quite a bit of fun to use, but tucks away some of the useful database functionality.  One useful thing is to know if a property on a database entry has been changed since it was loaded.  DbEntityEntry exposes OriginalValues and CurrentValues, but actually comparing the two can be streamlined with Expressions.&lt;/p&gt;

&lt;h2&gt;DbEntityEntry.PropertyChanged&lt;/h2&gt;

&lt;pre style="brush:csharp"&gt;
public static class DbEntityEntryExtensions
{
    /// &amp;lt;summary&amp;gt;
    /// Determine if a property has changed since being loaded.
    /// &amp;lt;remarks&amp;gt;
    /// If comparing a property that is a sub-object against another instance, it will always throw true (changed).
    /// Complex properties should implement IEquatable to properly handle how equality is determined.
    /// &amp;lt;/remarks&amp;gt;
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;typeparam name="TEntity"&amp;gt;&amp;lt;/typeparam&amp;gt;
    /// &amp;lt;typeparam name="TProperty"&amp;gt;&amp;lt;/typeparam&amp;gt;
    /// &amp;lt;param name="entity"&amp;gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;param name="expression"&amp;gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
    public static bool PropertyChanged&amp;lt;TEntity, TProperty&amp;gt;(this DbEntityEntry&amp;lt;TEntity&amp;gt; entity, Expression&amp;lt;Func&amp;lt;TEntity, TProperty&amp;gt;&amp;gt; expression)
        where TEntity : class
    {
        var name = ((MemberExpression)expression.Body).Member.Name;

        return !entity.CurrentValues.GetValue&amp;lt;TProperty&amp;gt;(name).Equals(entity.OriginalValues.GetValue&amp;lt;TProperty&amp;gt;(name));
    }
}
&lt;/pre&gt;

&lt;p&gt;Determining if a loaded POCO property has changed is pretty easy:&lt;/p&gt;

&lt;pre style="brush:csharp"&gt;
var o = MyDbContext.TestClasses.Find(1);
o.Id = 2;

var changed = MyDbContext.Entry(o).PropertyChanged(c =&amp;gt; c.Id);   // True
&lt;/pre&gt;


&lt;p&gt;This works fine for primitive types such as int, string and float.  However, if your property is another object, it won't work.  This is because at it's heart, we're calling Equals.&lt;/p&gt;

&lt;pre style="brush:csharp"&gt;

class TestClass
{
    public int Id { get; set; }
}

var a = new TestClass { Id = 1 };
var b = new TestClass { Id = 1 };

var equal = a.Equals(b);  // False!&lt;/pre&gt;

&lt;p&gt;To show this with EF 4.1...&lt;/p&gt;

&lt;pre style="brush:csharp"&gt;

class TestClass
{
    public int Id { get; set; }
    public AssociationClass Association { get; set; }
}

class AssociationClass
{
    public int Id { get; set; }
}

// Assume that the stored o.Association has an ID of 1
var o = var o = MyDbContext.TestClasses.Find(1);

// Set to a new, identical instance of the class
o.Association = new AssociationClass { Id = 1 };

// This is supposed to be false.  The database holds that TestClass:1
// is associated with AssociationClass:1.  However, since the objects
// are different, Equals will return false, and PropertyChanged will
// return true - thinking that the association has changed.
var changed = MyDbContext.Entry(o).PropertyChanged(c =&amp;gt; c.Association);   // True (wrong)
&lt;/pre&gt;

&lt;p&gt;There is probably a way to check if the property is an association and check possible entity keys, but that's for another time.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3527266406367929266-5363748167982853075?l=blog.chronoclast.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chronoclast.com/feeds/5363748167982853075/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chronoclast.com/2011/07/entry-extensions.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/5363748167982853075'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/5363748167982853075'/><link rel='alternate' type='text/html' href='http://blog.chronoclast.com/2011/07/entry-extensions.html' title='Entry Extensions'/><author><name>his leniency</name><uri>http://www.blogger.com/profile/08563846927500523919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_5PU69EU356k/S2IRaPkvuTI/AAAAAAAAAUQ/iwH8AkkCVyc/S220/Profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3527266406367929266.post-7139040794799497889</id><published>2011-04-19T21:50:00.001-06:00</published><updated>2011-04-19T21:50:58.585-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Entity Systems'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>EntitySystems Part 3: EntityCollections</title><content type='html'>&lt;p&gt;In &lt;a href="http://blog.chronoclast.com/2010/12/entity-systems-part-1-entity-and.html"&gt;part one&lt;/a&gt; we looked at the base for an Entity and EntityManager.  In there we can create new entities and compose them of components.  In &lt;a href="http://blog.chronoclast.com/2010/12/entity-systems-part-2-components.html"&gt;part 2&lt;/a&gt;, we looked at actually storing components by their type.&lt;p&gt;

&lt;p&gt;When viewing an Entity System as a relational database, the component types are single table with the entity id as the primary key.  Then entity represents a single joined row across multiple tables.  Systems that consume entities will often rely on multiple component types.  We could reference the component collections but that would require a lot of duplicate checking in each system to ensure that an entity contained all types it was looking for.  Better to create a new type that tracks this for us.&lt;/p&gt;

&lt;h2&gt;EntityCollection&lt;/h2&gt;

&lt;pre class="brush: csharp"&gt;
public sealed class EntityCollection : IEnumerable&lt;Entity&gt;
{
    readonly EntityManager _manager;

    readonly Type[] _filter;
    readonly int _hashCode;
&lt;/pre&gt;

&lt;p&gt;Each collection is composed a collection of types, so the first step is to store all of these types.  These are used to make the hashcode for the collection.  More explained in a bit.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
    readonly SortedSet&lt;Entity&gt; _sortedEntities;
    readonly Dictionary&lt;ulong, Entity&gt; _entities;
    readonly IComparer&lt;Entity&gt; _comparer;
&lt;/pre&gt;

&lt;p&gt;To store entities in the collection, we use two different internal collections.  An entity collection has two big requirements - O(1) lookup and sorting.  The sorted collections in C# don't offer O(1) lookup time and a plain Dictionary can't be sorted.  The solution - use two collections.  Dictionary offers the fastest lookup and SortedSet offers the most consistent insert speed.  The comparer is just that - an optional custom comaprer for sorted entries (think z-indexed sprites, etc...)&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
internal EntityCollection(EntityManager entityManager, Type[] types)
{
    _sortedEntities = new SortedSet&lt;Entity&gt;();
    _hashCode = EntityCollection.GetHashCode(types, null);

    // Check that all types are really components
    if (!types.All(t =&gt; typeof(EntityComponent).IsAssignableFrom(t)))
    {
        throw new Exception("Type is not of IComponent - cannot filter.");
    }

    _manager = entityManager;
    _entities = new Dictionary&lt;ulong, Entity&gt;();
    _filter = types;

    // Add any existing entites
    foreach (var entity in _manager)
    {
        if (MatchesFilter(entity))
        {
            Add(entity);
        }
    }
}

internal EntityCollection(EntityManager entityManager, Type[] types, Func&lt;Entity, Entity, int&gt; comparer)
    : this(entityManager, types)
{
    // 
    var lambdaComparer = new Engine.Tools.LambdaComparer&lt;Entity&gt;(comparer);

    _sortedEntities = new SortedSet&lt;Entity&gt;(lambdaComparer);
    _hashCode = EntityCollection.GetHashCode(types, lambdaComparer);
}

internal EntityCollection(EntityManager entityManager, Type[] types, IComparer&lt;Entity&gt; comparer)
    : this(entityManager, types)
{
    _sortedEntities = new SortedSet&lt;Entity&gt;(comparer);
    _hashCode = EntityCollection.GetHashCode(types, comparer);
}

internal bool MatchesFilter(Entity entity)
{
    return _filter.All(t =&gt; entity.Is(t));
}
&lt;/pre&gt;

&lt;p&gt;The constructor and most of the manipulations are internal.  EntityCollections are not meant to be added to and removed from by the game classes.  Systems that consume EntityCollection should only be iterating the collection.  Use the EntityManager to manipulate entities - they will be automatically added/removed from EntityCollections.&lt;/p&gt;

&lt;p&gt;Upon creation, the entity collection will search every entity and determine if it fits into the collection.  Later as new entites are created or components removed, the EntityManager is responsible for notifiying collections about updates.&lt;/p&gt;

&lt;p&gt;Seems like a good point to discus creating the hash code.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
public static int GetHashCode(Type[] types, IComparer&lt;Entity&gt; comparer)
{
    var hashCode = 0;

    // Hashcode is build off the filters, independent of their order
    for (int i = 0; i &lt; types.Length; i++)
        hashCode += types[i].GetHashCode();

    // Add on comparer hashcode if set - comparers should overload their
    // own GetHashCode to return a unique constant.
    hashCode += (comparer == null) ? 0 : comparer.GetHashCode();

    return hashCode;
}&lt;/pre&gt;

&lt;p&gt;Different consumers of EntityCollections may draw upon the same types.  Rather than have multiple collections representing the same types, we provide a mechanism to cache them in the EntityManager (where they're built).  The hash code is built from the types being monitored as well as the comparer.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
public delegate void EntityAddHandler(Entity entity);
public delegate void EntityRemoveHandler(Entity entity);&lt;/pre&gt;

&lt;p&gt;Systems consuming the collection like to be notified when the collection changes.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
internal bool Add(Entity entity)
{
    // Check if the collection already contains this
    if (_entities.ContainsKey(entity.Id))
        return;

    // Ensure that the entity matches the filter
    if (!MatchesFilter(entity))
        return false;

    _entities.Add(entity.Id, entity);
    _sortedEntities.Add(entity);

    if (_entities.Count != _sortedEntities.Count)
        throw new Exception("EntityCollection internal collections don't match.  Probably a bad comparer for SortedSet.");

    // Notify any listeners that a new entity was added
    if (OnEntityAdd != null)
    {
        OnEntityAdd(entity);
    }
}
internal void Remove(Entity entity)
{
    // Check if the collection actually contains the entity
    if (!_entities.ContainsKey(entity.Id))
        return;

    // Notify any listeners that an entity was removed
    if (OnEntityRemove != null)
    {
        OnEntityRemove(entity);
    }

    _sortedEntities.Remove(entity);
    _entities.Remove(entity.Id);
}&lt;/pre&gt;

&lt;p&gt;Finally, Add and Remove do just that as well as notifiy any listeners.  Notification is used to create or release resources or do extra initialization such as loading assets&lt;/p&gt;

&lt;p&gt;There's a few more utility functions to be found in the &lt;a href="https://bitbucket.org/leniency/bricle/src/5e9543e0438b/Engine/EntitySystems/EntityCollection.cs"&gt;full source&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;EntityManager&lt;/h2&gt;

&lt;p&gt;The EntityManager needs to have a few changes made to be able to present EntityCollections.  First, add the internal collection storage and add two internal functions to handle collections.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
readonly Dictionary&lt;int, EntityCollection&gt; _collections;

internal void RemoveFromCollections(Entity e)
{
    // Remove entity from any collections
    foreach (var collection in _collections.Values)
    {
        collection.Remove(e);
    }
}

internal void RemoveFromCollections(Entity e, Type t)
{
    // Remove entity from any collections
    foreach (var collection in _collections.Values)
    {
        if (collection.ContainsType(t))
        {
            collection.Remove(e);
        }
    }
}&lt;/pre&gt;

&lt;p&gt;Second, we actually call these where appropriate.&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;
public Entity Create(IEnumerable&lt;EntityComponent&gt; components)
{
    ...
    AddToCollections(e);
    ...
}
public void Remove(Entity entity)
{
    RemoveFromCollections(entity);     // Call this one first
    Components.Remove(entity.Id);
    _entities.Remove(entity.Id);
}
&lt;/pre&gt;

&lt;p&gt;And lastly, we need way to actually get the collections.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
public EntityCollection Get(params Type[] componentTypes)
{
    var hashCode = EntityCollection.GetHashCode(componentTypes);

    if (!_collections.ContainsKey(hashCode))
    {
        _collections.Add(hashCode, new EntityCollection(this, componentTypes));
    }

    return _collections[hashCode];
}

public EntityCollection Get(Type[] componentTypes, IComparer&lt;Entity&gt; comparer)
{
    var hashCode = EntityCollection.GetHashCode(componentTypes, comparer);

    if (!_collections.ContainsKey(hashCode))
    {
        _collections.Add(hashCode, new EntityCollection(this, componentTypes, comparer));
    }

    return _collections[hashCode];
}&lt;/pre&gt;

&lt;h2&gt;Using Collections&lt;/h2&gt;

&lt;pre class="brush: csharp"&gt;public MySystem(EntityManager manager)
{
    // Get the EntityCollection
    var entities = _entites = manager.Get(
        typeof(Foo),
        typeof(Bar));

    entities.OnEntityAdd += LoadComponent;
    entities.OnEntityAdd += UnloadComponent;
}

public void Draw(GameTime gameTime)
{
    foreach (var entity in _entities)
    {
        // Draw
    }
}

public void LoadComponent(Entity e)
{
    e.As&lt;Foo&gt;().Texture = _contentManager.Load&lt;Texture2D&gt;(e.As&lt;Foo&gt;().AssetName);
}

public void UnloadComponent(Entity e)
{
    // Unload component
}&lt;/pre&gt;

&lt;p&gt;Consuming collections is pretty straight forward.  The filter is created, events set, and it's good to go.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3527266406367929266-7139040794799497889?l=blog.chronoclast.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chronoclast.com/feeds/7139040794799497889/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chronoclast.com/2011/04/entitysystems-part-3-entitycollections.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/7139040794799497889'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/7139040794799497889'/><link rel='alternate' type='text/html' href='http://blog.chronoclast.com/2011/04/entitysystems-part-3-entitycollections.html' title='EntitySystems Part 3: EntityCollections'/><author><name>his leniency</name><uri>http://www.blogger.com/profile/08563846927500523919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_5PU69EU356k/S2IRaPkvuTI/AAAAAAAAAUQ/iwH8AkkCVyc/S220/Profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3527266406367929266.post-6512916518804475246</id><published>2011-01-04T21:30:00.006-07:00</published><updated>2011-01-06T09:25:50.079-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Sorted Collection Speeds</title><content type='html'>&lt;p&gt;C# and .Net offer a couple different sorted classes.  Arrays can be sorted, sure, but I'm looking at ones that offer some form of insertion sort.  For this, I'm looking at these three classes:&lt;/p&gt;

&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;Collection&lt;/th&gt;
&lt;th&gt;Insert(Random)&lt;/th&gt;
&lt;th&gt;Insert(Sorted)&lt;/th&gt;
&lt;th&gt;Remove&lt;/th&gt;
&lt;th&gt;Indexed Fetch&lt;/th&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/f7fta44c.aspx"&gt;SortedDictionary&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;O(log n)&lt;/td&gt;
&lt;td&gt;O(log n)&lt;/td&gt;
&lt;td&gt;O(log n)&lt;/td&gt;
&lt;td&gt;O(log n)&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms132319(v=VS.100).aspx"&gt;SortedList&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;td&gt;~O(log n) ?&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;td&gt;O(log n)&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/dd412070.aspx"&gt;SortedSet&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;O(log n)&lt;/td&gt;
&lt;td&gt;O(log n)&lt;/td&gt;
&lt;td&gt;O(log n)&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;

&lt;h2&gt;Runs&lt;/h2&gt;

&lt;h3&gt;SortedDictionary and SortedList using custom comparer&lt;/h3&gt;
&lt;pre&gt;
          Runs    Dictionary    SortedDict    SortedList     SortedSet
Insert
         50000    26,668          460,026      3,823,552     210,012
         60000    33,335          566,699      5,513,648     253,347
         70000    53,336          683,372      7,717,108     326,685
         80000    53,336          863,382     12,737,395     340,019
         90000    50,002          896,718     13,194,088     410,023
        100000    83,338        1,066,728     19,034,422     460,026
        110000    90,005        1,156,733     22,917,977     526,697
        120000    90,005        1,306,741     27,244,891     650,037
Fetch
         50000    13,334        313,351       293,350
         60000    13,334        550,031       363,354
         70000    16,667        506,695       463,359
         80000    23,334        570,032       520,029
         90000    26,668        666,705       610,034
        100000    26,668        753,376       703,373
        110000    30,001        870,049       796,712
        120000    30,002        976,722       896,718&lt;/pre&gt;

&lt;p&gt;Part of the problem comparing all these collections is that don't compare in the same way.  SortedDictionary and SortedList both default to comparing unique keys.  If you can guarantee each item in the collection has a unique sorting key, then they work great.  If you require more complicated sorting, such as comparing against a non-unique value within the TValue, then you add in the extra overhead of storage and lookup of the base collection.  SortedSet works better for comparing TValues.&lt;/p&gt;

&lt;h3&gt;SortedDictionary and SortedList using default key sorter (insert in order)&lt;/h3&gt;

&lt;pre&gt;
          Runs    Dictionary    SortedDict    SortedList     SortedSet
Insert
         50000        30,003       246,691       130,005       160,013
         60000        33,336       356,702       126,679       273,360
         70000        36,670       353,368        73,340       310,031
         80000        56,672       413,374        80,008       416,708
         90000        66,673       466,713        90,009       486,715
        100000        70,007       503,383       103,343       576,724
        110000        80,008       553,388       113,344       666,733
        120000       103,343       646,731       180,018       653,398
Fetch
         50000        10,001       123,345        73,340
         60000        13,334       160,016        90,009
         70000        16,668       186,685       106,677
         80000        16,668       233,356       130,013
         90000        20,002       246,691       140,014
        100000        20,002       266,693       156,682
        110000        23,335       310,031       190,019
        120000        23,335       330,033       190,019&lt;/pre&gt;

&lt;p&gt;Using the default key comparer in order, SortedList performs optimally.&lt;/p&gt;

&lt;h3&gt;SortedDictionary and SortedList using default key sorter (insert in reverse order)&lt;/h3&gt;
&lt;pre&gt;
          Runs    Dictionary    SortedDict    SortedList     SortedSet
Insert

         50000        30,000       273,333    23,233,332       210,000
         60000        30,000       293,333    28,999,999       276,666
         70000        46,666       350,000    29,679,999       343,333
         80000        50,000       433,333    60,493,330       370,000
         90000        50,000       526,666    49,526,662       500,000
        100000        56,666       560,000    79,496,663       600,000
        110000        56,666       716,666   114,516,661       640,000
        120000        63,333       753,333    98,069,995       720,000
Fetch

         50000        10,000       123,333        73,333
         60000        13,333       150,000        93,333
         70000        13,333       176,666       106,666
         80000        20,000       200,000       123,333
         90000        20,000       243,333       140,000
        100000        23,333       263,333       153,333
        110000        26,666       293,333       173,333
        120000        30,000       323,333       186,666&lt;/pre&gt;

&lt;p&gt;Do the same run only with reversed keys and SortedList falls apart.  SortedDictionary is most consistent with key comparisons (SortedSet still comparing values in these runs).&lt;/p&gt;

&lt;h3&gt;Notes&lt;/h3&gt;

&lt;p&gt;These are an average of three runs each.  I'm not sure if I'm doing something wrong for the SortedList inserts or not - it's way above everything else.  Otherwise for purely random data inserts, SortedSet seems to be the most consistent.  If the data is mostly pre-sorted, then SortedList will beat them all, but then bombs with random data.  Indexed fetch isn't available for SortedSet so it's not shown.  SortedDictionary and List both perform and scale similarly with a custom comparer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://bitbucket.org/leniency/sortedspeedtest/"&gt;Repository for test code&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3527266406367929266-6512916518804475246?l=blog.chronoclast.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chronoclast.com/feeds/6512916518804475246/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chronoclast.com/2011/01/sorted-speeds.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/6512916518804475246'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/6512916518804475246'/><link rel='alternate' type='text/html' href='http://blog.chronoclast.com/2011/01/sorted-speeds.html' title='Sorted Collection Speeds'/><author><name>his leniency</name><uri>http://www.blogger.com/profile/08563846927500523919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_5PU69EU356k/S2IRaPkvuTI/AAAAAAAAAUQ/iwH8AkkCVyc/S220/Profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3527266406367929266.post-277505869393282321</id><published>2010-12-24T22:14:00.005-07:00</published><updated>2011-04-18T22:14:31.496-06:00</updated><title type='text'>Entity Systems Part 2: Components</title><content type='html'>&lt;p&gt;Entities are essentially disconnected collections of components.  Or as disconnected as possible.  Some components depend on others to mean anything in game, but can be processed individually.  We should start looking at how components are stored and associated with entities.&lt;/p&gt;

&lt;p&gt;It's useful to think of each component type having it's own database table.  Each row then is an instance of that component type.  The primary key is the entity key.&lt;/p&gt;

&lt;p&gt;Components are just data containers so there's no standard functionality across all of them.  The only functionality they should contain are things like operator overloads, type conversions, or internal data manipulation (getters, setters).  A few will have events to indicate that a value has crossed a threshold for example an OnDied event when int Health == 0&lt;/p&gt;

&lt;p&gt;I've found it useful for the component to have on small bit of common functionality - the owner.  My original design was an empty interface, but this didn't provide a link back to the owning entity unless the component type specified it.  I added an abstract base that implemented this.&lt;/p&gt;

&lt;h2&gt;IEntityComponent&lt;/h2&gt;
&lt;pre class="brush: csharp"&gt;
public interface IEntityComponent
{
    ulong Owner { get; set; }
}&lt;/pre&gt;

&lt;h2&gt;EntityComponent&lt;/h2&gt;
&lt;pre class="brush: csharp"&gt;public abstract class EntityComponent : IEntityComponent
{
    private ulong _owner;

    public virtual ulong Owner
    {
        get
        {
            return _owner;
        }
        set
        {
            if (_owner == 0)
                _owner = value;
            else
                throw new FieldAccessException("Cannot reset component to different entity.");
        }
    }
}&lt;/pre&gt;

&lt;p&gt;And that's it.  Just an interface so our component managers can enforce some semblance of type control.&lt;/p&gt;

&lt;h2&gt;IComponentManager&lt;/h2&gt;

&lt;p&gt;This is really the meat of components - holding and manipulating typed collections.  I use a base interface to make it easier to swap out different implementations.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
interface IComponentManager : IEnumerable&amp;lt;Type&amp;gt;
{
    void Add&amp;lt;T&amp;gt;(ulong entityId, T o) where T : EntityComponent;
    void Add(ulong id, IEnumerable&lt;EntityComponent&gt; components);

    void Remove(ulong id);
    bool Remove&amp;lt;T&amp;gt;(ulong id) where T : EntityComponent;

    T Get&amp;lt;T&amp;gt;(ulong id) where T : EntityComponent;

    bool Contains(ulong id, Type t);
}
&lt;/pre&gt;

&lt;p&gt;The interface specifies the functionality to add components singly or as a list.  It can remove a whole entity or a single type from an entity.  Finally, it can retrieve components.&lt;/p&gt;

&lt;p&gt;This is not meant to be a forward facing class.  It's designed to be internal to the EntityManager.  It provides the mechanisms for the entities to report about themselves.&lt;/p&gt;


&lt;h2&gt;Default ComponentManager&lt;/h2&gt;

&lt;p&gt;The default ComponentManager is mostly just a wrapper for a dictionary that conforms to the interface.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
internal class ComponentManager : IComponentManager
{
    ...

    Dictionary&amp;lt;Type, Dictionary&amp;lt;ulong, EntityComponent&amp;gt;&amp;gt; _components;

    ...
}
&lt;/pre&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Everything up till now has been fairly straightforward.  Things get more complicated when we start creating systems that require multiple component types.  To put it in SQL terms again, how do we write a JOIN query?  Well, that's for part 3.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3527266406367929266-277505869393282321?l=blog.chronoclast.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chronoclast.com/feeds/277505869393282321/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chronoclast.com/2010/12/entity-systems-part-2-components.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/277505869393282321'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/277505869393282321'/><link rel='alternate' type='text/html' href='http://blog.chronoclast.com/2010/12/entity-systems-part-2-components.html' title='Entity Systems Part 2: Components'/><author><name>his leniency</name><uri>http://www.blogger.com/profile/08563846927500523919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_5PU69EU356k/S2IRaPkvuTI/AAAAAAAAAUQ/iwH8AkkCVyc/S220/Profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3527266406367929266.post-3585958430838562909</id><published>2010-12-24T15:26:00.003-07:00</published><updated>2010-12-24T20:35:15.766-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Entity Systems'/><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Entity Systems Part 1: Entity and EntityManager</title><content type='html'>&lt;p&gt;The current state can be found in &lt;a href="https://bitbucket.org/leniency/amoebal/changeset/e73319ab32fd"&gt;changeset e73319ab32fd.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Entity&lt;/h2&gt;

&lt;p&gt;First things first, an entity is essentially an id number.  There are a few useful utility functions that can be encapsulated inside of it, but embedding too many will cause problems down the line.  Most of this is duplicated in C# from &lt;a href="http://t-machine.org/index.php/2010/05/09/entity-system-1-javaandroid/"&gt;Adam Martin's post here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Entities know where to find the component store to add and retrieve associated components.  Arguments can be made about storing basic things like position and orientation in the entity, but as will be shown later, systems don't hold references to entities, just lists of components to operate on.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;/// &amp;lt;summary&amp;gt;
/// Basic entity class.  Consists of an id and a list of components.  Ideally it
/// should only be an id, but it's useful to be able to know what components it
/// is built of and to find them quickly.
/// &amp;lt;/summary&amp;gt;
public class Entity
{
    readonly ulong _id;

    public ulong Id
    {
        get
        {
            return _id;
        }
    }

    /// &amp;lt;summary&amp;gt;
    /// Static instance of the entity manager.  Entities should be able to add 
    /// themselves to the manager on creation - saves having to remember to do this.
    /// &amp;lt;/summary&amp;gt;
    public static EntityManager EntityManager { get; set; }
        
    public Entity(ulong id)
    {
        _id = id;

        if (EntityManager == null)
            throw new ArgumentNullException("Entity manager cannot be null.");

        EntityManager.Add(this);
    }

    /// &amp;lt;summary&amp;gt;
    /// Add a new component to the entity
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;typeparam name="T"&amp;gt;&amp;lt;/typeparam&amp;gt;
    /// &amp;lt;param name="component"&amp;gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
    public Entity Add&amp;lt;T&amp;gt;(T component) where T : IComponent
    {
        EntityManager.Components.Add(Id, component);
        return this;
    }

    /// &amp;lt;summary&amp;gt;
    /// Return this as a component
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;typeparam name="T"&amp;gt;&amp;lt;/typeparam&amp;gt;
    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
    public T As&amp;lt;T&amp;gt;() where T : IComponent
    {
        return EntityManager.Components.Get&amp;lt;T&amp;gt;(Id);
    }
}
&lt;/pre&gt;

&lt;h2&gt;EntityManager&lt;/h2&gt;

&lt;p&gt;The manager is responsible for creating and tracking loaded entities and assigning them ids.  Entity ids are transient - rebuilt every load.  &lt;i&gt;Template&lt;/i&gt; ids persist between game runs.  Currently I have two Get&amp;lt;T&amp;gt; functions that aren't implemented - still thinking if those are actually needed or not.  Leaning towards no.  Not show here are the details of the ComponentManager - that's another long post.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;public class EntityManager
{
    static ulong _nextAvailableId;

    Dictionary&amp;lt;ulong, Entity&amp;gt; _entities;

    /// &amp;lt;summary&amp;gt;
    /// Store of all loaded components, indexed by type and entity id
    /// &amp;lt;/summary&amp;gt;
    public ComponentManager Components { get; set; }

    public Entity this[ulong index]
    {
        get
        {
            // TODO: Should we be doing this?
            // If we're looking for a non-existant entity, go ahead and add it
            if (!_entities.ContainsKey(index))
            {
                Add(new Entity(index));
            }

            return _entities[index]; 
        }
    }

    public EntityManager()
    {
        _entities = new Dictionary&amp;lt;ulong, Entity&amp;gt;();
        _nextAvailableId = 0;
        Components = new ComponentManager();

        // Check that entities know this is the manager
        if (Entity.EntityManager == null)
        {
            Entity.EntityManager = this;
        }
    }

    /// &amp;lt;summary&amp;gt;
    /// Return all entities containing a particular type of component
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;typeparam name="T"&amp;gt;&amp;lt;/typeparam&amp;gt;
    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
    public IEnumerable&amp;lt;Entity&amp;gt; Get&amp;lt;T&amp;gt;() where T : IComponent
    {
        throw new NotImplementedException();
    }

    /// &amp;lt;summary&amp;gt;
    /// Return all entities containing all of the parameter types
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;typeparam name="T"&amp;gt;&amp;lt;/typeparam&amp;gt;
    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
    public IEnumerable&amp;lt;Entity&amp;gt; Get(params Type[] componentTypes)
    {
        throw new NotImplementedException();
    }

    /// &amp;lt;summary&amp;gt;
    /// Add an existing entity to this
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;param name="entity"&amp;gt;&amp;lt;/param&amp;gt;
    public void Add(Entity entity)
    {
        if (!_entities.ContainsKey(entity.Id))
        {
            _entities.Add(entity.Id, entity);
        }
    }

    /// &amp;lt;summary&amp;gt;
    /// Create and return a new entity
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
    public Entity Create()
    {
        _nextAvailableId++;

        // Ensure that the next available id is, in fact, available
        while (_entities.ContainsKey(_nextAvailableId))
        {
            _nextAvailableId++;
        }

        return new Entity(_nextAvailableId);
    }

    /// &amp;lt;summary&amp;gt;
    /// Remove an entity
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;param name="entity"&amp;gt;&amp;lt;/param&amp;gt;
    public void Remove(Entity entity)
    {
        Components.Remove(entity.Id);
        _entities.Remove(entity.Id);
    }

    /// &amp;lt;summary&amp;gt;
    /// Remove an entity
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;param name="entity"&amp;gt;&amp;lt;/param&amp;gt;
    public void Remove(ulong id)
    {
        Components.Remove(id);
        _entities.Remove(id);
    }
}
&lt;/pre&gt;

&lt;p&gt;Currently entity id's are just ulong's incremented for every entity.  Theoretically it's possible to reach the max, but even creating one new entity every millisecond, it would take over 500,000,000 years to reach the max.  ulong's are really big.  Even just a plain int would give us 2,147,483,647 possibilities (positive ints only).&lt;/p&gt;

&lt;h3&gt;Sample Usage&lt;/h3&gt;

&lt;pre class="brush: csharp"&gt;_manager = new EntityManager();

_manager.Create()
    .Add&amp;lt;Transform&amp;gt;(new Transform() { })
    .Add&amp;lt;Renderable&amp;gt;(new Renderable() { });

var transform = _manager[1L].As&amp;lt;Transform&amp;gt;();
&lt;/pre&gt;

&lt;p&gt;Nothing really special here - most of the work is done in the ComponentManager.  That's coming up next.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3527266406367929266-3585958430838562909?l=blog.chronoclast.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chronoclast.com/feeds/3585958430838562909/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chronoclast.com/2010/12/entity-systems-part-1-entity-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/3585958430838562909'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/3585958430838562909'/><link rel='alternate' type='text/html' href='http://blog.chronoclast.com/2010/12/entity-systems-part-1-entity-and.html' title='Entity Systems Part 1: Entity and EntityManager'/><author><name>his leniency</name><uri>http://www.blogger.com/profile/08563846927500523919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_5PU69EU356k/S2IRaPkvuTI/AAAAAAAAAUQ/iwH8AkkCVyc/S220/Profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3527266406367929266.post-7070912592615804608</id><published>2010-12-18T23:15:00.002-07:00</published><updated>2010-12-24T20:34:52.714-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Entity Systems'/><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Entity System Test Project</title><content type='html'>&lt;p&gt;Entity Systems are a great way to build up game objects, but a significant thought shift from traditional OOP inheritance trees.  Simply getting started is one of the bigger challenges as well as being aware of, and avoiding, functionality creep into entity and component objects.&lt;/p&gt;

&lt;p&gt;Much has been written on entity systems, although most of it is at a very high level overview of what they are.  There are some examples in a few books, but I'm cheap.  Browsing the net though, here's a quick list of some of the best examples and most helpful collections:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://scottbilas.com/files/2002/gdc_san_jose/game_objects_slides_with_notes.pdf"&gt;Scott Bilas's 2002 GDC Presentation&lt;/a&gt; - From 2002, but still very relevant.  He discusses the the advantages of entity systems (game objects as he calls them) and a few details of how they implemented them in Dungeon Siege.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://t-machine.org/index.php/2007/09/03/entity-systems-are-the-future-of-mmog-development-part-1//"&gt;Adam Martin's series on ES&lt;/a&gt; - Parts 2, 3, and 5 are especially good foundation material.  There's a lot to absorb here.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://t-machine.org/index.php/2010/05/09/entity-system-1-javaandroid/"&gt;Adam Martin again implements ES on Android&lt;/a&gt; - some create implementation details.  Much more explained in the comments.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www-cs-students.stanford.edu/~amitp/gameprog.html#oop"&gt;Amit's Epic Game Programming Links&lt;/a&gt; - Here's where I got started into this.  Also, he has a lot of other wonderful things.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Step 1&lt;/h2&gt;

&lt;p&gt;I plan on stepping away from OTD for a little while here.  It has a ton of code behind it, a lot which has been sitting there for over a year without refactoring.  I'm starting a much smaller project to focus on entity systems for a while as well as clean up some of my engine code.&lt;/p&gt;

&lt;h3&gt;&lt;a href="https://bitbucket.org/leniency/amoebal"&gt;Amoebal&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;Source code is up on BitBucket.  It's still &lt;i&gt;very, very&lt;/i&gt; early, but a decent foundation to build on.  Further posts will detail the process of creating an entity system in XNA and C# as well as try to explain my reasoning behind a few things.&lt;/p&gt;

&lt;h3&gt;Questions to deal with&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;How will lists of components be sent to systems? &lt;i&gt;Big dictionaries?&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;How will component types be cached and then pruned? &lt;i&gt;Entities can register components on add&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3527266406367929266-7070912592615804608?l=blog.chronoclast.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chronoclast.com/feeds/7070912592615804608/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chronoclast.com/2010/12/entity-system-test-project.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/7070912592615804608'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/7070912592615804608'/><link rel='alternate' type='text/html' href='http://blog.chronoclast.com/2010/12/entity-system-test-project.html' title='Entity System Test Project'/><author><name>his leniency</name><uri>http://www.blogger.com/profile/08563846927500523919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_5PU69EU356k/S2IRaPkvuTI/AAAAAAAAAUQ/iwH8AkkCVyc/S220/Profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3527266406367929266.post-7362429282803470541</id><published>2010-12-11T15:22:00.004-07:00</published><updated>2010-12-11T15:54:29.673-07:00</updated><title type='text'>Mesh Levels</title><content type='html'>&lt;p&gt;Got some various debugging info in place and finally decided to get some stats on the various levels of the map build.&lt;/p&gt;

&lt;table&gt;
&lt;caption&gt;Build Data&lt;/caption&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Level&lt;/th&gt;
&lt;th&gt;Cells&lt;/th&gt;
&lt;th&gt;Avg. Distance&lt;/th&gt;
&lt;th&gt;Time (ms)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;1.051462&lt;/td&gt;
&lt;td&gt;56&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;92&lt;/td&gt;
&lt;td&gt;0.396275&lt;/td&gt;
&lt;td&gt;243&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;252&lt;/td&gt;
&lt;td&gt;0.2403322&lt;/td&gt;
&lt;td&gt;1264&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;492&lt;/td&gt;
&lt;td&gt;0.1721796&lt;/td&gt;
&lt;td&gt;3594&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;812&lt;/td&gt;
&lt;td&gt;0.1340831&lt;/td&gt;
&lt;td&gt;11187&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;1212&lt;/td&gt;
&lt;td&gt;0.1097718&lt;/td&gt;
&lt;td&gt;19649&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;1692&lt;/td&gt;
&lt;td&gt;0.09291888&lt;/td&gt;
&lt;td&gt;34545&lt;/td&gt;
&lt;/tr&gt;

&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;The cells increase at a slight exponential rate while the time at a much steeper rate.  The generating code could be a lot more optimal, and the vast majority of this time is spent in the mesh generate.  Each cell is locally subdivided down three levels.  There are probably a lot of optimizations that could be run, and a couple of the loops could be consolidated.  Over time I've managed to optimize most loops to just n * n.neighbors.  I've opted more for understandable code (as much as possible) vs highly optimized loops.  Considering that all of this is done once at compile time, it's not a big deal really.&lt;/p&gt;

&lt;h2&gt;Graphs&lt;/h2&gt;

&lt;h3&gt;Cells&lt;/h3&gt;

&lt;img src="http://lh6.ggpht.com/_5PU69EU356k/TQP_8Lb6ofI/AAAAAAAALtM/tinirQLbGpk/s800/graph%20%281%29.jpg" /&gt;

&lt;h3&gt;Time&lt;/h3&gt;
&lt;img src="http://lh4.ggpht.com/_5PU69EU356k/TQP_8fUfWqI/AAAAAAAALtQ/0y6vXgyfSEE/s800/graph%20%282%29.jpg" /&gt;

&lt;h3&gt;Distance&lt;/h3&gt;
&lt;img src="http://lh6.ggpht.com/_5PU69EU356k/TQP_8q-gXpI/AAAAAAAALtU/zRr2_tsN11c/s800/graph%20%283%29.jpg" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3527266406367929266-7362429282803470541?l=blog.chronoclast.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chronoclast.com/feeds/7362429282803470541/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chronoclast.com/2010/12/mesh-levels.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/7362429282803470541'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/7362429282803470541'/><link rel='alternate' type='text/html' href='http://blog.chronoclast.com/2010/12/mesh-levels.html' title='Mesh Levels'/><author><name>his leniency</name><uri>http://www.blogger.com/profile/08563846927500523919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_5PU69EU356k/S2IRaPkvuTI/AAAAAAAAAUQ/iwH8AkkCVyc/S220/Profile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_5PU69EU356k/TQP_8Lb6ofI/AAAAAAAALtM/tinirQLbGpk/s72-c/graph%20%281%29.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3527266406367929266.post-2935326442815035947</id><published>2010-12-03T09:45:00.004-07:00</published><updated>2010-12-03T12:47:19.792-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>IEnumerable.ToString()</title><content type='html'>&lt;p&gt;One useful thing is to be able to concatenate IEnumerable's into a string for printing.  A couple extension methods take care of this.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
public static string ToString&amp;lt;T&amp;gt;(this IEnumerable&amp;lt;T&amp;gt; collection)
{
    return collection.ToString(",");
}

public static string ToString&amp;lt;T&amp;gt;(this IEnumerable&amp;lt;T&amp;gt; collection, string separater)
{
    return String.Join(",", collection);
}

public static string ToString&amp;lt;T&amp;gt;(this IEnumerable&amp;lt;T&amp;gt; collection, Func&amp;lt;T, object&amp;gt; field) where T : class
{
    return collection.ToString(",", field);
}

public static string ToString&amp;lt;T&amp;gt;(this IEnumerable&amp;lt;T&amp;gt; collection, string separater, Func&amp;lt;T, object&amp;gt; field) where T : class
{
    return String.Join(separater, collection.Select(field));
}
&lt;/pre&gt;

&lt;p&gt;But couldn't we just use String.Join as the extension methods are?  Sure, but this is more fun and provides a more logical response to ToString() as well as more control over objects with anonymous functions.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
var testList = new List&amp;lt;SimpleObject&amp;gt;()
{
    new SimpleObject() { Id = 1, Name = "asdf" },
    new SimpleObject() { Id = 2, Name = "qwer" },
    new SimpleObject() { Id = 3, Name = "zxcv" },
};
var s = testList.ToString&amp;lt;SimpleObject&amp;gt;(",", c =&gt; c.Id);
&lt;/pre&gt;

&lt;p&gt;One caveat, the base IEnumerable.ToString() is still there, and simple prints out something like System.Collections.Generic.... Not what we expect.  To call the basic extension method, we have to specify it with the type parameter: &lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
var fail = testList.ToString();  // Ruh-roh!
var works = testList.ToString&amp;lt;SimpleObject&amp;gt;();  // Woot!
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3527266406367929266-2935326442815035947?l=blog.chronoclast.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chronoclast.com/feeds/2935326442815035947/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chronoclast.com/2010/12/ienumerable-tostring.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/2935326442815035947'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/2935326442815035947'/><link rel='alternate' type='text/html' href='http://blog.chronoclast.com/2010/12/ienumerable-tostring.html' title='IEnumerable&lt;T&gt;.ToString()'/><author><name>his leniency</name><uri>http://www.blogger.com/profile/08563846927500523919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_5PU69EU356k/S2IRaPkvuTI/AAAAAAAAAUQ/iwH8AkkCVyc/S220/Profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3527266406367929266.post-8103806598685143991</id><published>2010-10-26T21:18:00.002-06:00</published><updated>2010-10-28T10:27:23.902-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OTD'/><title type='text'>Rabbit Hole</title><content type='html'>&lt;p&gt;Well, almost 4 months later and a ton of work and I think it's time to scrap cell blending.&lt;/p&gt;

&lt;img src="http://lh3.ggpht.com/_5PU69EU356k/TMeY0IUb0qI/AAAAAAAALr8/K8qr4TBoC7k/s800/earth-blended.jpg" /&gt;

&lt;p&gt;Heightmaps still work and I will probably keep those, but getting cell blending to look good will take just too much work.  Leaving the art style simpler will help preserve the board game feel.  Cell borders may get some rounding if I can figure out an easy way.&lt;/p&gt;

&lt;h2&gt;Edit:&lt;/h2&gt;

&lt;p&gt;Nope, not scrapping texture blending.  Looks much better if the influence radius is set smaller.  Screenshots later as I'm working on loading heightmaps from the saved map file.  Oceans will have a sandy texture on the grid and a separate inner sphere for the actual water.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3527266406367929266-8103806598685143991?l=blog.chronoclast.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chronoclast.com/feeds/8103806598685143991/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chronoclast.com/2010/10/rabbit-hole.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/8103806598685143991'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/8103806598685143991'/><link rel='alternate' type='text/html' href='http://blog.chronoclast.com/2010/10/rabbit-hole.html' title='Rabbit Hole'/><author><name>his leniency</name><uri>http://www.blogger.com/profile/08563846927500523919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_5PU69EU356k/S2IRaPkvuTI/AAAAAAAAAUQ/iwH8AkkCVyc/S220/Profile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_5PU69EU356k/TMeY0IUb0qI/AAAAAAAALr8/K8qr4TBoC7k/s72-c/earth-blended.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3527266406367929266.post-883003225212930724</id><published>2010-10-08T16:41:00.006-06:00</published><updated>2010-12-26T17:22:54.940-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='Entity Framework'/><title type='text'>Entity Framework and Max Field Length</title><content type='html'>&lt;p&gt;Being able to check the maximum length of an entity field can be incredibly useful.  Later, I'll be exploring how to automatically validate entity lengths, but for the moment we just need to find them.  Worry about using them for later post.&lt;/p&gt;

&lt;p&gt;Entity Framework 4 Data Models, edmx files, provide all the database metadata, but it takes a bit of finding.  First, you need a valid ObjectContext.  I'm using the Repository/UnitOfWork pattern and my UnitOfWork acts as a wrapper around the ObjectContext that gets passed into the repositories.  At the moment the functionality to check length is in the UnitOfWork, but can reasonably be moved anywhere that has access to the database context, such as the repository base.  Might make more sense there even.&lt;/p&gt;

&lt;p&gt;Anyways, to the code.  There are &lt;a href="http://stackoverflow.com/questions/748939/field-max-length-in-entity-framwork"&gt;several examples&lt;/a&gt; around the web and they provided starting points on where to find the correct metadata.  In the end, the code is actually quite short.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
/// &amp;lt;summary&amp;gt;
/// Find the maximum length of an entity field in this context
/// &amp;lt;/summary&amp;gt;
/// &amp;lt;param name="field"&amp;gt;&amp;lt;/param&amp;gt;
/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
public int Length&amp;lt;TEntity&amp;gt;(string field)
{
    var item = Context.MetadataWorkspace.GetItem&amp;lt;EntityType&amp;gt;(typeof(TEntity).FullName, DataSpace.CSpace);
    return (int)item.Properties[field].TypeUsage.Facets["MaxLength"].Value;
}
&lt;/pre&gt;

&lt;p&gt;I leave error checking to be handled by the caller.  The only errors that should be thrown are if the Context is invalid, ArgumentExceptions if you send an invalid entity, field name, or perhaps most importantly, you try to run this against a non-string type like int or bool.&lt;/p&gt;

&lt;p&gt;To explain a bit of the code, you need access to the &lt;a href="http://msdn.microsoft.com/en-us/library/system.data.metadata.edm.metadataworkspace.aspx"&gt;MetadataWorkspace&lt;/a&gt;.  I believe that ADO.Net and Linq to SQL all create this object and provide access to it one way or another.  From there, you can get EntityType metadata.  Other examples online pulled all the entities, but that isn't really necessary.  The GetItem&lt;EntityType&gt; function works fine.  If the TEntity typ is invalid, this function will throw an error.  Once we have the EntityType item, we have the full info about that particular tracked entity, and within the Properties, we can get field data.  There are other Facets available depending on the data type.  Strings contain these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nullable&lt;/li&gt;
&lt;li&gt;DefaultValue&lt;/li&gt;
&lt;li&gt;MaxLength&lt;/li&gt;
&lt;li&gt;Unicode&lt;/li&gt;
&lt;li&gt;FixedLength&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So it would be pretty easy to rework this function to provide any one of those meta values.&lt;/p&gt;

&lt;p&gt;The TEntity type should be a valid model type tracked by the context, and the field is just a property name.  There's probably some fancy-dancy reflection way to eliminate the string here, but I haven't found it yet.&lt;/p&gt;

&lt;p&gt;Calling the function looks something like this:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;
int length = _unitOfWork.Length&amp;lt;User&amp;gt;("UserName");
&lt;/pre&gt;

&lt;p&gt;Again, placing this in the UnitOfWork might not make the best sense.  Perhaps in a Repository which contains an actual ObjectSet would be a bit safer.&lt;/p&gt;

&lt;p&gt;It should be noted that for other data types, int, bool, floats, etc., different Facets are available, and for some, trying to reference MaxLength will result in an exception being thrown.  More information about the actual field type can be found in EntityType.Properties([field]).TypeUsage.EdmType.  Greater error checking can, and probably shoud, be put in place.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3527266406367929266-883003225212930724?l=blog.chronoclast.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chronoclast.com/feeds/883003225212930724/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chronoclast.com/2010/10/entity-framework-and-max-field-length.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/883003225212930724'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/883003225212930724'/><link rel='alternate' type='text/html' href='http://blog.chronoclast.com/2010/10/entity-framework-and-max-field-length.html' title='Entity Framework and Max Field Length'/><author><name>his leniency</name><uri>http://www.blogger.com/profile/08563846927500523919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_5PU69EU356k/S2IRaPkvuTI/AAAAAAAAAUQ/iwH8AkkCVyc/S220/Profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3527266406367929266.post-6075718361727522882</id><published>2010-09-17T11:19:00.007-06:00</published><updated>2010-12-14T15:42:48.326-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='Linq'/><title type='text'>LINQ and IEquality</title><content type='html'>&lt;p&gt;Linq provides several handy set functions - Union, Except, and Intersect.  They even provide a way to override how equality comparisons are done by declaring a concrete &lt;a href="http://msdn.microsoft.com/en-us/library/ms132151.aspx"&gt;IEqualityComparer&lt;T&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When working with POCO objects though, it is quite cumbersome to have to provide comparers for every object.  True, they could all implement an interface and go through a generic comparer, but a much easier option would be to allow anonymous functions to be defined.  We need two things - a comparer class that takes delegates and some Linq extensions to make use of this.&lt;/p&gt;

&lt;p&gt;Thankfully, &lt;a href="http://brendan.enrick.com/"&gt;Brendan Enrick&lt;/a&gt; already implemented a comparer that takes anonymous functions and runs them in &lt;a href="http://msdn.microsoft.com/en-us/library/ms132154.aspx"&gt;IEqualityComparer.Equals()&lt;/a&gt;

&lt;pre class="brush: csharp"&gt;
/// &amp;lt;summary&amp;gt;
/// Generic equality comparer allowing lambda expressions
/// &amp;lt;/summary&amp;gt;
/// &amp;lt;typeparam name="T"&amp;gt;&amp;lt;/typeparam&amp;gt;
/// &amp;lt;see cref="http://csharpfeeds.com/post/10941/LINQ_Your_Collections_with_IEqualityComparer_and_Lambda_Expressions.aspx"/&amp;gt;
public class LambdaComparer&amp;lt;T&amp;gt; : IEqualityComparer&amp;lt;T&amp;gt;
{
    private readonly Func&amp;lt;T, T, bool&amp;gt; _comparer;
    private readonly Func&amp;lt;T, int&amp;gt; _hash;

    public LambdaComparer(Func&amp;lt;T, T, bool&amp;gt; comparer) : this(comparer, o =&amp;gt; o.GetHashCode())
    { }

    public LambdaComparer(Func&amp;lt;T, T, bool&amp;gt; comparer, Func&amp;lt;T, int&amp;gt; hash)
    {
        if (comparer == null)
            throw new ArgumentNullException("comparer");
        if (hash == null)
            throw new ArgumentNullException("hash");

        _comparer = comparer;
        _hash = hash;
    }

    public bool Equals(T a, T b)
    {
        return _comparer(a, b);
    }

    public int GetHashCode(T o)
    {
        return _hash(o);
    }
}
&lt;/pre&gt;

&lt;p&gt;Now we can call this as so:&lt;/p&gt;
&lt;pre class="brush: csharp; gutter: false"&gt;
myCollection.Intersect(otherCollection, new LambdaComparer&amp;lt;PocoType&amp;gt;((a, b) =&gt; a.Id == b.Id));
&lt;/pre&gt;

&lt;p&gt;Having to declare a new LambdaComparer every time can be further simplified by adding some new Linq extensions that handle creating a new LambdaComparer for us.&lt;/p&gt;
&lt;pre class="brush: csharp; gutter: false"&gt;
public static class LinqExtensions
{
    public static IEnumerable&amp;lt;T&amp;gt; Except&amp;lt;T&amp;gt;(this IEnumerable&amp;lt;T&amp;gt; first,  IEnumerable&amp;lt;T&amp;gt; second, Func&amp;lt;T, T, bool&amp;gt; comparer)
    {
        return first.Except(second, new LambdaComparer&amp;lt;T&amp;gt;(comparer));
    }

    public static IEnumerable&amp;lt;T&amp;gt; Union&amp;lt;T&amp;gt;(this IEnumerable&amp;lt;T&amp;gt; first, IEnumerable&amp;lt;T&amp;gt; second, Func&amp;lt;T, T, bool&amp;gt; comparer)
    {
        return first.Union(second, new LambdaComparer&amp;lt;T&amp;gt;(comparer));
    }

    public static IEnumerable&amp;lt;T&amp;gt; Intersect&amp;lt;T&amp;gt;(this IEnumerable&amp;lt;T&amp;gt; first, IEnumerable&amp;lt;T&amp;gt; second, Func&amp;lt;T, T, bool&amp;gt; comparer)
    {
        return first.Intersect(second, new LambdaComparer&amp;lt;T&amp;gt;(comparer));
    }

    public static IEnumerable&amp;lt;T&amp;gt; Distinct&amp;lt;T&amp;gt;(this IEnumerable&amp;lt;T&amp;gt; first, Func&amp;lt;T, T, bool&amp;gt; comparer)
    {
        return first.Distinct(new LambdaComparer&amp;lt;T&amp;gt;(comparer));
    }
}
&lt;/pre&gt;

&lt;p&gt;This further simplifies the call and makes it a bit more elegant.  We can do sets based on aribitary fields without having to declare a whole new comparison class.&lt;/p&gt;
&lt;pre class="brush: csharp; gutter: false"&gt;
myCollection.Intersect(otherCollection, (a, b) =&gt; a.Id == b.Id);
myCollection.Union(otherCollection, (a, b) =&gt; a.Name == b.Name);
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3527266406367929266-6075718361727522882?l=blog.chronoclast.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chronoclast.com/feeds/6075718361727522882/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chronoclast.com/2010/09/linq-and-iequality.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/6075718361727522882'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/6075718361727522882'/><link rel='alternate' type='text/html' href='http://blog.chronoclast.com/2010/09/linq-and-iequality.html' title='LINQ and IEquality'/><author><name>his leniency</name><uri>http://www.blogger.com/profile/08563846927500523919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_5PU69EU356k/S2IRaPkvuTI/AAAAAAAAAUQ/iwH8AkkCVyc/S220/Profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3527266406367929266.post-5125366001961210836</id><published>2010-08-25T10:55:00.005-06:00</published><updated>2010-10-28T10:39:14.745-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OTD'/><title type='text'>Epiphanies</title><content type='html'>So after four months of ever-so-slowly moving forward on cell blending, I had finally see the light at the end of the tunnel.  Just in time to have a sudden inspiration on how to do it all easier (sort of).&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;The goal:&lt;/strong&gt; enable heightmap and texture blending between cells.&lt;br /&gt;
It sounds innocent enough - just fine affected mesh vertices and blend away!  Four months of slow work (broken by countless TF2 sessions and some monumental &lt;a href="http://www.minecraft.net/"&gt;Minecraft&lt;/a&gt; bases), and I've finally got step 1 working.  There's still some clean-up work on step 1, but that'll be easier and the motivation is now returning.&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;The problems:&lt;/strong&gt; The previous major version did a couple things wrong.  I got heightmapping and texturing working over the entire sphere using a &lt;a href="http://blog.chronoclast.com/2010/04/some-screen-shots.html"&gt;Miller projection&lt;/a&gt;.  This had potential, but lacked in several areas: the 'hexness' of the map was lost and it required a very, very high resolution texture to look decent.&lt;br /&gt;
&lt;br /&gt;
I wanted to maintain the hex feel of the map, yet be able to blend heightmaps to create continuous mountain ranges, sea beds, and other land features.  Each cell has the potential to align differently in UV space meaning that seams wouldn't match up easily like a flat 2d grid.  The first idea was to add more texture channels to each mesh vertex:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Base cell UV's&lt;/li&gt;
&lt;li&gt;Neighbor channel 1 (neighbors 1 &amp;amp; 3)&lt;/li&gt;
&lt;li&gt;Neighbor channel 2 (neighbors 2 &amp;amp; 4)&lt;/li&gt;
&lt;li&gt;Neighbor channel 3 (neighbors 3 &amp;amp; 6)&lt;/li&gt;
&lt;li&gt;Optional detail channel 1 (micro detail - bumpmap, etc...)&lt;/li&gt;
&lt;li&gt;Optional detail channel 2 (macro, miller projection - color shifts, shading...)&lt;/li&gt;
&lt;/ol&gt;
Then to write the HLSL shader to handle the custom vertex format...&lt;br /&gt;
&lt;br /&gt;
Then to write all the testing tools to ensure that the mesh is being build correctly...&lt;br /&gt;
&lt;br /&gt;
The testing tools allowed me to achieve a nice unwrap of the icosahedron mesh and from there to write a 2d-map importer... This step turned out very useful.  I can open up Photoshop, set an indexed color palette, and draw the map over the top of an exported unwrap of the cell points, then read it back into the game.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/_5PU69EU356k/THVMD0kJe3I/AAAAAAAALTo/FGMNh0aY_ws/s1600/unwrapIcosahedronVertNumbered.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_5PU69EU356k/THVMD0kJe3I/AAAAAAAALTo/FGMNh0aY_ws/s320/unwrapIcosahedronVertNumbered.gif" /&gt;&lt;/a&gt;&lt;/div&gt;
Finally, the blending step.  The problem lies in that each cell is independently textured.  This will ensure better resolution when zoomed in without massive textures and help to maintain the hex board game feel.  The first plan went something like this:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Create base cells&lt;/li&gt;
&lt;li&gt;Build base UV coordinates as a single large hexagon or pentagon&lt;/li&gt;
&lt;li&gt;Find and sort neighbor cells&lt;/li&gt;
&lt;li&gt;Start building render mesh
&lt;ul&gt;
&lt;li&gt;Subdivide each cell for the render mesh.&lt;/li&gt;
&lt;li&gt;Lookup neighbor mesh vertices 'affected' by each cell vertex.&lt;/li&gt;
&lt;li&gt;Take affected vertices appropriate texture channel (each vertex has 4+ texture channels - base, neighbor 1, 2, and 3) and align to the cell edge.  This is the part that proved to take the longest and I've still got the texture blending ahead.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;&lt;/ol&gt;
The epiphany here is to incorporate polar coordinates for better affected vertex lookup and UV texturing.  Hexes bordered by a pentagon have some alignment issues with the pentagons along neighbor seams due to the pentagon's having different base angles.  Switching to building mesh UV's off polar coordinates will solve this issue as well as some of the slight texture warping that will occur.&lt;br /&gt;

&lt;h2&gt;Edit:&lt;/h2&gt;

&lt;p&gt;Scrap that, polar's didn't work for helping with UV mapping.  Things get too funky around the poles.&lt;/p&gt;

&lt;h3&gt;Random Picture&lt;/h3&gt;
&lt;img src="http://lh4.ggpht.com/_5PU69EU356k/THSVecriMdI/AAAAAAAALTU/L5nIdRWKWgg/s800/Mesh.gif" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3527266406367929266-5125366001961210836?l=blog.chronoclast.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chronoclast.com/feeds/5125366001961210836/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chronoclast.com/2010/08/epiphanies.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/5125366001961210836'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/5125366001961210836'/><link rel='alternate' type='text/html' href='http://blog.chronoclast.com/2010/08/epiphanies.html' title='Epiphanies'/><author><name>his leniency</name><uri>http://www.blogger.com/profile/08563846927500523919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_5PU69EU356k/S2IRaPkvuTI/AAAAAAAAAUQ/iwH8AkkCVyc/S220/Profile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_5PU69EU356k/THVMD0kJe3I/AAAAAAAALTo/FGMNh0aY_ws/s72-c/unwrapIcosahedronVertNumbered.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3527266406367929266.post-951920958610556567</id><published>2010-08-04T15:11:00.002-06:00</published><updated>2010-08-04T15:15:01.774-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MVC'/><category scheme='http://www.blogger.com/atom/ns#' term='asp.net'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>ASP.Net MVC ImageActionLink</title><content type='html'>&lt;p&gt;The default &lt;a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.html.linkextensions.actionlink.aspx"&gt;Html.ActionLink()&lt;/a&gt; only takes text, and I like doing icons often to save space for for aesthetics.  Here's a simple helper that takes the image url and action as the only required parameters and C# 4.0's fancy new optional parameters for the rest.  Doing all the various method overloads for ActionLink sounded like overkill.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
/// &amp;lt;summary&amp;gt;
/// Returns an anchor element to the virtual path of the specified action with an image for the content
/// &amp;lt;/summary&amp;gt;
/// &amp;lt;param name="html"&amp;gt;&amp;lt;/param&amp;gt;
/// &amp;lt;param name="imageUrl"&amp;gt;&amp;lt;/param&amp;gt;
/// &amp;lt;param name="action"&amp;gt;&amp;lt;/param&amp;gt;
/// &amp;lt;param name="altText"&amp;gt;&amp;lt;/param&amp;gt;
/// &amp;lt;param name="controllerName"&amp;gt;&amp;lt;/param&amp;gt;
/// &amp;lt;param name="routeValues"&amp;gt;&amp;lt;/param&amp;gt;
/// &amp;lt;param name="htmlAttributes"&amp;gt;&amp;lt;/param&amp;gt;
/// &amp;lt;returns&amp;gt;MvcHtmlString&amp;lt;/returns&amp;gt;
public static MvcHtmlString ImageActionLink(
    this HtmlHelper html, 
    string imageUrl, 
    string action, 
    string altText = null, 
    string controllerName = null, 
    object routeValues = null,
    IDictionary&amp;lt;string, object&amp;gt; imageHtmlAttributes = null,
    IDictionary&amp;lt;string, object&amp;gt; htmlAttributes = null)
{
    MvcHtmlString link = html.ActionLink(
        "[replace_me]", 
        action, 
        controllerName, 
        routeValues, 
        htmlAttributes);

    TagBuilder builder = new TagBuilder("img");
    builder.MergeAttributes(imageHtmlAttributes);
    builder.MergeAttribute("src", imageUrl);
    if (altText != null)
        builder.MergeAttribute("alt", altText);
   
    return MvcHtmlString.Create(
        link.ToString().Replace(
            "[replace_me]",
            builder.ToString(TagRenderMode.SelfClosing))
    );
}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3527266406367929266-951920958610556567?l=blog.chronoclast.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chronoclast.com/feeds/951920958610556567/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chronoclast.com/2010/08/aspnet-mvc-imageactionlink.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/951920958610556567'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/951920958610556567'/><link rel='alternate' type='text/html' href='http://blog.chronoclast.com/2010/08/aspnet-mvc-imageactionlink.html' title='ASP.Net MVC ImageActionLink'/><author><name>his leniency</name><uri>http://www.blogger.com/profile/08563846927500523919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_5PU69EU356k/S2IRaPkvuTI/AAAAAAAAAUQ/iwH8AkkCVyc/S220/Profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3527266406367929266.post-1832633014713986254</id><published>2010-08-02T18:47:00.003-06:00</published><updated>2010-08-02T19:08:24.664-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>XNA 4 Beta</title><content type='html'>&lt;p&gt;Microsoft's been pushing Windows Phone 7 development quite hard for the past few months.  The XNA and Silverlight teams have been pushing out news, examples and generally evangelizing it.  I don't have much interest in phone development yet, but the latest version of the Windows Phone 7 SDK included the XNA beta (and is the only place to download it).  The team's been hard at work updating XNA for greater cross-platform development and cleaning up some of the oddities in the API.  In switching OTD over to the beta, I found a fair number of issues that either haven't been implemented or just moved somewhere new.  I actually gave up after a while and started up a new dummy project to walk through the basics and start from a cleaner code base.&lt;/p&gt;

&lt;h2&gt;Changes&lt;/h2&gt;

&lt;p&gt;This is by no means a comprehensive list, but a short list of things that I've encountered and my solutions (if any) so far.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Content folder is now a separate project by default.  Cool, this works, no problem here.&lt;/li&gt;
&lt;li&gt;BasicEffect no longer uses SetParameter, but rather all parameters are properties.&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;BasicEffect&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/bb203926.aspx"&gt;MSDN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/bb203926.aspx"&gt;How to Use (MSDN)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Shawn Hargreaves talks about two changes to Basic Effect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2010/04/22/effect-api-changes-in-xna-game-studio-4-0.aspx"&gt;Effect API Changes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2010/04/25/basiceffect-optimizations-in-xna-game-studio-4-0.aspx"&gt;BasicEffect Optimizations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Rendering Sample&lt;/h3&gt;

&lt;p&gt;Below is a simple object generated from the pipeline and consists of just a VertexBuffer and IndexBuffer.  We reference the BasicEffect and Graphics Device statically.  View, World, and Projection are much simpler as properties now.  Within the effect pass loop, we no longer begin() and end() the effect and passes, but only Apply() each pass at the start.  Less code for less mistakes.&lt;/p&gt;

&lt;p&gt;The way vertex and index buffers are set on the device has changed as well to a simpler interface. Vertex buffers contain the information of their contained format and a single stream has only on vertex type.  We set the length now by number of vertices and indices rather than byte sizes.  The call to set the vertex buffer is much simpler.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
class Sphere
{
    public VertexBuffer Vertices;
    public IndexBuffer Indices;

     public void Draw(Matrix view, Matrix projection)
     {
         // Set shader projections
         Core.BasicEffect.View = view;
         Core.BasicEffect.World = Matrix.Identity;
         Core.BasicEffect.Projection = projection;

         // Set vertex and index buffers on the device
         Core.GraphicsDevice.SetVertexBuffer(Vertices);
         Core.GraphicsDevice.Indices = Indices;

         foreach (EffectPass pass in Core.BasicEffect.CurrentTechnique.Passes)
         {
             pass.Apply();

             Core.BasicEffect.GraphicsDevice.DrawIndexedPrimitives(
                 PrimitiveType.TriangleList,
                 0,
                 0,
                 Vertices.VertexCount,
                 0,
                 Indices.IndexCount / 3);
         }
     }
 }
&lt;/pre&gt;

&lt;h3&gt;Content Pipeline&lt;/h3&gt;

&lt;p&gt;When building vertex buffers in the pipeline, a few things have changed here as well.  Since vertex formats are now embedded in the buffer object, it takes an extra bit of initialization.  A new class, &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.content.pipeline.processors.vertexbuffercontent(XNAGameStudio.40).aspx"&gt;VertexBufferContent&lt;/a&gt; is now needed.&lt;/p&gt;

&lt;h4&gt;VertexBufferContent&lt;/h4&gt;

&lt;p&gt;Building the VertexBufferContent is pretty simple since the information is available in the vertex format - we just need to loop through the VertexElements.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
// Generate the VertexDeclarationContent from the VertexElements in our format
VertexDeclarationContent vdc = new VertexDeclarationContent();
foreach (VertexElement ve in VertexPositionColor.VertexDeclaration.GetVertexElements())
{
    vdc.VertexElements.Add(ve);
}

// Set the declaration fors the buffer
Vertices.VertexDeclaration = vdc;
&lt;/pre&gt;


&lt;h3&gt;Code&lt;/h3&gt;

&lt;p&gt;Here's the whole pipeline object that gets processed.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
public class SphereContent
{
    public VertexBufferContent Vertices;
    public IndexCollection Indices;

    public SphereContent(int subdivisionLevel)
    {
        Vertices = new VertexBufferContent();
        Indices = new IndexCollection();

        // Generate the vertices
        List&amp;lt;VertexPositionColor&amp;gt; vertices;
        List&amp;lt;int&amp;gt; indices;
        Generate(out vertices, out indices);

        // Generate the VertexDeclarationContent from the VertexElements in our format
        VertexDeclarationContent vdc = new VertexDeclarationContent();
        foreach (VertexElement ve in VertexPositionColor.VertexDeclaration.GetVertexElements())
        {
            vdc.VertexElements.Add(ve);
        }

        // Set the declaration fors the buffer
        Vertices.VertexDeclaration = vdc;

        // Write to the vertex buffer
        Vertices.Write&amp;lt;VertexPositionColor&amp;gt;(
            0, 
            VertexPositionColor.VertexDeclaration.VertexStride, 
            vertices
        );

        // Add indices
        Indices.AddRange(indices);
    }

    private void Generate(out List&amp;lt;VertexPositionColor&amp;gt; vertices, out List&amp;lt;int&amp;gt; indices)
    {
        // Magic!
    }
}
&lt;/pre&gt;

&lt;p&gt;More coming as I explore further.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3527266406367929266-1832633014713986254?l=blog.chronoclast.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chronoclast.com/feeds/1832633014713986254/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chronoclast.com/2010/08/xna-4-beta.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/1832633014713986254'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/1832633014713986254'/><link rel='alternate' type='text/html' href='http://blog.chronoclast.com/2010/08/xna-4-beta.html' title='XNA 4 Beta'/><author><name>his leniency</name><uri>http://www.blogger.com/profile/08563846927500523919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_5PU69EU356k/S2IRaPkvuTI/AAAAAAAAAUQ/iwH8AkkCVyc/S220/Profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3527266406367929266.post-5667103520969812337</id><published>2010-07-31T17:59:00.002-06:00</published><updated>2010-07-31T18:01:02.874-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Dictionary Stuff</title><content type='html'>&lt;h2&gt;Serialization&lt;/h2&gt;

&lt;p&gt;Most of the C# Generics are XML serializable.  &lt;a href="http://msdn.microsoft.com/en-us/library/xfhwa508.aspx"&gt;Dictionary&lt;/a&gt;, however, is not.  It can be extended with &lt;a href="http://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable.aspx"&gt;IXmlSerializable&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://weblogs.asp.net/pwelter34/archive/2006/05/03/444961.aspx"&gt;Paul Welter's Example&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3527266406367929266-5667103520969812337?l=blog.chronoclast.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chronoclast.com/feeds/5667103520969812337/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chronoclast.com/2010/07/serializable-dictionary.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/5667103520969812337'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/5667103520969812337'/><link rel='alternate' type='text/html' href='http://blog.chronoclast.com/2010/07/serializable-dictionary.html' title='Dictionary Stuff'/><author><name>his leniency</name><uri>http://www.blogger.com/profile/08563846927500523919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_5PU69EU356k/S2IRaPkvuTI/AAAAAAAAAUQ/iwH8AkkCVyc/S220/Profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3527266406367929266.post-3434839828034221402</id><published>2010-07-28T12:03:00.001-06:00</published><updated>2010-07-28T12:04:30.499-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Yield and State Machine</title><content type='html'>&lt;p&gt;Interesting post about Yield as a state machine.&lt;/p&gt;

&lt;a href="http://shadowcoding.blogspot.com/2009/01/yield-and-c-state-machine.html"&gt;Shadow Coding&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3527266406367929266-3434839828034221402?l=blog.chronoclast.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://shadowcoding.blogspot.com/2009/01/yield-and-c-state-machine.html' title='Yield and State Machine'/><link rel='replies' type='application/atom+xml' href='http://blog.chronoclast.com/feeds/3434839828034221402/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chronoclast.com/2010/07/yield-and-state-machine.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/3434839828034221402'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/3434839828034221402'/><link rel='alternate' type='text/html' href='http://blog.chronoclast.com/2010/07/yield-and-state-machine.html' title='Yield and State Machine'/><author><name>his leniency</name><uri>http://www.blogger.com/profile/08563846927500523919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_5PU69EU356k/S2IRaPkvuTI/AAAAAAAAAUQ/iwH8AkkCVyc/S220/Profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3527266406367929266.post-5182257225553920066</id><published>2010-07-27T16:57:00.009-06:00</published><updated>2010-07-27T17:03:39.700-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MVC'/><category scheme='http://www.blogger.com/atom/ns#' term='asp.net'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>ASP.Net Helper Extensions</title><content type='html'>Been a while since I've put anything up here, so just tossing a few simple things here.&lt;br /&gt;
Helper Extensions!  Holy cow things things are nice!  Some of these aren't terribly well tested yet, and there should be more coming.&lt;br /&gt;
&lt;h2&gt;

Capitalize&lt;/h2&gt;
Found this somewhere where I can't remember.  Acts like php's ucwords() function in that it takes a string "foo bar" and returns "Foo Bar"&lt;br /&gt;
&lt;pre class="brush: csharp"&gt;public static string Capitalize(this String s)
{
    return s.ToCharArray().Aggregate(
        string.Empty,
        (working, next) =&amp;gt;
        {
            if (working.Length == 0 &amp;amp;&amp;amp; next != ' ')
            {
                return next.ToString().ToUpper();
            }
            else if (working.EndsWith(" "))
            {
                return working + next.ToString().ToUpper();
            }
            else
            {
                return working + next.ToString();
            }
        });
}
&lt;/pre&gt;
&lt;h2&gt;

Even/Odd&lt;/h2&gt;
Simple enough and useful for zebra striping tables.&lt;br /&gt;
&lt;pre class="brush: csharp"&gt;public static bool Even(this int i)
{
    return (i &amp;amp; 1) == 0;
}

public static bool Odd(this int i)
{
    return (i &amp;amp; 1) == 1;
}
&lt;/pre&gt;
&lt;h2&gt;Newlines&lt;/h2&gt;

Useful for displaying input from textareas&lt;br /&gt;

&lt;pre class="brush: csharp"&gt;/// &lt;summary&gt;
/// Replace line breaks with &amp;lt;br /&amp;gt; tags and encode the output.
/// &lt;/summary&gt;
/// &lt;returns&gt;&lt;/returns&gt;
public static string Nl2br(this HtmlHelper html, string text)
{
    return html.Encode(text).Replace(Environment.NewLine, "&amp;lt;br /&amp;gt;");
}
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3527266406367929266-5182257225553920066?l=blog.chronoclast.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chronoclast.com/feeds/5182257225553920066/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chronoclast.com/2010/07/aspnet-helper-extensions.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/5182257225553920066'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/5182257225553920066'/><link rel='alternate' type='text/html' href='http://blog.chronoclast.com/2010/07/aspnet-helper-extensions.html' title='ASP.Net Helper Extensions'/><author><name>his leniency</name><uri>http://www.blogger.com/profile/08563846927500523919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_5PU69EU356k/S2IRaPkvuTI/AAAAAAAAAUQ/iwH8AkkCVyc/S220/Profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3527266406367929266.post-1208417349559304131</id><published>2010-06-03T10:37:00.000-06:00</published><updated>2010-06-03T10:37:14.197-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='science'/><title type='text'>Alka-Seltzer added to spherical water drop in microgravity</title><content type='html'>&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/bgC-ocnTTto&amp;amp;hl=en_US&amp;amp;fs=1"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;embed src="http://www.youtube.com/v/bgC-ocnTTto&amp;amp;hl=en_US&amp;amp;fs=1" width="425" height="344" allowScriptAccess="never" allowFullScreen="true" wmode="transparent" type="application/x-shockwave-flash"&gt;&lt;/embed&gt;&lt;/object&gt;

Cool stuff in space!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3527266406367929266-1208417349559304131?l=blog.chronoclast.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chronoclast.com/feeds/1208417349559304131/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chronoclast.com/2010/06/alka-seltzer-added-to-spherical-water.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/1208417349559304131'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/1208417349559304131'/><link rel='alternate' type='text/html' href='http://blog.chronoclast.com/2010/06/alka-seltzer-added-to-spherical-water.html' title='Alka-Seltzer added to spherical water drop in microgravity'/><author><name>his leniency</name><uri>http://www.blogger.com/profile/08563846927500523919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_5PU69EU356k/S2IRaPkvuTI/AAAAAAAAAUQ/iwH8AkkCVyc/S220/Profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3527266406367929266.post-7529989446847905632</id><published>2010-04-28T21:03:00.003-06:00</published><updated>2010-07-22T08:53:30.195-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>KeyedCollection</title><content type='html'>&lt;p&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms132438.aspx"&gt;System.Collections.ObjectModel.KeyedCollection&lt;/a&gt; is an interesting class, but with one drawback: it serializes in XNA's IntermediateSerializer, but doesn't deserialize.  There're ways to write a custom serializer for this class, but I chose a little bit different route - making my own that doesn't need a custom serializer.&lt;/p&gt;

&lt;h2&gt;Advantages&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Different methods can be exposed between the pipeline and runtime versions.  This can help make the collection &lt;a href="http://en.wikipedia.org/wiki/Immutable_object"&gt;immutable&lt;/a&gt; if desired.&lt;/li&gt;
&lt;li&gt;Hides methods that may not be needed at runtime like adding and removing elements.&lt;/li&gt;
&lt;li&gt;Provides regular for loop access for speed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Disadvantages&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Extra complexity of a new class&lt;/li&gt;
&lt;li&gt;Have to re-implement any methods&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Code&lt;/h2&gt;
&lt;p&gt;This is an abstract base class that serves solely as a container, provides an iterator, and a method of accessing by key.&lt;/p&gt;


&lt;pre class="brush: csharp"&gt;
abstract class KeyedCollection&amp;lt;T&amp;gt; : IEnumerable&amp;lt;T&amp;gt;
{
    #region Internal Data

    [ContentSerializer]
    private List&amp;lt;T&amp;gt; _collection;

    /// &amp;lt;summary&amp;gt;
    /// Keyed lookup: &amp;lt;Key, Collection Index&amp;gt;
    /// &amp;lt;/summary&amp;gt;
    [ContentSerializer]
    private Dictionary&amp;lt;int, int&amp;gt; _lookup;

    #endregion;

    #region Properties

    /// &amp;lt;summary&amp;gt;
    /// Indexer
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;param name="index"&amp;gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
    [ContentSerializerIgnore]
    public T this[int index]
    {
        get
        {
            return _collection[_lookup[index]];
        }
    }

    /// &amp;lt;summary&amp;gt;
    /// Number of elements in the collection
    /// &amp;lt;/summary&amp;gt;
    [ContentSerializerIgnore]
    public int Count
    {
        get
        {
            return _collection.Count;
        }
    }

    #endregion;

    /// &amp;lt;summary&amp;gt;
    /// Constructor
    /// &amp;lt;/summary&amp;gt;
    public KeyedCollection()
    {
        _collection = new List&amp;lt;T&amp;gt;();
        _lookup = new Dictionary&amp;lt;int, int&amp;gt;();
    }

    /// &amp;lt;summary&amp;gt;
    /// Find the neighbor at the given keyed index.
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;param name="index"&amp;gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
    public T Key(int index)
    {
        return _collection[_lookup[index]];
    }

    #region IEnumerable

    /// &amp;lt;summary&amp;gt;
    /// Enumerator
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
    public IEnumerator&amp;lt;T&amp;gt; GetEnumerator()
    {
        foreach (T element in _collection)
        {
            yield return element;
        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    #endregion;
}
&lt;/pre&gt;

&lt;p&gt;Pipeline compiler directives already included too!  It's a bit sparse for now, but a start.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3527266406367929266-7529989446847905632?l=blog.chronoclast.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chronoclast.com/feeds/7529989446847905632/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chronoclast.com/2010/04/keyedcollection.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/7529989446847905632'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/7529989446847905632'/><link rel='alternate' type='text/html' href='http://blog.chronoclast.com/2010/04/keyedcollection.html' title='KeyedCollection'/><author><name>his leniency</name><uri>http://www.blogger.com/profile/08563846927500523919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_5PU69EU356k/S2IRaPkvuTI/AAAAAAAAAUQ/iwH8AkkCVyc/S220/Profile.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3527266406367929266.post-5693007871732174852</id><published>2010-04-28T09:25:00.006-06:00</published><updated>2010-06-30T12:45:12.453-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Web'/><category scheme='http://www.blogger.com/atom/ns#' term='Icons'/><title type='text'>Icons!</title><content type='html'>&lt;h2&gt;
&lt;a href="http://www.komodomedia.com/blog/2009/06/social-network-icon-pack/"&gt;Social Networking Icons&lt;/a&gt;&lt;/h2&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://www.komodomedia.com/wp-content/uploads/2009/06/social_network_icons_blog_banner.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="213" src="http://www.komodomedia.com/wp-content/uploads/2009/06/social_network_icons_blog_banner.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h2&gt;
&lt;a href="http://p.yusukekamiyamane.com/"&gt;p.yusukekamiyamane Fugue Icons&lt;/a&gt;&lt;/h2&gt;
A huuuuuge set of general purpose icons.  Not as ubiquitous as the famfamfam icons.&lt;br /&gt;
&lt;a href="http://p.yusukekamiyamane.com/"&gt;&lt;img src="http://p.yusukekamiyamane.com/icons/images/index/image-01.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;h2&gt;
&lt;a href="http://www.famfamfam.com/lab/icons/silk/"&gt;FamFamFam Silk&lt;/a&gt;&lt;/h2&gt;
Entirely ubiquitous now - you see these everywhere.&lt;br /&gt;
&lt;a href="http://damieng.com/creative/icons/silk-companion-1-icons"&gt;Silk Companion 1&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3527266406367929266-5693007871732174852?l=blog.chronoclast.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chronoclast.com/feeds/5693007871732174852/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chronoclast.com/2010/04/social-network-icon-pack.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/5693007871732174852'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/5693007871732174852'/><link rel='alternate' type='text/html' href='http://blog.chronoclast.com/2010/04/social-network-icon-pack.html' title='Icons!'/><author><name>his leniency</name><uri>http://www.blogger.com/profile/08563846927500523919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_5PU69EU356k/S2IRaPkvuTI/AAAAAAAAAUQ/iwH8AkkCVyc/S220/Profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3527266406367929266.post-7841808002299846677</id><published>2010-04-16T11:26:00.003-06:00</published><updated>2010-04-16T12:10:49.499-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OTD'/><title type='text'>Shaders!</title><content type='html'>&lt;p&gt;Learning some HLSL as the plan requires sometime more than what BasicEffect can handle.  It doesn't do multiple diffuse textures per vertex.  The plan is still very theoretical, and I'm not sure if I'm even smart enough to make it happen.&lt;/p&gt;

&lt;p&gt;The screenshots before are simply a &lt;a href="http://en.wikipedia.org/wiki/Miller_projection"&gt;Miller projection&lt;/a&gt; wrapped around the grid.  This means however that the texture border's don't line up to the grid borders.  What I want is a more 'cellular' look and feel to it, along with a height map.&lt;/p&gt;

&lt;h3&gt;Cell Influence&lt;/h3&gt;

&lt;pre&gt;
foreach (neighbor in neighbors)
{
    foreach (vertex in neighbor.Vertices)
    {
        Calculate distance and then cell's influence on this vertex
        Cell.NeighborVertices[ neighbor.Index ].Add( Vertex, Influence );
    }
}
&lt;/pre&gt;

&lt;p&gt;Now, we have a list of neighbor vertices that the cell has influence over.  The distance and amount can be adjusted like a drawing brush - soft or hard brush.  In this step, the neighbor vertices should be given a UV channel that lines up with the cell.&lt;/p&gt;

&lt;h3&gt;Blended Textures and UV Channels&lt;/h3&gt;

&lt;p&gt;Each vertex will have a minimum of three UV coordinates as it will have at most, three cell textures to blend (cell brushes shouldn't extend beyond one neighbor).  Add in another texture channel or two for normal maps or detail overlays (just a tiled Miller wrap) and soon, every vertex has 5 UV channels.  Currently I'm focusing on the first 3.&lt;/p&gt;

&lt;p&gt;Paged textures will allow multiple textures to be used and not have to create channels in every cell for each texture.  Each neighbor lookup will have assigned to a channels 1 or 2.  Then just alternate channels for each neighbor.  Except the 12 pentagons... Yeah, going to have to figure out something different there...&lt;/p&gt;

&lt;h3&gt;Height Maps&lt;/h3&gt;

&lt;p&gt;The current screenshots show a simple height-map retrieved from the diffuse texture.  When moving to a more cellular approach, this kind of height-mapping won't be satisfactory.  Instead, a series of small height-maps can be loaded and applied to cells individually.  Using the neighbor influence lookup, the map can spill over and scale down into neighboring cell.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3527266406367929266-7841808002299846677?l=blog.chronoclast.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chronoclast.com/feeds/7841808002299846677/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chronoclast.com/2010/04/shades.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/7841808002299846677'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/7841808002299846677'/><link rel='alternate' type='text/html' href='http://blog.chronoclast.com/2010/04/shades.html' title='Shaders!'/><author><name>his leniency</name><uri>http://www.blogger.com/profile/08563846927500523919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_5PU69EU356k/S2IRaPkvuTI/AAAAAAAAAUQ/iwH8AkkCVyc/S220/Profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3527266406367929266.post-7516789554468871948</id><published>2010-04-04T21:52:00.000-06:00</published><updated>2010-04-04T21:52:19.548-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OTD'/><title type='text'>Some Screen Shots</title><content type='html'>&lt;p&gt;Borders still working.  Have it set to wrap a Miller projection to the grid.  There's a nasty seem on the back side to figure out.  This isn't quite the ultimate goal though - I want a blended grid, not a single texture over the mesh.  Height-mapping is working though.&lt;/p&gt;

&lt;h3&gt;Options:&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Texture Splatting: more limited textures due to the blending mask.  Might need a bit different type of unwrap?&lt;/li&gt;
&lt;li&gt;Just leave the cell edges: easy, but doesn't look as nice&lt;/li&gt;
&lt;/ul&gt;

&lt;img src="http://lh3.ggpht.com/_5PU69EU356k/S7lcHp7L64I/AAAAAAAAId8/SqNANKnEQvk/s800/OTD2%204-4-10.jpg"&gt;
&lt;img src="http://lh5.ggpht.com/_5PU69EU356k/S7lcG1BkJkI/AAAAAAAAId4/744Eh4JzZgU/s800/OTD%20-%204-4-10.jpg"&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3527266406367929266-7516789554468871948?l=blog.chronoclast.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chronoclast.com/feeds/7516789554468871948/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chronoclast.com/2010/04/some-screen-shots.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/7516789554468871948'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/7516789554468871948'/><link rel='alternate' type='text/html' href='http://blog.chronoclast.com/2010/04/some-screen-shots.html' title='Some Screen Shots'/><author><name>his leniency</name><uri>http://www.blogger.com/profile/08563846927500523919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_5PU69EU356k/S2IRaPkvuTI/AAAAAAAAAUQ/iwH8AkkCVyc/S220/Profile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_5PU69EU356k/S7lcHp7L64I/AAAAAAAAId8/SqNANKnEQvk/s72-c/OTD2%204-4-10.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3527266406367929266.post-3861634594104917301</id><published>2010-03-07T18:13:00.004-07:00</published><updated>2010-03-08T10:07:51.696-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OTD'/><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Spherical Coordinates in XNA</title><content type='html'>&lt;p&gt;OTD uses a globe based board.  As such, spherical coordinates can be useful.  The aim is to eventually be able to load a terrain map from a 2D image file.  While I have a ways to go before that, I do have a utility class for managing spherical coordinates.  Taking from DirectX's Vector2 and Vector3, I settled on Polar3 as a short yet descriptive stuct name.&lt;/p&gt;

&lt;p&gt;Spherical coordinates need three basic elements - the azimuth phi, &amp;Phi;; elevation theta &amp;theta;; and a radius, R.  &amp;Phi; runs between 0 and 2&amp;pi;.  &amp;theta; however presents some choices.  We can set one of the poles to be 0 and the other &amp;pi;, or set the equator to 0 and the poles to be +/- &amp;pi;/2.  I haven't gotten far enough to determine which is the best way, leaving the north pole at 0 appears to be the easiest option when dealing with rotations.  We'll see in practice though.  Two properties for latitude and longitude can be set up that handle as expected.&lt;/p&gt;

&lt;p&gt;Another thing to remember is which direction is up.  The &lt;a href="http://en.wikipedia.org/wiki/Spherical_coordinate_system"&gt;equations over at wikipedia&lt;/a&gt; and elsewhere place up as the Z axis.  However, the default in XNA is Y axis, so Cartesian conversions need to account for this.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
/// &amp;lt;summary&amp;gt;
/// Spherical Coordinate
/// &amp;lt;/summary&amp;gt;
/// &amp;lt;see cref="http://en.wikipedia.org/wiki/Spherical_coordinates"/&amp;gt;
/// &amp;lt;see cref="http://www.radicalcartography.net/?projectionref"/&amp;gt;
public struct Polar3 : IEquatable&amp;lt;Polar3&amp;gt;
{
    /// &amp;lt;summary&amp;gt;
    /// Angle in the Right, Forward plane
    /// &amp;lt;/summary&amp;gt;
    public float Phi;

    /// &amp;lt;summary&amp;gt;
    /// Angle around the Up axis
    /// &amp;lt;/summary&amp;gt;
    public float Theta;

    /// &amp;lt;summary&amp;gt;
    /// Radius
    /// &amp;lt;/summary&amp;gt;
    public float R;

    #region Latitude and Longitude Properties

    /// &amp;lt;summary&amp;gt;
    /// Latitude in radians
    /// -pi/2 &amp;lt;= theta &amp;lt;= pi/2
    /// &amp;lt;/summary&amp;gt;
    public float Latitude
    {
        get
        {
            return MathHelper.PiOver2 - Theta;
        }
    }

    /// &amp;lt;summary&amp;gt;
    /// Longitude in radians
    /// 0 &amp;lt;= phi &amp;lt; 2pi
    /// &amp;lt;/summary&amp;gt;
    public float Longitude
    {
        get
        {
            return Phi + (float)Math.PI;
        }
    }

    #endregion;


    #region Constructors

    public Polar3(float theta, float phi, float r)
    {
        Theta = theta;
        Phi = phi;
        R = r;
    }

    #endregion;

    #region Operators

    /// &amp;lt;summary&amp;gt;
    /// Equals
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;param name="value1"&amp;gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;param name="value2"&amp;gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
    public bool Equals(Polar3 other)
    {
        return ((this.Theta == other.Theta) &amp;&amp;
            (this.Phi == other.Phi) &amp;&amp;
            (this.R == other.R));
    }

    /// &amp;lt;summary&amp;gt;
    /// Equality Operator
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;param name="value1"&amp;gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;param name="value2"&amp;gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
    public static bool operator ==(Polar3 value1, Polar3 value2)
    {
        return value1.Equals(value2);
    }

    /// &amp;lt;summary&amp;gt;
    /// Inequality Operator
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;param name="value1"&amp;gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;param name="value2"&amp;gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
    public static bool operator !=(Polar3 value1, Polar3 value2)
    {
        return !value1.Equals(value2);
    }

    /// &amp;lt;summary&amp;gt;
    /// Get the object hashcode
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
    public override int GetHashCode()
    {
        return Theta.GetHashCode() + Phi.GetHashCode() + R.GetHashCode();
    }

    #endregion;

    #region 2D Map Projections

    /// &amp;lt;summary&amp;gt;
    /// Returns the xy Miller projection
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;see cref="http://en.wikipedia.org/wiki/Miller_cylindrical_projection"/&amp;gt;
    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
    public Vector2 ProjectMiller()
    {
        Vector2 xy = new Vector2();

        xy.X = Longitude;
        
        /*
         * (5/4) * ln( tan( pi/4 + 2theta/5 ) )
         */
        xy.Y = Latitude * 2 / 5;
        xy.Y = xy.Y + MathHelper.PiOver4;
        xy.Y = (float)Math.Log( Math.Tan(xy.Y) );
        xy.Y = xy.Y * 1.25f;

        return xy;
    }

    #endregion;

    /// &amp;lt;summary&amp;gt;
    /// Create a polar coordinate from a cartesian vector.
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;param name="vector"&amp;gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
    public static Polar3 CreateFromVector(Vector3 vector)
    {
        /*
         * DirectX defines up as (0,1,0), so we need to move some coords around.
         * Theta becomes the vertical angle against the Y axis
         * Phi becomes the horizontal angle in the XZ plane.
         */
        Polar3 coordinate = new Polar3(
            (float)Math.Acos(vector.Y / vector.Length()),
            (float)Math.Atan2(vector.X, vector.Z),
            vector.Length()
            );
        return coordinate;
    }

    /// &amp;lt;summary&amp;gt;
    /// To String
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
    public override string ToString()
    {
        return (String.Format("(Theta:{0}, Phi:{1}, R:{2}, Lat:{3}, Long:{4})", Theta, Phi, R, Latitude, Longitude));
    }
}
&lt;/pre&gt;

&lt;h3&gt;Map Projections&lt;/h3&gt;

&lt;p&gt;ProjectMiller() returns 2D coordinate when using a &lt;a href="http://en.wikipedia.org/wiki/Miller_cylindrical_projection"&gt;Miller projection&lt;/a&gt;.  It needs a little bit of work still, but the coordinates appear to be sound (just needs some offsetting) to map to a 2D image.&lt;/p&gt;

&lt;p&gt;Other projections such as &lt;a href="http://en.wikipedia.org/wiki/Mercator_projection"&gt;Mercator&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Mollweide_projection"&gt;Mollweide&lt;/a&gt; could be added as well.&lt;/p&gt;

&lt;h3&gt;Notes&lt;/h3&gt;

&lt;p&gt;Currently all the available values (Phi, Theta) and properties (Latitude, Longitude) are in radians.  Given that all other C# functions use radians, this seemed the simplest.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3527266406367929266-3861634594104917301?l=blog.chronoclast.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chronoclast.com/feeds/3861634594104917301/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chronoclast.com/2010/03/spherical-coordinates-in-xna.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/3861634594104917301'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/3861634594104917301'/><link rel='alternate' type='text/html' href='http://blog.chronoclast.com/2010/03/spherical-coordinates-in-xna.html' title='Spherical Coordinates in XNA'/><author><name>his leniency</name><uri>http://www.blogger.com/profile/08563846927500523919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_5PU69EU356k/S2IRaPkvuTI/AAAAAAAAAUQ/iwH8AkkCVyc/S220/Profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3527266406367929266.post-6389235981750504275</id><published>2010-02-27T23:49:00.005-07:00</published><updated>2010-02-28T00:02:35.053-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OTD'/><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Simple Settings Manager for XNA</title><content type='html'>&lt;p&gt;Being able to load settings into a game is a must.  There are a number of ways to accomplish this.  My current method works well enough for now, although it needs a bit of work in a few areas.  I accomplish this by creating a series of settings classes that can be serialized into XML and back again at run time using my &lt;a href="http://blog.chronoclast.com/2010/02/simple-serializer-for-c.html"&gt;simple serializer.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Settings Manager&lt;/h2&gt;
&lt;pre class="brush: csharp"&gt;
public class SettingsManager
{
    const string Extension = ".xml";
    const string Directory = "Content\\Settings\\";

    /// &amp;lt;summary&amp;gt;
    /// Loaded settings - Not currently implemented
    /// &amp;lt;/summary&amp;gt;
    //SerializableDictionary&amp;lt;string, SettingsBase&amp;gt; _settings;

    /// &amp;lt;summary&amp;gt;
    /// Constructor
    /// &amp;lt;/summary&amp;gt;
    public SettingsManager()
    {
    }

    /// &amp;lt;summary&amp;gt;
    /// Load a settings file
    /// &amp;lt;/summary&amp;gt;
    public T Load&amp;lt;T&amp;gt;()
    {
        Type t = typeof(T);
        return Load&amp;lt;T&amp;gt;(t.Name);
    }

    /// &amp;lt;summary&amp;gt;
    /// Attempt to load a settings file.  If not found, it will
    /// load a new, default instance of the settings class.
    /// &amp;lt;/summary&amp;gt;
    public T Load&amp;lt;T&amp;gt;(string name)
    {
        try
        {
            return Serializer.Read&amp;lt;T&amp;gt;(
                SettingsManager.Directory + 
                name +
                SettingsManager.Extension);
        }
        catch (Exception e)
        {
            e = null;
            Type t = typeof(T);
            return (T)Activator.CreateInstance(t);
        }
    }

    /// &amp;lt;summary&amp;gt;
    /// Save a settings object
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;typeparam name="T"&amp;gt;&amp;lt;/typeparam&amp;gt;
    public void Save&amp;lt;T&amp;gt;(T o)
    {
        Type t = typeof(T);
        Save&amp;lt;T&amp;gt;(o, t.Name);
    }

    /// &amp;lt;summary&amp;gt;
    /// Save a settings object
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;typeparam name="T"&amp;gt;&amp;lt;/typeparam&amp;gt;
    /// &amp;lt;param name="file_name"&amp;gt;&amp;lt;/param&amp;gt;
    public void Save&amp;lt;T&amp;gt;(T o, string name)
    {
        Serializer.Write&amp;lt;T&amp;gt;(
            o,
            SettingsManager.Directory + name + SettingsManager.Extension);
    }
}
&lt;/pre&gt;

&lt;p&gt;The basic idea is that we can load and save settings files either based on an arbitrary name or, for simplicity, the settings class Type.Name.  This is still a rough class - it assumes a lot about the settings files being loaded such as the files being serializable.  I currently have a simple class that settings files inherit from:&lt;/p&gt;

&lt;h2&gt;Settings Base&lt;/h2&gt;
&lt;pre class="brush: csharp"&gt;
[Serializable]
public abstract class SettingsBase
{
}
&lt;/pre&gt;

&lt;p&gt;More functionality could be added here such as a Save() function that allowed settings objects to save themselves via the SettingsManager.  The only special thing in this class is adding the [Serializable] tag at the top to ensure that all inheriting objects get this.&lt;/p&gt;

&lt;h2&gt;Simple Settings Example&lt;/h2&gt;

&lt;pre class="brush: csharp"&gt;
public class PlayerSettings : SettingsBase
{
    public int Id;
    public string Name;

    public PlayerSettings()
    {
        Id = 1;
        Name = "Spartacus";
    }
}
&lt;/pre&gt;

&lt;p&gt;Now, the settings manager can be used to load/save this.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
// Load default settings
PlayerSettings ps = settingsManager.Load&amp;lt;PlayerSettings&amp;gt;();

// Change something
ps.Name = "Hercules";

// Save with default name
settingsManager.Save&amp;lt;PlayerSettings&amp;gt;(ps);
&lt;/pre&gt;

&lt;h2&gt;Future Improvements&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;SettingsManager does not ensure that loaded files inherit from SettingsBase at all.&lt;/li&gt;
&lt;li&gt;SettingsManager does not track previously loaded settings files.  Tracking and storing loaded files would prevent costly file IO, deserialization and reflection.&lt;/li&gt;
&lt;li&gt;Settings classes assume that the constructor will set the default settings.&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3527266406367929266-6389235981750504275?l=blog.chronoclast.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chronoclast.com/feeds/6389235981750504275/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chronoclast.com/2010/02/simple-settings-manager-for-xna.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/6389235981750504275'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3527266406367929266/posts/default/6389235981750504275'/><link rel='alternate' type='text/html' href='http://blog.chronoclast.com/2010/02/simple-settings-manager-for-xna.html' title='Simple Settings Manager for XNA'/><author><name>his leniency</name><uri>http://www.blogger.com/profile/08563846927500523919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_5PU69EU356k/S2IRaPkvuTI/AAAAAAAAAUQ/iwH8AkkCVyc/S220/Profile.jpg'/></author><thr:total>0</thr:total></entry></feed>
