Monthly Archives: March 2014

Xojo: About cables, chains and other curves…

Mimicking Propellerheads Reason interface in Xojo

Mimicking Propellerheads Reason interface in Xojo

When I first saw Propellerheads Reason interface years ago, I was mesmerised by the cabling system. It seemed so intuitive to connect devices with each other. I rebuilded such an interface in RealBasic and was very satisfied with it. Lataly, I stumbled on this old project and I decided to give it a go in Xojo. It seemed like a good idea for an article on my blog.

For this article I wrote some classes (ABCable mainly) so it’s easy to implement in other projects in Xojo. I wrote a quick and dirty system to add and move cables cutting a couple of corners, as you may know I tend to do 🙂
When you want to use such a system, I urge you to rewrite that part in a more stable framework. But all the principles are here.

The Windows and OSX versions will also look slightly different. I did not find a good way to draw a smooth Catenary curve with the MacOSLib so I decided to use different functions for them, simulating the Windows version as much as possible. (Check DrawOSX and DrawWIN in the ABCable class to see what I’ve done). You can rewrite them as you please.

ABCable has three possible constructors:

' use for itaerations
' the start and end point, the color, the minimum length of the cable (will not be exact), the cable thickness (experimental)
Constructor(iStartPoint as ABPoint, iEndPoint as ABPoint, iCableColor as Color, iCableMinimumLength as double, iCableThickness as double )
' is the same as above but with an additional parameter: iPointSpacing
' this param can be used to 'smoothen' the curve by considering more points. The default is 8 segments. Increasing this number will slow down the animation.
Constructor(iStartPoint as ABPoint, iEndPoint as ABPoint, iCableColor as Color, iCableMinimumLength as double, iPointSpacing as Double, iCableThickness as double )

The other functions you’ll need from the ABCable class are:

Draw(DrawType as integer)

This function updates the graphics. I added two types of drawing. You can use DrawType to change it to the way you like:
DRAWBEZIER: Draw the curve as a Bezier curve
DRAWCATENARY: Draw the curve as a Catenary curve (for OSX it’s a simulation as described above)

The left one is as a Bezier, the other as a Catenary.

Drawtype as Bezier and as Caterary

Drawtype As Bezier and as Caterary

SetStartPoint(value as ABPoint)
SetEndPoint(value as ABPoint)

With these functions you can change the the Start en End connection points of the cable.

All the rest is done automatically (the shadow of the cable, the length increases/decreases when needed, etc…)

Let’s get into the rest of the program using this class.

I’m using a trick we learned in a previous canvas lesson to find where cables are and if there are connection points. We need 3 pictures. Our background without cables, a picture with the possible connection points in yellow (&cFFFF00) and a third one with the current connections. This last one will be created within the program and changes dynamically. (I’ll go deeper into this last one later in this article)


Click to enlarge

I’ll go through some of the source code and explain each part as we encounter it.

First, setup manual double buffering as we did in all the other lessons (using pBuffer as Picture, gBuffer as Graphics) so that our paint event in the canvas can simply be:

Sub Paint(g As Graphics)
  if pBuffer <> nil then
    g.DrawPicture pBuffer,0,0
  end if
End Sub

In the open event of the Window, we’ll set everything up:

Sub Open()
  ' setup the buffer
  pBuffer = New Picture(Canvas1.Width, Canvas1.Height, 32)
  gBuffer = pBuffer.Graphics

  ' setup the connections bitmap
  CurrentConnections = New Picture(Canvas1.Width, Canvas1.Height, 32)

  ' try = DRAWBEZIER to see another effect

  ' Important! Set lastColor to 2 so even numbers, not = 0, are startpoints, odd numbers are endpoints
  ConnectionLastColor = 2

  ' draw it
End Sub

We initialized our Buffer and also our CurrentConnections bitmap (the third picture from above). It has the same dimensions as the canvas (and background). We pick a Drawing method (here the Catenary type) and a help variable for identifying the start and end points of each cable we will draw. As the background is black, we’ll start at 2 so our starts will be even numbers (not being 0) and our odd numbers will be the end points. Finally, we draw the cables (in this case, none are defined, so just the background).

