Copyright (c) Hyperion Entertainment and contributors.
Layers Library
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. |
Contents
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.
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:
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.
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:
- 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.
- 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 */ /* 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 <proto/exec.h> #include <proto/dos.h> #include <proto/graphics.h> #include <proto/layers.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #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 GraphicsIFace *IGraphics = 0; struct LayersIFace *ILayers = 0; /* 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 */ 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)); } /* ** write a message into a layer with a delay. */ VOID pMessage(struct Layer *layer, UBYTE *string) { IDOS->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); IDOS->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 (!ILayers->MoveLayerInFrontOf(layer_array[1], layer_array[0])) error(msgLayer, "MoveLayerInFrontOf() failed."); pMessage(msgLayer, "MoveLayer 2 InFrontOf 1"); if (!ILayers->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 (!ILayers->MoveLayer(DUMMY, layer_array[1], -1, 0)) error(msgLayer, "MoveLayer() failed."); if (!ILayers->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 (!ILayers->UpfrontLayer(DUMMY, layer_array[0])) error(msgLayer, "UpfrontLayer() failed."); pMessage(msgLayer, "make Layer 2 the BehindLayer"); if (!ILayers->BehindLayer(DUMMY, layer_array[2])) error(msgLayer, "BehindLayer() failed."); pMessage(msgLayer, "Incrementally MoveLayers again..."); for(ktr = 0; ktr < 30; ktr++) { if (!ILayers->MoveLayer(DUMMY, layer_array[1], 0, 1)) error(msgLayer, "MoveLayer() failed."); if (!ILayers->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 (!ILayers->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 (!ILayers->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 (!ILayers->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++) { ILayers->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++) { ILayers->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"); IDOS_>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 (!ILayers->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] = ILayers->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] = ILayers->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"); IGraphics->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]) IGraphics->FreeRaster(bitmap->Planes[ktr], width, height); } IExec->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 = IExec->AllocMem(sizeof(*bitmap),NULL))) { IGraphics->InitBitMap(bitmap,depth,width,height); for (ktr = 0; ktr < depth; ktr++) { if (NULL == (bitmap->Planes[ktr] = (PLANEPTR)IGraphics->AllocRaster(width,height))) bit_map_failed = TRUE; else IGraphics->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 = ILayers->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 (!ILayers->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 = ILayers->NewLayerInfo())) { if (NULL != (theColorMap = IGraphics->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))) { IGraphics->InitView(&theView); IGraphics->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; IGraphics->MakeVPort(&theView, &theViewPort); IGraphics->MrgCop(&theView); IGraphics->LoadView(&theView); IGraphics->WaitTOF(); startLayers(theLayerInfo, theBitMap); /* put back the old view, wait for it to become ** active before freeing any of our display */ IGraphics->LoadView(oldview); IGraphics->WaitTOF(); /* free dynamically created structures */ IGraphics->FreeVPortCopLists(&theViewPort); IGraphics->FreeCprList(theView.LOFCprList); disposeBitMap(theBitMap, SCREEN_D, SCREEN_W, SCREEN_H); } IGraphics->FreeColorMap(theColorMap); /* free the color map */ } ILayers->DisposeLayerInfo(theLayerInfo); } } } /* ** Open the libraries used by the example. Clean up when done. */ int main(int argc, char **argv) { struct Library *GfxBase = IExec->OpenLibrary("graphics.library", 50); struct Library *LayersBase = IExec->OpenLibrary("layers.library", 50); IGraphics = (struct GraphicsIFace*)IExec->GetInterface(GfxBase, "main", 1, NULL); ILayers = (struct LayersIFace*)IExec->GetInterface(LayersBase, "main", 1, NULL); if (IGraphics != NULL && ILayers != NULL) { runNewView(); } IExec->DropInterface((struct Interface*)ILayers); IExec->DropInterface((struct Interface*)IGraphics); IExec->CloseLibrary(LayersBase); IExec->CloseLibrary(GfxBase); return 0; }
Function Reference
The following are brief descriptions of the layers library functions. See the SDK for details on each function call.
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. |