NLarge v1.1.2 (once more, with feeling, multimon and text annotation support)
Barry‘s teaching a course this week and noticed that NLarge didn’t support multimon – or rather, it always zoomed in on the primary monitor. So NLarge got another update. Good thing I don’t sleep!
Changelist:
- Added Multimonitor support – zooms in on the monitor currently containing the mouse pointer.
- Added Text support – annotate zoomed-in images with text by using the ‘T’ key
[Update 5 Apr:]
- v1.1.3 – Fixed a bug in the multimonitor support that caused strange behavior after Hibernate/Restore
Download the update here on Codeplex.
NLarge v1.1.1 (once more, with feeling)
I immediately wanted to update NLarge again because its new default hotkeys (Ctrl-1 for Zoom, Ctrl-2 to Draw, Ctrl-3 for Break Timer) conflict with Outlook 2007′s hotkeys for Inbox, Calendar, and Contacts.
Changelist:
- Added ability to select your own hotkeys for zoom, draw and countdown timer.
- Added ability to Alt-Tab away from break timer, and Alt-Tab back
- Added ability to press ‘w’ while zoomed in to clear canvas for drawing.
- Added a little opacity fade before and after zooms to remove glitching (and for effect).
- Automatic smoothing of lines sketched on the canvas.
NLarge screen magnifier v1.1
NLarge is the screen magnification and annotation utility that I use for technical presentations. It magnifies the screen through a smooth animation, and allows you to pan and zoom around the magnified screen. You can annotate the magnified image using the mouse or a Tablet PC pen.
Today I added a few features to NLarge to respond to feature requests, and released version 1.1.
Here are the updated features:
- Removed glitching from start of zoom (hooray!)
- Added ability to change drawing pen colour and width
- Added a countdown timer
- Changed hotkeys from using Alt to Control to avoid conflict with Office 2007 default hotkeys
- Moved settings from the registry to a Settings file
- Updated solution to Visual Studio 2008 (leaving target .NET framework at 3.0)
NLarge is available for download from CodePlex. The code is all available there as well.
I noticed that since I last updated NLarge, its inspiration, ZoomIt, has been updated to provide a smoother zoom-in animation. However, ZoomIt still lacks NLarge’s smooth zoom-out animations, which is a shame, because I find the snap-out jarring and potentially disruptive. I believe NLarge adds to the professionalism of my presentations by not potentially losing the context of what I’m presenting before or after I draw the audience’s attention to something via a zoom.
If ZoomIt could just zoom smoothly in and out, I’d retire NLarge, but for now, I hope you enjoy v1.1.
Continue ReadingSilverlight 2 Greasepole Game Engine
If you’re authoring multimedia applications in Silverlight, you might be interested in how each of the core game engine services for Legend of the Greasepole is now implemented for the Silverlight 2 Beta.
From C/C++ to a Provider Model-Based .NET Engine
Some brief history to explain how we got here: Greasepole’s first incarnation was manky C/C++ stuff that I’d perf-optimized to bits back in 1997-98. Trainwreck stuff.
Migrating that C/C++ mess to a C# mess involved writing a lot of Visual Studio 2008 macros. These macros could gain surprising insight into non-compiling half-C++, half-C# code, in order to sweep through and perform laborious changes.
What came out the other end of the refactor was a C# core engine for the game that required the implementation of five platform-specific services:
- RenderingService,
- SoundService,
- InputService,
- GameTimerService, and
- GameSettingsService.
I previously implemented those services for the XNA version. Now let’s look at the Silverlight versions of these services.
Silverlight RenderingService
When each frame is rendered, the engine ultimately requests that the RenderingService draws a series of sprites from particular “frame descriptions” or “FrameDesc”s (a vestigial name, essentially meaning bitmaps with metadata) at given (x,y) coordinates:
public void DrawBitmap(TSprite associatedSprite, FrameDesc frameDesc, int nScrx, int nScry, byte[] replaceRGB, byte[] substituteRGB)
The bitmaps themselves are stored as Resources in two assemblies (SilverLegendAssetsMenu.dll and SilverLegendAssetsGame.dll) that I download on-demand using WebClient. This has the advantage of dramatically reducing startup time, and only requiring the game engine to manage the downloading of two files over the web after startup. An equivalent option would have been downloading archives full of bitmaps, but I was concerned that this would require decompressing the bitmaps at runtime.
The RenderingService pre-caches the URIs for the bitmap associated with each FrameDesc (e.g. “SilverLegendAssetsGame;component/Graphics/Frosh4a.BMP”) so that the bitmap can be looked up without string manipulation whenever it is requested by a sprite.
Each game sprite is assigned its own System.Windows.Control.Image by the RenderService, which is initialized by having its UriSource Property set to a System.Windows.Media.Imaging.BitmapImage. When the FrameDesc for the sprite changes (and therefore the sprite’s bitmap appearance has changed), the Source Property of the BitmapImage, a URI, is changed to the appropriate cached Uri. (It looks as though you’re not permitted to re-use BitmapImage instances across multiple Images.)
Mirrored images are achieved by setting a MatrixTransform on the sprite’s Image’s RenderTransform.
Z-Ordering is performed by using the ZOrder property on the Images.
After each frame is rendered, the RenderingService iterates through all the Images on the Canvas, looking for any that weren’t rendered during that frame and therefore should be removed from the Canvas.
But what’s with the byte[] replaceRGB, byte[] substituteRGB parameters on the DrawBitmap call? In all the other versions of Greasepole, the characters became multicultural by performing color-key swapping of their solid skintones. The DirectX engine used two BitBlts, and the XNA engine uses custom shaders. Achieving this in real-time with Silverlight 2 is something I haven’t yet figured out.
Silverlight SoundService
Sounds assets are stored as MP3 Resources in the previously-mentioned download-on-demand assemblies SilverLegendAssetsMenu.dll and SilverLegendAssetsGame.dll.
Just as with with RenderService, the SoundService pre-caches the URIs to all the sound files.
The SoundService keeps a static collection of MediaElements around. These are added as children to an invisible Canvas called SoundCanvas. When the engine requests that a sound is played, the SoundService finds an unused MediaElement in the static collection, sets its Source Property to the correct URI, and Play()s it.
The MediaElement’s MediaEnded event is handled to either loop the sound by either (1) setting .Position=TimeSpan.Zero and calling Play() again, or, (2) if it’s not looping, to add the MediaElement back to the static collection of available Media Elements.
Incidentally, this whole MediaElement juggling trick was a highly unstable process in the Silverlight 2 Alpha which seems to work reliably in the beta.
Silverlight InputService
In the Silverlight 2 Beta, handling input was a piece of cake. Mouse and Keyboard events are handled for events on the main Canvas to inform the InputService of human interaction.
Unfortunately for game developers, keyboard input is more or less crippled when Silverlight is in fullscreen mode. Luckily, we’d designed Greasepole to be playable with just one mouse button.
I also wish I could use the right mouse button for input, but instead it brings up the Silverlight Configuration menu.
Silverlight GameTimerService
To create a game loop, Greasepole uses the “empty Storyboard technique” outlined at Silverlight Games 101. The game loop calls Update enough time to ensure a constant 24 updates-per-second update rate, and Render whenever possible, which triggers the RenderingService (see above).
In every other respect, the game timer is the exact same as in the XNA version. DateTime.Now works as advertised! Here’s to a common set of .NET Framework classes!
Silverlight GameSettingsService
The IsolatedStorageFile API makes it very easy to rapidly save and load game settings in a local sandbox.
See this sample for more information on how to use the virtual file system in Silverlight. The GameSettingsService uses a very similar technique.
Continue Reading