Archive for February 2012

 
 

Picture Round 2/20/12

Lockspot trivia picture round, on President’s Day so also a president.
PDF
Answers

Raster-to-Vector plus not bitching about significant whitespace

So this weekend I learned Python and implemented a basic raster to vector converter in it. It converts whatever file formats the Python PIL module supports to SVG.

Here’s the little guys from Joust embedded as SVG (This probably doesn’t work on Internet Explorer, but if you’re using IE you have bigger problems, brother)

and here’s the fruits from Pac-Man: (My favorite is the Galaxian fruit)

Specifically I implemented classical contour extraction as described in the 1985 paper “Topological Structural Analysis of Digitized Binary Images by Border Following”, which is the algorithm that OpenCV’s cvFindContours uses, modified such that it supports color images rather than black-and-white bitmaps. (This is something that I may eventually have to do at work for real, i.e. in C++, so I thought it would be a good way to learn Python and make sure my modified algorithm was actually going to work — it’s not a trivial change because color images allow two contours to be adjacent which can’t happen in a bit map image)

Here’s the code. Usage is like:

python Sprite2Svg.py “c:\work\fruits.png” “c:\work\fruits.svg” 4 “#000000”

where the last two arguments are optional. The 3rd argument is a scale factor in pixels. The 4th argument is a background color that will be removed from the output. I think there’s a bug right now in which the code doesn’t support paletted images; trivial to fix, but I wanted to fix it in some general way and then forgot about it.

Anyway, things I like about Python:

  • Significant whitespace turns out to not be annoying. (Who knew?)
  • Coroutines!… about twenty years ago I was in a class in which I had to write a compiler in a language called CLU. All I remember about CLU is that (a) I once apparently wrote a compiler in it and (b) Coroutines! — well it had the generator/yield construct, anyway. I wish C++ had generator/yield
  • It isn’t Perl. Can’t stress this one enough.

Things I don’t like about Python:

  • The thing with version 3 being better but nobody using it.
  • The issue I’m talking about here is annoying and I think the “nonlocal” declaration isn’t the best solution in the world.

Picture Round – 2/13/12

Our Lockspot picture round before Valentine’s Day … so famous couples.
PDF
Answers

Playing simultaneous sounds in Win32

There is a nice unscary Win32 API call for playing sounds that is unpretentiously called “PlaySound”. It is extremely easy to use. Unfortunately, PlaySound(…) has one problem that makes it unsuitable for even casual game development: although it will play audio asynchronously, it will not play two sounds simultaneously. Depending on what you are doing this may not be a big deal, e.g. warning beeps in an editor app and such, but for anything that is media rich it basically means that you can’t use PlaySound.

This leaves you with several options:

  1. Use a third party library.
  2. Use the new Windows Audio Session API which came in with Vista.
  3. Use the (legacy) low-level Win32 MCI routines.
  4. Use the (legacy) low-level Win32 waveOut interface

So if you have serious audio needs The Right Thing is 1. or 2. above.

A little background on what I’m doing: I’m working on a Win32 C++ implementation of a puzzle game that I am eventually going to directly port to iOS. I don’t really need serious audio as I just want something that is playable for game design debugging, i.e. balancing. I do want simultaneous sound effects though because I plan on releasing this Win32 prototype to gather feedback and I think sound effects add playability in this case.

Anyway, I looked into 1. and 2. On 1., I couldn’t find a library that was dirt simple enough to justify its use in my project given all I am really looking for is a drop-in replacement for PlaySound that supports asynchronous simultaneous audio. On 2., well, the API is dense; I’m not looking for a research project and I couldn’t find a lot of sample code — maybe, it’s too new? or maybe I wasn’t looking in the right places.

On 3., if you don’t know what I’m talking about, I’m talking about this function and friends. I remember using the MCI (multimedia command interface, I believe) routines back in the day, probably around 1997, and they are pretty easy to use. It’s a weird little API relative to the rest of win32. You send command strings to a device object that look like “LOAD ‘foo.wav’ as Foo” and so forth, and I think that they will do simultaneous audio output. The problem is the MCI routines don’t let you play sounds from memory and I want to play from WAVE resources that are embedded into the executable. To use MCI I would have to write my resources to a temp directory at start up and then play the serialized files. This seemed too ugly.

Which leaves 4. The problem with 4. is that waveOut et. al. are like the opposite of PlaySound: super low-level and absolutely un-user friendly. Fortunately there is a lot of code out there. In particular I found CWaveBox on CodeProject by a CodeProject user named Zenith__ that does basically what I need. I had lots of problems with this code, however, and ended up significantly re-working some code that was itself a re-work of the original CWaveBox that is posted in the CodeProject comments. I basically chose to work with the comments version because it executed the demo app as well as the original, but it was much shorter.

