Tag Archives: Pixel

Let’s shrink the world: A Tilt Shift Effect

Everybody has seen the cute pictures floating around showing a mini world! Some examples:

But how is it done? And can it be done fast?

Answers: Easy and Yes!

How does it work?
For a digital Tilt-Shift we use some kind of gradient blur. What I mean is a blur that is very light where the focus lens is and gets blurrier the further something is in the picture. Some ‘faster’ systems only use one blur and then put the focused part back into the picture but this creates an ugly edge between the sharp and blurred part of the picture. And we do not want this!

To get his effect we could do several blurs where we enlarge the focus box in the loop so we get some gradience. Eg. If we do it 8 times we get a gradient of 8 layers. Not bad but…we want more!

Doing a blur in languages like Realstudio and Basic4Android (or Java) is not that fast. This is the first issue we’ll have to tackle because we want to be close to doing it real-time.

Second, a lot of focusses can only be a rectangle or a circle. This has a side effect: some objects in the picture will be in focus while we do not want that because it spoils the illusion. So our focus needs to be able to be irregular. In this tutorial the example uses also a rectangle but I’ll show you how to change this to anything you want.

In some cases changing the saturation of the picture can even more give the illusion of a miniature.

So in short we want:
1. few blurs, but still have 255 gradient levels
2. the blur must be fast
3. an irregular focus
4. some kind of saturation
5. did I mention fast?

How will Basic4Android (or java) and Realbasic be able to do this?

Well, we’re gonna cheat! :D

Instead of creating a gradient blur, we are going to write one heavy blur and then resharpen it. In fact you’ll see we can do the 255 levels of sharpness with only two blurs!

In Realbasic we can take advantage of the great mask property in a picture we’ve used a lot in the past. In Basic4Android I’m going to simulate this so the code can be very similar.

For our example let’s say we want to make this:

Let me show you in a schema what the steps are we’re going to use in our Tilt-Shift (click the picture to see full size):

1. our orignal picture. Make sure it is a sharp one
2. a blurred version of (1)
3. our focus area.
4. a blurred version of (3)
5. we use our blurred (4) as a mask on our original (1). As you can see in the schema, (5) fades out to its background (the alpha channel increases), in this case white.
6. so if we draw (5) on our blurred (2) the blurred pixels will re-sharpen! Do you see the magic happening here :-)
7. the saturation is optional but may make the effect more real.

And the clever part is step 3: you can draw any shape you want here! Some examples for Realbasic:

And remember, in Basic4Android (java) it needs to be inverted:

And now for the code.
(For B4A you’ll need my ABExtDrawing library version 1.7 here)

First we’ll need a fast blur. Again we’ll cheat as we’re not doing a real gaussian blur. We are ging to exploit our mask feature again and do a diagonal blur.

We’ll need some help functions:
Resize()

Realbasic:

Function Resize(pic as picture, Percentage as integer) As Picture
  #pragma BackgroundTasks false
  #pragma BoundsChecking false
  #pragma NilObjectChecking false
  #pragma StackOverflowChecking false
  
  dim p as Picture
  dim w,h as Integer
  dim by as Double = Percentage / 100
  
  w = pic.Width * by
  h = pic.Height * by
  
  p = NewPicture(w,h,32)
  p.Graphics.UseOldRenderer=true
  p.Graphics.DrawPicture pic,0,0,w,h, 0,0,pic.Width, pic.Height
  
  Return p
End Function

Java (B4A library):

public Bitmap Resize(Bitmap bmp, float Percentage)
{
	float by = (float) (Percentage/100.0);
	
	int w = (int) (bmp.getWidth()*by);
	int h = (int) (bmp.getHeight()*by);
	
	if (Percentage>100) {
		return Bitmap.createScaledBitmap(bmp, w, h, true);
	} else {
		return Bitmap.createScaledBitmap(bmp, w, h, false);
	}
	
}

Innerblur()
We create a mask on our picture and draw it a number of times on each other, just shifting bits to the left, top, right and bottom.

Realbasic:

Function InnerBlur(Pic as picture, Level as double) As Picture
  #pragma BackgroundTasks false
  #pragma BoundsChecking false
  #pragma NilObjectChecking false
  #pragma StackOverflowChecking false
  
  dim p,t as Picture
  dim L,w,h as Integer
  
  w=pic.Width
  h=pic.Height
  p=NewPicture(w,h,32)
  p.Graphics.UseOldRenderer=true
  p.Graphics.DrawPicture pic,0,0
  
  t=NewPicture(w,h,32)
  t.Graphics.UseOldRenderer=true
  t.Mask.Graphics.UseOldRenderer=true
  t.Mask.Graphics.ForeColor=&c7F7F7F
  t.Mask.Graphics.FillRect 0,0,t.Width,t.Height
  
  for L=abs(Level) DownTo 1
    t.Graphics.DrawPicture p,0,0
    p.Graphics.DrawPicture t,-L,-L   'upper left
    
    t.Graphics.DrawPicture p,0,0
    p.Graphics.DrawPicture t,-L,L    'lower left
    
    t.Graphics.DrawPicture p,0,0
    p.Graphics.DrawPicture t,L,L     'lower right
    
    t.Graphics.DrawPicture p,0,0
    p.Graphics.DrawPicture t,L,-L    'upper right
  next
  
  Return p
End Function

Java (B4A library):

private Bitmap InnerBlur(Bitmap bmp, float Level) {
	int w = bmp.getWidth();
	int h = bmp.getHeight();
	
	Paint paint = new Paint();
	paint.setAlpha(0x7F);
	
	Bitmap t = Bitmap.createBitmap(w, h, Config.ARGB_8888);
	Canvas tc = new Canvas(t);
	
	Bitmap p = Bitmap.createBitmap(w, h, Config.ARGB_8888);
	Canvas pc = new Canvas(p);
	pc.drawBitmap(bmp, 0, 0, null);
	
	int Lev = (int) Level;
	
	for (int L=Lev;L>0;L--) {
		tc.drawBitmap(p, 0, 0, paint);
		pc.drawBitmap(t, -L, -L, null);
		
		tc.drawBitmap(p, 0, 0, paint);
		pc.drawBitmap(t, -L, L, null);
		
		tc.drawBitmap(p, 0, 0, paint);
		pc.drawBitmap(t, L, L, null);
		
		tc.drawBitmap(p, 0, 0, paint);
		pc.drawBitmap(t, L, -L, null);
	}
	
	t.recycle();
	return p;
}

Blur()
The actual blur function is a mix of Resizes and Innerblurs.
1. Resize to smaller
2. Innerblur to level
3. Resize back to original size
4. Innerblur with level 1 to make it smooth

Realbasic:

Function Blur(Pic as picture, Level as double, Speed as Integer) As Picture
  #pragma BackgroundTasks false
  #pragma BoundsChecking false
  #pragma NilObjectChecking false
  #pragma StackOverflowChecking false
  
  dim p as Picture
  dim L,w,h as Integer
  
  w=pic.Width
  h=pic.Height
  p=NewPicture(w,h,32)
  p.Graphics.UseOldRenderer=true
  p.Graphics.DrawPicture pic,0,0
  
  L=Level-round(Level*.4)
  
  select case speed
  case 0
    // shrink the image, blur it
    p=Resize(p,50)
    p=InnerBlur(p, L )
    // back to normal, smooth it
    p=Resize(p, 200)
    p=InnerBlur(p, 1)
  case 1
    // shrink the image, blur it
    p=Resize(p,25)
    p=InnerBlur(p, L )
    // back to normal, smooth it
    p=Resize(p, 400)
    p=InnerBlur(p, 1)
    
  end select
  
  Return p
End Function

Java (B4A library):

/**
 * blur and image. 
 * Speed: 0 = normal, 1 = fast
 */
public Bitmap Blur(Bitmap bmp, float Level, int Speed)
{
	int L = (int) (Level - Math.round(Level*.4));
	Bitmap p = null;	 
	
	switch (Speed) {
	case 0:
		p = Resize(bmp, 50);
		p = InnerBlur(p, L);
		p = Resize(p,200);
		p = InnerBlur(p, 1);
		break;
	case 1:
		p = Resize(bmp, 25);
		p = InnerBlur(p, L);
		p = Resize(p,400);
		p = InnerBlur(p, 1);
		break;		
	}		
	return p;
}

This is, as far as I know, the fastest way to do a blur in Realbasic and Java. If someone knows of a faster one, please contact me, I’ll be very interested. :-)

Before we continue, I’m going to make a function in B4A to merge a Mask layer with a picture so we can do the tilt Shift in a way similar to Realbasic.
As mentioned in a previous article, you have to make sure your images are in a certain format on Android otherwise you can strange colors or resizes.
Here is a function that makes sure the picture is in ARGB_8888 format:

Basic4Android:

' exDraw was dimmed before as Dim ExDraw As ABExtDrawing '(version 1.70 or higher required)
Sub Convert_RGB565_To_ARGB8888(iFolder As String, iFile As String) As Bitmap	
	Dim iBmp As Bitmap
	iBmp.Initialize(iFolder, iFile)

	' only convert it if it is a RGB565
	If ExDraw.GetConfig(iBmp) = ExDraw.RGB_565 Then
		Dim w, h As Int
		
		w = iBmp.Width
		h = iBmp.Height
	
		Dim tmpBmp As Bitmap
		tmpBmp.InitializeMutable(w,h)
		Dim cnvRect As Rect
		cnvRect.Initialize(0,0,w, h)
		Dim cnvCanv As Canvas
		cnvCanv.Initialize2(tmpBmp)
		
		Dim aRect As Rect
		aRect.Initialize(0,0,w,h)
		
		cnvCanv.DrawBitmap(iBmp,Null, aRect)		
		Return tmpBmp
	Else
		Return iBmp
	End If
End Sub

And here is our merge function:

Basic4Android:

Sub MergeWithAlphaLayer(iBmp As Bitmap, iLayerBmp As Bitmap) As Bitmap
	Dim MergedBmp As Bitmap
	Dim MergedBmpCanv As Canvas
	
	Dim w, h As Int
	
	w = iBmp.Width
	h = iBmp.Height
	
	Dim aRect As Rect
	aRect.Initialize(0,0,w,h)
	
	MergedBmp.InitializeMutable(w,h)
	MergedBmpCanv.Initialize2(MergedBmp)
	
	Dim Alpha As Bitmap
	Alpha.InitializeMutable(w,h)
	
	' pic
	MergedBmpCanv.DrawBitmap(iBmp, Null, aRect)
	
	' mask
	Dim Pixels(w*h) As Int
	ExDraw.getPixels(iLayerBmp,Pixels , 0, w, 0, 0, w, h)
	Dim count As Int
	count = (w*h) - 1
	For i = 0 To count
    	    Pixels(i) = Bit.ShiftLeft(Pixels(i),8) 'move the red pixel value to the alpha channel
	Next
	ExDraw.setPixels(Alpha, Pixels, 0, w, 0, 0, w, h)
	
	Dim AlphaP As ABPaint
	AlphaP.Initialize
	AlphaP.SetAntiAlias(True)
	AlphaP.SetPorterDuffXfermode(ExDraw.PorterDuffMode_DST_IN) 'DST_IN only takes over the alpha values
	
	ExDraw.drawBitmap2(MergedBmpCanv, Alpha, 0, 0, AlphaP)
	
	ExDraw.Recycle(Alpha)
	
	Return MergedBmp
End Sub

Ok, back on track! The saturation function. I admit the one in Java has some room for improvement.

Realbasic:

Sub Saturation(Pic as picture, Ammount as integer)
  #pragma BackgroundTasks false
  #pragma BoundsChecking false
  #pragma NilObjectChecking false
  #pragma StackOverflowChecking false
  
  dim c as color
  dim d as Double
  dim a,x,y,w,h,m() as Integer
  dim s as RGBSurface
  dim p as Picture
  dim ir,ig,ib as Integer
  
  s=pic.RGBSurface
  d=Ammount/100
  w=pic.Width-1
  h=pic.Height-1
  
  Redim m(510)
  for x=0 to 510
    m(x)=(x-255)*d
  Next
  
  for y=0 to h
    for x=0 to w
      c=s.Pixel(x,y)
      ir=c.red
      ig=c.green
      ib=c.blue
      a=( ir + ig + ib ) \ 3
      s.Pixel(x,y)=rgb( ir+m(ir-a+255) , ig+m(ig-a+255) , ib+m(ib-a+255) )
    next
  next
End Sub

Java (B4A library):

public Bitmap Saturate(Bitmap bmp,float Ammount) {
	//Initialize the ColorMatrix object  
	ColorMatrix colorMatrix = new ColorMatrix();  
	//Initialize the ColorMatrixColorFilter object  
	ColorMatrixColorFilter cmFilter = new ColorMatrixColorFilter(colorMatrix);  

	//Initialize the cmPaint  
	Paint cmPaint = new Paint();  
	//Set 'cmFilter' as the color filter of this paint  
	cmPaint.setColorFilter(cmFilter);  
	
	colorMatrix.setSaturation(Ammount/(float)100);  
	//Create a new ColorMatrixColorFilter with the recently altered colorMatrix  
	cmFilter = new ColorMatrixColorFilter(colorMatrix);  

	//Assign the ColorMatrix to the paint object again  
	cmPaint.setColorFilter(cmFilter);  

	//Draw the Bitmap into the mutable Bitmap using the canvas. Don't forget to pass the Paint as the last parameter
	Bitmap alteredBitmap = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), bmp.getConfig());
	Canvas canvas = new Canvas(alteredBitmap);
	canvas.drawBitmap(bmp, 0, 0, cmPaint);
	
	return alteredBitmap;
}

The actual Tilt Shift. This is nothing more that going over the steps I’ve shown in the schema.

Realbasic:

Sub DoTiltShiftRect(bmp as Picture, BlurRadius as integer, focusX as integer, focusY as integer, focusW as integer, focusH as integer, DoSaturtion as boolean)
  mBuffer = new Picture(640,480, 32)
  tmpPic = NewPicture(640,480, 32)
  tmpMask = NewPicture(640,480, 32)
  
  mBuffer = Blur(bmp,blurRadius,0)
  
  tmpPic.Graphics.DrawPicture bmp,0,0
  
  tmpMask.Graphics.FillRect(focusX,focusY - focusH/2, focusW,focusH)
  tmpMask = Blur(tmpMask, 7,1)
  
  tmpPic.Mask.Graphics.DrawPicture tmpMask,0,0
  
  mBuffer.Graphics.DrawPicture tmpPic,0,0
  
  if DoSaturtion then
    Saturation mBuffer,80
  end if
  
  Canvas1.Refresh(false)
End Sub

Basic4Android:

Sub DoTiltShiftRect(iBmp As Bitmap, BlurRadius As Int, focusR As Rect, DoSaturation As Boolean) As Bitmap
	Dim tgtCanv As Canvas
	
	Dim w, h As Int
		
	w = iBmp.Width
	h = iBmp.Height

	Dim tgtBmp As Bitmap
	tgtBmp.InitializeMutable(w, h)
	tgtCanv.Initialize2(tgtBmp)
	
	' blur the picture
	Dim srcBlurred As Bitmap
	srcBlurred = ExDraw.Blur(iBmp, BlurRadius, 0)	
	
	' create the sharp box
	Dim Alpha As Bitmap
	Alpha.InitializeMutable(w, h)
	Dim AlphaCanv As Canvas
	AlphaCanv.Initialize2(Alpha)
	' draw a full white rect on a black background
	Dim tmpR As Rect
	tmpR.Initialize(0,0,w, h)
	AlphaCanv.DrawRect(tmpR, Colors.black, True, 0dip)
	AlphaCanv.DrawRect(focusR, Colors.white, True, 0dip)
	' blur the white box to emulate a gradient blur, may be fast and ugly
	Dim AlphaBlurred As Bitmap
	AlphaBlurred = ExDraw.Blur(Alpha, 7, 1)
	
	' merge the blurred alpha layer with the bitmap into the overlay
	Dim Overlay As Bitmap
	Overlay = MergeWithAlphaLayer(iBmp, AlphaBlurred)		
	
	' saturate the picture to make it more life like
	Overlay = ExDraw.Saturate(Overlay, 80)
		
	Dim aRect As Rect
	aRect.Initialize(0,0,w,h)
	
	' draw the blurred image
	tgtCanv.DrawBitmap(srcBlurred, aRect, aRect)
	' draw the overlay
	tgtCanv.DrawBitmap(Overlay, aRect, aRect)	
	
	' saturate
	If DoSaturation Then
		tgtBmp = ExDraw.Saturate(tgtBmp, 90)
	End If
	
	ExDraw.Recycle(srcBlurred)
	ExDraw.Recycle(Alpha)
	ExDraw.Recycle(AlphaBlurred)
	ExDraw.Recycle(Overlay)
	
	Return tgtBmp
End Sub

And that’s it! Remember I’ll only did it for a rectangle here in the tutorial, but you can use anything.

Notes about the programs:

1. you can point anywhere on the y-axe in the picture to re-position the focusbox.
2. in the Realbasic version you can change the picture in the main.open() event: CurrentPicture = beach2
3. for the compiled RB version you can use the command line:

	Syntax: TiltShift.exe /PIC=picturename.jpg;focusleft;focustop;focuswidth;focusheight;dosaturation

		focus variables = the focus box
		DoSaturation: 0 = false, 1 = true

		Example:

		TiltShift.exe /PIC=beach2.jpg;30;300;580;240;1

4. in the Basic4Android version you can change the picture in the Activity_Create() sub: srcBmp = ABBitmapTools.Convert_RGB565_To_ARGB8888(File.DirAssets, "beach2.jpg")
5. the TiltShift.apk can be found in the B4A version in the folder \Objects\.

It would be nice if you give me credit if you use this code in your own program. ;-)

The full source code can be downloaded from:
Realbasic: download here
Basic4Android: download here

And some more eye candy!

Click here to Donation if you like my work


