Category Archives: Canvas

ABXPlay for Xojo is dead, long live ABMXPlay for B4J!

abmxplaylogo

As many will have noticed in the last year,  there are fewer articles about Xojo on Alwaysbusy’s Corner.  I do like to write graphics projects/frameworks and Xojo is more a language for business apps. Over the years, I’ve written several ‘Proof of Concept’ articles on graphics programming with RB/Xojo.  And although the algorithms could be written, I always quickly hit a wall when it came to speed. I sometimes get requests to update the existing articles, but IMHO, Xojo is becoming the new VB6.  Just like at the end of the popular VB6, using declares in Xojo are in many cases the only solution to make your program work in a modern way.

But it has been fun and I’m sure Xojo can be used to write several other type of projects. I have no regrets having learned RB/Xojo in the past.

But in this view, I have discontinued the ABXPlay for Xojo project and decided to start all over again with ABMXPlay for B4J as a ABMaterial 2.0 component. B4J is excellent when it comes to pure speed in WebApps and that is exactly what is needed for a game framework.

The complete rewrite of ABMXPlay for B4J is better than the Xojo version.  It is integrated in ABMaterial so it can make use of this engine too.  As the B4J syntax is a lot easier than the one in Xojo to interpret (it is very similar to what RB used to be) and the used file format is plain text, I’m working on a B4JS transpiler that will translate B4J code to Javascript.  This changes everything massively!  While still being able to write simple Basic syntax, you are actually writing powerful and fast client side Javascript.

ABMXPlay is going to be the first ABMaterial component with this functionality. In the following months, I’ll gradually will introduce this to other ABMaterial components as they can equally benefit from B4JS. Imagine having a form, being able to check the input fields, making some price calculations etc without having to talk to the server.  Only when the user hits the ‘buy’ button, an actual request is made to the server.  And for you as a programmer, all you have to do is continue programming in B4J as you always did!

So, still a lot of work to do. Coffee and Red bull will be my best friends in the upcoming nights. But it is going to be worth it!

Note: ABXVision for Xojo is also DISCONTINUED: Interested parties in purchasing the source code for the Xojo versions can contact me via email.

Until the next update,

Alwaysbusy

Click here to Donation and support ABMaterial


Xojo: Sketching with Real-time Contrast Preserving Decolorization and Potrace

Sketcher

Always looking for some ways to learn the computer to ‘see’, I came accross two very interesting algorithms: ‘Real-time Contrast Preserving Decolorization’ by Cewu Lu, Li Xu and Jiaya Jia. And Potrace by Peter Selinger

Decolorization – the process to transform a color image to a grayscale one – is a basic tool in digital printing, stylized black-and-white photography, and in many single channel image processing applications. RTCPD is aiming at maximally preserving the original color contrast alleviate a strict order constraint for color mapping based on human vision system.

An example can be seen here:
RTCPD

The second algorithm Potrace(TM) is a tool for tracing a bitmap, which means, transforming a bitmap into a smooth, scalable image.

Example:
potrace

Playing around with both algorithms, I came up with the idea to use them for a project I had in mind for some time: Sketching pictures on my wall using a Pico projector.

First I had to implement both algorithms in Xojo. The result of RTCPR can be found in the attached source code in the RTCPRGB2Gray() method:

Private Sub RTCPRGB2Gray(pic as Picture)
  dim imcols as Integer = pic.Width
  dim imrows as Integer = pic.Height
  dim sRGB as RGBSurface = pic.RGBSurface

  dim Mat(-1,-1) as ABDoubleVector
  redim Mat(imrows-1,imcols-1)
  dim c as Color
  for y as Integer = 0 to  imrows - 1
    for x as Integer = 0 to imcols - 1
      c = sRGB.Pixel(x,y)
      mat(y,x) = new ABDoubleVector(c.Blue, c.Green, c.Red) ' switch to BRG
    next
  next

  dim s as Double = 64.0 / sqrt(imcols*imrows)
  dim cols as Integer = (s * imcols) + 0.5
  dim rows as Integer = (s * imrows) + 0.5

  dim sigma as Double = 0.05
  dim W() as ABDoubleVector = wei()

  dim P() as ABDoubleVector
  dim det() as Double

  dim pos0() as ABDoublePoint
  dim pos1() as ABDoublePoint
  for i as Integer = 0 to cols - 1
    for j as Integer = 0 to rows - 1
      dim x as Integer = (i+0.5) * imcols/cols
      dim y as Integer = (j+0.5) * imrows/rows
      pos0.Append new ABDoublePoint(x,y)
      pos1.Append new ABDoublePoint(x,y)
    next
  next

  pos1.Shuffle

  for i as Integer = 0 to pos0.Ubound
    dim c0 as ABDoubleVector = mat(pos0(i).y, pos0(i).x)
    dim c1 as ABDoubleVector = mat(pos1(i).y, pos1(i).x)

    add c0,c1, P, det
  next

  cols = cols / 2
  rows = rows / 2

  for i as Integer = 0 to cols - 2
    for j as integer = 0 to rows - 1
      dim x0 as integer = (i + 0.5) * imcols / cols
      dim x1 as integer = (i + 1.5) * imcols / cols
      dim y as integer = (j + 0.5) * imrows / rows

      dim c0 as ABDoubleVector = mat(y, x0)
      dim c1 as ABDoubleVector = mat(y, x1)

      add(c0, c1, P, det)
    next
  next

  for i as integer = 0 to cols - 1
    for j as Integer = 0 to rows - 2
      dim x as integer = (i + 0.5) * imcols / cols
      dim y0 as integer = (j + 0.5) * imrows / rows
      dim y1 as integer = (j + 1.5) * imrows / rows

      dim c0 as ABDoubleVector = mat(y0, x)
      dim c1 as ABDoubleVector = mat(y1, x)

      add(c0, c1, P, det)
    next
  next

  dim maxES as Double = -99999999999
  dim bw as Integer
  for i as integer = 0 to w.Ubound
    dim es as Double
    for j as integer = 0 to p.Ubound
      dim l as Double = P(j).x * W(i).x + P(j).y * W(i).y + P(j).z * W(i).z
      dim detM as Double = det(j)

      dim a as double = (L + detM) / sigma
      dim b as double = (L - detM) / sigma

      es = es + log(exp(-a * a) + exp(-b * b))
    next
    es = es / (p.Ubound+1)
    if eS > maxEs then
      maxEs = Es
      bw = i
    end if
  next

  dim result(-1,-1) as Double
  redim result(imrows-1,imcols-1)

  for y as Integer = 0 to  imrows - 1
    for x as Integer = 0 to imcols - 1
      result(y,x) = mat(y,x).z*W(bw).x + mat(y,x).y*w(bw).y+0
      result(y,x) = mat(y,x).x*W(bw).z + result(y,x)*1+0
      sRGB.Pixel(x,y) = rgb(result(y,x),result(y,x),result(y,x))
    next
  next

  bw = 0
End Sub

Potrace is a complete framework to trace an image and converting it to Xojo did take some time. While writing it, I also made some changes to it to optimize the result. One of it was doing my own thresholding using the surrounding pixels to smoothen the edge detection.

Snippet:

  dim v, v1, v2, v3, v4, v5, v6, v7, v8 as Integer
  dim ex,ey, weight, weighttotal, total as Double

  'SISThreshold2 alain
  for y = 1 to H - 2
    for x = 1 to W - 2
      v = sDebugPicRGB.Pixel(x, y).red
      v1 = sDebugPicRGB.Pixel(x+1, y).red
      v2 = sDebugPicRGB.Pixel(x-1, y).red
      v3 = sDebugPicRGB.Pixel(x, y+1).red
      v4 = sDebugPicRGB.Pixel(x, y-1).red
      v5 = sDebugPicRGB.Pixel(x+1, y-1).red
      v6 = sDebugPicRGB.Pixel(x-1, y-1).red
      v7 = sDebugPicRGB.Pixel(x+1, y+1).red
      v8 = sDebugPicRGB.Pixel(x-1, y+1).red
      ex = (v1+v2+v5+v6)/4
      ey = (v3+v4+v7+v8)/4
      if ex > ey then
        weight = ex
      else
        weight = ey
      end if
      weighttotal = weighttotal + weight
      total = total + weight * (v)
    next
  next

  dim  Threshold as Integer = 128

  if weighttotal <> 0 then
    Threshold = total/weighttotal
  end if

  dim ret as Boolean = (sDebugPicRGB.Pixel(0, 0).Red >= Threshold)

  for y = 0 to H
    for x = 0 to W
      c = sDebugPicRGB.Pixel(x, y)
      if c.red >= Threshold then
        Matrix(x+1, y + 1) =true
      else
        Matrix(x+1, y + 1) = false
      end if
    next
  next 

  for x = 0 to MatrixW
    Matrix(x,0) = true
    Matrix(x, MatrixH) = true
  next
  for y = 0 to MatrixH
    Matrix(0,y) = true
    Matrix(MatrixW, y) = true
  next