I’ll come back to the DrawCables function in a moment. First let’s check the canvas mouse events:

Function MouseDown(X As Integer, Y As Integer) As Boolean
  ' check if it is an existing cable
  dim c as ABCable
  c = CheckCables(X,Y)
  if c <> nil then
  end if

  Return true
End Function

Sub MouseDrag(X As Integer, Y As Integer)
  if IsDraggingEnd then
    Cables(UBound(Cables)).SetEndPoint(new ABPoint(X,Y))
    me.MouseCursor = System.Cursors.InvisibleCursor
  Elseif IsDraggingStart then
    Cables(UBound(Cables)).SetStartPoint(new ABPoint(X,Y))
    me.MouseCursor = System.Cursors.InvisibleCursor
  end if
End Sub

Sub MouseUp(X As Integer, Y As Integer)
  if IsDraggingStart or IsDraggingEnd then
    dim col as Color
    col = CurrentConnections.Graphics.Pixel(X,Y)
    if col <> &c000000 then ' it's used by another one, cannot be connected
      ' is it a connection point?
      col = BackgroundConnections.Graphics.Pixel(X,Y)
      if col <> &cFFFF00 then ' not yellow, so can not be used to connect a cable
      end if
    end if
    IsDraggingStart = false
    IsDraggingEnd = false
  end if

  me.MouseCursor = System.Cursors.StandardPointer
End Sub

In the MouseDown we’ll check if we have an existing cable or if we have to create a new one. This is done with the CheckCables() function. This function uses the CurrentConnections picture to check which, if any, cable you clicked on. We grab the pixel at postion X,Y and if it’s not black, we’ve touched a start or end point of a cable. If the color is even, we have a start point so we set IsDraggingStart = true. If it is odd, we’ll set IsDraggingEnd = true.

If it is black, we’ll check if it may be a possible connection point. We grab the pixel at position X,Y in the BackgroundConnections picture. If it is yellow, we can create a new Cable. We always assume you’re dragging the end of the cable to we’ll set IsDraggingEnd = true.

In both cases, we return the existing cable, the new cable or nil if you just clicked on the background. Check out the code to see how it works. I’ve added comments to make it easier to follow.

Function CheckCables(X as integer, Y as integer) As ABCable
  Dim c as ABCable

  dim col as Color
  dim colInt as Integer
  ' check if a cable is already connected to this connection point
  col = CurrentConnections.Graphics.Pixel(X,Y)
  if col <> &c000000 then ' it's an existing one
    for each c in Cables
      if c.StartPointColor = col or c.EndPointColor = col then
        ' found the cable
        colInt = ColorToInteger(col)
        if colInt mod 2 = 0 then
          ' is the start
          IsDraggingStart = true
          ' is the end
          IsDraggingEnd = true
        end if
        Return c
      end if
  else ' it's a new one, can it be connected
    col = BackgroundConnections.Graphics.Pixel(X,Y)
    if col = &cFFFF00 then ' yellow, so can be used to connect a cable
      dim i as Integer
      ' pick a random color for the cable
      dim NewCableColor as Color
      i = rnd*4
      select case i
      case 0
        NewCableColor = RGB(242, 131, 42)
      case 1
        NewCableColor = RGB(97,149,102)
      case 2
        NewCableColor = RGB(110,196,196)
      case 3
        NewCableColor = RGB(206,73,78)
      end select
      ' create a new cable
      c = new ABCable(new ABPoint(X,Y), new ABPoint(X,Y), NewCableColor,400,30)
      ' set its start end end color for the CurrentConnections bitmap to trace the mouse
      c.StartPointColor = IntegerToColor(ConnectionLastColor)
      c.EndPointColor = IntegerToColor(ConnectionLastColor+1)
      ' update the new last color for the next cable
      ConnectionLastColor = ConnectionLastColor + 2
      ' add the cable
      Cables.Append c
      ' always assume it's the end
      IsDraggingEnd = true
    end if
  end if

  Return c
End Function

Now we return to the MouseDown() event. If we have a Cable (c not nil), bring this cable to the front and draw again.

When we pass through the MouseDrag() event, one of our ends (start or end) will be active. Depending on which one it is, we’ll adjust the position by using SetStartPoint and SetEndPoint of the last Cable in our stack. Because we used the BringToFront() function, the last one in the stack is always our current one.

In the MouseUp() event we’ll do something similar as in the CheckCables() function. Now we first check if nobody is yet connected to this connection point (CurrentConnections.Graphics.Pixel(X,Y) not &c000000). In this case, we’ll just remove the cable. If it is black, we’ll check if it is a possible connection point (BackgroundConnections.Graphics.Pixel(X,Y) not &cFFFF00 ‘ yellow). If it is something else than yellow, remove the cable also.

Reset the Dragging variables to false and Draw the cables.

In the DrawCables() function, we’ll do five things:
1. Setup our GDIPlusGraphics for windows or our CGContextGraphicsPort for OSX if not done yet
2. We draw the background
3. We reset the CurrentConnection picture
4. We’ll draw all the cables on it
5. We’ll draw the current Start and End points of the cables to our CurrentConnection picture

Sub DrawCables()
  #if TargetWin32
    if WINGfx = nil then
      dim s as Status
      WINGfx =  new GdiPlusGraphics( gBuffer.Handle( Graphics.HandleTypeHDC ) )
      s = WinGfx.SetInterpolationMode(InterpolationMode.High)
      s = WinGfx.SetCompositingQuality(CompositingQuality.High)
      s = WinGfx.SetSmoothingMode(SmoothingMode.AntiAlias)
    end if
    gBuffer.DrawPicture BackGround,0,0
    if OSXGfx = nil then
      OSXGfx = new CGContextGraphicsPort( gBuffer )


      OSXGfx.TranslateCTM(0, gBuffer.Height)
      OSXGfx.ScaleCTM(1.0, -1.0)
    end if
    OSXGfx.ScaleCTM(1.0, -1.0)
    dim r as CGRect = CGRectMake(0,0,gBuffer.Width, gBuffer.Height)
    if ImageOSX = nil then
      dim f as FolderItem
      dim p as Picture
      f = GetFolderItem("Background.png")
      if f.Exists then
        ImageOSX = CGImage.NewCGImage(p.Open(f))
      end if
    end if
    OSXGfx.DrawImage(ImageOSX, r)

  CurrentConnections.Graphics.ForeColor = &c000000
  CurrentConnections.Graphics.FillRect 0,0, CurrentConnections.Width, CurrentConnections.Height

  dim c as ABCable
  for each c in Cables
    c.Draw(gBuffer, DrawMethod)
    ' if it's not the current cable
    if c <> Cables(UBound(Cables)) then
      CurrentConnections.Graphics.ForeColor = c.StartPointColor
      CurrentConnections.Graphics.FillOval(c.StartPoint.x-6, c.StartPoint.y-6, 12,12)
      CurrentConnections.Graphics.ForeColor = c.EndPointColor
      CurrentConnections.Graphics.FillOval(c.EndPoint.x-6, c.EndPoint.y-6, 12,12)
      'if it is, see if it is being dragged
      if not IsDraggingStart then
        CurrentConnections.Graphics.ForeColor = c.StartPointColor
        CurrentConnections.Graphics.FillOval(c.StartPoint.x-6, c.StartPoint.y-6, 12,12)
      end if
      if not IsDraggingEnd then
        CurrentConnections.Graphics.ForeColor = c.EndPointColor
        CurrentConnections.Graphics.FillOval(c.EndPoint.x-6, c.EndPoint.y-6, 12,12)
      end if
    end if
End Sub

The result is this:

ConnectionPoints Principle

Click to enlarge

The first is the result in our Buffer. The second one is the result of the CurrentConnections Drawings. We’ll see the start and end points. The third picture is just to show you where each point in CurrentConnections comes from. So now you see when we use the CheckCables function, we can know exactly which cable and at what end we clicked by checking the pixel color of currentConnections.

