Improving Download Time (2-3x) for Full Screen Background Images

Jan 4, 2010

Getting your backgrounds quickly is very important for games, especially at startup time when you're downloading a lot of stuff anyway (like menu buttons, simple effects, such as explosions and other things that didn't make it into the "core" xap to reduce initial load time).

Since you are full screen, it is a good idea to detect the resolution (that would be the ActualWidth and ActualHeight properties of your root control) and programatically return a suitable sized background.

For example, a 1920x1080 JPG image is about 200K while the same image 800x600 is about 50K.

The source code is simple, but I post it in case someone needs it and doesn't have to write it from scratch:

/// <summary>
/// The background resolutions available
/// </summary>
private static int[] _resAvailable = new int[] { 800, 1024, 1280, 1600, 1920 };

/// <summary>
/// Returns the most appropriate resolution from the list of available resolutions for the background images
/// Best resolution is defined as the closest resolution that is bigger than the resolution input as an argument
/// </summary>
/// <param name="currentXResolution"></param>
/// <returns></returns>
private static int GetBestStockResolution(int currentXResolution) {
    int count = _resAvailable.Length;

    for (int i = 0; i < count; i++) {
        if (_resAvailable[i] >= currentXResolution) {
            return _resAvailable[i];
        }
    }

    // no suitable resolution found, return largest
    return _resAvailable[count - 1];
}

