Friday, September 30, 2011

Speak softly and carry an extension pole

Making your customer happy can be difficult, no matter what your line of work.  When developing features in software, we know we'll never make all of the customers happy all the time, so we often cite the 80-20 rule: 80% of your customers will use 20% of the features, etc.  It's a good rule to remember when deciding which features to ship that will make your customers happy.

The longer I'm in the software development industry, the more I become aware of the need to listen for features the customer needs, as opposed to the features they want.  It's a subtle but important difference, and I've been lucky to work with several people who are experts at differentiating the two.  Sometimes I'm successful at it...other times (like this past week), not so much.  It is rare that I get to experience this applied to myself.

Last weekend I went to Home Depot.  I've been painting a few walls in our new place in Austin and had reached the wall in the living room which goes up to the 15-foot vaulted ceiling.  There was no way I could use my step stool to reach the top of the wall.  I'd need a ladder to get up that high.  Not just any ladder: a big ladder, preferably a 12-footer.  Since I drive a Prius, I'd also have to rent a truck to haul it.

These were the thoughts in my head when I drove to the Home Depot to check rental prices.  The ladder would be $24 for four hours, and the truck was close to $30 for just over an hour.  Not only was this going to be an expensive task, it would have to be fast.

The next morning, I went back to the store to pick up the ladder and truck so I could get it over with.  A different associate was working at the rental center.  "What do you need a ladder for?," she asked.

"I'm painting a 15 foot ceiling and can't reach the top with my roller brush."

"Oh, I see.  I think our extension poles will reach that far."

Extension poles?

Next time you're painting, take a look at your roller brush handle.  See that threaded hole in the bottom?  It's a standard size so you can add extensions to your brush.  For $5 I got a six foot pole, which is, of course, reusable.  I even ended up utilizing it on the parts of the wall I could reach without my stool, because it gave me more leverage on the brush and didn't wear out my forearms.

By taking the time to listen and understand my problem, the associate saved me time, hassle, and a lot of money.  She also helped me remember that just because a customer understands their problem, it doesn't mean they understand their solution.

Friday, April 29, 2011

XNA content pipeline: from asset to instance

Download the code for this example here.

I haven't gotten to do much new game work lately, so I thought I'd document some experiences I had several months ago when trying to use the XNA content pipeline.  It took me a while to figure this stuff out from the various blog posts and document pages out there, so maybe it will be of use to someone else.

The XNA pipeline has quite a bit of pre-baked functionality, such as creating textures from images, importing models, and compiling effects.  It also provides a great framework for custom behavior, which is what we're going to be doing here.


Q Games is making some really cool stuff in my favorite city in the world: Kyoto.  I was inspired by the game Shooter, published under their PixelJunk label, which performs extensive 2D fluid simulation on the PS3.  I did some fluid sim stuff back in college that was always a blast to work on, and I really miss getting to play around with the physically-based side of computer graphics.  The wow factor is huge, and Q Games found a great way to make a fun game out of it.  Jaymin Kessler did a great GDC presentation last year about it, called Go With the Flow! Fluid and Particle Physics in PixelJunk Shooter.

After seeing that presentation, I wanted to start messing around with ideas for a "fluid" tower defense.  I thought it might be cool to do something like "Defend Pompeii!" set in an alternate reality where Vesuvius is erupting and you have to use freeze ray towers to solidify the lava coming down the mountain before it gets to the town.  The solidified lava could form barriers that slow the flows down even further and give you time to use other types of towers.  An alternative theme could be a "ball pit" factory gone haywire, and you have to stop the wave of plastic balls before it hits the city.  It might be some pretty sweet eye-candy if you did a particle-based fluid simulation where the particles are different colors, to represent the balls.

I started experimenting using PhysX, which I'd never used before.  I'm using an open-source managed wrapper for PhysX, called PhysX.Net.  PhysX, like other NVIDIA products I've used, is an odd beast. The product seems solid, even if the API feels a little over-engineered.  However, the developer website is atrocious, and documentation is spotty at best.  You can find amazing videos of demos, but no actual code of the demos themselves, which seems to defeat the purpose.  I'm not sure where the PhysX community "hangs out," but I must have been looking in the wrong places; either way, I don't like programming in a vacuum.  I didn't get very far into prototyping before I was defeated by performance, or rather, lack thereof.  But, I did get to play with the content pipeline, so it wasn't a complete loss!

Level Importing

I wanted to begin with fluids interacting with a terrain.  This meant I'd need to create a heightfield in PhysX, and a heightfield for display.  I wanted to describe levels in XML, so I could easily create a level editor tool and eliminate the need to have assets and parameters hard-coded.  I also wanted to compile assets to binary format, as opposed to using the XML to read in assets at run time.

XNA provides a standard importer for reading XML.  However, it's up to you to specify what kind of assets you're describing in the XML for the importer to fill in using the XML elements.  To describe the heightfield, I decided to use image files.  Thus, the XML is an array of file names.  I created a class which describes the contents of the XML for the importer:

public class LevelFileFormat
    public string HeightFieldImageFileName { get; set; }

The XML describes an array of these LevelFileFormat objects inside an Asset node:

  <Asset Type="Antelope.Pipeline.LevelFileFormat[]">

Level Processing

In the XNA content pipeline, you begin with an importer, which reads the assets you include in the project.  Next, the imported assets are processed using a (what else?) processor, which creates the binary content files from the imported objects.  These binary files are read at runtime to load content.

After creating a basic description of levels as an array of LevelFileFormat objects, I created a custom LevelsProcessor, to generate content from the imported XML.  All custom processors in XNA inherit from ContentProcessor, which is a generic class that specifies the input asset and outputs the processed content to be written.  Additionally, all processors must be marked with the ContentProcessorAttribute.

[ContentProcessor(DisplayName = "Levels Processor")]
class LevelsProcessor : ContentProcessor<LevelFileFormat[], LevelContent[]>

Additionally, a DisplayName can be specified, which shows up under the Content Processor entry for the property grid of any asset in the content project:

I wanted to translate the input heightfield filename into content which could be used to create the heightfield for PhysX as a HeightFieldShapeDescription.  I also wanted to produce an object which XNA could display on screen.  Each of these objects is used for completely different purposes, and requires different information:
  • To create an XNA model, you need a triangle vertex list.  XNA provides a class to describe a model's content, called ModelContent.  
  • To create a PhysX HeightFieldShapeDescription, you must first create a HeightFieldDescription, for which you need the number of rows and columns in the heightfield, as well as a list of the height values.  I created a class to contain this information, called HeightFieldDescriptionContent.