This gave me all the tools to start tracing an image. But for my project I wanted to have a sort of ‘sketchy’ feeling. For this I needed a couple of things because I wanted the drawing and painting to be done gradually. I had to build it with delays, repetition, randomization and color fading. I wanted to start from a picture and create something like this:
jobs

DrawImage() does all that. It first draws the beziers with some little random mistakes in grey. A gradual painting is then used to fill in the polygons. Finaly it repeats the process with the correct lines in white.

You may notice that a lot of code is redundant, but this is intended because I needed to have enough delays to mimic a more natural feeling.

Here is a demo video showing the result of this project on my wall. It takes about ten seconds before it starts drawing as I had to grab my camera :-). Five different images are drawn.

The project with full source code can be downloaded here

Greetz!

Alwaysbusy

Click here to Donation if you like my work


Xojo: CHIP-8 Emulator

CHIP-8
Some weeks ago, Ashot Khachatryan contacted me on the Xojo forum with the question if I would be interested in writing a CHIP-8 Emulator in Xojo. I had no knowledge of the system and he had written a good part of an Emulator himself. It had some hard to find bugs in it and he was kind of stuck. As it is hard to debug someone elses code, especially if the subject is not very well known, I decided to start from scratch. Or, to say it in Barney Stinsons words, Challenge accepted!

CHIP-8 is an interpreted programming language, developed by Joseph Weisbecker. It was initially used on the COSMAC VIP and Telmac 1800 8-bit microcomputers in the mid-1970s. CHIP-8 programs are run on a CHIP-8 virtual machine. It was made to allow video games to be more easily programmed for said computers. Input is done with a hex keyboard that has 16 keys which range from 0 to F. The ‘8’, ‘4’, ‘6’, and ‘2’ keys are typically used for directional input.

There are a number of classic video games ported to CHIP-8, such as Pong, Space Invaders, Tetris, and Pac-Man.

So, the big question was, could we write a CHIP-8 CPU Emulator in Xojo? It needs to be able to read ROMS, interpret Opcodes, show it on the 64×32 pixels screen and handle input. An Opcode is a two bytes code like 00E0 (Clears the screen).

The ‘Virtual Machine’ ABCH8CPU would need to handle a couple of things:
Screen: a picture of 128×64 pixels
Memory: 4096 bytes. I decided a memoryblock would be ideal in Xojo to handle this
Registers: a CHIP-8 has 16 8-bit registers (V0-VF). A Byte array will be used
Timers: a byte array of size 2
Sound: Beep is used
Input: the Keyboard.AsynckeyDown() method would handle the state of the 16 keys.

There are a number of projects on the net in other programming languages available. (Just google CHIP-8 source code). I’ve studied several of them before I’ve wrote my Xojo version.

Here is the result (didn’t spend much time on the GUI):

ABChip8
It can handle CHIP ROMs and SCHIP (Super CHIP) ROMs. Unfortunately, speed is terrible. Xojo may not have been the right language to write this project in, but look at it as a proof of concept. And it can probably be optimized too, as I wrote this emulator in an evening or two.

You can change the keyboard (AZERTY/QUERTY) to emulate the 16-Keys keyboard. A memory dump and a list with the interpreted Opcodes is also shown.

All in all, this was a fun project to do!

The Xojo source code and some ROMs: http://gorgeousapps.com/ABCHIP8.zip

Bye for now!

Alwaysbusy

Click here to Donation if you like my work


Xojo: ABXPlay alpha 0.7

 

ABXPlay