Note: the colors in 2 and 3 are faked to make it clear how the principle works. In the real thing, all points are only one integer away from each other, but this is not very visible for us.

And that’s it! There are some help functions like IntegerToColor, ColorToInteger and an extra MouseMove event to hide the cursor but they need no explanation.

This was a fun project I think. Let’s look how it goes in this video:

You can download the full source code here:

This concludes the cable and chains tutorial.


Click here to Donation if you like my work

Xojo: ABPE Physics Engine OpenGL Version

AlwaysBusy Physics Engine Robot Demo

Robot Demo

I’m glad to share with you an update of the Physics Engine for Xojo! Thanks to Will Shank, ABPE now works fullscreen with smooth graphics by using OpenGL. Will did a fabelous job on converting the graphics functions to OpenGL. He also translated this nice Robot Demo to show off some nice capablilities of our Physics Engine.

For me it was a fascinating read to see how stuff is done in OpenGL so dive into the code and check it out for yourself.

Here is a movie of the Robot Demo!

Full source code (Xojo only!) for Windows and OSX can be downloaded from:

Bye for now!

Click here to Donation if you like my work

Xojo/RealBasic: ABPE, the Physics Engine!

ABPE Physics Engine

ABPE Physics Engine

ABPE is a true 2d Newton’s Physics Engine for Xojo and RealBasic! It is the translation of the latest stable (a045) Actionscript Physics Engine engine written by Alec Cove. It uses GDIPlus on Windows and Quartz 2D on Mac to get nice and fast graphics. It’s not an exact translation as some adaptions needed to be done to let it work in Xojo/Realbasic. (They were Actionscript specific). I also added the possiblity to add a texture to the elements. In the attached demo the car and rotator is skinned.

There may be other engines for Xojo, but this one is very easy to use. The basic idea is you can create classes to form ‘objects’ using Rectangles, Circles and Constraints holding the object together. Additional there are some objects like WheelParticles to help you get started. In just a few lines you add them to the engine and they will interact with each other.

Some Features:
– collision detection (Circle-Circle, Rect-Rect, Circle-Rect and Rect-Circle) between groups and within groups
– particles with elasticity, friction, traction, etc…
– Constraints with stiffness that connect particles
– groups of particles and constraints that can interact with each other
– self-buildable forces (like gravity, push, …)
– vector functions
– …

The car you see in the demo for example looks like this:

Sub Constructor(colC as Color, colE as Color)

  wheelParticleA = new ABPEWheelParticle(140, 10, 14, false, 2, 0.3, 0, 1)

  wheelParticleB = new ABPEWheelParticle(200, 10, 14, false, 2, 0.3, 0, 1)

  dim wheelConnector as new ABPESpringConstraint(wheelParticleA, wheelParticleB,0.5, true, 8, 1, false)
End Sub

When all objects are created, you add them to the engine like this:

  ABPEEngine.InitEngine(Canvas1, 0.25)

  dim massLessForces as new ABPEVector(0, 3)

  dim mySurfaces as new Surfaces(colA, colB, colC, colD, colE, colPad)

  dim myBridge as new Bridge(colB, colC, colD)

  dim myCapsule as new Capsule(colC)

  myRotator = new Rotator(colB, colE, colF)

  dim mySwingDoor as new SwingDoor(colC)

  myCar = new Car(colC, colE)



In a timer (set to 18ms), we handle the keys to drive the car, do an engine step and the drawing:

  dim keySpeed as Double = 0.2
  If Keyboard.AsyncKeyDown(&h7B) then
  elseif Keyboard.AsyncKeyDown(&h7C) then
  end if

I’ll try to write some help for this later.

Here is a demo of the engine on RB2007R4 for windows. It is the same on Xojo on Windows and OSX.

And here is the full source code. There are 2 versions:

RB2007R4 (Windows compatible only):

Xojo (Windows and OSX compatible)

Let’s make some games!


Click here to Donation if you like my work

%d bloggers like this: