Advertisement
Scroll to top

Processing is one of the most powerful libraries available today for creating visual algorithmic artworks, both 2D and 3D. It is open source, based on Java, and comes with a large variety of functions geared to making drawing and painting with code both fun and easy.

By using Processing's core library in your Android apps, you can create high-performance graphics and animations without having to deal with Android's OpenGL or Canvas APIs. Usually, you won't even have to bother with low-level tasks such as managing threads, creating render loops, or maintaining frame rates.

In this tutorial, I'll show you how to add Processing to an Android app and introduce you to some of its most useful features.

1. Project Setup

Processing comes with its own integrated development environment, which can be used to create Android apps. However, if you are an Android app developer already, I'm sure you'd prefer to use Android Studio instead. So go ahead and download the latest version of Processing's Android Mode.

Inside the ZIP file you downloaded, you'll find a file named processing-core.zip. Extract it and rename it to processing-core.jar using the command line or your operating system's file explorer.

Lastly, add the JAR file as one of the dependencies of your Android Studio project by placing it inside the app module's libs folder.

You now have everything you need to start using Processing.

2. Creating a Canvas

Almost all of Processing's core functionality is available through the PApplet class, which essentially serves as a canvas you can draw on. By extending it, you get easy access to all the methods it has to offer.

1
val myCanvas = object: PApplet() {
2
    // More code here

3
}

To configure the canvas, you must override its settings() method. Inside the method, you can specify two important configuration details: the desired dimensions of the canvas and whether it should use the 2D or the 3D rendering engine. For now, let's make the canvas as large as the device's screen and use the default 2D rendering engine. To do so, you can call the fullScreen() shortcut method.

1
override fun settings() {
2
    fullScreen()
3
}

The settings() method is a special method that's needed only when you are not using Processing's own IDE. I suggest you don't add any more code to it.

If you to want to initialize any variables or change any drawing-related parameters—such as the background color of the canvas or the number of frames it should display per second—you should use the setup() method instead. For example, the following code shows you how to use the background() method to change the background color of the canvas to red:

1
override fun setup() {
2
    background(Color.parseColor("#FF8A80")) // Material Red A100

3
}

3. Displaying the Canvas

Because the canvas is still not a part of any activity, you won't be able to see it when you run your app. To display the canvas, you must first create a container for it inside your activity's layout XML file. A LinearLayout widget or a FrameLayout widget can be the container.

1
<FrameLayout
2
    android:layout_width="match_parent"
3
    android:layout_height="match_parent"
4
    android:id="@+id/canvas_container">
5
    
6
</FrameLayout>

A PApplet instance cannot be directly added to the container you created. You must place it inside a PFragment instance first and then call the setView() method of the PFragment instance to associate it with the container. The following code shows you how to do so:

1
// Place canvas inside fragment

2
val myFragment = PFragment(myCanvas)
3
4
// Display fragment

5
myFragment.setView(canvas_container, this)

At this point, if you run the app, you should be able to see a blank canvas covering the entire screen of your device.

Blank canvas with red backgroundBlank canvas with red backgroundBlank canvas with red background

4. Drawing Simple Shapes

Now that you are able to see the canvas, let's start drawing. To draw inside the canvas, you must override the draw() method of the PApplet subclass you created earlier.

1
override fun draw() {
2
    // More code here

3
}

It might not seem obvious immediately, but Processing, by default, tries to call the draw() method as often as 60 times every second, as long as the canvas is being displayed. That means that you can easily create both still graphics and animations with it.

Processing has a variety of intuitively named methods that allow you to draw geometric primitives such as points, lines, ellipses, and rectangles. For instance, the rect() method draws a rectangle, and the ellipse() method draws an ellipse. Both the rect() and ellipse() methods expect similar arguments: the X and Y coordinates of the shape, its width, and its height.

The following code shows you how to draw a rectangle and an ellipse:

1
rect(100f, 100f, 500f, 300f) // Top-left corner is at (100,100)

2
ellipse(350f, 650f, 500f, 400f) // Center is at (350,650)

Many of the methods are overloaded too, allowing you to slightly modify the basic shapes. For example, by passing a fifth parameter to the rect() method, a corner radius, you can draw a rounded rectangle.

1
rect(100f, 900f, 500f, 300f, 100f) // Corner radius of 100 pixels

If you run your app now, you should see something like this:

Simple shapes drawn with default colorsSimple shapes drawn with default colorsSimple shapes drawn with default colors