public class HeightFieldDescriptionContent
    public HeightFieldDescriptionContent()
        HeightFieldSamples = new Collection<HeightFieldSample>();

    public int Rows { get; set; }
    public int Columns { get; set; }
    public Collection<HeightFieldSample> HeightFieldSamples { get; private set; }

LevelsProcessor takes an array of LevelFileFormat as input, and generates an array of LevelContent as output.  LevelContent contains HeightFieldContent, which is just a wrapper for the two types of heightfield content:

class HeightFieldContent
    public HeightFieldDescriptionContent HeightFieldDescription { get; set; }
    public ModelContent HeightFieldModel { get; set; }

Heightfield Processing

HeightFieldDescriptionContent and ModelContent each require their own processors.  Their processing is kicked off by the LevelProcessor, using the ContentProcessorContext that is passed in to each custom ContentProcessor.

First, I create an ExternalReference to the heightfield image file of type Texture2DContent, which XNA uses to represent a 2D texture.  The image files are not actually included in the content project, although I did add them to the content project's folder to make the relative paths the same.  I use the context to take the input Texture2DContent and create the output content, specifying the custom processors as a string:

var file = new ExternalReference<Texture2DContent>(filename);
var heightFieldDescription = context.BuildAndLoadAsset<Texture2DContent, HeightFieldDescriptionContent>(file, "HeightFieldDescriptionProcessor");
var heightFieldModel = context.BuildAndLoadAsset<Texture2DContent, ModelContent>(file, "HeightFieldModelProcessor");

The HeightFieldModelProcessor comes from the Microsoft example of generating a heightfield model using an image as a source for geometry, so I won't cover the details of that processor.  Suffice it to say, it generates a ModelContent object.

The HeightFieldDescriptionProcessor is simpler.  It gets the width and height of the heightfield image, and sets the content columns and rows.  Then it goes through each pixel of the image, reads the pixel value, and uses that as the height of the sample.

Content Writing

XNA already knows how to serialize a ModelContent object.  However, the HeightFieldDescriptionContent must be serialized using a custom ContentTypeWriter.  All custom type writers must apply the ContentTypeWriterAttribute.  Values to be serialized are written using the ContentWriter instance passed into the type writer:

class HeightFieldDescriptionContentWriter : ContentTypeWriter<HeightFieldDescriptionContent>
    protected override void Write(ContentWriter output, HeightFieldDescriptionContent value)

        WriteHeightFieldSamples(output, value.HeightFieldSamples);

    private void WriteHeightFieldSamples(ContentWriter output, Collection<HeightFieldSample> collection)
        foreach (var sample in collection)

Content Loading

Any content that is serialized should be marked with the ContentSerializerRuntimeTypeAttribute, which can be used to specify what assembly and type the content corresponds to when loaded at runtime:

class HeightFieldContent
    public HeightFieldDescriptionContent HeightFieldDescription { get; set; }
    public ModelContent HeightFieldModel { get; set; }

The HeightFieldContent content type corresponds to runtime type HeightField, which contains a PhysX HeightFieldShapeDescription and a Model:

public class HeightField
    public HeightFieldShapeDescription HeightFieldShapeDescription { get; set; }
    public Model HeightFieldModel { get; set; }

This means that as the binary content files are being deserialized, a Model and HeightFieldShapeDescription will be created.  However, a HeightFieldShapeDescription requires instantiation using the PhysX runtime, which XNA knows nothing about.  This is where things get cool.

Just as a custom writer was necessary for writing serialized content, a custom reader must be provided for reading serialized a HeightFieldDescriptionContent at runtime.  The reader which corresponds to a content type is specified in the ContentTypeWriter during generation of the binary content files:

public override string GetRuntimeReader(TargetPlatform targetPlatform)
    return typeof(HeightFieldDescriptionContentReader).AssemblyQualifiedName;

In the ContentTypeReader, a ContentReader instance is provided which must read back serialized values in the order they were written:

protected override HeightFieldShapeDescription Read(ContentReader input, HeightFieldShapeDescription existingInstance)
    var heightFieldDescription = ReadHeightFieldDescription(input);
    var heightField = Core.Singleton.CreateHeightField(heightFieldDescription);
    var heightFieldScale = AntelopeSettings.Default.HeightFieldScale / short.MaxValue;
    var heightFieldShapeDescription = new HeightFieldShapeDescription()
        HeightField = heightField,
        HeightScale = heightFieldScale
    return heightFieldShapeDescription;

private static HeightFieldDescription ReadHeightFieldDescription(ContentReader input)
    var columns = input.ReadInt32();
    var rows = input.ReadInt32();
    var samples = GetHeightFieldSamples(input, columns, rows);

    var description = new HeightFieldDescription()
        NumberOfColumns = columns,
        NumberOfRows = rows

    return description;

Once the HeightFieldDescription has been created from the serialized content files, a PhysX HeightField is created using the PhysX core.  This HeightField is used in the HeightFieldShapeDescription, which is a component of a Level object:

public class Level
    private static readonly SceneDescription SceneDescription = new SceneDescription()
        Gravity = new Vector3(0, -9.8f, 0)
    public Scene Scene { get; private set; }
    public HeightField HeightField { get; set; }

    public Level()
        Scene = Core.Singleton.CreateScene(Level.SceneDescription);

When XNA creates an instance of a Level object, the PhysX Scene is created as well, using the PhysX core. Finally, the XML's content can be loaded in the LoadContent method of the game:

var levels = Content.Load<Level[]>("Levels");

I use the HeightField property of a Level to create a DrawableGameComponent called HeightFieldGameComponent.  It uses the heightfield model to display the terrain and adds an actor to the scene using the HeightFieldShapeDescription:

var actorDescription = new ActorDescription()
    Shapes = { level.HeightField.HeightFieldShapeDescription }

PhysX provides a simple method of displaying the internal representation of a Scene, which can be useful for debugging.  If you run the game in debug build, you will see this PhysX debug display on top of the XNA model.

PhysX debug display in tandem with the XNA model of the terrain.
And there you have it.  I'd be excited to have another opportunity to experiment with the XNA content pipeline.  After this prototype, it seems like a very flexible API, and I get the impression there are many ways to approach the problem of getting assets into your game.  You may know a better way than what I've done here.  If so, by all means, fire away in the comments below!  I'm anxious to learn this stuff the best way possible.

Wednesday, March 23, 2011

Review: The Art of Game Design: A Book of Lenses, by Jesse Schell

I began reading The Art of Game Design in an attempt to find guidance while creating my own games.  Not only did the book satisfy my curiosity and give me the direction I desired, it actually provided inspiration: not just on the subject of creating games, but for succeeding at any endeavor which relies upon providing a pleasing experience for humans seeking a playful diversion.