DISCONTINUED and replaced by ABMXPlay in ABMaterial 2.0 for B4J. Interested parties in the source code for the Xojo version can contact me via email.

ORIGINAL ARTICLE:

It has been a while since my last post, but I’ve been busy. This is the first alpha release of ABXPlay! For now it is closed source as I want to keep control over changes and bugs, but it will probably be open source when the final version arrives.

ABXPlay is an advanced WebGL control for Xojo with a fall back to a HTML5 Canvas if the browser does not support WebGL.

Features:
Drawing of primitives (line, rectangles, circles, arcs, polygons, curves, …)
Sprites and Textures
Container objects that group primitives and other containers
Scaling, Alpha, Rotation, Position Tweening for all Containers
Drag/Drop of Containers
Multi user events
Audio support
Emitters
Spritesheets and Spines
Javascript injection
Filters and Shaders
Text (fonts, Google fonts and Bitmap fonts)
Basic DOM object support

Experimental
Basic Box2D support
Basic TMX support

Included is the help, all the examples shown in the Xojo forum posts with source code and of course the ABXPlay engine/control.

You can download alpha 0.7 here .
The help is included in the download, but can also be consulted here

For those who followed the adventures of our South Park friends, You’ll notice a final chapter. Although Chef solved the Kenny Ghost problem, it seems Eric still is suffering a bit. When he want’s to play some football (yes, I mean football, not soccer), one Kenny keeps giving him trouble!

This illustrates some basic Box2D support. (Physics engine, Collisions, Joints).

Box2D in ABXplay

Notes:

1. If you create a new project, make sure the control is locked on all sides of the window
2. Set the properties on the control in the inspector (like the view properties, if it should be interactive, the Scaletype, etc…)
3. Assets should be copied in the subfolder \Assets\ next to your project.
4. Make sure also the \Engines\ folder is next to your project!
5. To test another example, change the ‘DefaultWebPage’ to another one of the example WebPages.

But most of all, have fun with it!

Alwaysbusy

Click here to Donation if you like my work


Xojo: Nintendo Game & Watch Mario Bros

Mario Bros in Xojo Box
Last weekend I found back my old Nintendo Game & Watch game Mario Bros under some dust. I remember having a good time with this old game console. So why not rebuild it in Xojo?

I found some graphics and sounds on the internet and started rebuilding the game. A couple of evenings later, here it is!

I’m not 100% sure the gameplay is exactly the same as on the real console as the original source code is not released by Nintendo, but I think I’m close. Check out the video:

Use the mouse to:
1. start the games (Game A, Game B).
2. run a demo play (Time)
3. navigate Mario and Luigi up/down

Use the keyboard keys to:
1. ESC to close the game
2. D to move Luigi Up, C to move Luigi down
3. Upkey to move Mario Up, DownKey to move Mario Down.

Note: if you have problems moving Luigi (make sure caps lock is ON), or change the code in the canGame canvas KeyDown event to:

 select case asc(key)
    case 30 ' keyUp
      MyGame.Mario.Up
    case 31 ' keydown
      MyGame.Mario.Down
    case 68, 100  'd, D
      MyGame.Luigi.Up
    case 67, 99 ' c, C
      MyGame.Luigi.Down
    end select

Thanks to Alwyn for pointing this out!

You can download the full source here.
And the binaries (Windows & OSX) here.

Bye for now,

Alwaysbusy

Click here to Donation if you like my work


Xojo: Comanche 3D in about 100 lines UPDATE

Tomas made HUD and Maps active!

Tomas made HUD and Maps active!

A quick update with a much smoother and faster version of the ABComanche article. This one is using some tricks out of the ABXVision framework using Memoryblocks and pointers. (Don’t worry, sound worse than it is).

You can download this new version here

I’ve been amazed how many people enjoyed playing with this! Some of you made great additions like the HUD display, camera views and added sound. Thanks Tomas Jakobs for this! Will Shank even made a OpenGL viewer for the maps. It’s not using the voxel engine discribed in the previous article but it looks great!

Will Shanks OpenGL version!

Will Shanks OpenGL version!

Check out the Xojo forum post for their creations!

Cheers!

Alwaysbusy

Click here to Donation if you like my work


Xojo: Building Comanche 3D in 100 lines

Comanche: Maximum Overkill

Comanche: Maximum Overkill

