Copyright (c) Hyperion Entertainment and contributors.

Layers Library

From AmigaOS Documentation Wiki
Jump to navigation Jump to search
WIP.png This page is currently being updated to AmigaOS 4.x. Some of the information contained here may not yet be applicable in part or totally.

Layers Library

This chapter describes the layers library which provides routines that are used to manage overlapping rectangular drawing areas that share a common display. Intuition uses the layers library to manage its system of windows.

The chapter also describes the use of regions, special structures used to mask off areas where drawing can take place. Regions are installed through the layers library function InstallClipRegion() but the routines for the creation, disposal and manipulation of regions are part of the graphics library.

Layers

The concept of a layer is closely tied to Intuition windows. A layer is a rectangular drawing area. A layer can overlap other layers and has a display priority that determines whether it will appear in front or behind other layers. Every Intuition window has an associated Layer structure. Layers allow Intuition and application programs to :

  • Share a display's BitMap among various tasks in an orderly way by creating layers, separate drawing rectangles, within the BitMap.
  • Move, size or depth-arrange a layer while automatically keeping track of which portions of other layers are hidden or revealed by the operation.
  • Manage the remapping of coordinates, so the application need not track the layer's offset into the BitMap.
  • Maintain each layer as a separate entity, which may optionally have its own BitMap.
  • Automatically update same newly visible portions.

The layers library takes care of housekeeping: the low level, repetitive tasks which are required to keep track of where to place bits. The layers library also provides a locking mechanism which coordinates display updating when multiple tasks are drawing graphics to layers. The windowing environment provided by the Intuition library is largely based on layers.

WARNING
Layers may not be created or used directly with Intuition screens. Intuition windows are the only supported method of adding layers to Intuition screens. Only the layer locking and unlocking functions are safe to use with Intuition. An application must create and manage its own View if it will be creating layers directly on the display.

The Layer Structure

The internal representation of layers is essentially a set of clipping rectangles. Each layer is represented by an instance of the Layer structure. All the layers in a display are linked together through the Layer_Info structure. Any display shared by multiple layers (such as an Intuition screen) requires one Layer_Info data structure to handle interactions between the various layers.

Here is a partial listing of the Layer structure from <graphics/clip.h>. (For a complete listing refer to the SDK.)

struct Layer
{
    struct  Layer *front,*back;
    struct  ClipRect    *ClipRect;  /* read by ROMs to find first cliprect */
    struct  RastPort    *rp;
    struct  Rectangle   bounds;
      ...
 
    UWORD   Flags;                  /* obscured ?, Virtual BitMap? */
    struct  BitMap *SuperBitMap;
      ...
 
    struct  Region  *DamageList;    /* list of rectangles to refresh through */
};
The Layer Structure is Read-Only
Applications should never directly modify any of the elements of the Layer structure. In addition, applications should only read the front, back, rp, bounds, Flags, SuperBitMap and DamageList elements of the Layer structure. (Some of these elements are subject to dynamic change by the system so proper layer locking procedures must be followed when relying on what the application has read.)

The Layer's RastPort

When a layer is created, a RastPort is automatically to go along with it. The pointer to the RastPort is contained in the layer data structure. Using this RastPort, the application may draw anywhere into the layer's bounds rectangle. If the application tries to draw outside of this rectangle, the graphics routines will clip the graphics.

Here is sample code showing how to access the layer's RastPort:

struct RastPort *myRPort;    /* allocate a RastPort pointer for each layer */
 
myRPort = layer->rp;
 
/* The layer's RastPort may be used with any of the graphics library calls
** that require this structure.  For instance, to fill layer with color:
*/
IGraphics->SetRast(layer->rp, color);
 
/* set up for writing text into layer */
IGraphics->SetDrMd(layer->rp, JAM1);
IGraphics->SetAPen(layer->rp, 0);
IGraphics->Move(layer->rp, 5, 7);
 
/* write into layer */
IGraphics->Text(layer->rp, string, strlen(string));

Types of Layers

The layers library supports three types of layers: simple refresh, smart refresh and super bitmap. The type of the layer, specified by the Flags field in the Layers structure, determines what facilities the layer provides.

Use Only One Layer Type Flag
The three layer-type Flags are mutually exclusive. That is, only one layer-type flag (LAYERSIMPLE, LAYERSMART and LAYERSUPER) should be specified.

Simple Refresh Layer

When an application draws into the layer, any portion of the layer that is visible (not obscured) will be rendered into the common BitMap of the viewing area. All graphics rendering routines are "clipped" so that only exposed sections of the layer are drawn into. No back-up of obscured areas is provided.

If another layer operation is performed that causes an obscured part of a simple refresh layer to be exposed, the application must determine if the section need be refreshed, re-drawing the newly exposed part of the layer as required.

The basic advantage of simple refresh is that it does not require back-up area to save drawing sections that cannot be seen, saving memory. However, the application needs to monitor the layer to see if it needs refreshing. This is typically performed with statements like:

if (layer->Flags & LAYERREFRESH)
    refresh(layer);

When an application restores the layer by performing a full-layer redraw, only the damaged areas are redrawn, making the operation fairly time efficient.

Smart Refresh Layer

Under smart refresh, the system provides dynamic backup of obscured sections of the layer. The graphics routines will automatically draw into these backup areas when they encounter an obscured part of the layer. The backup memory will be used to automatically update the display when obscured sections later become exposed.

With smart refresh layers, the system handles all of the refresh requirements of the layer, except when the layer is made larger. When parts of the layer are exposed by a sizing operation, the application must refresh the newly exposed areas.

The advantage of smart refresh is the speed of updating exposed regions of the layer and the ability of the system to manage part of the updating process for the application.. Its main disadvantage is the additional memory required to handle this automatic refresh.

Super Bitmap Layer

A super bitmap layer is similar to a smart refresh layer. It too has a back-up area for rendering graphics for currently obscured parts of the display. Whenever an obscured area is made visible, the corresponding part of the backup area is copied to the display automatically.

However, it differs from smart refresh in that:

  • The back-up BitMap is user-supplied, rather than being allocated dynamically by the system.

  • The back-up BitMap may be as large or larger than the the current size of the layer. It may also be larger than the maximum size of the layer.

To see a larger portion of a super bitmap on-display, use SizeLayer(). To see a different portion of the super bitmap in the layer, use ScrollLayer().

When the graphics routines perform drawing commands, part of the drawing appears in the common BitMap (the on-display portion). Any drawing outside the displayed portion itself is rendered into the super bitmap. When the layer is scrolled or sized, the layer contents are copied into the super bitmap, the scroll or size positioning is modified, and the appropriate portions are then copied back into the layer. (Refer to the graphics library functions SyncSBitMap() and CopySBitMap().

Backdrop Layer

A layer of any type may be designated a backdrop layer which will always appear behind all other layers. They may not be moved, sized, or depth-arranged. Non-backdrop layers will always remain in front of backdrop layers regardless of how the non-backdrop layer is moved, sized or depth-arranged.

Opening the Layers Library

Like all libraries, the layers library must be opened before it may be used. Check the Layers Autodocs to determine what version of the library is required for any particular Layers function.

#include <proto/layers.h>
 
struct Library *LayersBase = IExec->OpenLibrary("layers.library", 50);
 
struct LayersIFace *ILayers = (struct LayersIFace*)IExec->GetInterface(LayersBase, "main", 1, NULL);
 
if (ILayers != NULL)
    {
    /* use Layers library */
    }
 
IExec->DropInterface((struct Interface*)ILayers);
IExec->CloseLibrary(LayersBase);

Working With Existing Layers

A common operation performed by applications is to render text or graphics into an existing layer such as an Intuition window. To prevent Intuition from changing the layer (for instance when the user resizes or moves the window) during a series of graphic operations, the layers library provides locking functions for obtaining exclusive access to a layer.

These locking functions are also useful for applications that create their own layers if the application has more than one task operating on the layers asynchronously. These calls coordinate multiple access to layers.

Functions for Intertask Control of Layers (Layers Library)
LockLayer() Lock out rendering in a single layer.
UnlockLayer() Release LockLayer() lock.
LockLayers() Lock out rendering in all layers of a display.
UnlockLayers() Release LockLayers() lock.
LockLayerInfo() Gain exclusive access to the display's layers.
UnlockLayerInfo() Release LockLayerInfo() lock.

The following routines from the graphics library also allow multitasking access to layer structures:

Functions for Intertask Control of Layers (Graphics Library)
LockLayerRom() Same as LockLayer(), from layers library.
UnlockLayerRom() Release LockLayerRom() lock.
AttemptLockLayerRom() Lock layer only if it is immediately available.

These functions are similar to the layers LockLayer() and UnlockLayer() functions, but do not require the layers library to be open. See the SDK for details.

Intertask Operations

If multiple tasks are manipulating layers on the same display they will be sharing a Layer_Info structure and their use of it and its related data structures need to be coordinated. To ensure that a structure remains cohesive, it should be operated on by only one task at a time. The Layer_Info encompasses all the layers existing on a single display.

LockLayerInfo() must be called whenever the visible portions of layers may be affected, or when the Layer_Info structure is changed.

VOID LockLayerInfo( struct Layer_Info *li );

The lock should be obtained whenever a layer is created, deleted sized or moved, as the list of layers that is being managed by the Layer_Info data structure must be updated.

It is not necessary to lock the Layer_Info data structure while rendering, or when calling routines like ScrollLayer(), because layer sizes and on-display positions are not being affected.

Use UnlockLayerInfo() when you have finished the layer operation:

VOID UnlockLayerInfo( struct Layer_Info *li );

If you don't unlock the Layer_Info then any other task calling LockLayerInfo() on the same Layer_Info structure will be blocked creating a potential deadlock situation.

In addition to locking the Layer_Info structure, the layer itself should be locked if it is shared between tasks so that only one task at a time renders graphics to it. LockLayer() is used to get exclusive graphics output to a layer.

VOID LockLayer( long dummy, struct Layer *layer );

If a graphics function is in process, the lock will return when the function is completed. Other tasks are blocked only if they attempt to draw graphics into this layer, or try to obtain a lock on this layer. The MoveLayer(), SizeLayer() and ScrollLayer() functions automatically lock and unlock the layer they operate on.

UnlockLayer() should be used after the graphics operation to make the layer available to other tasks again.

VOID UnlockLayer( struct Layer *layer );

If more than one layer must be locked, then the LockLayer() calls should be surrounded by LockLayerInfo() and UnlockLayerInfo() calls, to prevent deadlock situations.

The layers library provides two additional functions, LockLayers() and UnlockLayers(), for locking multiple layers.

VOID LockLayers( struct Layer_Info *li );
VOID UnlockLayers( struct Layer_Info *li );

LockLayers() is used to lock all layers in a single command. UnlockLayers() releases the layers lock. The system calls these routines during the BehindLayer(), UpfrontLayer() and MoveLayerInFrontOf() operations (described below).

Determining Layer Position

If the viewing area has been separated into several layers, the application may need to find out which layer is topmost at a particular x,y coordinate. Use the WhichLayer() function for this:

struct Layer *WhichLayer( struct Layer_Info *li, int32 x, int32 y );

To be sure that no task adds, deletes, or changes the sequence of layers before this information is used, call LockLayerInfo() before calling WhichLayer(), and call UnlockLayerInfo() when the operation is complete. In this way, the program may ensure that it is acting on valid information. Always check for a NULL return value (coordinate not in a layer) from WhichLayer().

Creating and Using New Layers

The functions described in this section are generally not safe to use with Intuition. To create new layers for Intuition you use Intuition window calls (see Intuition Windows).

Only applications that create and mange their own View will be able to call the layer creation and updating functions discussed here.

Functions for Creating and Updating Layers
NewLayerInfo() Allocating a Layer_Info structure.
DisposeLayerInfo() Deallocating a Layer_Info structure.
CreateUpfrontLayer() Make a new layer in front of others.
CreateBehindLayer() Make a new layer behind others.
DeleteLayer() Remove and delete an existing layer.
MoveLayer() Change the position (not depth) of a layer.
SizeLayer() Change the size of a layer.
ScrollLayer() Change the internal coordinates of a layer.
BehindLayer() Depth arrange a layer behind others.
UpfrontLayer() Depth arrange a layer in front of others.
MoveLayerInFrontOf() Depth arrange a layer to a specific position.
SwapBitsRastPortClipRect() Fast, non-layered and non-damaging display operation.
BeginUpdate() Synchronize optimized refreshing for layer.
EndUpdate() End optimized layer refresh.

Creating a Viewing Workspace

A viewing workspace may be created by using the primitives InitVPort(), InitView(), MakeVPort(), MrgCop(), and LoadView(). Please reference Graphics Primitives for details on creating a low-level graphics display. Do not create Layers directly on Intuition screens. Windows are the only supported method of creating a layer on a screen.

Creating the Layers

The application must first allocate and initialize a Layer_Info data structure which the system uses to keep track of layers that are created, use statements like:

struct Layer_Info *theLayerInfo;
 
if (NULL != (theLayerInfo = ILayers->NewLayerInfo()))
    {
    /* use Layer_Info */
 
    ILayers->DisposeLayerInfo(theLayerInfo);
    }

Layers may be created in the common bit map by calling CreateUpfrontLayer() or CreateBehindLayer(), with a sequence such as the following:

struct Layer      *layer;
struct Layer_Info *theLayerInfo;
struct BitMap     *theBitMap;
 
/* requests construction of a smart refresh layer. */
if (NULL == (layer = ILayers->CreateUpfrontLayer(theLayerInfo, theBitMap, 20, 20, 100, 80, LAYERSMART, NULL)))
    error("CreateUpfrontLayer() failed.");
else
    {
    ; /* layer successfully created here. */
    }

Allocating and Deallocating Layer_Info

Use NewLayerInfo() to allocate and initialize a Layer_Info structure and associated sub-structures.

struct Layer_Info *NewLayerInfo( VOID );

You must call this function before attempting to use any of the other layers functions described below. When you have finished with a Layer_Info structure, use DisposeLayerInfo() to deallocate it.

VOID DisposeLayerInfo( struct Layer_Info *li );

This function deallocates a Layer_Info and associated structures previously allocated with NewLayerInfo().

Allocating and Deallocating Layers

Layers are created using the routines CreateUpfrontLayer() and CreateBehindLayer(). CreateUpfrontLayer() creates a layer that will appear in front of any existing layers.

struct Layer *CreateUpfrontLayer( struct Layer_Info *li, struct BitMap *bm, int32 x0, int32 y0, int32 x1, int32 y1, int32 flags, struct BitMap *bm2 );

CreateBehindLayer() creates a layer that appears behind existing layers, but in front of backdrop layers.

struct Layer *CreateBehindLayer( struct Layer_Info *li, struct BitMap *bm, int32 x0, int32 y0, int32 x1, int32 y1, int32 flags, struct BitMap *bm2 );

Both of these routines return a pointer to a Layer data structure (as defined in the include file <graphics/layers.h>), or NULL if the operation was unsuccessful.

A New Layer Also Gets a RastPort
When a layer is created, the routine automatically creates a RastPort to go along with it. If the layer's RastPort is passed to the drawing routines, drawing will be restricted to the layer. See "The Layer's RastPort" section above.

Use the DeleteLayer() call to remove a layer:

int32 DeleteLayer( int32 dummy, struct Layer *layer );

DeleteLayer() removes a layer from the layer list and frees the memory allocated by the layer creation calls listed above.

Moving and Sizing Layers

The layers library includes three functions for moving and sizing layers:

int32 MoveLayer( int32 dummy, struct Layer *layer, int32 dx, int32 dy );
int32 SizeLayer( int32 dummy, struct Layer *layer, int32 dx, int32 dy );
int32 MoveSizeLayer( struct Layer *layer, int32 dx, int32 dy, int32 dw, int32 dh);

MoveLayer() moves a layer to a new position relative to its current position. SizeLayer() changes the size of a layer by modifying the coordinates of the lower right corner of the layer. MoveSizeLayer() changes both the size and position of a layer in a single call.

Changing a Viewpoint

The ScrollLayer() function changes the portion of a super bitmap that is shown by a layer:

VOID ScrollLayer( int32 dummy, struct Layer *layer, int32 dx, int32 dy );

This function is most useful with super bitmap layers but can also simulate the effect on other layer types by adding the scroll offset to all future rendering.

Reordering Layers

The layers library provides three function calls for reordering layers:

int32 BehindLayer ( int32 dummy, struct Layer *layer );
int32 UpfrontLayer( int32 dummy, struct Layer *layer );
int32 MoveLayerInFrontOf( struct Layer *layer_to_move, struct Layer *other_layer );

BehindLayer() moves a layer behind all other layers. This function considers any backdrop layers, moving a current layer behind all others except backdrop layers. UpfrontLayer() moves a layer in front of all other layers. MoveLayerInFrontOf() is used to place a layer at a specific depth, just in front of a given layer.

As areas of simple refresh layers become exposed, due to layer movement or sizing for example, the newly exposed areas have not been drawn into, and need refreshing. The system keeps track of these areas by using a DamageList. To update only those areas that need it, the BeginUpdate() EndUpdate() functions are called.

int32 BeginUpdate( struct Layer *l );
VOID EndUpdate  ( struct Layer *layer, uint32 flag );

BeginUpdate() saves the pointer to the current clipping rectangles and installs a pointer to a set of ClipRects generated from the DamageList in the layer structure. To repair the layer, use the graphics rendering routines as if to redraw the entire layer, and the routines will automatically use the new clipping rectangle list. So, only the damaged areas are actually rendered into, saving time.

Never Modify the DamageList
The system generates and maintains the DamageList region. All application clipping should be done through the InstallClipRegion() function.

To complete the update process call EndUpdate() which will restore the original ClipRect list.

Sub-Layer Rectangle Operations

The SwapBitsRastPortClipRect() routine is for applications that do not want to worry about clipping rectangles.

VOID SwapBitsRastPortClipRect( struct RastPort *rp, struct ClipRect *cr );

For instance, you may use The SwapBitsRastPortClipRect() to produce a menu without using Intuition. There are two ways to produce such a menu:

  1. Create an up-front layer with CreateUpfrontLayer(), then render the menu in it. This could use lots of memory and require a lot of (very temporary) "slice-and-dice" operations to create all of the clipping rectangles for the existing windows and so on.
  2. Use SwapBitsRastPortClipRect(), directly on the display drawing area:
    • Render the menu in a back-up area off the display, then lock all of the on-display layers so that no task may use graphics routines to draw over the menu area on the display.
    • Next, swap the on-display bits with the off-display bits, making the menu appear.
    • When finished with the menu, swap again and unlock the layers.

The second method is faster and leaves the clipping rectangles and most of the rest of the window data structures untouched.

Warning
All of the layers must be locked while the menu is visible if you use the second method above. Any task that is using any of the layers for graphics output will be halted while the menu operations are taking place. If, on the other hand, the menu is rendered as a layer, no task need be halted while the menu is up because the lower layers need not be locked.

Layers Example

For the sake of brevity, the example is a single task. No Layer locking is done. Also note that the routine myLabelLayer() is used to redraw a given layer. It is called only when a layer needs refreshing.

/* Layers.c
**
** SAS/C 5.10a
** lc -b1 -cfist -v -y layers
** blink FROM LIB:c.o layers.o TO layers LIB LIB:lc.lib LIB:amiga.lib
*/

/* Force use of new variable names to help prevent errors */
#define INTUI_V36_NAMES_ONLY

#include <exec/types.h>
#include <graphics/gfxbase.h>
#include <graphics/layers.h>
#include <graphics/displayinfo.h>

#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/graphics_protos.h>
#include <clib/layers_protos.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef LATTICE
int CXBRK(void)    { return(0); }  /* Disable Lattice CTRL/C handling */
int chkabort(void) { return(0); }  /* really */
#endif

#define L_DELAY  (100)
#define S_DELAY   (50)

#define DUMMY      (0L)

#define RED_PEN    (1)
#define GREEN_PEN  (2)
#define BLUE_PEN   (3)

#define SCREEN_D   (2)
#define SCREEN_W (320)
#define SCREEN_H (200)

/* the starting size of example layers, offsets are used for placement */
#define W_H (50)
#define W_T (5)
#define W_B ((W_T+W_H)-1)
#define W_W (80)
#define W_L ((SCREEN_W/2) - (W_W/2))
#define W_R ((W_L+W_W)-1)

/* size of the superbitmap */
#define SUPER_H SCREEN_H
#define SUPER_W SCREEN_W

/* starting size of the message layer */
#define M_H (10)
#define M_T (SCREEN_H-M_H)
#define M_B ((M_T+M_H)-1)
#define M_W (SCREEN_W)
#define M_L (0)
#define M_R ((M_L+M_W)-1)

struct GfxBase *GfxBase;
struct Library *LayersBase;

/* global constant data for initializing the layers */
LONG  theLayerFlags[3] = { LAYERSUPER, LAYERSMART, LAYERSIMPLE };
UWORD colortable[]     = { 0x000, 0xf44, 0x4f4, 0x44f };


/*
** Clear the layer then draw in a text string.
*/
VOID myLabelLayer(struct Layer *layer, LONG color, UBYTE *string)
{
/* fill layer with color */
SetRast(layer->rp, color);

/* set up for writing text into layer */
SetDrMd(layer->rp,JAM1);
SetAPen(layer->rp,0);
Move(layer->rp, 5, 7);

/* write into layer */
Text(layer->rp, string, strlen(string));
}



/*
** write a message into a layer with a delay.
*/
VOID pMessage(struct Layer *layer, UBYTE *string)
{
Delay(S_DELAY);
myLabelLayer(layer, GREEN_PEN, string);
}

/*
** write an error message into a layer with a delay.
*/
VOID error(struct Layer *layer, UBYTE *string)
{
myLabelLayer(layer, RED_PEN, string);
Delay(L_DELAY);
}



/*
** do some layers manipulations to demonstrate their abilities.
*/
VOID doLayers(struct Layer *msgLayer, struct Layer *layer_array[])
{
WORD ktr;
WORD ktr_2;

pMessage(msgLayer, "Label all Layers");
myLabelLayer(layer_array[0], RED_PEN,   "Super");
myLabelLayer(layer_array[1], GREEN_PEN, "Smart");
myLabelLayer(layer_array[2], BLUE_PEN,  "Simple");

pMessage(msgLayer, "MoveLayer 1 InFrontOf 0");
if (!MoveLayerInFrontOf(layer_array[1], layer_array[0]))
    error(msgLayer, "MoveLayerInFrontOf() failed.");

pMessage(msgLayer, "MoveLayer 2 InFrontOf 1");
if (!MoveLayerInFrontOf(layer_array[2], layer_array[1]))
    error(msgLayer, "MoveLayerInFrontOf() failed.");

pMessage(msgLayer, "Refresh Simple Refresh Layer");
myLabelLayer(layer_array[2], BLUE_PEN, "Simple");

pMessage(msgLayer, "Incrementally MoveLayers...");
for(ktr = 0; ktr < 30; ktr++)
    {
    if (!MoveLayer(DUMMY, layer_array[1], -1, 0))
        error(msgLayer, "MoveLayer() failed.");
    if (!MoveLayer(DUMMY, layer_array[2], -2, 0))
        error(msgLayer, "MoveLayer() failed.");
    }

pMessage(msgLayer, "Refresh Simple Refresh Layer");
myLabelLayer(layer_array[2], BLUE_PEN, "Simple");

pMessage(msgLayer, "make Layer 0 the UpfrontLayer");
if (!UpfrontLayer(DUMMY, layer_array[0]))
    error(msgLayer, "UpfrontLayer() failed.");

pMessage(msgLayer, "make Layer 2 the BehindLayer");
if (!BehindLayer(DUMMY, layer_array[2]))
    error(msgLayer, "BehindLayer() failed.");

pMessage(msgLayer, "Incrementally MoveLayers again...");
for(ktr = 0; ktr < 30; ktr++)
    {
    if (!MoveLayer(DUMMY, layer_array[1], 0, 1))
        error(msgLayer, "MoveLayer() failed.");
    if (!MoveLayer(DUMMY, layer_array[2], 0, 2))
        error(msgLayer, "MoveLayer() failed.");
    }

pMessage(msgLayer, "Refresh Simple Refresh Layer");
myLabelLayer(layer_array[2], BLUE_PEN, "Simple");

pMessage(msgLayer, "Big MoveLayer");
for(ktr = 0; ktr < 3; ktr++)
    {
    if (!MoveLayer(DUMMY, layer_array[ktr], -layer_array[ktr]->bounds.MinX, 0))
        error(msgLayer, "MoveLayer() failed.");
    }


pMessage(msgLayer, "Incrementally increase size");
for(ktr = 0; ktr < 5; ktr++)
    {
    for(ktr_2 = 0; ktr_2 < 3; ktr_2++)
        {
        if (!SizeLayer(DUMMY, layer_array[ktr_2], 1, 1))
            error(msgLayer, "SizeLayer() failed.");
        }
    }

pMessage(msgLayer, "Refresh Smart Refresh Layer");
myLabelLayer(layer_array[1], GREEN_PEN, "Smart");
pMessage(msgLayer, "Refresh Simple Refresh Layer");
myLabelLayer(layer_array[2], BLUE_PEN,  "Simple");

pMessage(msgLayer, "Big SizeLayer");
for(ktr = 0; ktr < 3; ktr++)
    {
    if (!SizeLayer(DUMMY,layer_array[ktr],
                SCREEN_W-(layer_array[ktr]->bounds.MaxX)-1,0))
        error(msgLayer, "SizeLayer() failed.");
    }

pMessage(msgLayer, "Refresh Smart Refresh Layer");
myLabelLayer(layer_array[1], GREEN_PEN, "Smart");
pMessage(msgLayer, "Refresh Simple Refresh Layer");
myLabelLayer(layer_array[2], BLUE_PEN,  "Simple");

pMessage(msgLayer, "ScrollLayer down");
for(ktr = 0; ktr < 30; ktr++)
    {
    for(ktr_2 = 0; ktr_2 < 3; ktr_2++)
        {
        ScrollLayer(DUMMY, layer_array[ktr_2], 0, -1);
        }
    }

pMessage(msgLayer, "Refresh Smart Refresh Layer");
myLabelLayer(layer_array[1], GREEN_PEN, "Smart");
pMessage(msgLayer, "Refresh Simple Refresh Layer");
myLabelLayer(layer_array[2], BLUE_PEN,  "Simple");

pMessage(msgLayer, "ScrollLayer up");
for(ktr = 0; ktr < 30; ktr++)
    {
    for(ktr_2 = 0; ktr_2 < 3; ktr_2++)
        {
        ScrollLayer(DUMMY, layer_array[ktr_2], 0, 1);
        }
    }

pMessage(msgLayer, "Refresh Smart Refresh Layer");
myLabelLayer(layer_array[1], GREEN_PEN, "Smart");
pMessage(msgLayer, "Refresh Simple Refresh Layer");
myLabelLayer(layer_array[2], BLUE_PEN,  "Simple");

Delay(L_DELAY);
}


/*
** delete the layer array created by allocLayers().
*/
VOID disposeLayers(struct Layer *msgLayer, struct Layer *layer_array[])
{
WORD ktr;

for (ktr = 0; ktr < 3; ktr++)
    {
    if (layer_array[ktr] != NULL)
        {
        if (!DeleteLayer(DUMMY, layer_array[ktr]))
            error(msgLayer, "Error deleting layer");
        }
    }
}


/*
** Create some hard-coded layers.  The first must be super-bitmap, with
** the bitmap passed as an argument.  The others must not be super-bitmap.
** The pointers to the created layers are returned in layer_array.
**
** Return FALSE on failure.  On a FALSE return, the layers are
** properly cleaned up.
*/
BOOL allocLayers(struct Layer *msgLayer, struct Layer *layer_array[],
    struct BitMap *super_bitmap, struct Layer_Info *theLayerInfo,
    struct BitMap *theBitMap)
{
WORD ktr;
BOOL create_layer_ok = TRUE;

for (ktr = 0;
     (ktr < 3) && (create_layer_ok);
     ktr++)
    {
    pMessage(msgLayer, "Create BehindLayer");
    if (ktr == 0)
        {
        if ((layer_array[ktr] = CreateBehindLayer(theLayerInfo, theBitMap,
                  W_L+(ktr*30), W_T+(ktr*30), W_R+(ktr*30), W_B+(ktr*30),
                  theLayerFlags[ktr], super_bitmap)) == NULL)
            create_layer_ok = FALSE;
        }
     else
        {
        if ((layer_array[ktr] = CreateBehindLayer(theLayerInfo, theBitMap,
                  W_L+(ktr*30), W_T+(ktr*30), W_R+(ktr*30), W_B+(ktr*30),
                  theLayerFlags[ktr], NULL)) == NULL)
            create_layer_ok = FALSE;
        }

    if (create_layer_ok)
        {
        pMessage(msgLayer, "Fill the RastPort");
        SetRast(layer_array[ktr]->rp, ktr + 1);
        }
    }

if (!create_layer_ok)
    disposeLayers(msgLayer, layer_array);

return(create_layer_ok);
}




/*
** Free the bitmap and all bitplanes created by allocBitMap().
*/
VOID disposeBitMap(struct BitMap *bitmap, LONG depth, LONG width, LONG height)
{
WORD ktr;

if (NULL != bitmap)
    {
    for (ktr = 0; ktr < depth; ktr++)
        {
        if (NULL != bitmap->Planes[ktr])
            FreeRaster(bitmap->Planes[ktr], width, height);
        }

    FreeMem(bitmap, sizeof(*bitmap));
    }
}







/*
** Allocate and initialize a bitmap structure.
*/
struct BitMap *allocBitMap(LONG depth, LONG width, LONG height)
{
WORD ktr;
BOOL bit_map_failed = FALSE;
struct BitMap *bitmap = NULL;

if (NULL != (bitmap = AllocMem(sizeof(*bitmap),NULL)))
    {
    InitBitMap(bitmap,depth,width,height);

    for (ktr = 0; ktr < depth; ktr++)
        {
        if (NULL == (bitmap->Planes[ktr] = (PLANEPTR)AllocRaster(width,height)))
            bit_map_failed = TRUE;
        else
            BltClear(bitmap->Planes[ktr], RASSIZE(width,height), 1);
        }
    if (bit_map_failed)
        {
        disposeBitMap(bitmap,depth,width,height);
        bitmap = NULL;
        }
    }
return(bitmap);
}

/*
** Set up to run the layers example, doLayers(). Clean up when done.
*/
VOID startLayers(struct Layer_Info *theLayerInfo, struct BitMap *theBitMap)
{
struct Layer  *msgLayer;
struct BitMap *theSuperBitMap;
struct Layer  *theLayers[3] = { NULL, NULL, NULL, };

if (NULL != (msgLayer = CreateUpfrontLayer(theLayerInfo, theBitMap,
                     M_L, M_T, M_R, M_B, LAYERSMART, NULL)))
    {
    pMessage(msgLayer, "Setting up Layers");

    if (NULL != (theSuperBitMap = allocBitMap(SCREEN_D, SUPER_W, SUPER_H)))
        {
        if (allocLayers(msgLayer, theLayers, theSuperBitMap, theLayerInfo, theBitMap))
            {
            doLayers(msgLayer, theLayers);

            disposeLayers(msgLayer, theLayers);
            }
        disposeBitMap(theSuperBitMap, SCREEN_D, SUPER_W, SUPER_H);
        }
    if (!DeleteLayer(DUMMY, msgLayer))
        error(msgLayer, "Error deleting layer");
    }
}

/*
** Set up a low-level graphics display for layers to work on.  Layers
** should not be built directly on Intuition screens, use a low-level
** graphics view.  If you need mouse or other events for the layers
** display, you have to get them directly from the input device.  The
** only supported method of using layers library calls with Intuition
** (other than the InstallClipRegion() call) is through Intuition windows.
**
** See graphics primitives chapter for details on creating and using the
** low-level graphics calls.
*/
VOID runNewView(VOID)
{
struct View        theView;
struct View       *oldview;
struct ViewPort    theViewPort;
struct RasInfo     theRasInfo;
struct ColorMap   *theColorMap;
struct Layer_Info *theLayerInfo;
struct BitMap     *theBitMap;
UWORD             *colorpalette;
WORD               ktr;

/* save current view, to be restored when done */
if (NULL != (oldview = GfxBase->ActiView))
    {
    /* get a LayerInfo structure */
    if (NULL != (theLayerInfo = NewLayerInfo()))
        {
        if (NULL != (theColorMap = GetColorMap(4)))
            {
            colorpalette = (UWORD *)theColorMap->ColorTable;
            for(ktr = 0; ktr < 4; ktr++)
                *colorpalette++ = colortable[ktr];

            if (NULL != (theBitMap = allocBitMap(SCREEN_D, SCREEN_W, SCREEN_H)))
                {
                InitView(&theView);
                InitVPort(&theViewPort);

                theView.ViewPort = &theViewPort;

                theViewPort.DWidth   = SCREEN_W;
                theViewPort.DHeight  = SCREEN_H;
                theViewPort.RasInfo  = &theRasInfo;
                theViewPort.ColorMap = theColorMap;

                theRasInfo.BitMap   = theBitMap;
                theRasInfo.RxOffset = 0;
                theRasInfo.RyOffset = 0;
                theRasInfo.Next     = NULL;

                MakeVPort(&theView, &theViewPort);
                MrgCop(&theView);
                LoadView(&theView);
                WaitTOF();

                startLayers(theLayerInfo, theBitMap);

                /* put back the old view, wait for it to become
                ** active before freeing any of our display
                */
                LoadView(oldview);
                WaitTOF();

                /* free dynamically created structures */
                FreeVPortCopLists(&theViewPort);
                FreeCprList(theView.LOFCprList);

                disposeBitMap(theBitMap, SCREEN_D, SCREEN_W, SCREEN_H);
                }
            FreeColorMap(theColorMap);       /* free the color map */
            }
        DisposeLayerInfo(theLayerInfo);
        }
    }
}

/*
** Open the libraries used by the example.  Clean up when done.
*/
VOID main(int argc, char **argv)
{
if (NULL != (GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",33L)))
    {
    if (NULL != (LayersBase = OpenLibrary("layers.library",33L)))
        {
        runNewView();

        CloseLibrary((struct Library *)LayersBase);
        }
    CloseLibrary((struct Library *)GfxBase);
    }
}

Regions

Regions allow the application to install clipping rectangles into layers. A clipping rectangle is a rectangular area into which the graphics routines will draw. All drawing that would fall outside of that rectangular area is clipped (not rendered).

User clipping regions are linked lists of clipping rectangles created by an application program through the graphics library routines described below. By combining together various clipping rectangles, any arbitrary clipping shape can be created. Once the region is set up, you use the layers library call InstallClipRegion() to make the clipping region active in a layer.

Regions are safe to use with layers created by Intuition (i.e., windows). The following table describes the routines available for the creation, manipulation and use of regions.

Functions Used with Regions
Routine Library Description
InstallClipRegion() Layers Add a clipping region to a layer.
NewRegion() Graphics Create a new, empty region.
DisposeRegion() Graphics Dispose of an existing region and its rectangles.
AndRectRegion() Graphics And a rectangle into a region.
OrRectRegion() Graphics Or a rectangle into a region.
XorRectRegion() Graphics Exclusive-or a rectangle into a region.
ClearRectRegion() Graphics Clear a rectangular portion of a region.
AndRegionRegion() Graphics And two regions together.
OrRegionRegion() Graphics Or two regions together.
XorRegionRegion() Graphics Exclusive-or two regions together.
ClearRegion() Graphics Clear a region.

With these functions, the application can selectively update a custom-shaped part of a layer without disturbing any of the other layers that might be present.

Never Modify the DamageList of a Layer Directly
Use the routine InstallClipRegion() to add clipping to the layer. The regions installed by InstallClipRegion() are independent of the layer's DamageList and use of user clipping regions will not interfere with optimized window refreshing.
Do Not Modify A Region After It Has Been Added
After a region has been added with InstallClipRegion(), the program may not modify it until the region has been removed with another call to InstallClipRegion().

Creating and Deleting Regions

You allocate a Region data structure with the NewRegion() call.

struct Region *NewRegion( VOID );

The NewRegion() function allocates and initializes a Region structure that has no drawable areas defined in it. If the application draws through a new region, nothing will be drawn as the region is empty. The application must add rectangles to the region before any graphics will appear.

Use DisposeRegion() to free the Region structure when you are done with it.

VOID DisposeRegion( struct Region *region );

DisposeRegion() returns all memory associated with a region to the system and deallocates all rectangles that have been linked to it.

Don't Forget to Free Your Rectangles
All of the functions that add rectangles to the region make copies of the rectangles. If the program allocates a rectangle, then adds it to a region, it still must deallocate the rectangle. The call to DisposeRegion() will not deallocate rectangles explicitly allocated by the application.

Installing Regions

Use the function InstallClipRegion() to install the region.

struct Region *InstallClipRegion( struct Layer *layer, struct Region *region );

This installs a transparent clipping region to a layer. All subsequent graphics calls will be clipped to this region. The region must be removed with a second call to InstallClipRegion() before removing the layer.

/*
** Sample installation and removal of a clipping region
*/
register struct Region     *new_region ;
register struct Region     *old_region ;

/* If the application owns the layer and has not installed a region,
** old_region will return NULL here.
*/
old_region = InstallClipRegion(win->WLayer, new_region);

/* draw into the layer or window */

if (NULL != (old_region = InstallClipRegion(win->WLayer, old_region)))
    {
    /* throw the used region away.  This region could be saved and
    ** used again later, if desired by the application.
    */
    DisposeRegion(new_region) ;
    }
A Warning About InstallClipRegion()
The program must not call InstallClipRegion() inside of a Begin/EndRefresh() or Begin/EndUpdate() pair. The following code segment shows how to modify the user clipping region when using these calls. See the Autodoc for BeginRefresh() for more details.
struct Region     *new_region ;
struct Region     *old_region ;

/* you have to have already setup the new_region and old_region */

BeginRefresh(window);
/* draw through the damage list */
/* into the layer or window */
EndRefresh(window, FALSE);              /* keep the damage list */

old_region = InstallClipRegion(win->WLayer, new_region);

BeginRefresh(window);
/* draw through the damage list and the new_region */
/* into the layer or window */
EndRefresh(window, FALSE);              /* keep the damage list */

/* put back the old region */
new_region = InstallClipRegion(win->WLayer, old_region);

BeginRefresh(window);
EndRefresh(window, TRUE);               /* remove the damage list */

old_region = InstallClipRegion(win->WLayer, new_region);

BeginRefresh(window);
/* draw through the new_region only into the layer or window */
EndRefresh(window, FALSE);

/* finally get rid of the new region, old_region still installed */
if (NULL != (new_region = InstallClipRegion(win->WLayer, old_region)))
    DisposeRegion(new_region) ;

Changing a Region

Regions may be modified by performing logical operations with rectangles, or with other regions.

Reuse Your Rectangles
In all of the rectangle and region routines the clipping rectangle is copied into the region. This means that a single clipping rectangle (Rectangle structure) may be used many times by simply changing the x and y values. The application need not create a new instance of the Rectangle structure for each rectangle added to a region.

For instance:

extern struct Region *RowRegion;  /* created elsewhere */

WORD ktr;
struct Rectangle rect;

for (ktr = 1; ktr < 6; ktr++)
    {
    rect.MinX = 50;
    rect.MaxX = 315;
    rect.MinY = (ktr * 10) - 5;
    rect.MaxY = (ktr * 10);

    if (!OrRectRegion(RowRegion, &rect))
        clean_exit(RETURN_WARN);
    }

Rectangles and Regions

There are four functions for changing a region through logical operations with a rectangle.

BOOL OrRectRegion   ( struct Region *region, struct Rectangle *rectangle );
VOID AndRectRegion  ( struct Region *region, struct Rectangle *rectangle );
BOOL XorRectRegion  ( struct Region *region, struct Rectangle *rectangle );
BOOL ClearRectRegion( struct Region *region, struct Rectangle *rectangle );

OrRectRegion() modifies a region structure by OR'ing a clipping rectangle into the region. When the application draws through this region (assuming that the region was originally empty), only the pixels within the clipping rectangle will be affected. If the region already has drawable areas, they will still exist, this rectangle is added to the drawable area.

AndRectRegion() modifies the region structure by AND'ing a clipping rectangle into the region. Only those pixels that were already drawable and within the rectangle will remain drawable, any that are outside of it will be clipped in future.

XorRectRegion() applies the rectangle to the region in an exclusive-or mode. Within the given rectangle, any areas that were drawable become clipped, any areas that were clipped become drawable. Areas outside of the rectangle are not affected.

ClearRectRegion() clears the rectangle from the region. Within the given rectangle, any areas that were drawable become clipped. Areas outside of the rectangle are not affected.

Regions and Regions

As with rectangles and regions, there are four layers library functions for combining regions with regions:

BOOL AndRegionRegion( struct Region *srcRegion, struct Region *destRegion );
BOOL OrRegionRegion ( struct Region *srcRegion, struct Region *destRegion );
BOOL XorRegionRegion( struct Region *srcRegion, struct Region *destRegion );
VOID ClearRegion    ( struct Region *region );

AndRegionRegion() performs a logical AND operation on the two regions, leaving the result in the second region. The operation leaves drawable areas wherever the regions drawable areas overlap. That is, where there are drawable areas in both region 1 AND region 2, there will be drawable areas left in the result region.

OrRegionRegion() performs a logical OR operation on the two regions, leaving the result in the second region. The operation leaves drawable areas wherever there are drawable areas in either region. That is, where there are drawable areas in either region 1 OR region 2, there will be drawable areas left in the result region.

XorRegionRegion() performs a logical exclusive-or operation on the two regions, leaving the result in the second region. The operation leaves drawable areas wherever there are drawable areas in either region but not both. That is, where there are drawable areas in either region 1 OR region 2, there will be drawable areas left in the result region. But where there are drawable areas in both region 1 AND region 2, there will not be drawable areas left in the result region.

ClearRegion() puts the region back to the same state it was in when the region was created with NewRegion(), that is, no areas are drawable.

Regions Example

The following example shows the use of the layers library call InstallClipRegion(), as well as simple use of the graphics library regions functions. Be aware that it uses Release 2 functions for opening and closing Intuition windows.

/* clipping.c
**
** SAS/C 5.10a
** lc -b1 -cfist -v -y clipping
** blink FROM LIB:c.o clipping.o TO clipping LIB LIB:lc.lib LIB:amiga.lib
*/

/* Force use of new variable names to help prevent errors */
#define INTUI_V36_NAMES_ONLY

#include <exec/types.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <graphics/displayinfo.h>

#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/intuition_protos.h>
#include <clib/graphics_protos.h>
#include <clib/layers_protos.h>

#include <stdio.h>

#ifdef LATTICE
int CXBRK(void)    { return(0); }  /* Disable Lattice CTRL/C handling */
int chkabort(void) { return(0); }  /* really */
#endif

#define MY_WIN_WIDTH  (300)
#define MY_WIN_HEIGHT (100)

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Library *LayersBase;

/*
** unclipWindow()
**
** Used to remove a clipping region installed by clipWindow() or
** clipWindowToBorders(), disposing of the installed region and
** reinstalling the region removed.
*/
void unclipWindow(struct Window *win)
{
struct Region     *old_region;

/* Remove any old region by installing a NULL region,
** then dispose of the old region if one was installed.
*/
if (NULL != (old_region = InstallClipRegion(win->WLayer, NULL)))
    DisposeRegion(old_region);
}

/*
** clipWindow()
** Clip a window to a specified rectangle (given by upper left and
** lower right corner.)  the removed region is returned so that it
** may be re-installed later.
*/
struct Region *clipWindow(struct Window *win,
    LONG minX, LONG minY, LONG maxX, LONG maxY)
{
struct Region    *new_region;
struct Rectangle  my_rectangle;

/* set up the limits for the clip */
my_rectangle.MinX = minX;
my_rectangle.MinY = minY;
my_rectangle.MaxX = maxX;
my_rectangle.MaxY = maxY;

/* get a new region and OR in the limits. */
if (NULL != (new_region = NewRegion()))
    {
    if (FALSE == OrRectRegion(new_region, &my_rectangle))
        {
        DisposeRegion(new_region);
        new_region = NULL;
        }
    }

/* Install the new region, and return any existing region.
** If the above allocation and region processing failed, then
** new_region will be NULL and no clip region will be installed.
*/
return(InstallClipRegion(win->WLayer, new_region));
}

/*
** clipWindowToBorders()
** clip a window to its borders.
** The removed region is returned so that it may be re-installed later.
*/
struct Region *clipWindowToBorders(struct Window *win)
{
return(clipWindow(win, win->BorderLeft, win->BorderTop,
    win->Width - win->BorderRight - 1, win->Height - win->BorderBottom - 1));
}

/*
** Wait for the user to select the close gadget.
*/
VOID wait_for_close(struct Window *win)
{
struct IntuiMessage *msg;
SHORT done;

done = FALSE;
while (FALSE == done)
    {
    /* we only have one signal bit, so we do not have to check which
    ** bit broke the Wait().
    */
    Wait(1L << win->UserPort->mp_SigBit);

    while ( (FALSE == done) &&
            (NULL != (msg = (struct IntuiMessage *)GetMsg(win->UserPort))))
        {
        /* use a switch statement if looking for multiple event types */
        if (msg->Class == IDCMP_CLOSEWINDOW)
            done = TRUE;

        ReplyMsg((struct Message *)msg);
        }
    }
}

/*
** Simple routine to blast all bits in a window with color three to show
** where the window is clipped.  After a delay, flush back to color zero
** and refresh the window borders.
*/
VOID draw_in_window(struct Window *win, UBYTE *message)
{
printf("%s...", message); fflush(stdout);
SetRast(win->RPort, 3);
Delay(200);
SetRast(win->RPort, 0);
RefreshWindowFrame(win);
printf("done\n");
}


/*
** Show drawing into an unclipped window, a window clipped to the
** borders and a window clipped to a random rectangle.  It is possible
** to clip more complex shapes by AND'ing, OR'ing and exclusive-OR'ing
** regions and rectangles to build a user clip region.
**
** This example assumes that old regions are not going to be re-used,
** so it simply throws them away.
*/
VOID clip_test(struct Window *win)
{
struct Region    *old_region;

draw_in_window(win,"Window with no clipping");

/* if the application has never installed a user clip region,
** then old_region will be NULL here.  Otherwise, delete the
** old region (you could save it and re-install it later...)
*/
if (NULL != (old_region = clipWindowToBorders(win)))
    DisposeRegion(old_region);
draw_in_window(win,"Window clipped to window borders");
unclipWindow(win);

/* here we know old_region will be NULL, as that is what we
** installed with unclipWindow()...
*/
if (NULL != (old_region = clipWindow(win,20,20,100,50)))
    DisposeRegion(old_region);
draw_in_window(win,"Window clipped from (20,20) to (100,50)");
unclipWindow(win);

wait_for_close(win);
}



/*
** Open and close resources, call the test routine when ready.
*/
VOID main(int argc, char **argv)
{
struct Window *win;

if (NULL != (IntuitionBase =
        (struct IntuitionBase *)OpenLibrary("intuition.library",37)))
    {
    if (NULL != (GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",37)))
        {
        if (NULL != (LayersBase = OpenLibrary("layers.library",37)))
            {
            if (NULL != (win = OpenWindowTags(NULL,
                                WA_Width,       MY_WIN_WIDTH,
                                WA_Height,      MY_WIN_HEIGHT,
                                WA_IDCMP,       IDCMP_CLOSEWINDOW,
                                WA_CloseGadget, TRUE,
                                WA_DragBar,     TRUE,
                                WA_Activate,    TRUE,
                                TAG_END)))
                {
                clip_test(win);

                CloseWindow(win);
                }
            CloseLibrary(LayersBase);
            }
        CloseLibrary((struct Library *)GfxBase);
        }
    CloseLibrary((struct Library *)IntuitionBase);
    }
}

Function Reference

The following are brief descriptions of the layers library functions and related routines from the graphics library. See the SDK for details on each function call.

Layers Library Functions

Function Description
NewLayerInfo() Allocating a Layer_Info structure.
DisposeLayerInfo() Deallocating a Layer_Info structure.
CreateUpfrontLayer() Make a new layer in front of others.
CreateBehindLayer() Make a new layer behind others.
DeleteLayer() Remove and delete an existing layer.
MoveLayer() Change the position (not depth) of a layer.
SizeLayer() Change the size of a layer.
ScrollLayer() Change the internal coordinates of a layer.
BehindLayer() Depth arrange a layer behind others.
UpfrontLayer() Depth arrange a layer in front of others.
MoveLayerInFrontOf() Depth arrange a layer to a specific position.
WhichLayer() Find the frontmost layer at a position.
SwapBitsRastPortClipRect() Fast, non-layered and non-damaging display operation.
BeginUpdate() Synchronize optimized refreshing for layer.
EndUpdate() End optimized layer refresh.
LockLayer() Lock out rendering in a single layer.
UnlockLayer() Release LockLayer() lock.
LockLayers() Lock out rendering in all layers of a display.
UnlockLayers() Release LockLayers() lock.
LockLayerInfo() Gain exclusive access to the display’s layers.
UnlockLayerInfo() Release LockLayerInfo() lock.
InstallClipRegion() Add a clipping region to a layer.

The following routines from graphics library are also required for certain layers library functions:

Routine Description
LockLayerRom() Same as LockLayer(), from layers library.
UnlockLayerRom() Release LockLayerRom() lock.
AttemptLockLayerRom() Lock layer only if it is immediately available.
NewRegion() Create a new, empty region.
DisposeRegion() Dispose of an existing region and its rectangles.
AndRectRegion() AND a rectangle into a region.
OrRectRegion() OR a rectangle into a region.
XorRectRegion() Exclusive-OR a rectangle into a region.
ClearRectRegion() Clear a region.
AndRegionRegion() AND two regions together.
OrRegionRegion() OR two regions together.
XorRegionRegion() Exclusive-OR two regions together.
ClearRegion() Clear a region.