The Art of Game Design: A Book of Lenses, by Jessie Schell

Schell's book addresses the subject of game design from a much higher conceptual level than "pick your theme, design your levels, blow stuff up," which was an unexpected surprise.  While I hesitate to scare a potential reader away, these are lessons in human psychology which identify the reason that people play games in the first place, as we have for thousands of years.  Throughout the book are literary "lenses."  Lenses are not laws or rules: each lens is formed from simple questions that pose whether a game fulfills identified human needs and wants that arise during gameplay.  To that end, Schell is quite brilliant: considering his target audience, he still succeeds in writing a book about the study of human nature that masquerades as a book about gaming.

Rather than coming off as intimidating, the lessons presented by the lenses throughout the book are a welcome change from the typical image associated with video games and their design.  Other design books provide more specific guidance, but may not be as applicable or flexible.  Even with its high-level approach, the book remains grounded in reality and is filled with examples from Schell's own experiences in the industry.  It excels at answering not just the "what?" questions about game development, but also the "why?", which can be all-too-easily overlooked for something as simple and fun as playing a game.

The book has a rough organization that introduces important concepts of game creation.  Earlier chapters deal with the definition of gameplay and why it is important to humans, as well as methods of finding inspiration for creating games of your own, and how to give your player a game they will enjoy.  The book then moves into the elements of games, and how important it is to balance gameplay to keep the game interesting and fun from beginning to end.  Later chapters deviate somewhat, and deal with the process of creating a game with topics such as teamwork, playtesting, and the business of video games.

I appreciate and respect what Schell writes in the later chapters, although it does feel as though he has to stretch to fit it into the framework of his book.  The lessons are universal when considering how to exceed with people who are excited and passionate about their work, and how to handle conflict that arises when so many strongly-opinionated people work together on a single creative vision.  They are relevant not only to video game development teams or software engineers, but to anyone who values the amazing things that can be accomplished with a team who works together because they share a common goal.

Perhaps the most important point of the book for myself is Schell's assertion that a game must create an experience for the player.  This can be difficult, since everyone will interact with the game in different ways.  A game is not an experience itself; it enables an experience, one that must be "interesting enough that it holds the player's focus as long and as intensely as possible."  At first, this seems obvious.  But, for myself and other developers, it is important that throughout the discussions about implementations of technology and the latest techniques, the ultimate goal is to give the player an experience they will remember.  All other goals of a game are secondary to this, and the best games demonstrate this trait.

For instance, few people will deny the incredible experiences that Minecraft has already given so many players.  Indeed, after reading Schell's book, his collection of lenses seem to define the recipe that Markus Persson followed when creating his popular game.  One initial complaint about the game that I've heard from several younger players who have yet to try the game concerns the simplicity of the graphics.

Upon trying the game, these players have been instantly compelled to build, explore, and feel the freedom of the "sandbox."  After reading The Art of Game Design, I believe this is because advanced 3D graphics are not an essential part of the experience a player derives from the game.  By boiling the graphics down to the necessary elements, Persson was able to focus completely on the experience he wanted to create, and in the process gave his game a distinctive look and feel.

The kinds of games you create and what you want the player to feel while playing is, of course, up to you, but it's something I will always keep in mind with any game I work on from this point: what is the essential experience I'm trying to create.

This is a wonderful book for anyone curious about the human desire to play games, and is an easy read no matter what your background may be.  I imagine even non-gamers would find themselves wanting to get out the Monopoly board or the Checkers set and come up with a few custom rules of their own.

Monday, March 7, 2011

Fairy rings

I recently read The Art of Game Design, by Jessie Schell, for which I should have a review up in the next few weeks.  I picked up the book to try and better understand game development at the highest conceptual level: while it's still a developing idea.  In the process, I became inspired to create a small game of my own.

While driving home from work on a rainy day, I noticed a fairy ring growing while I was waiting at a traffic signal.  The ring I saw was comprised of just a few mushrooms, but they can grow to be quite large.

One section of Schell's book talks about the importance of using your subconscious mind to think of cool and crazy ideas.  There are few things that let your subconscious mind wander like driving home in Houston traffic, and what's more crazy than a giant ring of mushrooms?  I started to think, if the mushrooms in a fairy ring grow from a single point, what if the other mushrooms in the ring could start rings of their own?  Would it just keep growing and growing in a fractal pattern?

I'm not a mycologist, but as the idea took off in my head, I could have cared less about the scientific reality of the situation.  I thought it sounded like an interesting idea for some kind of game.  I got home and immediately started jotting down ideas.  After iterating on different concepts for a few days, I had come up with some better developed notions of what gameplay could be like.  I tried not to think too deep about it, so I wouldn't latch onto an idea and have a difficult time changing my mind if something didn't work.  Here's the minimalist basics, from my notes:

  • mushrooms are growing in a forest
  • the ground starts bare; tap to plant a seed
  • seeds grow until they pop, and spread a ring of mushrooms, which can be popped themselves
  • mushrooms cannot be popped until fully grown
  • there are different mushroom types which have varying attributes
    • fast growth, small burst radius
    • moderate growth, moderate burst radius
    • slow growth, large burst radius
  • tapping on a mushroom selects it; tapping it again causes it to pop
  • mushrooms destroy everything inside their blast radius
  • quiet and relaxing
  • ambient noise: bugs, wind, rain, thunder
  • dark with high contrast colors: environment lit from glowing mushrooms, fireflies, stars, and distant lighting flashes
  • mushrooms glow in different colors, depending on their attribute types
  • mushrooms rings are not perfect circles and all attributes have a slight randomness
  • mushrooms have subtle anthropomorphic qualities so that casual punishment and reward can be incorporated
  • top down view
  • touch interface
  • pinch to zoom in/out
  • touch a mushroom centers and zooms

After reading that outline, you may have noticed something missing: goals and objectives. They're missing because I haven't figured out what they are. I honestly don't know what I could do with gameplay of this type that would be fun: a strategy game, where there's gameplay AI controlling "enemy" mushrooms?; a puzzle game, where you have to cover the ground with spores, similar to Qix?; an abstract game, where all you do is pop mushrooms and form random patterns in your "mushroom garden"? Since I'm not an experienced game designer, it's difficult for me to answer these questions before the gameplay has been implemented.

