Macaroni Isis software documentation


Macaroni is a library of Isis objects for handling complex two-dimensional compositions of visual geometry, images, and video. You can create objects such as rectangles, lines, images, movies, etc., and combine these into complex scenes to be rendered in real-time. Each object can be transformed in a variety of ways by modifying position, scale, rotation, color, opacity, and other attributes.

Macaroni uses OpenGL to do all of its rendering and the GLUT library for handling window operations. You can extend on Macaroni's functionality by writing your own Macaroni objects or by calling OpenGL and GLUT routines directly in appropriate places. Information on extending the system may be found near the end of this document.

Initializing the Macaroni system

(load "macaroni.isis") (macaroni-initialize program-name) An Isis script that uses Macaroni must load macaroni.isis and call macaroni-initialize once near the beginning of the program. This routine will initialize OpenGL and the GLUT library. You should pass a name for your program that will be used in error messages. For example:
(load "macaroni.isis") (macaroni-initialize "Othello")

Creating Macaroni windows

(macaroni-create-window name size position double-buffer) macaroni-create-window creates a window for Macaroni to render into. You must specify its name, size, position, and a boolean indicating whether you want to use double buffering in the window. A window ID will be returned that will be used later. The following example creates a window named "Cabiria" that will be 400 x 300 pixels in size, positioned at (100, 100) on the screen, with double buffering turned on:
(set macwin (macaroni-create-window "Cabiria" [400 300] [100 100] True))
Currently, you may only render into a single window, although there are ways to handle multiple windows (see Stefan for more info).

Understanding Macaroni objects

There are three main kinds of Macaroni objects: primitives, transforms, and scenes. Primitives are the lowest-level drawing primitives of the system (rectangles, lines, points, polygons, images, text, movies, etc.). Transforms are objects that allow you to control the way another object is rendered, by changing its position, scale, rotation, color, opacity, etc. Scenes are collections of several objects that will be rendered together in a certain order.

Each instantiated object contains parameters that control its state that are initially set to intuitive default values. Some of these parameters will contain references to other objects in the system, allowing a complex web to be constructed. For example, a transform refers to the object that will be transformed. A scene refers to a list of objects.

Any type of object may be referenced by any other type. For example, a scene may refer to a collection of primitives, transforms, or other scenes, or a mixture of these. Similarly, transforms may refer to scenes, primitives, or other transforms.

A single object may be referenced by several other objects. For example, a single image primitive may be referenced by several transform objects that are all referenced by a single scene, thereby creating a scene consisting of several copies of the same image transformed in different ways.

All media and device interaction is controlled from within the objects---all you have to do is create the web of connections between the appropriate objects and write a procedure that will update their parameters depending on the values of timers, sensors, user identity, or whatever other response factors. You can add and remove objects from scenes at will and control when and how scenes will be drawn to the window.

Creating and controlling Macaroni objects

Before writing your script, make a plan of the structure of media objects in your presentation and how they will be combined and layered together. Then decide how you will represent this structure using Macaroni objects. If possible and pratical, start your script by creating all of the Macaroni objects you will need for the entire presentation.

Below is a list of all the kinds of Macaroni objects you might create and their corresponding "constructor" functions:

Regular Polygonmac-new-regular-polygon
Dynamic Imagemac-new-dynamic-image
Raster Imagemac-new-raster-image
Bitmap Textmac-new-bitmap-text
Stroke Textmac-new-stroke-text
Isis Moviemac-new-isis-movie
Texture Rectanglemac-new-texture-rectangle

You may instantiate as many objects of any type as you like by calling the corresponding constructor (mac-new-whatever). The constructor returns a procedure that serves as your interface to that object. By passing different kinds of arguments to this procedure, you operate on the object in different ways. Each object accepts either commands or queries, as described below.

Commands take the form of lists in which the first item is an "opcode" specifying which command to execute, and the rest of the items are the arguments for that command. Several commands may be passed in each call to the object, and they will be carried out in order. Commands may also be passed when calling the constructor of the object.

Queries do not take any particular action--they just return the state of a particular aspect of the object. To perform a query, pass a query code as the ONLY argument to the object and the result will be returned.

Every object will always accept two particular commands:

[mac-render] # Draw the object [mac-destroy] # Destroy the object You will not have to send the mac-render command to the objects you create, as this is automatically done by Macaroni during window updates. The mac-destroy command should be passed whenever an object is not needed any more, as this will deallocate any memory or other resources associated by the object.

Later sections explain each object in greater detail, including the kinds of commands and queries that each will accept. For the purposes of brevity, the mac-render and mac-destroy commands will not be listed in each description, although they are always available. Also, if a particular object inherits properties from another kind of object, the parent object type will be indicated but any inherited commands and queries will not be listed.

Important notes: Unless otherwise specified, all numerical values, including positions, scale factors, etc., should be expressed as real numbers, not integers. Also, in contrast to most windowing systems, the origin of Macaroni windows is at the lower left corner, and the positive vertical axis points in the upward direction. Express object positions accordingly.

Rendering and animating

(macaroni-update-window window-id macaroni-object clear-flag) (macaroni-start update-function) These two functions are used together to actually draw Macaroni objects in the window. macaroni-update-window marks the specified Macaroni object (usually a scene) to be drawn in the specified window. If clear-flag is True, the window will be cleared before the object is drawn. If it is False, the object will be drawn on top of the previous contents of the window (this only makes sense if the window is NOT double buffered).

No windows will actually be drawn and nothing will happen until you call macaroni-start. Once called, macaroni-start will not return. However, you can pass your own function to macaroni-start to modify and animate your scene. This function will be called repeatedly by the system and should accept no arguments (it serves as the GLUT "idle" callback). The body of the function should do any processing that is needed, update object parameters appropriately, and finally make a call to macaroni-update-window to mark the window to be redrawn. If you do not need to animate your scene, you can pass Null for this function, but you should be sure to call macaroni-update-window at least once before macaroni-start.

A simple example

Below is a simple example to get you started. This short program displays a rotating image. The first line loads the Macaroni library, and the next two lines initialize Macaroni and create a 300 x 300 pixel window. Next, a Macaroni image object is created that references image data from a particular URL. After that, a Macaroni transform object is created that references the image object and positions it at half-scale in the center of the window. Finally, a procedure is passed to macaroni-start. This procedure, which will be called repeatedly by Macaroni, increments the rotation, sets the rotation parameter of the transform object to the new rotation value, and marks that object to be drawn in the window.

(load "macaroni.isis") (macaroni-initialize "Rotating image") (set macwin (macaroni-create-window "Rotating image" [300 300] [100 100] True)) (set iobj (mac-new-image [mac-url "file:/usr/local/isis/media/nana.jpg"])) (set itrans (mac-new-transform [mac-object iobj] [mac-position [150.0 150.0]] [mac-scale [0.5 0.5]])) (set rot 0.0) (macaroni-start (proc () (begin (set rot (+ rot 1.0)) (itrans [mac-rotation rot]) (macaroni-update-window macwin itrans True))))

Normally, you will want to render more than one object at the same time. In order to do so, you would create whatever objects you need and add all of them to a single Macaroni scene object. You would then pass this scene object when you call macaroni-update-window.

The following sections describe how each Macaroni object works in more detail. There are also many more examples in the EXAMPLES SECTION at the end of this document.

Macaroni object descriptions


Constructor: mac-new-scene


[mac-objects object-list] # list of objects to render, in order



A scene object represents a collection of other Macaroni objects that should all be rendered together. Use the mac-objects command to specify the list of objects to render. These objects will be rendered in the order given in the list.

Usually, you will create a number of other objects and include all of them in a single scene object that will be passed to the macaroni-update-window function to be rendered.


Constructor: mac-new-transform


[mac-object object] # object to be transformed [mac-scale [xscale yscale]] # horizontal and vertical scale factors [mac-rotation degrees] # rotation, positive = counterclockwise [mac-position [xpos ypos]] # drawing position of object [mac-color [r g b a]] # RGB and alpha (opacity), 0.0 - 1.0 [mac-line-width width] # width of lines [mac-line-factor factor] # integer line stipple repeat factor, 1 - 255 [mac-line-pattern pattern] # integer representing line stipple pattern [mac-point-size size] # size of points in pixels


mac-object mac-scale mac-rotation mac-position mac-color mac-line-width mac-line-factor mac-line-pattern mac-point-size

A transform object represents certain transformations to perform to another object when it is rendered. You must specify the object to be transformed with the mac-object command. The other commands allow you to change this object's scale, rotation, position, color, opacity, etc.

Scaling, rotation, and positioning are performed in that order, relative to the current coordinate system. If no other transform is affecting the object, the origin is at the lower left corner of the window, with the positive horizontal axis pointing rightward and the positive vertical axis pointing upward, and the units are pixels. Scales should be expressed as a list of two real numbers representing the horizontal and vertical scale factors for the object. Rotations should be given in degrees, where positive values represent counterclockwise rotation about the origin of the coordinate system.

Color and alpha (opacity) are specified together in the mac-color command. Red, green, blue, and alpha (opacity) values should be real numbers between 0.0 and 1.0.

Line widths and point sizes should be expressed in pixels. Line stipple patterns (used for making dotted or dashed lines) should be expressed in the form of an integer in which the low 16 bits represent the stipple pattern. The size of this pattern when drawn is specified as an integer between 1 and 255, or 0 to disable stippling.

Transforms can be combined with each other to create more complex transformations. Scales, rotations, and positions are composed with previous coordinate system transformations, whereas the color, line and point parameters, if specified, will override any previous settings.


Constructor: mac-new-points


[mac-points point-list] # list of point vertices



The points object can be used to render points, which appear as small dots. Use the mac-points command to specify a list of point positions. Use a transform object to change point color and size or to further scale, rotate, or position the entire group of points.


Constructor: mac-new-lines


[mac-lines line-list] # list of lines, where each line is a list of vertices



The lines object will render several lines, each of which may have several segments. Use the mac-lines command to specify a list of lines, each of which is a list of vertices. There must be at least two vertices in each line.

Use a transform object to change line color, width, and other attributes, or to further scale, rotate, or position the lines.


Constructor: mac-new-rectangle


[mac-size [xsize ysize]] # size of rectangle (default [100.0 100.0]) [mac-position [xpos ypos]] # position of rectangle (default [0.0 0.0])


mac-size mac-position

A rectangle object creates a solid filled rectangle. You can set the size of the rectangle (in pixels) and the position of its lower left corner relative to the origin, or you can use a transform object to scale, rotate, and position it, in addition to setting its color and opacity.

Regular Polygon

Constructor: mac-new-regular-polygon


[mac-size [xsize ysize]] # horizontal and vertical extent from center [mac-sides numsides] # integer number of sides [mac-position [xpos ypos]] # position of center (default [0.0 0.0])


mac-size mac-sides mac-position

A regular polygon object creates a solid filled regular polygon. The polygon is centered at the origin unless changed with the mac-position command. You set the number of sides of the polygon with the mac-sides command, and the horizontal and vertical extent of the polygon can be set with the mac-size command.

Equilateral triangles, squares, pentagons, hexagons, etc., can be created by setting mac-sides appropriately. Circles may be simulated by setting the number of sides to a high enough value, say 32 or 64. Shapes like oblique triangles and ovals can be created by setting the horizontal and vertical sizes differently. A transform object must be used to set the color and opacity of the polygon and can be used to scale, rotate, and position it as well.


Constructor: mac-new-image

Inherits from: Texture rectangle


[mac-url url] # retreive image from this URL [mac-filename filename] # retrieve image from this file [mac-image image] # Isis image to use [mac-images image-list] # list of Isis images to use [mac-frame framenum] # set current frame (if more than one available)


mac-url mac-textures mac-frame mac-framecount mac-size

An image object renders an image. You may specify the source image data for the object in one of four ways:

  1. Use mac-url to specify a URL from which to retrieve the image.
  2. Use mac-filename to specify a file name from which to retrieve the image.
  3. Use mac-image to specify the Isis image buffer to load into the object.
  4. Use mac-images to specify a list of Isis image buffers to load into the object.

The mac-frame command allows you to select from different frames if more than one is available, for example, from a GIF animation or a list of images specified with mac-images.

The center of the image is placed at the origin of the current coordinate system. Use a transform object to scale, rotate, position, or otherwise modify the rendering of the image. The mac-framecount query can be used to retrieve the number of frames that are available in the object. the mac-size query will return the size of the first frame.

Although you specify a new URL, filename, image, or list of images at any time, updating the image data in this way is not efficient. For rapidly changing image data, use the dynamic image object instead.

Dynamic image

Constructor: mac-new-dynamic-image

Inherits from: Texture rectangle


[mac-image gl-image] # set current image (see info below) [mac-subimage gl-image [xpos ypos]] # update a portion of current image


(no additional queries)

Like the plain image object, the dynamic image object also renders an image, but it is optimized to handle images that might need to change rapidly, such as movies or real-time data.

The mac-image command accepts an Isis image to load into the object. This image must be a interleaved byte-sampled image, and its dimensions must both be powers of 2. The image may have up to four channels---the red, green, blue, and alpha (opacity) data, respectively.

The mac-subimage command allows you to change a portion of the currently loaded image. You specify the Isis image and a position to load it into. Again, the image must be an interleaved byte-sampled image, but its dimensions do not have to be powers of 2.

(gl-new-image chans [xsize ysize]) may be used to create a new image with the appropriate characteristics. See the OpenGL utilities documentation for more information.

The center of the image is placed at the origin of the current coordinate system. A transform object may be used to scale, rotate, position, or otherwise modify the rendering of the image.

Raster image

Constructor: mac-new-raster-image


[mac-image gl-image] # Image to use (see info below) [mac-position [xpos ypos]] # raster position [mac-scale [xzoom yzoom]] # zoom factors


mac-image mac-position mac-scale

A raster image object renders an image without texture mapping. Depending on the platform, it is usually the most efficient way of rendering an image, especially one that may be changing rapidly over time. However, the image cannot be rotated or otherwise warped, and it usually cannot be scaled to arbitrary scale factors. Varying color and opacity will usually not work either. Therefore, this object should only be used if you want to efficiently render an image without any other transformations.

The mac-image command allows you to specify the Isis image to render from. It must be a 4-channel interleaved byte-sampled image, with each channel representing the red, green, blue, and alpha (opacity) data, respectively. Once the image buffer has been specified, it need not be given again, as the object renders its image data directly from this buffer. Consequently, you should not free the image buffer that you give to the object until you are finished with the object as well.

Use the mac-position to specify the starting raster position with respect to the current coordinate system. This position must not lie outside the window. You can change the scale of the image using the mac-scale command, although only non-integral scale factors may be available on your platform. Usually it is necessary to set the vertical scale factor to -1.0 to flip the image vertically, since the vertical axes in OpenGL and Isis images point in opposite directions.


Constructor: mac-new-text


[mac-text text] # string of text [mac-font fontinfo] # font info structure (see info below) [mac-fixed fixed-flag] # boolean, use fixed character size? [mac-halign halign] # mac-left, mac-center, or mac-right [mac-valign valign] # mac-top, mac-center, or mac-bottom [mac-char-spacing cscale] # character spacing scale factor [mac-line-spacing lscale] # line spacing scale factor


mac-text mac-font mac-fixed mac-halign mac-valign mac-char-spacing mac-line-spacing

The text object renders multiple lines of texture-mapped text using a particular font. You specify the text with the mac-text command. No control characters are allowed, except for newlines.

Use the mac-font command to specify the font descriptor of the font to use. This font descriptor must be created previously using gl-load-font from the Isis OpenGL utilities library (see documentation for more information). These fonts usually consist of variable width characters, but to force the use of fixed-width character spacing, set mac-fixed to True.

By default, the center of the entire region of text is positioned at the origin. mac-halign and mac-valign can be used to change this positioning point. Scale factors for character and line spacing can be specified using mac-char-spacing and mac-line-spacing. You can use a transform object to further scale, rotate, or position the text, as well as change its color and opacity.

Bitmap Text

Constructor: mac-new-bitmap-text


[mac-text text] # string of text (no newlines) [mac-font fontinfo] # font identifier (see info below) [mac-position position] # position of start of text


mac-text mac-font mac-position

The bitmap text object renders a single line of text using the GLUT bitmap character rendering engine. You specify the text with the mac-text command, and the font with the mac-font command, which should be one of the GLUT bitmap font identifiers:

GLUT_BITMAP_8_BY_13 GLUT_BITMAP_9_BY_15 GLUT_BITMAP_TIMES_ROMAN_10 GLUT_BITMAP_TIMES_ROMAN_24 GLUT_BITMAP_HELVETICA_10 GLUT_BITMAP_HELVETICA_12 GLUT_BITMAP_HELVETICA_18 GLUT_BITMAP_8_BY_13 is the default. The mac-position command or a transform object can be used to control the starting position of the text. Bitmap text cannot be scaled or rotated.

Stroke Text

Constructor: mac-new-stroke-text