/// <summary>
/// Determines the correct url for an image based on teh current resolution and short image name
/// </summary>
/// <param name="imageShortName">the short name of the image (e.g. "shockLord"</param>
/// <returns>url to the image, including resolution ("http://.../image1920.jpg">http://.../image1920.jpg) </returns>
public static string GetBackgroundImageUrl(string imageShortName) {
    return String.Format("">http://www.mysite.com/images/{0}{1}.jpg", imageShortName, GetBestStockResolution((int)Globals.XResolution));
}

 

In the above code Globals.XResolution is set to the current full screen resolution when the player clicks play to go full screen.

To use the code, you need to have the same image with various resolutions, e.g. mysite.com/images/background1920.jpg, mysite.com/images/background1024.jpg and so on.

Last but not least, you can use a low-quality background image when the game goes full screen for the first time, and then replace it with the high-quality image once available. I made a special control just for that: SmoothImage in the Controls Pack on Nokola.com. The SmoothImage control will preserve its previous image, whenever you change it's Source and will display the new image once it's available. You can see the SmoothImage sample by launching http://nokola.com/shock and switching between the classes - note how the backroung changes "smoothly" and you don't see a period of transparent/missing image background while the new background gets downloaded.

 

  

Tips/Tricks: Short Sounds, Fireworks and BitmapCache Speed

Jan 4, 2010

This blog post is a follow-up of the previous one dedicated to the Shock improvements.

I'll just list all tips or other interesting findings/updates in no particular order:

Playing Short Sounds in Silverlight (Improved)

You probably know by now that Silverlight (2,3) has an annoying issue with short sounds - sometimes the sound is not played correctly. The simple workaround is here

If you happen to play too many sounds/sec, the above workaround can cause your memory usage to grow more than you want to for short time. The easiest way to avoid the surge in mem usage is to cache the streams that contain the .mp3 sounds, like this:

private static Dictionary<string, Stream> _streams = new Dictionary<string, Stream>();

public static void PlayShortSound(string embeddedSoundName, double volume)
{
    Stream stream;
    if (!_streams.TryGetValue(embeddedSoundName, out stream))
    {
        stream = Application.GetResourceStream(new Uri(String.Format("/Shock;component/Sounds/{0}", embeddedSoundName), UriKind.Relative)).Stream;
        _streams[embeddedSoundName] = stream;
    }
    MediaElement media = new MediaElement();
    _soundContainer.Children.Add(media);
    media.MediaFailed += media_MediaFailed;
    media.MediaEnded += media_MediaEnded;
    media.Volume = volume;
    media.AutoPlay = true;
    media.Position = TimeSpan.FromMilliseconds(0);
    media.SetSource(stream);
}

Then, just call the function like this example: PlayShortSound("explosion.mp3"). You can use this trick, because multiple sounds using the same stream don't cause issues with each other, which is nice.

"Shatter" Effect

In my previous blog post I mentioned the "shatter" brick effect, which is based on this one:  http://www.shinedraw.com/animation-effect/flash-vs-silverlight-colorful-fireworks/

I changed the effect and made it self-recycling: removes itself from the parent after a given time period. It will also display "fireworks" in an area, not  a dot. All of these are really small modifications, but help make the effect "run and forget", and easy to use for "shattering" stuff like bricks.

Here's an usage sample:

public static TimeSpan ShatterEffectTimeSpan = TimeSpan.FromSeconds(0.3);              

Fireworks fireworks = new Fireworks(TimeSpan.FromSeconds(0.3), (int)width, (int)height, brickAppearance == BrickAppearance.Ice);
Canvas.SetLeft(fireworks, centerX);
Canvas.SetTop(fireworks, centerY);
Globals.BoomContaier.Children.Add(fireworks);
fireworks.Start();

And here's the source code. Note: get the complete sample from the shinedraw.com link above and then change the 2 files below. The code won't compile, but you just have to call your own Random() function, and maybe fix few other basic things.

Fireworks.xaml.cs (4.98 kb)  MagicDot.cs (2.89 kb)

I want to call out something very interesting in the above effect (not made by me originally) - each MagicDot is created within its own container. I believe it will cause less layout work than putting all dots within the same container (this is a gut-feeling unverified speculation)

If you want to see the shatter effect in action, break the ice bricks on level 2 of Shock: http://nokola.com/shock

When (Not) To Use BitmapCache, Even For Images That Don't Move

I found out that if I use CacheMode="BitmapCache" for each brick (100+ per level), the performance suffers. This is very interesting, and is something to keep in mind when using bitmap cache.

Seems like the larger the image, the better.

More On Speed

Some blogs (don't remember where) mention that images with Opacity=0 still render and take valuable CPU/GPU time - I tested it and it seems that in Silverlight 4 Beta this is not the case.

I observed no noticeable speed change when a UserControl (the highscore) had Opacity=0 vs Visibility=Invisible. Note, however that Opacity=0 means you get hit testing, so there is some speed difference - don't just blindly overuse Opacity=0 instead of Visibility=Invisible.

 

      

Shock Game got new character - Old Man (the one with the raindeer)

Dec 25, 2009

Now with music (again), special effects. Read more about the effects and other improvements here:

Yes! Thanks to few donations and some out-of-pocket money, I was able to buy back some of Shock's music.

  • Each character has a theme song now. The new character - Old Man, is named after that guy that flies raindeers and distributes gifts through his Christmas distribution chain.
  • The music has new engine now, with "announcing" control (a popup that displays the song title with information).
  • Other improvements include sounds for everything - ball hit, shattering glass, etc. To make this work, I had to create an AutoPlay MediaElement for each mp3 and play it. There are few tricks here that you can use to minimize objects created and mem usage - code will follow!
  • New visual effects include "shatter" effect which is based on this: http://www.shinedraw.com/animation-effect/flash-vs-silverlight-colorful-fireworks/, with the following simple changes/improvements:
    • Fireworks consist of 2 ellipses instead of 5 - speed optimization
    • The effect has "range" - e.g. you can make the dots appear everywhere on the brick, not just one point
    • The effect takes TimeSpan (e.g. 0.5 sec), and plays for a specific time, then the Canvas removes itself from it's parent. This allows to just add the effect anywhere and then start it and forget it. Nice and self-manageable :)
  • Many speed improvements related to GPU and BitmapCache. For some weird reason, I've left the bitmap cache off many of the images before...most notably the background image that takes a lot of space

I have few more improvements in the pipeline - mainly perf and resolving few minor issues (I doubt if anyone will notice most of them)

It is a busy Christmas :) I'll post some code from v3 of the game soon...first let's wrap it up.

Yes, the game is here: http://nokola.com/shock

I strongly advise playing with the Old Man, as it provides the most festive experience! :)

Please let me know your opinion - does it play well? What do you think about it and what would you change or improve?

Thanks!

Note: donations are still open, since the game hasn't paid for itself just yet and I'm planning more games :)

    

Fast Tile Brush in Silverlight, And Easiest Way to Shader Effects

Dec 22, 2009

Here is one monster, tiled as 6 monsters down here:

This is actually 1 monster, tiled twice horizontally and 3 times vertically using a Silverlght Tile brush shader effect.

Download source code

I'm not 100% sure if this is the fastest way, but it's definitely worth it (fast). There are 2 other possible ways to do fast tiling:

  1. Do it manually or "hardcoded" - if your tile will never change, just do it in any image editor and then display the tiled result using an Image tag
  2. Display several images next to each other - relatively harder, but might end up being faster than the pixel shader (this is just a speculation on my side since I haven't tested it yet, but it is worth a try). Image-s can be rendered on the GPU, if you enable BitmapCache and GPU acceleration in Silverlight, while the pixel shaders are currently (in Silverlight 3) calculated on the CPU.

The pixel shader code:

// Amount of tiling in the X and Y direction
float2 TileCount : register(C0);
sampler2D implicitInput : register(s0);

float4 main(float2 uv : TEXCOORD) : COLOR
{
 return tex2D(implicitInput, frac(uv.xy * TileCount.xy));
}

Sample usage:

<Image Source="http://nokola.com/clientbin/images/icons/games.png">
  <Image.Effect>     
    <local:TileEffect TileCount="2,3" />   
  </Image.Effect> 
</Image>

And I also mentioned the easiest way to shader effects.

Currently I believe you can start almost immediately with Shazzam: http://shazzam-tool.com/.

It's a tool you can use to test out your shader effects, and will create the required Silverlight or WPF code-behind for you.

I know there are other Tile brushes for Silverlight out there, but I haven't found a simple pixel shader (with one instruction and frac()). The pixel shaders I found usually use 2 variables - one for x-tiling, one for y-tiling. Since Pixel shaders, even on the CPU, supposedly favour SIMD (single instruction, multiple data), less instructions should mean faster performance (depends on the shader compiler too).

What can you use it for?

In a side-scroller or many other types of games, tiling textures is crucial - e.g. brick wall, metal, and other things.

  

Adorners in Silverlight - Move, Size, Rotate, Custom Mouse Cursor

Dec 13, 2009

This adorner took me few days to get right!

Edit Dec, 15: Andrej Tozon created an updated source supporting Behaviours (and drag-drop without code in Blend). Here's a link to his version. Thanks Andrej!

This is work in progress, but the base functionality is there and stable!

Download source code

View Sample

 

The adorner currently has the following features:

  • Shows custom mouse cursors that get rotated and aligned to the object being rotated/sized in realtime. The cursors are Path elements, so this makes the cursor rotation possible. To see the effect in action, try rotating a window and then sizing: the size cursor is always perpendicular to the sizing edges.
  • Move. It also does click detection on activation - so that you can click a non-adorned object and immediately start dragging.
  • Two resize modes: center-preserving and edge-preserving (currently set via private bool property).
  • Rotate: hover outside any corner with the mouse to see the rotating adorner
  • Extension panel: allows to add additional adorner controls (e.g. "send backwards" icon on top of adorner). This is currently private, but will become properly exposed in later versions
  • The element being adorned can choose any algorithm to rotate/move itself (e.g. use TranslateTransform vs Canvas.Left and Canvas.Top). The functionality with the element being adorned is loosely coupled with the adorner through a simple IAdornedOject interface.
  • Nice glass border (from http://www.sixin.nl/antoni-dol-blog/09-11-15/Silverlight_Style_GlassBorderStyle.aspx)

Turns out, properly doing rotation, translation and all those adorner-specific things, wasn't easy for me...in fact it took me quite a bit of time! I'm glad it's done for now! :)

Here is a quick extract of the source and how to use the interfaces:

     public interface IAdornedObject
    {
        double Angle { get; set; }
        double X { get; set; }
        double Y { get; set; }
        double Width { get; set; }
        double Height { get; set; }
    }

Usage is straight-forward:

Adorner adorner = new Adorner();
AdornedObject item = new AdornedObject(testImage);
adorner.SetAdornedObject(item);
panelDisplay.Children.Add(adorner);

To avoid hassles with Thumbs moving around, the core of the move/size/rotate code is in thumb_MouseMove() - giving it nice absolute mouse coordinates!

What do you think this adorner?

  

Super Cool Silverlight Game (Not Mine) + Source

Dec 10, 2009

This is mind blowing!!

A desktop-like RPG Chinese game in Silverlight: http://silverfuture.cn/ 

It's 10.7 MB but worth the wait! It's in Chinese.

I'm sure in future versions it can be much less (e.g. Shock is 17 MB, but 680KB in order to play with the rest being downloaded as you play)

And!! The source code is here: http://code.msdn.microsoft.com/QXGameEngine

Some notable things (other than the graphics, implementation and overall coolness):

1. The map is made of PNG's sized 400x300, it is pre-drawn. The big level, looks quite nice and takes 144 PNGs. Size is 1.75MB! Not bad... This approach looks quite feasible :)

2. Effects and animation are done with separate images. You could also do it with one image and clipping regions..I think it might be faster with one image if BitmapCache is enabled

Edit: last but not least, this game is moderately light on the CPU. Even better, from the source code it doesn't seem to be using BitmapCache!!! Which is great news - it can probably be even lighter!

Overall pretty cool!!!

  

Realtime Bump Mapping in Silverlight

Dec 6, 2009

Ah yes! Bump mapping is an effect that makes "plain" textures - such as stone wall, appear bumpy under a light.

Even for a 2D game, bump mapping has a lot of uses. For example, if you're building a space shooter, it would be 10000 times cooler if lights from explosions illuminate the ship, showing it's ridged surfaces.

I've seen the effect used in games in the main menu as well, where the light of the cursor illuminated a rough surface. This is what we're doing today:

Download Source Code

Notice how the light reflects properly off the bumpy surface as you move the mouse around.

I haven't optimized the effect (just a tiny bit Embarassed), but it still runs at 1024x768, with 3 lights on 1 CPU thread. You can add more (e.g with images of lightbugs) if you'd like or take it full screen - I think it can handle it!

I found a really good old tutorial on bump mapping while digging through my files today. It's from a person named Sqrt(-1) and unfortunately I didn't find his current website to point you there.

Anyway, here's another website that shows how to do this effect: http://tfpsly.free.fr/Docs/TomHammersley/bumpmap.htm

In my implementation the effect of the lights is limited to twice their radius, which pretty much gives the same effect as if you don't limit it. This reduces the effect's complexity to O(L1+L2+...LN) where Lx is the surface area of each light.

That's why you can scale large, especially with smaller lights. 

Edit: One possible optimization is to pre-calculate the normals for each x,y - this doubles the memory size for the bitmap but saves a lot of computations!

Hope you like it! Please comment!

  

Silverlight 4 Improvements for Gaming

Nov 18, 2009

Yes! Silverlight 4 Beta is here! And it comes with quite a few improvements, mostly LOB, but there are some cool things for game developers as well!

The full list of Silverlight 4 features is here. Also check http://video.microsoftpdc.com/ - the keynote at 1:47:09, showing a cool Facebook app (1:47:56).

Here is a quick overview of some of the new features that I think will improve gaming in Silverlght 4:

Faster

Silverlight 4 has better performance than Silverlight 3. I think that says it all :) The keynote at PDC says "2 times faster".

Full Keyboard Access in Full Screen

Yes! Finally we can have a fullscreen Silverlight game have all cool controls, potions, and whatever else you may want to use the keyboard for.

This feature requires trusted application, so the user will get a security prompt when you try to activate it from within your code.

Right-Click Mouse Events

Another great feature for games that are mostly mouse controlled. For example, right-click and drag can be used to rotate the screen (like in Heroes in Might and Magic 5) or fire a missile.

Video and Sample Code: Right-click Mouse Events

Mouse Wheel Events

Good for supercharding a car engine, or just plain navigating an interface :) You could do this with some code behind in Silverlight 3, but it's much nicer now. Also you'll notice that scrolling controls like list boxes can now be scrolled with the wheel by default.

Video and Sample Code: Handling MouseWheel Events

COM Interoperability

I'm still investigating here - what COM objects are available? How to use DirectX effects, etc. For example, using DXImageTransform...

This feature requires trusted app, so your fellow gamer will get a security prompt.

Video and Sample Code: COM Object Access in Trusted Applications

Bi-directional and complext text, Right-to-left support in controls

This feature can help you make your game read better for more people, if needed.

Video and Sample Code: BiDi and Right-to-left Support

Fluid user interface support

What this means is that instead of having to do weird "hacks" in code to transition between your images (like I did in Shock's backgrounds), you can now hook up to more events that will make your life easier and your game look more "fluid" (think "cooler" :)). Those are BeforeLoaded, Loaded and Unloaded states for ItemsControl

There are many more features coming up in Silverlight 4 (http://timheuer.com/blog/archive/2009/11/18/whats-new-in-silverlight-4-complete-guide-new-features.aspx), but I believe the ones above are more important for gaming scenarios.

What is your opinion and/or favourite feature?

Please comment

 

  

Detect the CPU Core Count From Silverlight

Nov 12, 2009

If you're are writing an application that is heavy on multi-threaded computations (e.g. full screen blur, game, or scientific data processing), you will want to know how many threads to run optimally.

Edit: just fixed a bug reported where the initial assesment woult be 0 msec, thanks Morten for reporting it!

The answer is easy: run as many threads as the CPU cores. For example, on Dual Core, you should run 2 threads and on Quad Core 4 threads.

Download Source Code

This is how to find the number of cores:

  1. Create a simple computing function (e.g. that adds +1 to a number continuously) and run it with 1, 2, 4, 8, and 16 threads
  2. Measure the time it takes for the function to complete for each set of threads.

Once you hit the "core limit" of the client system, the time will significantly increase. Here's an example from my box:

  • 1 thread: 132 msec
  • 2 threads: 111 msec
  • 4 threads: 140 msec
  • 8 threads: 822 msec

If you look at the above data, you can easily tell I'm running on a quad-core system, because jumping from 4 to 8 threads significanly increases the computational time needed (more than 1.8 times).

This is how to use the source code:

int coreCount = PerformanceMeasure.GetCoreCount();

You can call the above function from the UI thread.

There are also two tweaks in the code that allows it to run roughly at the same speed on all machines and run faster on single-core machines too:

  • Once the core limit is hit, the algorithm stops. E.g. if you find that 4 threads take more than 1.8x the time as compared to 2 threads, this means you have 2 cores and there is no need to test with 8 threads
  • Before the main algorithm (above) starts, there is an estimation step, which calculates how many operations can be executed for 100 msec on 1 thread. This ensures that the assesment will run fast even on slow machines.

Please comment! I would be interesting to know how well the algorithm works and if it detected your cores as you expected!

  

Best Way To Clear WriteableBitmap?

Nov 11, 2009

If you're doing a lot of custom drawing using WriteableBitmap (e.g. full screen game), it will be extremely important to be able to clear the WriteableBitmap or "screen" quickly.

Lets assume you want to clear the screen to specific color.

What is the best way to do it?

Here is a short comparison of few methods to clear a 512x512 bitmap:

  • Clear with for loop: 1000 FPS
  • Clear with Array.Copy: 4100 FPS
  • Clear with Array.Clear: 11000 FPS

1. Clear with for() loop. This method is the most straight-forward, and also the slowest:

public static void ClearForLoop(int[] pixels, int len, int color)
{
    for (int i = 0; i < len; i++)
    {
        pixels[i] = color;
    }
}

2. Clear by using Array.Copy. This method is not only fast, but it also allows to "clear" to an image (not just color), which is great if you have a pre-defined background or something like that.

public static void ClearArrayCopy(int[] pixels, int[] clearTo, int len)
{
    Array.Copy(clearTo, 0, pixels, 0, len);
}

This method assumes that you have already pre-initialized the "clear" bitmap (just do it once! :) with the color/image:

// note: do this ONCE!, NOT on every frame! obvious, but worth mentioning just in case

int[] clearScreen = new int[pixels.Length];

for (int i = 0; i < pixels.Length; i++)
{
    clearScreen[i] = color;
}

3. Clear with Array.Clear: the fastest way, but unfortunately allows you to clear to 0 only (meaning transparent image).

Array.Clear(pixels, 0, pixels.Length);

Depending on the application you'd either choose Array.CopyTo(), since it's the most versatile or Array.Clear(). You may also choose Array.CopyTo() over Array.Clear() because Array.CopyTo() is easily multithreaded, and can take advantage of multiple cores, while Array.Clear() currently runs on a single thread/core.

Note that all measurements assume single-core used. If you have multiple-core system you can improve the speed quite a bit by running those multithreaded.

  

nokola.com | Terms | Log in

Recent

About the author

Happy & enjoying life. Software enthusiast.
The opinions I express here and on nokola.com are mine and not my employeer's (Microsoft).
This is the official blog of nokola.com. You can find Silverlight samples, coding stuff, and hopefully other interesting things here.