Fluid Morphing for 2D Animations

In June 2014 I defended my Master’s Thesis: Fluid Morphing for 2D Animations. The thesis includes a C++ library and demo programs that allow arbitrary *.PNG images to be morphed in a fluid and fully automated fashion. The paper can be accessed here:

For the original demo of the library I used Allegro 5 and thus I believe I have good reasons to create this topic here. What is more, on page 16 of the original paper I refer to the allegro.cc forums. The thesis is primarily dedicated to game developers and thus I believe these forums suit well for such an announcement.

You can download the source code here:

I also suggest checking out my blog entry: http://www.hyena.net.ee/?p=199

Development footage featuring Allegro 5 is below:


Some notable results produced with the atomorph library:
Other images are here: http://atomorph.org/img/

Arthur Kalliokoski

Very impressive! Can images be morphed in real time?


Real time morphing is possible and all the development footage is actually real time!


That was an interesting read :D

If I have the time, I'm definitely going to play with this.

Neil Roy

Very nicely done.

Edgar Reynaldo

You've got some pretty great results here! :)

I downloaded your pdf and src. I will be sure to read them over later. :)


Wow, this looks great. Is it all MIT licensed? I'll probably try to port it to C so I can use it in my own game engine.. :)

Chris Katko

Oh, my gosh. This is absolutely amazing.

This may or may not go perfectly with my previous goal of creating a 2-D in 3-D sprite engine. Basically, skeletal animation for 2-D linkages plus "doom style" billboard sprites (for each "limb" piece) that change for given camera angles. "Morphing" could provide intermediate stages to reduce source sprite development time and provide un-intuitive merges.

The goal would be fluid isometric skeletal animation, ala Crusader: No Remorse with unlimited sprites.


Here's a preliminary question: Is it possible to "morph" to an intermediate stage between 3 (or more) different pictures?

Lastly: How did you get approved to do a Master's thesis on 2-D sprites?

Edgar Reynaldo

I would love to build this, but MinGW 4.8.1 doesn't support std::thread yet, even though the <thread> header is there. Or else I'm doing something wrong trying to compile it.

I can't even get this :

#include <thread>