RealBasic: isolated project 4 -> A Sepia filter


Like the good old fashion style? As the name suggested, this filter will apply sepia tone (effect) to your photos, and it’s very easy to use.

Converting a photo to sepia is a relatively easy effect.

For each pixel in the image, we first convert the pixel to greyscale. We then add a value to the green component, and double that value to the red component to give the sepia effect.

The depth of the sepia effect is determined by this value, which we pass here as the depth parameter. A value of 0 will give a standard greyscale image.
In the above image a depth value of 20 was used.

Here is the function to do this:

Sub ApplySepia(Byref pic as picture, depth as Integer)
  Dim R As Integer
  Dim G As Integer
  Dim B As Integer
  Dim pixelColor As Color
  Dim picRGB as RGBSurface
  
  picRGB = pic.RGBSurface
  
  For y As Integer = 0 To pic.Height - 1
    For x As Integer = 0 To pic.Width - 1
      pixelColor = picRGB.Pixel(x, y)
      R = (0.299 * pixelColor.Red) + (0.587 * pixelColor.Green) + (0.114 * pixelColor.Blue)
      B = R
      G = B
      
      R = R + (depth * 2)
      If R > 255 Then
        R = 255
      End If
      G = G + depth
      If G > 255 Then
        G = 255
      End If
      
      picRGB.Pixel(x, y) = RGB(R,G,B)
    Next
  Next
End Sub

RealBasic: isolated project 3 -> Liquid physics


This is a very rudimentary physics simulation of liquid water. It cannot show al lot of particles in plain RealBasic. I suspect if you rewrite it for GDI+ or even OpenGL you could use thousands of particles.

It was based on the work of Grant Kot (who made several demos for HTML5) and jgittins/quinbd’s version for Android.

It’s Grant Kots implementation of the Material Point Method (MPM). Wiki: http://en.wikipedia.org/wiki/Material_Point_Method

Grant Kot:

For interpolation, I use the quadratic B-spline presented here: Analysis and Reduction of Quadrature Errors in the Material Point Method. Please note that there is an error in equation 17, for the cubic B-spline. The middle two equations should end with 2/3. I don’t use the cubic spline though, because I’m interested in real-time simulation and I feel that the quadratic spline is the best balance of speed and quality.

Instead of integrating the density over time (which is what most of the MPM papers do), I do a density summation every frame. Because this is not dependent on previously calculated values of density, there is no accumulated error. To minimize grid artifacts, I use the cubic interpolation method presented here: A Semi-Lagrangian CIP Fluid Solver without Dimensional Splitting.

I had to read it also several times before it made any sense. :-)

If you want to get deeper into the mechanism read:
Analysis and Reduction of Quadrature Errors in the Material Point Method: http://www.gorgeousapps.com/steffen_08_IJNME_mpm_preprint.pdf

and
A Semi-Lagrangian CIP Fluid Solver without Dimensional Splitting: http://www.gorgeousapps.com/PA-08-09-19.pdf

Anyhow, the result of it was this piece of code I translated to RealBasic:

  Dim drag As Boolean = False
  Dim mdx As Single
  Dim mdy As Single
  
  Dim i, j as Integer
  Dim cxi As Integer
  Dim cyj As Integer
  Dim cyi as Integer
  Dim n As ABNode
  
  Dim phi As Single
  Dim dx, dy As Single
  Dim x, y As Single
  
  Dim cx As Integer
  Dim cy As Integer
  
  Dim p00 As Single
  Dim x00 As Single
  Dim y00 As Single
  Dim p01 As Single
  Dim x01 As Single 
  Dim y01 As Single 
  Dim p10 As Single 
  Dim x10 As Single 
  Dim y10 As Single 
  Dim p11 As Single 
  Dim x11 As Single 
  Dim y11 As Single 
  
  Dim pdx As Single 
  Dim pdy As Single 
  Dim C20 As Single 
  Dim C02 As Single 
  Dim C30 As Single 
  Dim C03 As Single 
  Dim csum1 As Single 
  Dim csum2 As Single 
  Dim C21 As Single 
  Dim C31 As Single 
  Dim C12 As Single 
  Dim C13 As Single 
  Dim C11 As Single 
  
  Dim u As Single 
  Dim u2 As Single 
  Dim u3 As Single 
  Dim v As Single 
  Dim v2 As Single 
  Dim v3 As Single 
  Dim density As Single 
  
  Dim gx,gy as Single
  Dim mu, mv As Single 
  Dim gu, gv As Single 
  
  Dim pressure As Single 
  
  Dim fx As Single
  Dim fy As Single
  
  Dim p as ABParticle
  
  Dim vx As Single
  Dim vy As Single
  Dim weight As Single
  
  If (pressed) And (pressedprev) Then
    drag = True
    mdx = 0.25 * (mx - mxprev)
    mdy = 0.25 * (my - myprev)
  End If
  
  pressedprev = pressed
  mxprev = mx
  myprev = my
  
  For Each n  In active
    n.m = 0
    n.d = 0
    n.gx = 0
    n.gy = 0
    n.u = 0
    n.v = 0
    n.ax = 0
    n.ay = 0
    n.active = False
  Next
  Redim active(-1)
  
  For Each p  In Particles
    p.cx = p.x - 0.5
    p.cy = p.y - 0.5
    
    x = p.cx - p.x
    p.px(0) = (0.5 * x * x + 1.5 * x + 1.125)
    p.gx(0) = (x + 1.5)
    x = x + 1.0
    p.px(1) = (-x * x + 0.75)
    p.gx(1) = (-2.0 * x)
    x = x + 1.0
    p.px(2) = (0.5 * x * x - 1.5 * x + 1.125)
    p.gx(2) = (x - 1.5)
    
    y = p.cy - p.y
    p.py(0) = (0.5 * y * y + 1.5 * y + 1.125)
    p.gy(0) = (y + 1.5)
    y = y + 1.0
    p.py(1) = (-y * y + 0.75)
    p.gy(1) = (-2.0 * y)
    y = y + 1.0
    p.py(2) = (0.5 * y * y - 1.5 * y + 1.125)
    p.gy(2) = (y - 1.5)
    
    For i  = 0 To 2
      For j  = 0 To 2
        cxi = p.cx + i
        cyj = p.cy + j
        n = grid(cxi,cyj)
        If Not n.active Then
          n.active = True
          active.Append n
        End If
        phi = p.px(i) * p.py(j)
        n.m = n.m + phi * p.mat.m
        n.d = n.d + phi
        dx = p.gx(i) * p.py(j)
        dy = p.px(i) * p.gy(j)
        n.gx = n.gx + dx
        n.gy = n.gy + dy
      Next
    Next
  Next
  
  For Each p In Particles
    cx = p.x
    cy = p.y
    cxi  = cx + 1
    cyi  = cy + 1
    
    p00 =grid(cx,cy).d
    x00 =grid(cx,cy).gx
    y00 =grid(cx,cy).gy
    p01 =grid(cx,cyi).d
    x01 =grid(cx,cyi).gx
    y01 =grid(cx,cyi).gy
    p10 =grid(cxi,cy).d
    x10 =grid(cxi,cy).gx
    y10 =grid(cxi,cy).gy
    p11 =grid(cxi,cyi).d
    x11 =grid(cxi,cyi).gx
    y11 =grid(cxi,cyi).gy
    
    pdx = p10 - p00
    pdy = p01 - p00
    C20 = 3.0 * pdx - x10 - 2.0 * x00
    C02 = 3.0 * pdy - y01 - 2.0 * y00
    C30 = -2.0 * pdx + x10 + x00
    C03 = -2.0 * pdy + y01 + y00
    csum1 = p00 + y00 + C02 + C03
    csum2 = p00 + x00 + C20 + C30
    C21 = 3.0 * p11 - 2.0 * x01 - x11 - 3.0 * csum1 - C20
    C31 = -2.0 * p11 + x01 + x11 + 2.0 * csum1 - C30
    C12 = 3.0 * p11 - 2.0 * y10 - y11 - 3.0 * csum2 - C02
    C13 = -2.0 * p11 + y10 + y11 + 2.0 * csum2 - C03
    C11 = x01 - C13 - C12 - x00
    
    u = p.x - cx
    u2 = u * u
    u3 = u * u2
    v = p.y - cy
    v2 = v * v
    v3 = v * v2
    density = p00 + x00 * u + y00 * v + C20 * u2 + C02 * v2 + C30 * u3 + C03 * v3 + C21 * u2 * v + C31 * u3 * v + C12 * u * v2 + C13 * u * v3 + C11 * u * v
    
    pressure  = density - 1.0
    If pressure > 2.0 Then
      pressure = 2.0
    End If
    
    fx = 0.0
    fy = 0.0
    
    If p.x < 4.0 Then
      fx = fx + p.mat.m * (4.0 - p.x)
    ElseIf p.x > gsizeX - 5 Then
      fx = fx + p.mat.m * (gsizeX - 5 - p.x)
    End If
    If p.y < 4.0 Then
      fy = fy + p.mat.m * (4.0 - p.y)
    ElseIf p.y > gsizeY - 5 Then
      fy = fy + p.mat.m * (gsizeY - 5 - p.y)
    End If
    
    If drag Then
      vx = Abs(p.x - 0.25 * mx)
      vy = Abs(p.y - 0.25 * my)
      If (vx < 10.0) And (vy < 10.0) Then
        weight = p.mat.m * (1.0 - vx / 10.0) * (1.0 - vy / 10.0)
        fx = fx + weight * (mdx - p.u)
        fy = fy + weight * (mdy - p.v)
      End If
    End If
    
    For i  = 0 To 2
      For j  = 0 To 2
        n = grid((p.cx + i),(p.cy + j))
        phi  = p.px(i) * p.py(j)
        gx  = p.gx(i) * p.py(j)
        gy  = p.px(i) * p.gy(j)
        
        n.ax = n.ax + -(gx * pressure) + fx * phi
        n.ay = n.ay + -(gy * pressure) + fy * phi
      Next
    Next
  Next
  
  For Each n  In Active
    If n.m > 0.0 Then
      n.ax = n.ax / n.m
      n.ay = n.ay / n.m
      n.ay = n.ay + 0.03
    End If
  Next
  For Each p in Particles
    For i  = 0 To 2
      For j  = 0 To 2
        n = grid((p.cx + i),(p.cy + j))
        phi = p.px(i) * p.py(j)
        p.u = p.u + phi * n.ax
        p.v = p.v + phi * n.ay
      Next
    Next
    mu = p.mat.m * p.u
    mv = p.mat.m * p.v
    For i  = 0 To 2
      For j  = 0 To 2
        n = grid((p.cx + i),(p.cy + j))
        phi  = p.px(i) * p.py(j)
        n.u = n.u + phi * mu
        n.v = n.v + phi * mv
      Next
    Next
  Next
  For Each n  In Active
    If n.m > 0.0 Then
      n.u = n.u / n.m
      n.v = n.v / n.m
    End If
  Next
  For Each p  In Particles
    gu = 0.0
    gv = 0.0
    For i  = 0 To 2
      For j  = 0 To 2
        n = grid((p.cx + i),(p.cy + j))
        phi = p.px(i) * p.py(j)
        gu = gu + phi * n.u
        gv = gv + phi * n.v
      Next
    Next
    p.x = p.x + gu
    p.y = p.y + gv
    p.u = p.u + 1.0 * (gu - p.u)
    p.v = p.v + 1.0 * (gv - p.v)
    If p.x < 1.0 Then
      p.x = (1.0 + rnd() * 0.01)
      p.u = 0.0
    ElseIf p.x > gsizeX - 2 Then
      p.x = (gsizeX - 2 - rnd() * 0.01)
      p.u = 0.0
    End If
    If p.y < 1.0 Then
      p.y = (1.0 + rnd() * 0.01)
      p.v = 0.0
    ElseIf p.y > gsizeY - 2 Then
      p.y = (gsizeY - 2 - rnd() * 0.01)
      p.v = 0.0
    End If
  Next 

The full source code and demo can be downloaded from: http://www.gorgeousapps.com/ABLiquid.zip

Until next time!


RealBasic: isolated project 2 -> Fire!

The second one is a little ‘old school’ demo effect of moving fire. I know it’s not the most convincing version out there but it is a quick and dirty one. Maybe if you play around with the params you’ll get it better. I’m not sure who made the original code. It may even be a mix of several projects.

First we need to setup the fire color palette. There are some formulas out there to generate the colors. A typical one is this (pseudo):

HSLtoRGB is used to generate colors:
Hue goes from 0 to 85: red to yellow
Saturation is always the maximum: 255
Lightness is 0..255 for x=0..128, and 255 for x=128..255

But I was lazy and just filled a table of 256 items with the colors I would need ;-)

The next part is the main loop that animates the fire.

  'start the loop (one frame per loop)
  While Not StopFire
    'make the background black
    gBuffer.ForeColor = &c000000
    gBuffer.FillRect(0,0,w,h)
    
    'randomize the bottom row of the fire buffer
    For x = 0 To w - 1
      fire(x, h - 1) = Abs(32768 + rnd()*256) Mod 256 + 128
      if fire(x, h - 1) > 255 then
        fire(x, h - 1) = 255
      end if
    Next
    'do the fire calculations for every pixel, from top to bottom
    'I remember there are other formulas out there that have different effects. Just Google it.
    For y  = 0 To h - 2
      For x  = 0 To w - 1
        fire(x, y) = ((fire((x - 1 + w) Mod w, (y + 1) Mod h) + fire((x) Mod w, (y + 1) Mod h) + fire((x + 1) Mod w, (y + 1) Mod h) + fire((x) Mod w, (y + 2) Mod h)) * 32) / 130 + rnd()
      Next
    Next
    
    'set the drawing buffer to the fire buffer, using the palette colors
    For x  = 0 To w - 1
      For y  = 0 To h - 1
        rgbBuffer.pixel(x, y) = palette(fire(x, y))
      Next
    Next
    
    'redraw the screen
    me.Refresh(false)
    app.DoEvents
   wend

That’s it! Or as Tom Hanks would have said in Cast Away: “I have made fire!”

The code and demo can be downloaded from: http://www.gorgeousapps.com/ABFire.zip

Happy coding!


RealBasic: Canvas tutorial lesson 3 Detecting pixel precise click/touch in irregular shapes

Here is a little trick to do a very fast pixel precise detection of a click/touch within a irregular shape without doing complicated calculations.

It’s a trick I use a lot in Realbasic, but is also usable in other languages like Basic4Android. By using a color map, you can get pixel precise detection very simple.

Let’s say we want to make a nice round menu. Make a second picture with exactly the same dimensions, but now we are going to draw the ‘click’ parts.
Give every clickable area another color. For our example, it look something like this:

Note: Make sure the map picture is 32-bit! This is needed for Basic4Android because if we use a 24-bit picture, Android messes with the colors.

You can check if a picture is 32 bit by right-clicking on the file, select properties and pick the details tab:

You can use a free tool like gimp http://www.gimp.org/ to convert a 24 bit png to a 32 bit png.

In gimp, add a transparent layer and save the picture:

And now for the coding. I’ll show it in both Realbasic and Basic4Android:

RealBasic:

MouseDown(X as integer, Y as integer) As Boolean
  Select case CircMenuMap32Bit.Graphics.Pixel(x,y)
  case &cFF0000
    StaticText1.caption = "Clicked on Recycle"
  case &cFFFF00
    StaticText1.caption = "Clicked on Film roll"
  case &c00FF00
    StaticText1.caption = "Clicked on Rubik cube"
  case &c00FFFF
    StaticText1.caption = "Clicked on Old Radio"
  case &c0000FF
    StaticText1.caption = "Clicked on Record player"
  case &cFF00FF
    StaticText1.caption = "Clicked on Box with stuff"
  case &cFFC0C0
    StaticText1.caption = "Clicked on Old TV"
  case &cFFFFC0
    StaticText1.caption = "Clicked on Folder with pictures"
  case &cC0FFC0
    StaticText1.caption = "Clicked on LadyBug"
  case &CFFFFFF
    StaticText1.caption = "Clicked on Big Button"
  End Select
End function

You can do a similar thing in the MouseMove() event:

Sub MouseMove(X as integer, Y as integer)
  Select case CircMenuMap32Bit.Graphics.Pixel(x,y)
  case &c000000
    me.MouseCursor = System.Cursors.StandardPointer
  case else
    me.MouseCursor = System.Cursors.FingerPointer
  End Select
End Sub

In Basic4Android:

Sub Panel1_Touch (Action As Int, X As Float, Y As Float)
	If action = activity.ACTION_DOWN Then
		Dim c As Int
		c = bmp.GetPixel(x,y)
		Select c
		Case Colors.RGB(255,0,0)
			label1.Text = "Clicked on Recycle"
		Case Colors.RGB(255,255,0)
			label1.Text ="Clicked on Film roll"
		Case Colors.RGB(0,255,0)
			label1.Text ="Clicked on Rubik cube"
		Case Colors.RGB(0,255,255)
			label1.Text ="Clicked on Old Radio"
		Case Colors.RGB(0,0,255)
			label1.Text ="Clicked on Record player"
		Case Colors.RGB(255,0,255)
			label1.Text ="Clicked on Box with stuff"
		Case Colors.RGB(255,192,192)
			label1.Text ="Clicked on Old TV"
		Case Colors.RGB(255,255,192)
			label1.Text ="Clicked on Folder with pictures"
		Case Colors.RGB(192,255,192)
			label1.Text ="Clicked on Ladybug"
		Case Colors.RGB(255,255,255)
			label1.Text ="Clicked on Big Button"
		Case Else
			label1.Text =""
		End Select
		Return
	End If
End Sub

And that’s it! Pretty simple no?

The realbasic source: http://www.gorgeousapps.com/Tut3.zip
The Basic4Android source: http://www.gorgeousapps.com/IrregularShapesTut3.zip

See you!

Click here to Donation if you like my work


Follow

Get every new post delivered to your Inbox.

Join 79 other followers