The code I started with is verbose, baroque, and in C rather than C++. I re-factored it in the following ways:

  • Added the ability to load WAV’s from resources
  • Replaced two C-style arrays: one with a std::vector and the other with an std::map
  • Cleaned up the .h file by making things that should be private private and moving as many implementation details into the .cpp file as I could
  • Simplified some of the thread synchronization stuff by using WaitSingleObject instead of looping and polling
  • Got rid of all C-isms i.e. mallocs, callocs, memsets, memcpys, etc. Replaced with C++-style allocation, std::copy, std::fill, etc.
  • Got rid of magic constants by noticing many of them served as booleans, so replaced them with booleans
  • Changed names of crazily named variables and functions
  • Generally got rid of craziness … we’re talking goto’s.

I honestly don’t understand the code involved, which is weird given the amount of work I did on it. I mean, I get that there’s a thread that’s running and that it is playing chunks of waves in a loop, etc. That’s the level at which I understand it … kind of reminds me of this time I was working a DARPA contract and ported a function for converting from Military Grid Reference Numbers to longitude and latitude from Fortran to C without actually understanding the algorithm or knowing Fortran…

My code is here. Usage goes likes this:

#include "WaveManager.h"
#include "resource.h"
// ...
{
   WaveManager wave_mgr( kNumSimultaneousWaves );
   
   wave_mgr.LoadFromResource(ID_SND_BUZZ, MAKEINTRESOURCE(ID_SND_BUZZ));
   wave_mgr.LoadFromResource(ID_SND_CLICK, MAKEINTRESOURCE(ID_SND_CLICK));

   // ...
   wave_mgr.Play(ID_SND_BUZZ);
   // ...
   // etc.
}

It actually works remarkably well.

However, the code still needs work if anyone is interested. There are a lot of functions returning error codes that are never checked. I think most of these should be changed to return void and should just throw if something serious happens. Also I think in the original implementation there could have been a race condition if you tried to load a wave after the playing thread was running. I wrapped the loading stuff in the critical section the playing thread uses, but this still might be a problem — I’m not sure. If you use this code it is safest to load all your sound assets at start up before you start playing anything. But in terms of fixing it up more, I think the main thing is that someone who actually knows what they are doing vis-à-vis wave output could probably cut the verbosity in half or so.

Oh, and one more note on my work, I used some C++11 stuff in there … basically I implemented loading from memory by taking the guts of the existing LoadFromFile implementation and making it into a function template that takes a handle type as the template parameter and has an additional formal parameter that is an std::function used for loading data. In the LoadFromFile case I instantiate the template with a file HANDLE as the template parameter and pass the function the Win32 call ReadFile wrapped thinly in a lambda. In the load from resource case, the template parameter is a custom buffer struct and the functor argument becomes, basically, a lambda wrapper around std::copy. But, anyway, just a heads up that this code will only compile under Visual Studio 2010 because of the lambdas. If you’re interested in using it but don’t do lambdas, it would be pretty easy to replace them with regular function pointers.

Picture Round – 2/7/2012

Here’s the picture round from our pub trivia at Lockspot last night.
PDF
Answers

Blitting with per-pixel alpha in Win32

I don’t know how long the Win32 API has included an AlphaBlend() function. I mean, it came in whenever Msimg32.lib did but I’m not sure when that was, probably Windows XP era, I guess.

It’s always been a pain in the ass to use; easy to use global alpha but per-pixel is a chore. You see a lot of people asking how to use this call at StackOverflow and other sites but basically never see a comprehensive reply. Generally the replies are variants of “It’s easy … you just need to pre-multiply the alpha”, which is true but unhelpful for two reasons: (1) doing so is a pain in the ass i.e. show me some code, buddy, and more importantly (2) in order to burn the alpha values into the RGB you need to actually have image data that contains an alpha channel but Win32 only natively supports loading BMP’s which generally don’t.

So on (2), for completeness, I should say I think that it is possible to get Photoshop to spit out a BMP file with alpha information. I haven’t tried it but the advanced options when saving a BMP have an option for the format “a8 r8 g8 b8”; I always see it grayed out but am guessing that it’s possible to do this somehow. Also I think that you can load PNG’s using GDI+ — I know next to nothing about GDI+ but if that’s what you use I’m not sure the solution I propose below is worth it just to get out of having to write the pre-multiply function yourself.