int main(int argc , char** argv) {

   std::thread t;

   return 0;

to compile, even with -std=c++11 or -std=gnu++11. It says 'thread is not a member of namespace std'.

Couldn't you just use pthreads, instead of trying to support experimental features?

Chris Katko

Hyena_: Hey, did you ever file that std::modf bug with GNU?

Couldn't you just use pthreads, instead of trying to support experimental features?

Or, you know, use a development platform that includes support for modern features. Perhaps you should update MinGW?


Reminds me of Kai's power tools photo morpher that was all the rage back in the mid-late 90's.


Or else I'm doing something wrong trying to compile it.

You might be, this compiles fine for me with MinGW.
On my compiler, g++ -v outputs:

1Using built-in specs. 2COLLECT_GCC=g++ 3Target: i686-w64-mingw32 4Configured with: ../../../src/gcc-4.8.0/configure --host=i686-w64-mingw32 --buil 5d=i686-w64-mingw32 --target=i686-w64-mingw32 --prefix=/mingw32 --with-sysroot=/t 6emp/x32-480-posix-dwarf-r2/mingw32 --enable-shared --enable-static --disable-mul 7tilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes --enable- 8threads=posix --enable-libgomp --enable-lto --enable-graphite --enable-checking= 9release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --d 10isable-sjlj-exceptions --with-dwarf2 --disable-isl-version-check --disable-cloog 11-version-check --disable-libstdcxx-pch --disable-libstdcxx-debug --disable-boots 12trap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --d 13isable-symvers --with-gnu-as --with-gnu-ld --with-arch=i686 --with-tune=generic 14--with-host-libstdcxx='-static -lstdc++' --with-libiconv --with-system-zlib --wi 15th-gmp=/temp/mingw-prereq/i686-w64-mingw32-static --with-mpfr=/temp/mingw-prereq 16/i686-w64-mingw32-static --with-mpc=/temp/mingw-prereq/i686-w64-mingw32-static - 17-with-isl=/temp/mingw-prereq/i686-w64-mingw32-static --with-cloog=/temp/mingw-pr 18ereq/i686-w64-mingw32-static --enable-cloog-backend=isl --with-pkgversion='rev2, 19 Built by MinGW-builds project' --with-bugurl=http://sourceforge.net/projects/mi 20ngwbuilds/ CFLAGS='-O2 -pipe -I/temp/x32-480-posix-dwarf-r2/libs/include -I/temp 21/mingw-prereq/x32-zlib/include -I/temp/mingw-prereq/i686-w64-mingw32-static/incl 22ude' CXXFLAGS='-O2 -pipe -I/temp/x32-480-posix-dwarf-r2/libs/include -I/temp/min 23gw-prereq/x32-zlib/include -I/temp/mingw-prereq/i686-w64-mingw32-static/include' 24 CPPFLAGS= LDFLAGS='-pipe -L/temp/x32-480-posix-dwarf-r2/libs/lib -L/temp/mingw- 25prereq/x32-zlib/lib -L/temp/mingw-prereq/i686-w64-mingw32-static/lib -L/temp/x32 26-480-posix-dwarf-r2/mingw32/opt/lib' 27Thread model: posix 28gcc version 4.8.0 (rev2, Built by MinGW-builds project)

Specifically of interest is "enable-threads=posix", maybe your binary is built without threading support?


I might not have enough personal motivation to continue the development, thus I decided to at least deliver the proof of concept for the interested parties to see as an inspiration. The atom cloud morphing is a really simple concept and could just be implemented application-specifically. Many game developers prefer to build their own sprite engine for example. Atom cloud morphing should be seen as a potential side aspect of that engine instead of a separate library.

I've never been part of any open source project development and I'm mostly a solo programmer. However, should the atomorph library spark interest in some veteran open-source developers I'd be happy to cooperate. For that purpose I have registered the domain names atomorph.org and atomorph.com.

Answering all the questions made so far.

Is it all MIT licensed?
All of the code I personally have written is MIT but you might want to check out Appendix D (it originates from http://svn.lam.fr/repos/glnemo2/trunk/).

Is it possible to "morph" to an intermediate stage between 3 (or more) different pictures?
If I understand correctly then you mean taking a weighted average of multiple pictures. Please see page 68 (N-way fluid morphing). I believe what you are asking for is easily possible but requires a custom implementation of the atom cloud morphing procedure.

How did you get approved to do a Master's thesis on 2-D sprites?
I told my idea to the director of my study programme and he allowed me to do such a thesis. In retrospect I can say that the thesis turned out to have strong connections with typical data mining tasks. Data mining was a mandatory part of the software engineering programme. In my institute they value it greatly if the student has their own research ideas for the thesis. My bachelor's thesis was about random world generation for example (http://www.hyena.net.ee/?p=127).

Couldn't you just use pthreads, instead of trying to support experimental features?
I believe it's time to get used to C++11. For a full-blown library it might not be the best idea just yet but for a proof of concept library it can be justified.

Hyena_: Hey, did you ever file that std::modf bug with GNU?
No I did not :P it's hard to believe that they don't know about it. I suspect they would answer "it's not a bug, it's a feature" because that's how double arithmetic works --- sometimes 1.0 turns into 0.(999)?

Chris Katko

One more thing. You said it runs on real-time, which is GREAT!

Did you try a load test to see at what point it became slow? 10, 100, 1000 sprites, etc?

And on what hardware did you test this on?

Edgar Reynaldo

My gcc -v says "... --enable-threads ..." but there's no "=posix" there. Apparently plain mingw doesnt' support threads but mingw-64 does. :P

Plain MinGW cannot support std::thread. You will need to use a MinGW-w64 toolchain (such as those shipped with Qt 5) that has "posix" threading enabled, so that libstdc++ exposes the <thread>, <mutex> and <future> functionality.

You can find an installer here, but you can also try just replacing the whole mingw toolchain root folder with one of these packages. You can choose 32- or 64-bit, remember to select threads-posix if you want to play with std::thread and friends. No special compiler options other than the ones you already have are needed. I do suggest using -std=c++11 if you don't need GCC 4.6 compatibility.

That's a real pita. I just upgraded to 4.8.1 not that long ago for C++11 support and it turns out it doesn't actually have full support. :P And only MSVC 2010 is supported on Vista so I can't use MSVC either. What was MinGW thinking, not supporting something like std::thread?


You simply have to switch to a mingw-64 toolchain, no need for it to be a 64-bit one thou.

Plain Mingw is outdated and behind.

Edgar Reynaldo

Well I have MSYS2 and mingw-w64 installed, and it successfully built the library and atomorph.exe. I'll try them out later.

Chris Katko

Personally, I do all my development in a Linux VM inside Windows 7. I didn't use to, but I love it now.


Chris Katko: I have not load tested it.

Once you have computed a morph of satisfactory quality you can stop seeking for better morphs and just use the one you have found. It will no longer consume processing power. However, if you also enable fluid simulation then it gets pretty slow.

I strongly suggest using a Linux environment for testing out the library because I have included a whole lot of automated tests as shell scripts. These tests make up a pretty good example set of how to use AtoMorph.

For example, a "rotating" green star is produced with the following script:

1#!/bin/bash 2# ImageMagick is needed for these tests to run properly. 3 4cd output 5 6# TEST 1: Rotation 7# Intuitively, this test should generate a 8# perfectly rotating star. However, instead 9# it generates interestingly anomalous yet 10# smooth rotation. 11TITLE="rotation" 12../../atomorph -f test_${TITLE} -i ../data --blobs-as-texture shape_1.png shape_2.png shape_3.png shape_4.png shape_5.png shape_6.png -F 48 --verbose -t 255 -M 1 -O 10 -D 2 13convert -channel A -threshold 99% -delay 10 -loop 0 -dispose background test_${TITLE}_*.png test_${TITLE}.gif 14montage test_${TITLE}_*.png -tile 8x6 -geometry 64x64+1+1 -frame 3 -background white -bordercolor white montage_${TITLE}.png 15rm test_${TITLE}_*.png 16convert montage_${TITLE}.png -background white -flatten montage_${TITLE}.jpg 17rm montage_${TITLE}.png


Thread #614535. Printed from Allegro.cc