If you are a child of the 90s, you certainly will remember Comanche: Maximum Overkill. The graphics were awesome and way ahead of its time. Remember, we did’t have fancy 3D accelerated graph cards. They used a technique called voxel space. Using only a picture containing the colors and another one with the depths they displayed wonderful landscapes on your screen. With your Comanche chopper you could fly over this landscape, diving towards the enemy. It was fun! I’ve must have spend hundreds of hours playing with this.

It is surprising how little code is needed to reproduce this experience. In this article, we’ll build the 3D world and will be able to fly, dive etc over the landscape with Xojo in less than 100 lines of code! The code is based on the work of Sebastian Macke.

First some background on the algorithm. Voxel Space is very similar to raycasting (the technique used in games like *Wolfenstein 3D, the old one). The algorithm draws simply perspectively correctly vertical lines by shooting a ray from the camera into the map. This image illustrates this:

Voxel Space Raytracing

Voxel Space Raytracing

*Note: I first had Doom also listed but thedeemon at Reddit pointed out Doom uses another algorithm, BSP trees (binary space partition).

The algorithm goes like this:
1. For every column of the screen define a light ray which starts at the camera and ends at the horizon somewhere far away.
2. Divide the ray into very small segments so that every pixel lying on the map is considered.
3. Load the height and color from the 2D maps corresponding to the position on the ray.
4. Do some clever perspective corrections for the height coordinate. This is the hard part of the algorithm but it uses some easy math.
5. Draw a vertical line with the corresponding color with the height retrieved from the perspective correction.

So we need two pictures to do this. One containing the colors and one with the depth levels (0 – 255). The original Comanche game used 1024×1024 pictures, so that’s what we are going to do. Here is an example of both maps:

Example color and depth maps

Example color and depth maps

Ok, let’s do some code! This is what we’re going to build:

Example screen of what we will build

Example screen of what we will build

In the Open event we initialize some pictures

Sub Open()
  ' initialize the buffers
  mBuffer = new Picture(1024,768,32)
  mBuildBuffer = new Picture(VoxWidth, VoxHeight, 32)
  mBuildBufferRGB = mBuildBuffer.RGBSurface

  ' create the chopper picture with the transparent areas
  Chopper = new Picture(1024,768,32)
  Chopper.Graphics.DrawPicture Comanche,0,0
  Chopper.Mask.Graphics.DrawPicture ComancheMask,0,0

  ' load a map
  CurrentMap = 1
  LoadMap(CurrentMap)
End Sub

LoadMap is just a simple method to load the maps and reinitialize our start position:

Sub LoadMap(MapID as integer)
  dim x,y as Integer
  'Initialize the position and the lookup/lookdown vars
  xp = 512
  yp = 800
  hp = -50
  vp = -100

  ' prebuild the tables holding the pixel data of the map and depthmap to speed things up
  select case MapID
  case 1
    VoxelMapRGB = C1W.RGBSurface
    for y = 0 to 1023
      for x = 0 to 1023
        VoxelHeight(y,x) = C1D.RGBSurface.Pixel(y,x).Red
      next
    next
  case 2
    VoxelMapRGB = C2W.RGBSurface
    for y = 0 to 1023
      for x = 0 to 1023
        VoxelHeight(y,x) = C2D.RGBSurface.Pixel(y,x).Red
      next
    next
  case 3
    VoxelMapRGB = C3W.RGBSurface
    for y = 0 to 1023
      for x = 0 to 1023
        VoxelHeight(y,x) = C3D.RGBSurface.Pixel(y,x).Red
      next
    next
  case 4
    VoxelMapRGB = C4W.RGBSurface
    for y = 0 to 1023
      for x = 0 to 1023
        VoxelHeight(y,x) = C4D.RGBSurface.Pixel(y,x).Red
      next
    next
  end select

  ' Draw!
  Update
End Sub

Now, we just have to make our algorithm. The Update function will go over every vertical line and calculate what needs to be drawn to mimic the 3D view.

