Seamless Tiles

Actionscript:
  1. [SWF(width=600, height=500, backgroundColor=0xFFFFFF, frameRate=30)]
  2.  
  3. function seamlessTile(img:BitmapData, featherSize:Number = 5):BitmapData{
  4.     var pnt:Point = new Point(0,0);
  5.     var tile:BitmapData = new BitmapData(img.width, img.height, true, 0xFF000000);
  6.     tile.copyPixels(img, img.rect, pnt, null, null, true);
  7.    
  8.     var flipped:BitmapData = new BitmapData(img.width, img.height, true, 0xFF000000);
  9.     var m:Matrix = new Matrix();
  10.     m.scale(-1, 1);
  11.     m.translate(tile.width,0);
  12.     flipped.draw(tile, m);
  13.    
  14.     var aChannel:BitmapData = new BitmapData(img.width, img.height, true, 0x00000000);
  15.     var grad:Sprite = new Sprite();
  16.     m.createGradientBox(img.width, img.height, 0, 0, 0);
  17.    
  18.     grad.graphics.beginGradientFill(GradientType.LINEAR, [0xFFFFFF, 0xFFFFFF],  [1, 0], [0, (255 / img.width) * img.width / featherSize], m, SpreadMethod.PAD);
  19.    
  20.     grad.graphics.drawRect(0,0,img.width, img.height);
  21.     aChannel.draw(grad);
  22.  
  23.     tile.copyPixels(flipped, flipped.rect, pnt, aChannel, pnt, true);
  24.    
  25.     m.identity();
  26.     m.scale(1, -1);
  27.     m.translate(0,tile.height);
  28.     flipped.draw(tile, m)
  29.    
  30.     aChannel.fillRect(aChannel.rect, 0x00000000);
  31.     m.createGradientBox(img.width, img.height, Math.PI / 2, 0, 0);
  32.     grad.graphics.clear();
  33.     grad.graphics.beginGradientFill(GradientType.LINEAR, [0xFFFFFF, 0xFFFFFF], [1, 0], [0, (255 / img.height) * img.height / featherSize],  m, SpreadMethod.PAD);
  34.    
  35.     grad.graphics.drawRect(0,0,img.width, img.height);
  36.     aChannel.draw(grad, grad.transform.matrix);
  37.    
  38.     tile.copyPixels(flipped, flipped.rect, pnt, aChannel, pnt, true);
  39.     return tile;
  40. }
  41.  
  42. // test out the function:
  43. var canvas:BitmapData = new BitmapData(600, 470, true, 0xFF000000);
  44. addChild(new Bitmap(canvas));
  45.  
  46. var image:Loader = new Loader();
  47. image.load(new URLRequest("http://actionsnippet.com/imgs/paper.jpg"));
  48. image.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaded);
  49. var texture:BitmapData;
  50.  
  51. function onLoaded(evt:Event):void {
  52.     texture =  Bitmap(image.content).bitmapData;
  53.     addEventListener(Event.ENTER_FRAME, onLoop);
  54.     image.removeEventListener(Event.COMPLETE, onLoaded);
  55. }
  56.  
  57. function onLoop(evt:Event):void{
  58.     var tile:BitmapData = seamlessTile(texture, Math.max(1,mouseX/30));
  59.     var p:Point = new Point();
  60.     for (var i:int = 0; i<8; i++){
  61.         p.x = (i % 4) * tile.width;
  62.         p.y = int(i / 4) * tile.height;
  63.         canvas.copyPixels(tile, tile.rect, p);
  64.     }
  65. }

The above demos a function called seamlessTile() which takes a BitmapData object and uses an oldschool seamless tile technique on it.

The result is that you can have an image that would normally tile like this:


end up looking like this:



You can take a look at the swf here.

I learned how seamless tiles worked by observing the KPT seamless welder filter while I was in highschool. I wish I could dig up all that old KPT stuff again....

There are better seamless tile algorithms out there.... this one is very primitive, but it will work nicely if used properly. Could work well with a composite texture in Papervision 3D for instance...

This entry was posted in BitmapData, graphics algorithms, pixel manipulation and tagged , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

4 Comments

  1. Posted January 26, 2009 at 12:08 pm | Permalink

    This may actually come in handy on a project I’m going to be starting soon. What kind of performance hit is it to run this continually on an enter frame? or just what kind of performance does this get in general?

  2. Posted January 26, 2009 at 12:27 pm | Permalink

    Well… it could be modified slightly to get better performance. Currently I wrote it to run once to create a tiled texture for use with background or PV3D textures. Despite that, on an enterframe it gets nice performance. You could speed up performance significantly however by doing the following:

    First off, wrap it in a class, not for performance, but for organizational purposes. Next, don’t do any object creation on the enterframe….. initialize all BitmapData objects, Points, Sprites, Matrix instances etc… in your constructor - or a method that gets run in your constructor. Object instantiation is expensive so avoiding it on a loop will help.

    copypixels() is real fast, and drawing gradients is rather fast so doing the above will help the most I think. The only other optimization I can think of is to have 3 separate precalculated Matrix objects instead of continuously altering one… that’s overkill though, matrix operations aren’t super expensive so unless your doing a bunch of them you won’t see a significant improvement.

  3. Posted January 26, 2009 at 1:36 pm | Permalink

    gotcha, thanks. if i end up needing something like this i’ll wrap it up nice and neat and let you know.

  4. Posted January 26, 2009 at 1:46 pm | Permalink

    cool… sounds good.

One Trackback

  1. By Weekly Shared Items - 30. January, 2009 « toxin 2.0 on January 30, 2009 at 12:53 am

    [...] Seamless Tiles [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*