Some concept art I did in Photoshop for a glowing mushroom and fireflies.  I'm not an artist, so don't be too hard on me.
I think my favorite idea so far is to create a multiplayer game. Since mushrooms destroy everything inside their blast radius, I could potentially do something along the lines of Missile Command, where one player has to destroy the other player's mushrooms while growing their own mushrooms. Playing around with XNA networking services would be a lot of fun, and would be a great learning experience. If I pursue that course of action, I will, of course, be sure to share my trials.

With networked multiplay, one player could have cool-colored mushrooms, while the other could have warm-colored mushrooms.  In this image, the green mushroom on the left has been popped and is launching its spores.
I was able to get very basic gameplay developed in one quick iteration.  This is just a prototype, so the code was not test-driven.  I've discovered that when thinking creatively, I can move quickly and get more things accomplished without writing tests.  If I were to develop this fully, I would start with a clean slate and write my gameplay logic using TDD.

One of the most challenging aspects of designing a game like this, which is essentially a one-button game, is accomplishing what Schell refers to as "balancing." I've experienced the feeling of an unbalanced game during development, but I was unable to articulate or appreciate the problem. I imagine mobile designers deal with this in an attempt to keep their games as casual as possible. Since the player cannot (or does not want to) control the customization of the game as in a traditional PC game, it becomes important for the elements of gameplay (such as my mushroom attributes) to "feel" correct and behave as expected.

Sorry about the FRAPS watermark.  I'm cheap.

This is my first time developing with a touch interface.  I have an iPhone, so I've been using the Windows Phone emulator that ships with Visual Studio.  Because the performance of the emulator isn't optimal, I also have a Windows game project in tandem with the phone project.  My friend and colleague, Jacob Beaudoin, has a Windows Phone, for which he recently began developing games.  He will, undoubtedly, be doing some amazing stuff, so you should visit his website.

While writing this code, I found myself questioning a lot of my design decisions when attempting to decouple gameplay components.  For previous projects that I've worked on, this was never much of an issue.  After speaking with Jacob, I believe the next book I'm going to read is Game Engine Architecture.  The title sounds as inviting as a Junior High health textbook, but it's a topic I could definitely afford to learn more about.  I'd also like to try reimplementing this game in UDK, to get some experience with UnrealScript and the Unreal Editor.  All these objectives would dovetail together nicely.

Writing this prototype was fun, and it was good to feel inspired and excited after the tedium that my day job has become lately.  I will keep developing this only as long as it feels right.  I appreciate other people's opinions, so if you think this is lame or awesome, be sure to give me some feedback.

In the meantime, I'll see if I can incorporate additional...


Thursday, March 3, 2011

Review: Secret of Mana, by Square Enix

What started as an essay on one of my favorite games has turned into something new I'd like to try.  I'm going to experiment with writing reviews of relevant media I consume, such as books, movies and games. I won't blog exhaustively on everything I put in front of my face, but I think it's important that I am able to articulate why something does or does not work for me.  I am an easily entertained and laid-back person, but I need to improve my constructive criticism of creative formats if I want to successfully produce something of value myself.

I'm going to begin with an easy one: Secret of Mana, released as Seiken Densetsu 2 in Japan.  I just purchased the game for my iPhone, available in the App Store for 8.99 USD.  I can't say this is my first rodeo with Randi (or, as he was known back then, Justin) and the gang: we were first introduced when I was 12.  I'd won a free SNES cartridge that I already owned (Super Mario All-Stars) from a Nintendo Power contest.  I took it to Wal-Mart, said I'd gotten it as a duplicate birthday present; they took it back, no questions asked.  Now you know what a horrible person I am for ripping off a mom and pop establishment.

1993 Version

That last bullet point on the right used to haunt me as I stared at this beautiful box art: "When's the sequel coming out?!"
Secret of Mana wasn't my first RPG, but it did mark the point where I started to get "serious" about gaming.  I'd already owned a CoCo 3 and NES, and I'd played plenty of games.  But, the games I owned were the popular selections all my friends had, or were just some weird stuff I picked up because the box looked cool.  SoM, however, was the first time I researched a game and went into the store knowing specifically what I wanted to buy.

An hour after popping in the cartridge, I was submerged.  The beautiful graphics; the classic musical score; the thrill of getting weapon upgrades; the mystery of what was going to be in the next dungeon; the expansive world with different people and settings.  For the first time, the characters were well-developed, which is something that's always attracted me to movies and games.  Sure, it was no Mass Effect, but they were more dimensional than a certain Italian plumber.

Gameplay was simple and fun.  You could play as a button-masher if you wanted, or get a little more strategic by dodging and feinting.  The menu command system of Final Fantasy (loved by some, abhorred by others) is absent, in the style of The Legend of Zelda.  This casual gameplay is a reason others and myself originally took to the game so quickly.  This game and its English fan-translated sequel, Seiken Densetsu 3, remain two of my wife's favorites, and we have played both cooperatively many times.

As an angst-filled teen growing up in a small town, the story of SoM and its successors (Final Fantasy VI, Chrono Trigger, etc.) struck a particular chord with me.  The hero was brave and optimistic about saving the world with his friends, even though he was kicked out of his village by the people he loved.  He could go anywhere he wanted, and each town he visited had a neatly-packaged happy ending when he left.  He and his friends were forced to grow up quickly and leave those dear to them.  Those feelings were reflected in me even as I played the game.  I would wonder what would eventually become of my home and the things that I thought were important, once I grew older.

Even the subject of life and death was addressed, albeit in a simplified and kid-friendly manner.  But, for someone becoming self-aware and cognizant of his own mortality, it made me feel like I could handle the challenges that faced me the same way the game's characters faced their own problems.  I related to them, and felt like they could relate to me, if we were to meet.  This is a powerful storytelling device, and something I feel writers often overlook when they create sullen or hyper-stylized "cool" characters.

Looking back, it's easy to dismiss these impressions as the over-romanticized musings of someone remembering his childhood with nostalgia, because the game definitely had its faults.  The battle system was simple, but the supporting character AI was driven by a complex grid that 12-year-old me could never figure out.

My opinion of the leveling system held then as it holds today: my anxiousness to play the game and advance the story far exceeds my desire to grind magic and weapons for hours on end.  I would rather spend my time exploring castles and forests than wandering around casting the same spells over and over.  When discussing the game with friends, I realize this is a common complaint of those early Square RPGs, and I believe they've tried to address with subsequent releases in their franchises.  SoM attempts to balance some of the tedium associated with grinding by giving you destructive "power ups" for weapon attacks and increasingly fun magic animations.  However, powering up your weapon takes so long, the payoff is rarely worth the wait.

The dimensionality of the characters seems to have diminished, but the villains, in particular, are simple caricatures.  Imagine the worst Scooby-Doo bad guys if their dialog were reduced to one or two sentences ("Take care of my pet!  Remember to feed him, HA HA HA!!"), and you've got an accurate picture of SoM's antagonists.  I'm not demanding Colonel Hans Landa-levels of sadism in a light, Japanese RPG, but for all that great adventuring and exploration, it would be nice to have a credible threat to back it up.

2010 Version

As you would expect, it's a huge thrill to be able to revisit a favorite game of mine outside the confines of a PC-based emulator (too bad a certain jerk-faced noob couldn't get his threads together for playing it on the Xbox).  Imagining the old setup of my CRT television, Super Nintendo console and controllers, and particle-board stand all being condensed down to a hunk of metal not much bigger than a credit card amazes me, and I work with "Technology and Cyber Bits" for a living!

The game has been given a subtle face-lift, but, mercifully, this is no "Special Edition."  Colors and textures are richer and the "cartoon-y" feel has been enhanced, while a few enemy sprites have been inexplicably redesigned.

One of the most obvious graphical upgrades is a reflection of the sky and animated clouds in standing bodies of water.  It's a simple effect, but makes the scene feel much more dynamic.

The touch interface is mostly intuitive and welcome.  One of the best side effects of this new gameplay mechanic is a shortcut toolbar on the side of the screen.  Commands are dragged and dropped from the ring menus.  Tapping on a shortcut appears to execute a macro which drills down through the menu system to the selected location.  The cryptic supporting character AI grid has been replaced with a "multiple choice" selection for controlling behavior, making it more suitable for younger players.  Gameplay remains well-balanced, as long as you don't mind spending some time leveling up between dungeons.  Unfortunately, the cooperative mode for which the game was so well-loved, has been removed.

Some elements of the touch interface feel as though they could have been streamlined and improved.  In particular, the ring menus seem as though they've been shoe-horned into the game for the sake of nostalgia and continuity.  A look at the description in the App Store page for SoM gives one the impression that this is a selling point for Square.

This wouldn't be so bad if the menu didn't rotate when you ran your finger around it.
With touch interfaces, scrolling through menu choices is unnecessary, and becomes a liability.  Rather than preserve each ring menu as it was in 1993, I would have preferred to have the top of the menu hierarchy presented in a table, laid out for quick selection.  Bringing up the menu system already interrupts gameplay, so I'd rather not derail it completely by panning to the menu and option I'm searching for.  Additionally, some choices in menu and store interfaces generate a "popup" message, which is a particular thorn in my application developer side.  Once the popup is displayed, you have to tap to dismiss it, which is completely unintuitive and slows down menu transactions to a crawl.

I would have rather silently assumed I was feeding his family with my continued patronage.
Perhaps the most disappointing element is that the script for the game remains almost identical to the version released in 1993.  Ted Woolsey's translations of the old Square RPGs are golden oldies, but it's no secret that they were rushed.  Original material and plot was omitted, due to the technological constraint of limited text.  Thankfully, the font has improved, but those mysterious plot elements must remain lost in the janitor's closet of an Oslo mental institution, along with La Passion de Jeanne d'Arc and my innocence.  Hélas!

In conclusion, I couldn't be happier that Square Enix has started to revisit some of their old IP, which they've defended for so many years.  With the release of this game, Chaos Rings, and a few of the older Final Fantasy games, the company has made it clear that they won't be participating in the "< $0.99" casual games market on the App Store.  If that business model includes the release of high-quality, compelling experiences such as this, I believe they will continue to have success.

It's easy for me to geek out when I think of the possibilities of Square Enix investing in the 2D mobile market: porting their backcatalog of RPGs (Final Fantasies III-VI, Chrono Trigger, Secret of Evermore, and all the other GameBoy releases); official translations of Japan-release-only games (Seiken Densetsu 3, Star Ocean, Bahamut Lagoon); and finally, most unlikely but most mouth-watering of all: new games based on these incredibly successful franchises, developed in 16-bit, 2D graphics.  C'mon, Chrono fans, you know you'd buy an iPhone just to play that long-overdue sequel.

But, that's just wishful thinking.  In the meantime, I'll continue to enjoy Secret of Mana for many more years to come, and praise the developers responsible for this port with jealous (of their jobs) admiration.

Sunday, February 27, 2011

Porting bsnes to C#: Part Two

As I explained in my last post, I recently worked on a project, SnesBox, whose goal was to port the bsnes Super Nintendo (SNES) emulator so I could play emulated games on an Xbox 360.  It didn't succeed because of performance reasons, but I learned more about the differences between C++ and C# in the process.  This post will detail some of the challenges I had to overcome to complete this port.  All bsnes code samples I include are from bsnes 0.72.

Type Safety

C# is a type safe language, meaning it has type enforcement for objects.  This requires reexamination of the operation taking place whenever a type in C++ is implicitly cast to another type.  For instance, in this function, several implicit casts are taking place:

void CPUcore::op_ror_imm_b() 
 bool carry = regs.p.c;
 regs.p.c = (regs.a.l & 0x01);
 regs.a.l = (carry << 7) | (regs.a.l >> 1);
 regs.p.n = (regs.a.l & 0x80);
 regs.p.z = (regs.a.l == 0);

The variable carry is a boolean, which is bit-shifted as an integer.  The result of the bitwise-or operation is then assigned to a byte value, regs.a.l.  Additionally, regs.p.c and regs.p.n are both boolean values which take assignments from integer values produced by the bitwise-and operations.  C# is type safe, so these sorts of cases must be handled using explicit type casts and static methods in System.Convert.

public void op_ror_imm_b(CPUCoreOpArgument args)
    bool carry = regs.p.c;
    regs.p.c = Convert.ToBoolean(regs.a.l & 0x01);
    regs.a.l = (byte)((Convert.ToInt32(carry) << 7) | (regs.a.l >> 1));
    regs.p.n = Convert.ToBoolean(regs.a.l & 0x80);
    regs.p.z = (regs.a.l == 0);

The .NET Framework also contains the BitConverter class, which can be used to convert from byte arrays to primitive types, and vice-versa.  This is demonstrated in the following method.

private void echo_write(int ch)
 if (!Convert.ToBoolean(m.t_echo_enabled & 0x20))
  Array.Copy(BitConverter.GetBytes((ushort)m.t_echo_out[ch]), 0, m.ram, m.t_echo_ptr + ch * 2, 2);
 m.t_echo_out[ch] = 0;

Here, the lower two bytes in the integer value indexed by ch in the integer array m.t_echo_out are converted to an array of bytes, then copied into the byte array m.ram.

I wanted my code to stay as close as possible to bsnes code, for debugging purposes.  Even if a design was not necessary from a C# perspective, I went with it to prevent any ambiguity or confusion later on.  Type safety is one of the most obvious places this was observed, particularly with boolean types being converted to numerical values, and vice-versa.  Lines such as these:

Input.input.port_set_device(Convert.ToBoolean(0), Configuration.config.controller_port1);
Input.input.port_set_device(Convert.ToBoolean(1), Configuration.config.controller_port2);

could be easily converted to use true and false, but their meaning is preserved as is.

Union Types

Union types are still lurking out there.  To be fair to bsnes, whose objects duplicate behavior of hardware registers, a union makes sense for accessing different chunks of register bits.  That being said, coming across unions in bsnes was probably my biggest, "oh crap," moment.

struct reg24_t 
  uint32 d;
   uint16 order_lsb2(w, wh); 
   uint8 order_lsb4(l, h, b, bh); 


I thought to myself, "C# doesn't support something like Feature X, it must not support unions, right?"  Wrong...sort of.  Enter: the FieldOffset attribute.

public class Reg24
    public uint d;

    public ushort w;
    public ushort wh;

    public byte l;
    public byte h;
    public byte b;
    public byte bh;


In this piece of code (which assumes little endian architecture), the StructLayout attribute with an argument of LayoutKind.Explicit tells the compiler, "I'm going to explicitly lay out the memory for the fields in this object."  LayoutKind.Sequential is the default.

The FieldOffset attribute is applied to fields you want to be part of your "union," where the offset is the number of bytes from the start of memory allocated to the object.  By offsetting the byte variable l to the zeroth byte in the Reg24 class, writing to that field will write to the upper byte in both w and d.  Congratulations, you've created a union and earned the curses of anyone who has to maintain your code.

Array Pointers

In C#, arrays are objects which encapsulate managed memory.  Consequently, there's no way to iterate through the elements of C# arrays using pointer arithmetic.  This also means you can't pass a pointer to an arbitrary location in array memory.  This presents a problem when translating logic such as this:

void Video::draw_cursor(uint16_t color, int x, int y) 
 uint16_t *data = (uint16_t*)ppu.output;
 if(ppu.interlace() && ppu.field()) 
  data += 512;


if(hires == false) 
  *((uint16_t*)data + vy * 1024 + vx) = pixelcolor;
  *((uint16_t*)data + vy * 1024 + vx * 2 + 0) = pixelcolor;
  *((uint16_t*)data + vy * 1024 + vx * 2 + 1) = pixelcolor;


Here, the variable data points to the beginning of the array ppu.output.  If a conditional is met, the memory address stored by the pointer is incremented by 512 bytes.  Later on in the method, the memory address is incremented using additional arithmetic to create a temporary address, which is dereferenced to write the pixelcolor value.

The .NET Framework contains a generic struct, ArraySegment, which can be used as a substitute for the functionality of an array pointer.

private void draw_cursor(ushort color, int x, int y)
    var data = PPU.ppu.output;
    if (PPU.ppu.interlace() && PPU.ppu.PPUCounter.field())
        data = new ArraySegment<ushort>(data.Array, data.Offset + 512, data.Count - 512);


    if (hires == false)
        data.Array[data.Offset + (vy * 1024 + vx)] = pixelcolor;
        data.Array[data.Offset + (vy * 1024 + vx * 2 + 0)] = pixelcolor;
        data.Array[data.Offset + (vy * 1024 + vx * 2 + 1)] = pixelcolor;


ArraySegments are created using an array, the offset into the arrray, and the number of elements in the array past the offset point.

Use of ArraySegment is one of the areas of the code I'm disappointed with.  I would revisit it if I were to continue work on the project.  The struct is painfully simple; there isn't even an indexer to access array elements directly.  Additionally, ArraySegment is immutable: if you wish to change the offset, you have to create a new struct.  These shortcomings could be easily solved by writing my own ArraySegment-style struct.

Reference Type Primitives

In C#, primitives are actually represented by structs in the System namespace, making them value types.  You can pass a value type by reference in C#, using the ref keyword, but there's no language feature which lets you explicitly declare a variable to be of reference type.  This became a problem when I came across the following struct in bsnes code:

struct regs_t 
 uint16_t pc;
 uint8_t r[4], &a, &x, &y, &sp;
 regya_t ya;
 flag_t p;
 regs_t() : a(r[0]), x(r[1]), y(r[2]), sp(r[3]), ya(r[2], r[0]) {}

The variables axy, and sp are references to the individual elements of the array r.  There were several ways I could have approached solving this.  The first was to write a class wrapper for byte.  Classes are passed by reference in C#, so any wrapper around a byte value would pull the member byte with it when passed around.  But with this approach, the array r would also have to be an array of byte wrappers.  Arrays are instances of a class in C#, so they're passed by reference.  Thus, an array of byte wrappers would be redundant.

Instead, since this was an isolated occurrence of primitive type references, I opted to solve the problem by using an ArraySegment struct as an offset to each of the elements of r.  

public class Regs
    public ushort pc;
    public byte[] r = new byte[4];
    public ArraySegment<byte> a, x, y, sp;
    public RegYA ya;
    public Flag p = new Flag();

    public Regs()
        a = new ArraySegment<byte>(r, 0, 1);
        x = new ArraySegment<byte>(r, 1, 1);
        y = new ArraySegment<byte>(r, 2, 1);
        sp = new ArraySegment<byte>(r, 3, 1);
        ya = new RegYA(new ArraySegment<byte>(r, 2, 1), new ArraySegment<byte>(r, 0, 1));

The ArraySegments themselves are passed by value, but the array they wrap is passed by reference.  Therefore, the value each of the variables index will remain the same wherever one of the structs is referenced.

Template Metaprogramming

C++ and C# templates are very different beasts.  I still have much learning to do to comprehend the differences between the two.  In C#, templates are called generics, and are a simplified version of C++ templates.  Most importantly for my port, C# generics do not allow non-type parameters.  In C++, a compile time constant can be specified as a template argument, allowing for methods in bsnes like this:

template<int bits> inline unsigned uclip(const unsigned x) 
 enum { m = (1U << bits) - 1 };
 return (x & m);

where uclip can have the desired number of bits generated at compile time by being called as

uclip<2>(data + 1);

Since C# does not allow generics to be used like this, functions such as these could be changed to:

uclip(2, data + 1);

However, this does not generate the same type of function call as C++, where the number 2 has been compiled into the function itself.

For some template methods, I had to get a little more creative, such as initializing the opcode tables for the processor cores.  In bsnes, non-type parameters were used to initialize the table's function calls at compile time:

op[0x34] = &SMPcore::op_read_a_dpx<&SMPcore::op_and>;
op[0x35] = &SMPcore::op_read_a_addrr<&SMPcore::op_and, X>;
op[0x36] = &SMPcore::op_read_a_addrr<&SMPcore::op_and, Y>;
op[0x37] = &SMPcore::op_read_a_idpy<&SMPcore::op_and>;
op[0x38] = &SMPcore::op_read_dp_const<&SMPcore::op_and>;
op[0x39] = &SMPcore::op_read_ix_iy<&SMPcore::op_and>;

Since all arguments were generated at compile time using template metaprogramming, the signature of the function pointers is void function(void), allowing the table to be initialized uniformly.

In C#, I pass my method arguments manually.  Since the delegate signatures of the opcode table entries have to match each other, it is necessary for each method to match a common signature.  I created an argument class, where I could initialize the parameters needed for a particular method:

opcode_table[0x34] = new SMPCoreOperation(op_read_a_dpx, new SMPCoreOpArgument() { op_func = op_and });
opcode_table[0x35] = new SMPCoreOperation(op_read_a_addrr, new SMPCoreOpArgument() { op_func = op_and, i = (int)OpCode.X });
opcode_table[0x36] = new SMPCoreOperation(op_read_a_addrr, new SMPCoreOpArgument() { op_func = op_and, i = (int)OpCode.Y });
opcode_table[0x37] = new SMPCoreOperation(op_read_a_idpy, new SMPCoreOpArgument() { op_func = op_and });
opcode_table[0x38] = new SMPCoreOperation(op_read_dp_const, new SMPCoreOpArgument() { op_func = op_and });
opcode_table[0x39] = new SMPCoreOperation(op_read_ix_iy, new SMPCoreOpArgument() { op_func = op_and });

The beauty of template metaprogramming is definitely lost in the translation.  However, this lack of functionality is most frustrating when porting the variant data types, such as 2-bit, 3-bit, and 17-bit unsigned integers, found in SNES hardware.  bsnes contains an elegant, although somewhat cryptic, template class to generate these types:

template<unsigned bits> class uint_t 
 enum { bytes = (bits + 7) >> 3 };
 typedef typename static_if<
  sizeof(int) >= bytes,
  unsigned int,
  typename static_if<
  sizeof(long) >= bytes,
  unsigned long,
  typename static_if<
  sizeof(long long) >= bytes,
  unsigned long long,
 >::type T;
 static_assert(!std::is_same<T, void>::value, "");
 T data;


and a new variant data type can be defined with the line

typedef uint_t<2> uint2;

As a TDD developer and all-around fan of simple development, I have quite a pet peeve for duplicated code.  It increases the number of things I have to keep in my brain at any given time, and when I make a change to duplicated code, I have to change it everywhere the code has been duplicated.  It therefore came as a huge disappointment when I had to copy/paste the entire class of every variant data type I wanted to generate:

public struct uint2
    private uint data;
    private const int bits = 2;


public struct uint9
    private uint data;
    private const int bits = 9;


Gross.  If someone knows a way around this, please come forward, as the solution eludes me.  After this experience, non-type parameter generic methods are a feature I anxiously await in a future version of C#.

Overloaded Operators

There was some confusion on my part when I first started using overloaded operators in C#.  I had never worked on a project that required them, so I expected them to behave like overloaded operators in C++.

inline operator T() const { return data; }
inline T operator ++(int) { T r = data; data = uclip<bits>(data + 1); return r; }
inline T operator --(int) { T r = data; data = uclip<bits>(data - 1); return r; }
inline T operator ++() { return data = uclip<bits>(data + 1); }
inline T operator --() { return data = uclip<bits>(data - 1); }
inline T operator  =(const T i) { return data = uclip<bits>(i); }
inline T operator |=(const T i) { return data = uclip<bits>(data  | i); }
inline T operator ^=(const T i) { return data = uclip<bits>(data  ^ i); }
inline T operator &=(const T i) { return data = uclip<bits>(data  & i); }
inline T operator<<=(const T i) { return data = uclip<bits>(data << i); }
inline T operator>>=(const T i) { return data = uclip<bits>(data >> i); }
inline T operator +=(const T i) { return data = uclip<bits>(data  + i); }
inline T operator -=(const T i) { return data = uclip<bits>(data  - i); }
inline T operator *=(const T i) { return data = uclip<bits>(data  * i); }
inline T operator /=(const T i) { return data = uclip<bits>(data  / i); }
inline T operator %=(const T i) { return data = uclip<bits>(data  % i); }

The first operator overloaded in this example, the cast operator, converts the variant struct to a primitive data type.  This can also be accomplished in C#, using the static explicit operator overload:

public static explicit operator uint(uint2 number)

Continuing through the list of overloaded operators, the assignment operator cannot be overloaded in C#.  Instead, I created an Assign method.

public uint Assign(uint i)
    return data = Bit.uclip(bits, i);

At first I was concerned I wouldn't remember to use this function when converting an expression where a uint is assigned to the uint2 class.  However, because of type safety in C#, this situation was avoided by a compile error.

Finally, the overloaded arithmetic and bit-wise operators.  These operators caused me the most confusion, since all the arithmetic operators I overload are actually assignment operators.  In C++, this is addressed by assigning the result of the operation to the internal unsigned integer, data.

In C#, you cannot overload the operator/assignment operations.  For example, you can overload +, but not +=.  I learned that this is because C# handles the += operator for you automatically, once the + operator has been overloaded.  Rather than assign the result of an operation back to the object itself, you return the value only.  C# determines whether the assignment should take place based on the context:

public static uint2 operator +(uint2 number, uint i)
    return new uint2(Bit.uclip(bits, + i));

The same is true of the pre and post-increment and decrement operators.  Rather than handle both cases, you overload the + and - operators and increment or decrement by 1.  C# handles the order issues automatically.
public static uint2 operator ++(uint2 number)
    return number + 1;

Multiple Inheritance

One of the first things a C++ developer discovers when learning C# is the lack of multiple class inheritance, to prevent the ambiguity that can arise from abuse of this language feature.  This immediately posed a problem for SnesBox, since bsnes uses extensive multiple inheritance, such as in the CPU class:

class CPU : public Processor, public CPUcore, public PPUcounter, public MMIO


There is no way to get around the lack of inheritance from multiple classes in C#, and no way to fully simulate the behavior of using more than one base class, such as overriding methods and accessing protected members.  Any technique which presumes to do so is, in the end, a trick or a hack.

C# does, however, allow the implementation of multiple interfaces.  Many developers have used this to their advantage in as many different ways when attempting to program multiple inheritance "into" the C# language.  Since I was writing all the SnesBox code myself and could define how the code interacted with itself, using multiple interfaces was an acceptable solution.  The SnesBox implementation of CPU looks like this:

partial class CPU : CPUCore, IPPUCounter, IProcessor, IMMIO


In the code for SnesBox, Processor still exists as an explicit class:

class Processor
    public Thread thread;
    public uint frequency;
    public long clock;


    public Processor()
        thread = null;

However, instead of making any class inherit directly from Processor, I use an IProcessor interface.

interface IProcessor
    Processor Processor { get; }

The Processor class is never used as an expected base class anywhere in the code.  Instead, any method which would have expected an instance of a Processor instead takes an instance of an IProcessor.  Processor functionality is then accessed through the Processor property in the interface.

For example, in the bsnes C++ code, the method "step" uses the clock and frequency fields it has inherited from the Processor base class.

void CPU::step(unsigned clocks) 
 smp.clock -= clocks * (uint64)smp.frequency;
 ppu.clock -= clocks;
 for(unsigned i = 0; i < coprocessors.size(); i++) 
  Processor &chip = *coprocessors[i];
  chip.clock -= clocks * (uint64)chip.frequency;

Inside the for loop, each element in the array of coprocessors is accessed as a Processor.  In the SnesBox C# code, the function looks mostly the same:

public void step(uint clocks)
    SMP.smp.Processor.clock -= (long)(clocks * (ulong)SMP.smp.Processor.frequency);
    PPU.ppu.Processor.clock -= clocks;
    for (uint i = 0; i < coprocessors.Count; i++)
        IProcessor chip = coprocessors[(int)i];
        chip.Processor.clock -= (long)(clocks * (ulong)chip.Processor.frequency);

Each piece of Processor functionality is accessed using the Processor property in IProcessor.  A method can still access an object as an IProcessor, rather than its derived type.  The step function does this inside the for loop.

There is not much "syntactic sugar" to be found in an implementation of multiple inheritance such as this.  Each time the interface-implemented functionality is used, the property which contains the actual object must come before any fields or methods.  CPUCore is the largest and most complicated of all the base classes used by CPU, and it is from this class that CPU inherits a significant amount of its functionality.  Because of the relative awkwardness of using interfaces as a source of multiple inheritance, I chose CPUCore as my one explicit base class.

Coroutines and Fibers

Much can be said about coroutines, since it was, ultimately, the issue that defeated this project.  In bsnes, each emulated processor is run on a fiber.  Fibers, and thus, the processors in bsnes, operate using cooperative multitasking.  This means that the fibers themselves control when they stop work, and when another fiber starts up after it.  This is where fibers differ from threads, which are scheduled by the OS.  For more on the subject from a gaming perspective, I suggest Ben Carter's post on #AltDevBlogADay.

As I mentioned in my last post, I got around this issue for debugging purposes by using deprecated methods in .NET threads which allow them to cooperatively multitask.  Since the feature is deprecated and the threads were heavyweight, the performance was abysmal.  This lead me to explore different means of preserving a stack at an arbitrary point during execution and resuming execution in a place where it last left off.

A coroutine is a function that has multiple entry and exit points.  The stack is effectively preserved each time a coroutine returns, allowing the coroutine to resume execution at the point it returned from when it is called again.  Coroutines are possible in C#, using the yield statement.  For a fantastic use of coroutines in C#, see Rob Eisenberg's presentation from MIX 2010, Build Your Own MVVM Framework (don't worry, the title makes it sound more intimidating than it actually is).  If you're interested in some of the finer details of what's happening under the hood of a C# coroutine, check out Jeremy Likness's blog on sequential asynchronous workflows.

When the yield keyword is used in a method, the C# compiler generates a class behind the scenes to implement an iterator block for that method.  This class is a state machine which allows iteration through the states in the method.  Each yield statement signifies that a new state in the iterator has been reached, and execution returns to the method doing the iterating.  The state inside the iterator is preserved until the next iteration.

For instance, in the threaded version of SnesBox, the CPU may yield its execution to the SMP at any time by calling:

public void synchronize_smp()
    if (SMP.smp.Processor.clock < 0)

In the Switch function, the current thread (the CPU) is paused, and the SMP thread is resumed.  In this way, processors hand off execution to one another thousands of time each frame.

Using coroutines, I can preserve state at the same point using a yield statement:

public IEnumerable synchronize_smp()
    if (SMP.smp.Processor.clock < 0)
        yield return SMP.smp.Processor.thread;

Here, the enumerator from the SMP iterator block is returned as the result of the iteration.  For nested coroutines to work properly, a method must become an enumerable method if it nests another enumerable method.  For instance, a method which calls synchronize_smp must also yield return any enumerable results of synchronize_smp, and so on:

private IEnumerable scanline()
    foreach (var e in synchronize_smp())
        yield return e;
    foreach (var e in synchronize_ppu())
        yield return e;
    foreach (var e in synchronize_coprocessor())
        yield return e;
    foreach (var e in System.system.scanline())
        yield return e;


Much like const-correctness in C++, nested coroutines in C# are "catching," and spread up the callstack.  At the top of the enumerable processors, the scheduler iterates through all returned enumerators until an exit code is received, indicating it is time to draw a frame.

I created a test project that had a class which used nested coroutines, four layers deep, and a corresponding class that did the same thing, but used .NET threads to preserve the stack.  I performed 10,000,000 switches back and forth and got the following timings:

Threading Start
Time: 00:01:52.0351499
Yielding Start
Time: 00:00:07.8278730

Coroutines produced a 14x speed increase.  This made me very optimistic about doing the same thing to SnesBox, so I began work in a separate branch.

I was quite disappointed when the version of SnesBox using coroutines ran more slowly than the version with threads.  I didn't investigate the cause of the performance loss thoroughly.  Since the processor switching can occur at nearly any place during execution of bsnes, it was necessary to place an iteration loop around almost every function in the codebase.  I suspect that doing an iteration at every level in the callstack produces so much overhead that the benefits of moving from heavyweight threads are lost.


As I asserted in my previous post, even though the project was a failure, I was glad I gave it a try.  It was exciting to try to make a contribution to the emulation community, and to learn a little more about what's going on inside the machine when I start up a cartridge.  Mostly, it was a fun experiment in porting code from C++ to C#.

I'll be keeping an eye open for any significant changes in bsnes related to fibers.  I also hold misplaced hope that a future release of the .NET Framework may contain support for lightweight threads.