[mac-text text] # string of text (no newlines) [mac-font fontinfo] # font identifier (see info below)


mac-text mac-font

The stroke text object renders a single line of text using the GLUT stroke character rendering engine. You specify the text with the mac-text command, and the font with the mac-font command, which should be one of the GLUT stroke font identifiers:

GLUT_STROKE_ROMAN GLUT_STROKE_MONO_ROMAN GLUT_STROKE_ROMAN is the default. You can use a transform object to control the position, scale, rotation, color, and other attributes of the text.

Isis movie

Constructor: mac-new-isis-movie

Inherits from: Dynamic image


[mac-movie movieobj] # set Isis movie object [mac-frame frame] # set current frame number [mac-mute muteflag] # make True to hide image, default is False


mac-movie mac-frame mac-mute

This object allows you to render frames from an Isis movie. Use mac-movie to specify the movie handle returned from new-isis-movie (see the Movie utilities documentation for more info). Use mac-frame to set the frame number of the movie to render. You can set mac-mute to True to hide the movie image, or False to make it visible (the default).

The center of the movie will be positioned at the origin of the current coordinate system. You can scale, rotate, and position the movie with a transform object, as well as change its color and opacity.

You may create and use several Isis movie objects, but the movies that they reference must all have the same frame size. You can also set the subsampling factors that are used internally when creating the movie's textures, using the following function:

(macaroni-init-isis-movies [xsize ysize] [xsub ysub]) This function must be called before any Isis movie objects are created. It accepts the frame size of the Isis movies to be used, and the integer horizontal and vertical subsampling factors. A subsampling factor of [5 4] is efficient for dealing with 320 x 240 resolution movies. If needed, a [2 1] factor will provide better image quality.

Texture Rectangle

Constructor: mac-new-texture-rectangle


[mac-texture texture] # OpenGL texture object [mac-size [xsize ysize]] # size of rectangle [mac-position [xpos ypos]] # position of rectangle (default [0.0 0.0]) [mac-texsize [xsize ysize]] # size of texture [mac-texposition [xpos ypos]] # position of the texture (default [0.0 0.0])


mac-texture mac-size mac-position mac-texsize mac-texposition

The texture rectangle object serves as a basis for a number of other Macaroni objects, including the image and dynamic image. If you have an image that you want to texture onto a rectangle, use those objects instead. Use this object only if you already have a raw OpenGL texture and you want to map it on to a rectangle.

You specify the OpenGL texture object to use with the mac-texture command. Use mac-size and mac-position to set the size of the rectangle and the position of its lower left corner. Use mac-texsize to specify the size, in world units, that the texture should be mapped to (usually the same as the rectangle size). The entire texture, regardless of its internal dimensions, will be mapped to this size. Use mac-texposition to specify the origin of the texture (usually the same as the rectangle position). This origin should be expressed in world coordinates, not relative to the rectangle's origin.

Use a transform object to change the color and opacity of the rectangle or to further modify its scale, rotation, or position.

Window interaction

You may use the native GLUT window callback routines to receive information about button clicks, mouse movements, key presses, and so on, in your Macaroni windows. For example, to receive key presses, you might add something like the following code before calling macaroni-start:
(set keyboard (proc (key x y) (if (= (character key) 'q') (exit)))) (glutKeyboardFunc glut_keyboard) (update-glut-callback-slot glut_keyboard_slot keyboard)
This bit of code enables the user to hit the 'q' key to quit the program. There are similar callbacks for many different kinds of window events. See the
Isis OpenGL documentation or the online GLUT documentation for more info.

Extending Macaroni

Writing your own Macaroni objects to perform special rendering tasks is easy. A Macaroni object is simply a procedure that accepts a variable number of arguments. Each argument represents a "command" to perform some kind of operation. Each such command comes in the form of a list in which the first item is an integer "opcode" indicating what operation to perform, and the rest of the items are any additional parameters needed for that command.

You can make custom Macaroni objects simply by writing procedures that accept arguments in this form. Your procedure need only recognize two commands: [mac-render] and [mac-destroy]. When rendering, Macaroni will call your procedure with the [mac-render] command, indicating that it should execute the OpenGL drawing routines to render your object. If a [mac-destroy] command is received, your procedure should deallocate or destroy any resources used by the object.












Scripts: (load "macaroni.isis")
Other: Needs OpenGL and GLUT libraries