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.
(load "macaroni.isis") (macaroni-initialize "Othello")
Currently, you may only render into a single window, although there are ways to handle multiple windows (see Stefan for more info).(set macwin (macaroni-create-window "Cabiria" [400 300] [100 100] True))
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.
Below is a list of all the kinds of Macaroni objects you might create and their corresponding "constructor" functions:
Scene | mac-new-scene |
Transform | mac-new-transform |
Points | mac-new-points |
Lines | mac-new-lines |
Rectangle | mac-new-rectangle |
Regular Polygon | mac-new-regular-polygon |
Image | mac-new-image |
Dynamic Image | mac-new-dynamic-image |
Raster Image | mac-new-raster-image |
Text | mac-new-text |
Bitmap Text | mac-new-bitmap-text |
Stroke Text | mac-new-stroke-text |
Isis Movie | mac-new-isis-movie |
Texture Rectangle | mac-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:
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.
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.
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.
(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.
Commands:
Queries:
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.
Commands:
Queries:
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.
Commands:
Queries:
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.
Commands:
Queries:
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.
Commands:
Queries:
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.
Commands:
Queries:
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.
Inherits from: Texture rectangle
Commands:
Queries:
An image object renders an image. You may specify the source image
data for the object in one of four ways:
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.
Inherits from: Texture rectangle
Commands:
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.
Commands:
Queries:
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.
Commands:
Queries:
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.
Commands:
Queries:
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:
Commands:
Queries:
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:
Inherits from: Dynamic image
Commands:
Queries:
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:
Commands:
Queries:
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.
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.
Transform
Constructor: mac-new-transform
Points
Constructor: mac-new-points
Lines
Constructor: mac-new-lines
Rectangle
Constructor: mac-new-rectangle
Regular Polygon
Constructor: mac-new-regular-polygon
Image
Constructor: mac-new-image
Dynamic image
Constructor: mac-new-dynamic-image
Raster image
Constructor: mac-new-raster-image
Text
Constructor: mac-new-text
Bitmap Text
Constructor: mac-new-bitmap-text
Stroke Text
Constructor: mac-new-stroke-text
Isis movie
Constructor: mac-new-isis-movie
Texture Rectangle
Constructor: mac-new-texture-rectangle
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:
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.
Examples
Simpleimage
Scripts: | (load "macaroni.isis")
|
Other: | Needs OpenGL and GLUT libraries
|