If you want to change the border color of the shapes, you can call the stroke() method and pass the desired color as an argument to it. Similarly, if you want to fill the shapes with a specific color, you can call the fill() method. Both the methods should be called before you actually draw the shape.

The following code draws a blue triangle with a green outline:

1
stroke(Color.GREEN)
2
fill(Color.BLUE)
3
triangle(100f, 1600f, 300f, 1300f, 500f, 1600f)

If you run your app now, you'll be able to see the blue triangle, but you'll also notice that every other shape has also turned blue.

Fill and stroke applied to all shapesFill and stroke applied to all shapesFill and stroke applied to all shapes

If the reason isn't obvious to you already, remember that the draw() method is called repeatedly. That means that any configuration parameter you change during a draw cycle will have an effect on subsequent draw cycles. So in order to make sure that all your shapes are drawn with the right colors, it is a good idea to always explicitly specify the color of every shape you draw, right before you draw it.

For instance, by adding the following code at the beginning of the draw() method, you can make the other shapes white again.

1
// Set the fill and stroke to white and black

2
// before drawing the rectangles and ellipses

3
stroke(Color.BLACK)
4
fill(Color.WHITE)

At this point, the canvas will look like this:

Different fills and strokes for different shapesDifferent fills and strokes for different shapesDifferent fills and strokes for different shapes

5. Handling Touch Events

With Processing, handling touch events is extremely easy. You don't need any event handlers whatsoever. All you need to do is check if a boolean variable named mousePressed is true to know when the user is touching the screen. Once you've confirmed that the user is touching the screen, you can use the mouseX and mouseY variables to determine the X and Y coordinates of the touch.

For example, the following code draws a new rectangle wherever the user touches the canvas.

1
// Check if user is touching the canvas

2
if(mousePressed) {
3
    // Specify fill and stroke colors

4
    stroke(Color.RED)
5
    fill(Color.YELLOW)
6
    
7
    // Draw rectangle

8
    rect(mouseX.toFloat(), mouseY.toFloat(), 100f, 100f)
9
}

If you run your app now and drag your finger across the screen, you should see a lot of yellow rectangles being drawn.

Rectangles drawn on touchRectangles drawn on touchRectangles drawn on touch

Before we move on, here's a quick tip: if at any point you wish to clear the canvas, you can simply call the background() method again.

1
background(Color.parseColor("#FF8A80")) // Material Red A100

6. Working With Pixels

There's only so far you can get with simple primitives. If you are interested in creating intricate and complex artwork, you'll probably need access to the individual pixels of the canvas.

By calling the loadPixels() method, you can load the colors of all the pixels of the canvas into an array named pixels. By modifying the contents of the array, you can very efficiently modify the contents of the canvas. Lastly, once you've finished modifying the array, you should remember to call the updatePixels() method to render the new set of pixels.

Note that the pixels array is a one-dimensional, integer array whose size is equal to the product of the width and height of the canvas. Because the canvas is two-dimensional, converting the X and Y coordinates of a pixel into a valid index of the array involves use of the following formula:

1
// index = xCoordinate + yCoordinate * widthOfCanvas

The following example code, which sets the color of each pixel of the canvas based on its X and Y coordinates, should help you better understand how to use the pixels array:

1
override fun draw() {
2
    loadPixels() // Load array

3
4
    // loop through all valid coordinates

5
    for(y in 0..height - 1) {
6
        for(x in 0..width - 1) {
7
8
           // Calculate index

9
           val index = x + y * width
10
11
           // Update pixel at index with a new color

12
           pixels[index] = Color.rgb(x % 255, y % 255, (x*y) % 255)
13
        }
14
    }
15
16
    // Render pixels with new colors

17
    updatePixels()
18
}

The Color.rgb() method you see above converts individual red, green, and blue values to an integer that represents a single color value that the Processing framework understands. Feel free to modify the arguments you pass to it, but do make sure that they are always within the range 0 to 255.

If you choose to run the code without any modifications, you should see a pattern that looks like this:

Modified pixels array rendered on canvasModified pixels array rendered on canvasModified pixels array rendered on canvas

Conclusion

You now know how to create 2D graphics using the Processing language. With the skills you learned today, you can not only make your Android apps more appealing, but also create full-fledged games from scratch. You are limited only by your creativity!

To learn more about Processing, I suggest you spend some time browsing through the official reference pages.

And while you're here, check out some of our other posts on Android app development!

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.