However, the above aside, if you want alpha-blended images in your application, you want to use PNG files and if you are writing to Win32 you need the use a 3rd-party library. The two 3rd party graphics libraries that people commonly use in Windows applications for things like loading PNG’s and JPEG’s are DevIL and FreeImage. I have no experience with DevIL and, frankly, it looks orphaned to me. What I suggest for blitting with semi-transparency in Win32 is using FreeImage, which seems tailor-made for doing this.

So below is an implementation on top of FreeImage demonstrating

  • Loading PNG’s (and other formats) as FreeImage data structures from Win32 resources.
  • Converting from FreeImage to HBITMAPs with alpha burned in.
  • Blitting the HBITMAPs with per-pixel alpha.

Here’s the code I use for loading a PNG from a resource to FreeImage’s data structures. FimgUtil::MemPtr and FimgUtil::Ptr are defined as

boost::shared_ptr<FIMEMORY>
boost::shared_ptr<FIBITMAP>

That is, I’m using smart pointers with custom deleters to call the appropiate FreeImage clean-up code on destruction. If this isn’t your style the following code can easily be modified to use raw pointers.

namespace {
    bool GetResourceData(const char* name, BYTE*& ptr, unsigned long& size) {
	    HRSRC hrsrc = FindResource(NULL, name, RT_RCDATA);
	    if (hrsrc == NULL) {
	        return false;
	    }
	    HGLOBAL handle = LoadResource(NULL, hrsrc);
	    if (handle == NULL) {
	        return false;
	    }
	    ptr = static_cast<BYTE*>(LockResource(handle));
	    size = SizeofResource(NULL, hrsrc);
	    return true;
    }
}

FimgUtil::MemPtr FimgUtil::GetMemoryPtr(FIMEMORY* fimem) {
    return FimgUtil::MemPtr(fimem, FreeImage_CloseMemory);
}

FimgUtil::Ptr FimgUtil::GetBitmapPtr(FIBITMAP* fibmp) {
    return FimgUtil::Ptr(fibmp, FreeImage_Unload);
}

FimgUtil::Ptr FimgUtil::LoadFiBitmapFromResource(const char* rsrc_name, FREE_IMAGE_FORMAT format) {
    BYTE* data;
    unsigned long size = 0;
    if (! GetResourceData(rsrc_name, data, size)) {
        return FimgUtil::Ptr ();
    }
    FimgUtil::MemPtr  buff = GetMemoryPtr(FreeImage_OpenMemory(data, size));
    if (buff.get() == 0) {
        return FimgUtil::Ptr ();
    }
    if (format == FIF_UNKNOWN) {
        format = FreeImage_GetFileTypeFromMemory(buff.get(), 0);
        if (format == FIF_UNKNOWN) {
            return FimgUtil::Ptr ();
        }
    }
    return GetBitmapPtr(
        FreeImage_LoadFromMemory(format, buff.get(), 0)
    );
}

To convert from an FIBITMAP* to a an HBITMAP and rolled together with the above:

HBITMAP FimgUtil::FiBitmapToWin32Bitmap(const FimgUtil::Ptr & src_ptr, bool premultiply_alpha) {
    if (premultiply_alpha) {
        FreeImage_PreMultiplyWithAlpha( src_ptr.get() );
    }
    HDC hdc_scr = GetDC(NULL);
    FIBITMAP* src = src_ptr.get();
    HBITMAP hbm = CreateDIBitmap( hdc_scr, FreeImage_GetInfoHeader(src),
        CBM_INIT, FreeImage_GetBits(src), 
        FreeImage_GetInfo(src), 
        DIB_RGB_COLORS);
    ReleaseDC(NULL, hdc_scr);
    return hbm;
}

HBITMAP FimgUtil::LoadPngResource( const char* rsrc_name, bool premultiply_alpha) {
    FimgUtil::Ptr fibmp = LoadFiBitmapFromResource( rsrc_name, FIF_PNG ); 
    return FiBitmapToWin32Bitmap( fibmp, premultiply_alpha);
}

and a wrapper for blitting:

void FimgUtil::BlitWithAlpha( HDC dst, int dst_x, int dst_y, int wd, int hgt, HDC src, int src_x, int src_y, float alpha ) {
    BLENDFUNCTION bf;

    ZeroMemory( &bf, sizeof(BLENDFUNCTION) );
    bf.BlendOp = AC_SRC_OVER;
    bf.BlendFlags = 0;
    bf.AlphaFormat = AC_SRC_ALPHA;
    bf.SourceConstantAlpha = static_cast<BYTE>( 255 * alpha );

    AlphaBlend( dst, dst_x, dst_y, wd, hgt, src, src_x, src_y, wd, hgt, bf);
}

Source for my FreeImage utility functions is here.