Sub Update()
  dim i as Integer
  dim x3d, y3d, rotx, roty as Double

  ' draw the sky first on the end picture
  mBuildBuffer.Graphics.DrawPicture Sky,0,0

  y3d = -VoxDepth

  ' update the view. Calculate the rotation and raycast every line
  while i < VoxWidth
    x3d = (i - VoxWidth / 2) * 1.5

    rotx =cos(angle) * x3d + sin(angle) * y3d
    roty = -sin(angle) * x3d + cos(angle) * y3d

    raycast(i, xp, yp, rotx + xp, roty + yp, y3d / sqrt(x3d * x3d + y3d * y3d))
    i = i + 1
  wend

  ' draw the result on the end picture
  mBuffer.Graphics.DrawPicture mBuildBuffer, 0,0, 1024, 512, 0,0,512,256
  ' draw the chopper overlay
  mBuffer.Graphics.DrawPicture Chopper,0,0

  ' refresh the canvas
  Canvas1.Refresh(False)
End Sub

And our Raycast method that will build the result:

Sub Raycast(line as integer, x1 as double, y1 as double, x2 as double, y2 as double, d as double)
  ' The magic! Raycast on the current line. 

  ' line: vertical line to compute
  ' x1, y1: initial points on map for ray
  ' x2, y2: final points on map for ray
  ' d: correction parameter for the perspective

  dim dx,dy as Double
  dx = x2 - x1
  dy = y2 - y1

  dim r as Double = sqrt(dx * dx + dy * dy)
  dx = dx / r
  dy = dy / r

  dim yMin as Integer = 256
  dim i,k as Integer
  dim h as Integer
  dim ci as Color
  dim y3 as Double
  dim z3 as Integer

  while i < r-20
    i = i + 1
    x1 = x1 + dx
    y1 = y1 + dy
    if x1 > 0 and y1 > 0 and x1 < 1024 and y1 < 1024 then
      ' get the height
      h = VoxelHeight(x1, y1)
      ' get the color
      ci = VoxelMapRGB.Pixel(x1, y1)

      ' calculate the ray depth. Do some perspective correction for the height.
      h = 256 - h
      h = h - 128 + hp
      y3 = abs(d) * i
      z3 = h / y3 * 100 - vp

      if (z3 < 0) then z3 = 0
      if (z3 < voxHeight) then
        k = z3
        While k < ymin
          ' draw a vertical line with the corresponding color with the height retrieved from the perspective correction
          mBuildBufferRGB.Pixel(line, k) = ci
          k = k + 1
        wend
      end if

      if (ymin > z3) then
         ymin = z3
      end if
    end if
  wend
End Sub

Finally the key handeling on the Canvas:

Sub KeyDown(Key as String) as Boolean
    elect case key
  case "4" ' left
    angle = angle + 0.1
  case "6" ' right
    angle = angle - 0.1
  case "8" ' forward
    xp = xp - 2.0 * sin(angle)
    yp = yp - 2.0 * cos(angle)
  case "2" ' backward
    xp = xp + 2.0 * sin(angle)
    yp = yp + 2.0 * cos(angle)
  case "7" ' up
    hp = hp + 2
  case "1" ' down
    hp = hp - 2
  case "9" ' look up
    vp = vp + 2
  case "3" ' look down
    vp = vp - 2
  case "m", "M" ' cycle through the maps
    CurrentMap = CurrentMap + 1
    if CurrentMap = 5 then CurrentMap = 1
    LoadMap(CurrentMap)
    Return true
  end select

  ' update with the new params
  Update

  Return true
End Sub

Note: Alwyn Bester noticed some problems with the key navigation and did this to fix it:

…Just a quick one, not sure if it’s a focus thing on Windows, but I had to move the KeyDown code from the Canvas event to the keydown event of the Form, for the navigation to work…

Done! Here is a video demonstrating what we just build with 100 lines of Xojo code:

Are Voxel engines a thing of the past? I don’t think so. As a matter of fact they are very hot nowadays. Being able to use 3D acceleration is producing some interesting engines like VoxelFarm and Atomontage. Check this last one out if you are interested in such engines.

Note: This is the original version of this article. There is a newer faster version in this article UPDATE

You can download the source code here.
Or the binaries here if you do not have Xojo.

The keys to play with it are:

Use the KeyPad!

Use the KeyPad!

Note: “M” to cycle through the maps!

See ya!

Alwaysbusy

Click here to Donation if you like my work


%d bloggers like this: