(This section can be mostly skipped if you’re not very familiar with C or low-level memory management. Just copy the specified code below into your raylib.i file and re-compile your native extension.)

While SWIG does a great job of mapping C constructs into Ruby constructs, there are times when the automated conversion doesn’t work so well. For example, there’s a function for drawing a polygon that takes an array of Vector2 structures. In typical C fashion, the function takes a pointer to the first structure, and a count of how many structures are present in the array:

void DrawPolyEx(Vector2 *points, int numPoints, Color color);

Unfortunately, in Ruby, you won’t be able to allocate space for multiple Vector2 objects contiguously in memory. What we actually want to do is:

Allow passing in a Ruby array, instead of a C array plus a count. Automatically convert that Ruby array into a C array and a count. The converted value should get passed into the underlying C function. Automatically clean up the temporarily allocated C array after the function call.

We can achieve this using a SWIG typemap. This typemap will recognize a particular pattern, namely the two parameters we want to replace in the above method signature. The typemap will then insert some code we specify at the beginning of any auto-generated function that wraps around a matching library function.

Insert the following code into ext/raylib/raylib.i :

%typemap(in, numinputs=1) (Vector2 *points, int numPoints) {

if (!RB_TYPE_P($input, T_ARRAY)) {

SWIG_exception_fail(

SWIG_TypeError,

Ruby_Format_TypeError(

"",

"array of struct Vector2 *",

"DrawPolyEx",

1,

$input));

} $2 = RARRAY_LEN($input);

$1 = malloc($2 * sizeof(Vector2)); for (int i = 0; i < $2; i++) {

VALUE entry = rb_ary_entry($input, i); void *vec2;

int res = SWIG_ConvertPtr(entry, &vec2, SWIGTYPE_p_Vector2, 0); if (!SWIG_IsOK(res)) {

SWIG_exception_fail(

SWIG_ArgError(res),

Ruby_Format_TypeError(

"wrong array element type: ",

"struct Vector2 *",

"DrawPolyEx",

i + 1,

entry));

} $1[i] = *(Vector2 *)(vec2);

}

};

The code does the following:

Check if the single input (instead of the two we would have gotten automatically) is a Ruby array. Set the count that will be passed to the underlying library function. The count is determined by using the Ruby C API to read the length of the passed in Ruby array. Allocate a C array and set this to the actual argument that will be passed to the underlying library function. Initialize this array by going through the Ruby array, converting each element to Vector2 * and storing it in the C array.

This process allocates a new array on the heap (it may be possible to allocate on the stack, but I haven’t gotten that working yet). This means, after the call to the underlying library function, we need to free the newly-allocated memory. Again, we can use a SWIG typemap, which we insert into the same file:

%typemap(freearg) (Vector2 *points, int numPoints) {

free($1);

}

This is one more place where we need custom code specific to Raylib’s functionality. Once again, this does mean our extension is more sensitive to updates in Raylib’s API, but I don’t know of a way around this.

Finally, there are a handful of Raylib functions that return a pointer to a heap-allocated array. This is in contrast to returning a structure by value, like most functions in the library. One example of such a function is GetImageData(Image) , which returns an array of Color . Because I haven’t used this function in Ruby, I don’t know what additional work I need to do in order to support its use.

Wrapping Raylib with more idiomatic Ruby

It’s already nice to access Raylib from Ruby, but the resulting code isn’t always the most idiomatic. Other interfaces to Raylib often spend enough time creating the wrapper by hand that it becomes hard to create higher-level abstractions over the C-style APIs. Because SWIG saved us so much work, I’ve found it easier to create some of these abstractions.

Constructing Raylib structures

I discussed in my last post that SWIG wraps Raylib struct s using Ruby classes. These classes are given no-parameter constructors, along with getters and setters for each of the structure’s fields. This makes constructing objects of these types verbose. For example, to create a reddish-brownish color, you need to write:

color = Color.new

color.r = 128

color.g = 64

color.b = 32

color.a = 255

You can, as I said before, create a helper method inside the Raylib module to create and initialize colors more conveniently. However, we can go one step further and re-define a class’ constructor. The important part is to call the original, SWIG-defined constructor in this new constructor so as to perform the initialization SWIG set up for us:

module Raylib

class Color

# Re-define the auto-generated constructor so parameters can be passed

# during initialization. alias_method :swig_initialize, :initialize

def initialize(r, g, b, a = 255)

swig_initialize

self.r = r

self.g = g

self.b = b

self.a = a

end

end

end color = Raylib::Color.new(128, 64, 32)

Abstracting common patterns using blocks

When experimenting with many small Raylib-based applications, I found myself writing the same top-level structure over and over again:

Raylib.InitWindow(500, 500, "Window title") Raylib.SetTargetFPS(30)

until Raylib.WindowShouldClose

# Do some per-frame processing like checking inputs Raylib.BeginDrawing

Raylib.ClearBackground(RAYWHITE)

# Call the drawing APIs

Raylib.EndDrawing

end Raylib.CloseWindow

The use of WindowShouldClose , BeginDrawing and EndDrawing felt like low-level APIs that could be abstracted over. In C, this is harder to achieve because the part that changes from application to application is the code inside the loop and the drawing block. Ruby, on the other hand, provides us with a powerful tool to implement this abstraction: blocks.

First, I collapsed the main loop with the FPS configuration, since the loop runs at the specified FPS. I also collapsed the closing of the window, as I always wanted to close the window when the main loop finished.

module Raylib

def self.main_loop(fps: 30)

Raylib.SetTargetFPS(fps) yield until Raylib.WindowShouldClose

Raylib.CloseWindow

end

end

My next abstraction collapsed the BeginDrawing and EndDrawing calls together. This is not only a convenience, but a safety feature, as EndDrawing is what allows the application to sleep in between frames instead of using up 100% of the CPU. With this abstraction, it’s not possible to forget the EndDrawing call.

I also found myself always clearing the background on each frame, as I redrew the frame based on the latest data. For this reason, I decided to collapse the ClearBackground call into this abstraction as well.

module Raylib

def self.draw_with_background(background_color)

Raylib.BeginDrawing Raylib.ClearBackground(background_color)

yield Raylib.EndDrawing

end

end

With these two abstractions, my top-level application structure is terser, freeing me to expend more cognitive load on the code unique to each application.

Raylib.InitWindow(500, 500, "Window title") Raylib.main_loop(fps: 30) do # we can omit the FPS if we want 30 FPS

# Do some per-frame processing like checking inputs Raylib.draw_with_background do

# Call the drawing APIs

end

end

Automating the build process