Copyright (c) Hyperion Entertainment and contributors.
Difference between revisions of "Layers Library"
Steven Solie (talk | contribs) |
Steven Solie (talk | contribs) |
||
(32 intermediate revisions by the same user not shown) | |||
Line 2: | Line 2: | ||
== Layers Library == |
== Layers Library == |
||
− | This |
+ | This article 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 |
+ | The Graphics Library 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 == |
== Layers == |
||
Line 26: | Line 26: | ||
Here is a partial listing of the Layer structure from <graphics/clip.h>. (For a complete listing refer to the SDK.) |
Here is a partial listing of the Layer structure from <graphics/clip.h>. (For a complete listing refer to the SDK.) |
||
+ | <syntaxhighlight> |
||
− | <pre> |
||
struct Layer |
struct Layer |
||
{ |
{ |
||
Line 41: | Line 41: | ||
struct Region *DamageList; /* list of rectangles to refresh through */ |
struct Region *DamageList; /* list of rectangles to refresh through */ |
||
}; |
}; |
||
+ | </syntaxhighlight> |
||
− | </pre> |
||
{{Note|title=The Layer Structure is Read-Only|text=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.)}} |
{{Note|title=The Layer Structure is Read-Only|text=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.)}} |
||
Line 51: | Line 51: | ||
Here is sample code showing how to access the layer's RastPort: |
Here is sample code showing how to access the layer's RastPort: |
||
+ | <syntaxhighlight> |
||
− | <pre> |
||
struct RastPort *myRPort; /* allocate a RastPort pointer for each layer */ |
struct RastPort *myRPort; /* allocate a RastPort pointer for each layer */ |
||
− | myRPort = layer- |
+ | myRPort = layer->rp; |
/* The layer's RastPort may be used with any of the graphics library calls |
/* 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: |
** that require this structure. For instance, to fill layer with color: |
||
*/ |
*/ |
||
− | SetRast(layer- |
+ | IGraphics->SetRast(layer->rp, color); |
/* set up for writing text into layer */ |
/* set up for writing text into layer */ |
||
− | SetDrMd(layer- |
+ | IGraphics->SetDrMd(layer->rp, JAM1); |
− | SetAPen(layer- |
+ | IGraphics->SetAPen(layer->rp, 0); |
− | Move(layer- |
+ | IGraphics->Move(layer->rp, 5, 7); |
/* write into layer */ |
/* write into layer */ |
||
− | Text(layer- |
+ | IGraphics->Text(layer->rp, string, strlen(string)); |
+ | </syntaxhighlight> |
||
− | </pre> |
||
=== Types of Layers === |
=== Types of Layers === |
||
Line 84: | Line 84: | ||
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: |
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: |
||
+ | <syntaxhighlight> |
||
− | <pre> |
||
− | if (layer- |
+ | if (layer->Flags & LAYERREFRESH) |
refresh(layer); |
refresh(layer); |
||
+ | </syntaxhighlight> |
||
− | </pre> |
||
When an application restores the layer by performing a full-layer redraw, only the damaged areas are redrawn, making the operation fairly time efficient. |
When an application restores the layer by performing a full-layer redraw, only the damaged areas are redrawn, making the operation fairly time efficient. |
||
Line 122: | Line 122: | ||
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. |
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. |
||
+ | <syntaxhighlight> |
||
− | <pre>struct Library *LayersBase; |
||
+ | #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 */ |
/* use Layers library */ |
||
+ | } |
||
+ | |||
+ | IExec->DropInterface((struct Interface*)ILayers); |
||
+ | IExec->CloseLibrary(LayersBase); |
||
+ | </syntaxhighlight> |
||
− | CloseLibrary((struct Library *)LayersBase); |
||
− | }</pre> |
||
=== Working With Existing Layers === |
=== Working With Existing Layers === |
||
Line 179: | Line 187: | ||
LockLayerInfo() must be called whenever the visible portions of layers may be affected, or when the Layer_Info structure is changed. |
LockLayerInfo() must be called whenever the visible portions of layers may be affected, or when the Layer_Info structure is changed. |
||
+ | <syntaxhighlight> |
||
− | <pre> |
||
VOID LockLayerInfo( struct Layer_Info *li ); |
VOID LockLayerInfo( struct Layer_Info *li ); |
||
+ | </syntaxhighlight> |
||
− | </pre> |
||
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. |
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. |
||
Line 189: | Line 197: | ||
Use UnlockLayerInfo() when you have finished the layer operation: |
Use UnlockLayerInfo() when you have finished the layer operation: |
||
+ | <syntaxhighlight> |
||
− | <pre> |
||
VOID UnlockLayerInfo( struct Layer_Info *li ); |
VOID UnlockLayerInfo( struct Layer_Info *li ); |
||
+ | </syntaxhighlight> |
||
− | </pre> |
||
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. |
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. |
||
Line 197: | Line 205: | ||
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. |
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. |
||
+ | <syntaxhighlight> |
||
− | <pre> |
||
VOID LockLayer( long dummy, struct Layer *layer ); |
VOID LockLayer( long dummy, struct Layer *layer ); |
||
+ | </syntaxhighlight> |
||
− | </pre> |
||
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. |
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. |
||
Line 205: | Line 213: | ||
UnlockLayer() should be used after the graphics operation to make the layer available to other tasks again. |
UnlockLayer() should be used after the graphics operation to make the layer available to other tasks again. |
||
+ | <syntaxhighlight> |
||
− | <pre> |
||
VOID UnlockLayer( struct Layer *layer ); |
VOID UnlockLayer( struct Layer *layer ); |
||
+ | </syntaxhighlight> |
||
− | </pre> |
||
If more than one layer must be locked, then the LockLayer() calls should be surrounded by LockLayerInfo() and UnlockLayerInfo() calls, to prevent deadlock situations. |
If more than one layer must be locked, then the LockLayer() calls should be surrounded by LockLayerInfo() and UnlockLayerInfo() calls, to prevent deadlock situations. |
||
Line 213: | Line 221: | ||
The layers library provides two additional functions, LockLayers() and UnlockLayers(), for locking multiple layers. |
The layers library provides two additional functions, LockLayers() and UnlockLayers(), for locking multiple layers. |
||
+ | <syntaxhighlight> |
||
− | <pre> |
||
VOID LockLayers( struct Layer_Info *li ); |
VOID LockLayers( struct Layer_Info *li ); |
||
VOID UnlockLayers( struct Layer_Info *li ); |
VOID UnlockLayers( struct Layer_Info *li ); |
||
+ | </syntaxhighlight> |
||
− | </pre> |
||
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). |
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). |
||
Line 224: | Line 232: | ||
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: |
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: |
||
+ | <syntaxhighlight> |
||
− | <pre> |
||
− | struct Layer *WhichLayer( struct Layer_Info *li, |
+ | struct Layer *WhichLayer( struct Layer_Info *li, int32 x, int32 y ); |
+ | </syntaxhighlight> |
||
− | </pre> |
||
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(). |
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(). |
||
Line 235: | Line 243: | ||
Only applications that create and mange their own View will be able to call the layer creation and updating functions discussed here. |
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 |
||
{| class="wikitable" |
{| class="wikitable" |
||
+ | |+ Functions for Creating and Updating Layers |
||
| NewLayerInfo() || Allocating a Layer_Info structure. |
| NewLayerInfo() || Allocating a Layer_Info structure. |
||
|- |
|- |
||
Line 276: | Line 283: | ||
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: |
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: |
||
+ | <syntaxhighlight> |
||
− | <pre>struct Layer_Info *theLayerInfo; |
||
+ | struct Layer_Info *theLayerInfo; |
||
− | if (NULL != (theLayerInfo = NewLayerInfo())) |
+ | if (NULL != (theLayerInfo = ILayers->NewLayerInfo())) |
{ |
{ |
||
/* use Layer_Info */ |
/* use Layer_Info */ |
||
− | DisposeLayerInfo(theLayerInfo); |
+ | ILayers->DisposeLayerInfo(theLayerInfo); |
− | } |
+ | } |
+ | </syntaxhighlight> |
||
− | |||
Layers may be created in the common bit map by calling CreateUpfrontLayer() or CreateBehindLayer(), with a sequence such as the following: |
Layers may be created in the common bit map by calling CreateUpfrontLayer() or CreateBehindLayer(), with a sequence such as the following: |
||
+ | <syntaxhighlight> |
||
− | <pre>struct Layer *layer; |
||
+ | struct Layer *layer; |
||
struct Layer_Info *theLayerInfo; |
struct Layer_Info *theLayerInfo; |
||
struct BitMap *theBitMap; |
struct BitMap *theBitMap; |
||
/* requests construction of a smart refresh layer. */ |
/* requests construction of a smart refresh layer. */ |
||
− | if (NULL == (layer = CreateUpfrontLayer(theLayerInfo, theBitMap, |
+ | if (NULL == (layer = ILayers->CreateUpfrontLayer(theLayerInfo, theBitMap, 20, 20, 100, 80, LAYERSMART, NULL))) |
+ | error("CreateUpfrontLayer() failed."); |
||
− | 20, 20, 100, 80, LAYERSMART, NULL))) |
||
− | error("CreateUpfrontLayer() failed."); |
||
else |
else |
||
{ |
{ |
||
; /* layer successfully created here. */ |
; /* layer successfully created here. */ |
||
− | } |
+ | } |
+ | </syntaxhighlight> |
||
+ | |||
==== Allocating and Deallocating Layer_Info ==== |
==== Allocating and Deallocating Layer_Info ==== |
||
− | |||
− | |||
Use NewLayerInfo() to allocate and initialize a Layer_Info structure and associated sub-structures. |
Use NewLayerInfo() to allocate and initialize a Layer_Info structure and associated sub-structures. |
||
+ | <syntaxhighlight> |
||
− | <pre>struct Layer_Info *NewLayerInfo( VOID );</pre> |
||
+ | struct Layer_Info *NewLayerInfo( VOID ); |
||
+ | </syntaxhighlight> |
||
+ | |||
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. |
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. |
||
+ | <syntaxhighlight> |
||
− | <pre>VOID DisposeLayerInfo( struct Layer_Info *li );</pre> |
||
+ | VOID DisposeLayerInfo( struct Layer_Info *li ); |
||
− | |||
+ | </syntaxhighlight> |
||
This function deallocates a Layer_Info and associated structures previously allocated with NewLayerInfo(). |
This function deallocates a Layer_Info and associated structures previously allocated with NewLayerInfo(). |
||
Line 318: | Line 330: | ||
Layers are created using the routines CreateUpfrontLayer() and CreateBehindLayer(). CreateUpfrontLayer() creates a layer that will appear in front of any existing layers. |
Layers are created using the routines CreateUpfrontLayer() and CreateBehindLayer(). CreateUpfrontLayer() creates a layer that will appear in front of any existing layers. |
||
+ | <syntaxhighlight> |
||
− | <pre> |
||
− | struct Layer *CreateUpfrontLayer( struct Layer_Info *li, struct BitMap *bm, |
+ | struct Layer *CreateUpfrontLayer( struct Layer_Info *li, struct BitMap *bm, int32 x0, int32 y0, int32 x1, int32 y1, int32 flags, struct BitMap *bm2 ); |
+ | </syntaxhighlight> |
||
− | LONG x0, LONG y0, LONG x1, LONG y1, LONG flags, struct BitMap *bm2 ); |
||
− | </pre> |
||
CreateBehindLayer() creates a layer that appears behind existing layers, but in front of backdrop layers. |
CreateBehindLayer() creates a layer that appears behind existing layers, but in front of backdrop layers. |
||
+ | <syntaxhighlight> |
||
− | <pre> |
||
− | struct Layer *CreateBehindLayer( struct Layer_Info *li, struct BitMap *bm, |
+ | struct Layer *CreateBehindLayer( struct Layer_Info *li, struct BitMap *bm, int32 x0, int32 y0, int32 x1, int32 y1, int32 flags, struct BitMap *bm2 ); |
+ | </syntaxhighlight> |
||
− | LONG x0, LONG y0, LONG x1, LONG y1, LONG flags, struct BitMap *bm2 ); |
||
− | </pre> |
||
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. |
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. |
||
+ | {{Note|title=A New Layer Also Gets a RastPort|text=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.}} |
||
− | {| class="wikitable" |
||
− | | ''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: |
Use the DeleteLayer() call to remove a layer: |
||
+ | <syntaxhighlight> |
||
− | <pre> |
||
− | + | int32 DeleteLayer( int32 dummy, struct Layer *layer ); |
|
+ | </syntaxhighlight> |
||
− | </pre> |
||
DeleteLayer() removes a layer from the layer list and frees the memory allocated by the layer creation calls listed above. |
DeleteLayer() removes a layer from the layer list and frees the memory allocated by the layer creation calls listed above. |
||
Line 348: | Line 356: | ||
The layers library includes three functions for moving and sizing layers: |
The layers library includes three functions for moving and sizing layers: |
||
+ | <syntaxhighlight> |
||
− | <pre> |
||
− | + | 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); |
|
+ | </syntaxhighlight> |
||
− | </pre> |
||
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. |
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. |
||
Line 358: | Line 366: | ||
==== Changing a Viewpoint ==== |
==== Changing a Viewpoint ==== |
||
+ | The ScrollLayer() function changes the portion of a super bitmap that is shown by a layer: |
||
+ | <syntaxhighlight> |
||
+ | VOID ScrollLayer( int32 dummy, struct Layer *layer, int32 dx, int32 dy ); |
||
+ | </syntaxhighlight> |
||
− | The ScrollLayer() function changes the portion of a super bitmap that is shown by a layer: |
||
− | |||
− | <pre>VOID ScrollLayer( LONG dummy, struct Layer *layer, LONG dx, LONG dy );</pre> |
||
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. |
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. |
||
Line 369: | Line 378: | ||
The layers library provides three function calls for reordering layers: |
The layers library provides three function calls for reordering layers: |
||
+ | <syntaxhighlight> |
||
− | <pre> |
||
− | + | 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 ); |
|
+ | </syntaxhighlight> |
||
− | </pre> |
||
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. |
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. |
||
Line 379: | Line 388: | ||
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. |
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. |
||
+ | <syntaxhighlight> |
||
− | <pre> |
||
− | + | int32 BeginUpdate( struct Layer *l ); |
|
− | VOID EndUpdate ( struct Layer *layer, |
+ | VOID EndUpdate ( struct Layer *layer, uint32 flag ); |
+ | </syntaxhighlight> |
||
− | </pre> |
||
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. |
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. |
||
+ | {{Note|title=Never Modify the DamageList|text=The system generates and maintains the DamageList region. All application clipping should be done through the InstallClipRegion() function.}} |
||
− | {| class="wikitable" |
||
− | | ''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. |
To complete the update process call EndUpdate() which will restore the original ClipRect list. |
||
Line 396: | Line 403: | ||
The SwapBitsRastPortClipRect() routine is for applications that do not want to worry about clipping rectangles. |
The SwapBitsRastPortClipRect() routine is for applications that do not want to worry about clipping rectangles. |
||
+ | <syntaxhighlight> |
||
− | <pre>VOID SwapBitsRastPortClipRect( struct RastPort *rp, struct ClipRect *cr );</pre> |
||
+ | VOID SwapBitsRastPortClipRect( struct RastPort *rp, struct ClipRect *cr ); |
||
+ | </syntaxhighlight> |
||
+ | |||
For instance, you may use The SwapBitsRastPortClipRect() to produce a menu without using Intuition. There are two ways to produce such a menu: |
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) |
+ | # 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: |
# 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. |
#* 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. |
||
Line 407: | Line 417: | ||
The second method is faster and leaves the clipping rectangles and most of the rest of the window data structures untouched. |
The second method is faster and leaves the clipping rectangles and most of the rest of the window data structures untouched. |
||
+ | {{Note|title=Warning|text=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.}} |
||
− | {| class="wikitable" |
||
− | | ''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 === |
=== Layers Example === |
||
Line 415: | Line 423: | ||
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. |
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. |
||
+ | <syntaxhighlight> |
||
− | <pre>/* Layers.c |
||
+ | /* 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 */ |
/* Force use of new variable names to help prevent errors */ |
||
#define INTUI_V36_NAMES_ONLY |
#define INTUI_V36_NAMES_ONLY |
||
− | #include |
+ | #include <exec/types.h> |
− | #include |
+ | #include <graphics/gfxbase.h> |
− | #include |
+ | #include <graphics/layers.h> |
− | #include |
+ | #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 |
+ | #include <proto/exec.h> |
− | #include |
+ | #include <proto/dos.h> |
− | #include |
+ | #include <proto/graphics.h> |
+ | #include <proto/layers.h> |
||
+ | #include <stdio.h> |
||
− | #ifdef LATTICE |
||
+ | #include <stdlib.h> |
||
− | int CXBRK(void) { return(0); } /* Disable Lattice CTRL/C handling */ |
||
+ | #include <string.h> |
||
− | int chkabort(void) { return(0); } /* really */ |
||
− | #endif |
||
#define L_DELAY (100) |
#define L_DELAY (100) |
||
Line 477: | Line 476: | ||
#define M_R ((M_L+M_W)-1) |
#define M_R ((M_L+M_W)-1) |
||
− | struct |
+ | struct GraphicsIFace *IGraphics = 0; |
− | struct |
+ | struct LayersIFace *ILayers = 0; |
/* global constant data for initializing the layers */ |
/* global constant data for initializing the layers */ |
||
Line 491: | Line 490: | ||
{ |
{ |
||
/* fill layer with color */ |
/* fill layer with color */ |
||
− | SetRast(layer- |
+ | IGraphics->SetRast(layer->rp, color); |
/* set up for writing text into layer */ |
/* set up for writing text into layer */ |
||
− | SetDrMd(layer- |
+ | IGraphics->SetDrMd(layer->rp,JAM1); |
− | SetAPen(layer- |
+ | IGraphics->SetAPen(layer->rp,0); |
− | Move(layer- |
+ | IGraphics->Move(layer->rp, 5, 7); |
/* write into layer */ |
/* write into layer */ |
||
− | Text(layer- |
+ | IGraphics->Text(layer->rp, string, strlen(string)); |
} |
} |
||
Line 509: | Line 508: | ||
VOID pMessage(struct Layer *layer, UBYTE *string) |
VOID pMessage(struct Layer *layer, UBYTE *string) |
||
{ |
{ |
||
− | Delay(S_DELAY); |
+ | IDOS->Delay(S_DELAY); |
myLabelLayer(layer, GREEN_PEN, string); |
myLabelLayer(layer, GREEN_PEN, string); |
||
} |
} |
||
Line 519: | Line 518: | ||
{ |
{ |
||
myLabelLayer(layer, RED_PEN, string); |
myLabelLayer(layer, RED_PEN, string); |
||
− | Delay(L_DELAY); |
+ | IDOS->Delay(L_DELAY); |
} |
} |
||
Line 532: | Line 531: | ||
WORD ktr_2; |
WORD ktr_2; |
||
− | pMessage(msgLayer, |
+ | pMessage(msgLayer, "Label all Layers"); |
− | myLabelLayer(layer_array[0], RED_PEN, |
+ | myLabelLayer(layer_array[0], RED_PEN, "Super"); |
− | myLabelLayer(layer_array[1], GREEN_PEN, |
+ | myLabelLayer(layer_array[1], GREEN_PEN, "Smart"); |
− | myLabelLayer(layer_array[2], BLUE_PEN, |
+ | myLabelLayer(layer_array[2], BLUE_PEN, "Simple"); |
− | pMessage(msgLayer, |
+ | pMessage(msgLayer, "MoveLayer 1 InFrontOf 0"); |
− | if (!MoveLayerInFrontOf(layer_array[1], layer_array[0])) |
+ | if (!ILayers->MoveLayerInFrontOf(layer_array[1], layer_array[0])) |
− | error(msgLayer, |
+ | error(msgLayer, "MoveLayerInFrontOf() failed."); |
− | pMessage(msgLayer, |
+ | pMessage(msgLayer, "MoveLayer 2 InFrontOf 1"); |
− | if (!MoveLayerInFrontOf(layer_array[2], layer_array[1])) |
+ | if (!ILayers->MoveLayerInFrontOf(layer_array[2], layer_array[1])) |
− | error(msgLayer, |
+ | error(msgLayer, "MoveLayerInFrontOf() failed."); |
− | pMessage(msgLayer, |
+ | pMessage(msgLayer, "Refresh Simple Refresh Layer"); |
− | myLabelLayer(layer_array[2], BLUE_PEN, |
+ | myLabelLayer(layer_array[2], BLUE_PEN, "Simple"); |
− | pMessage(msgLayer, |
+ | pMessage(msgLayer, "Incrementally MoveLayers..."); |
− | for(ktr = 0; ktr |
+ | for(ktr = 0; ktr < 30; ktr++) |
{ |
{ |
||
− | if (!MoveLayer(DUMMY, layer_array[1], -1, 0)) |
+ | if (!ILayers->MoveLayer(DUMMY, layer_array[1], -1, 0)) |
− | error(msgLayer, |
+ | error(msgLayer, "MoveLayer() failed."); |
− | if (!MoveLayer(DUMMY, layer_array[2], -2, 0)) |
+ | if (!ILayers->MoveLayer(DUMMY, layer_array[2], -2, 0)) |
− | error(msgLayer, |
+ | error(msgLayer, "MoveLayer() failed."); |
} |
} |
||
− | pMessage(msgLayer, |
+ | pMessage(msgLayer, "Refresh Simple Refresh Layer"); |
− | myLabelLayer(layer_array[2], BLUE_PEN, |
+ | myLabelLayer(layer_array[2], BLUE_PEN, "Simple"); |
− | pMessage(msgLayer, |
+ | pMessage(msgLayer, "make Layer 0 the UpfrontLayer"); |
− | if (!UpfrontLayer(DUMMY, layer_array[0])) |
+ | if (!ILayers->UpfrontLayer(DUMMY, layer_array[0])) |
− | error(msgLayer, |
+ | error(msgLayer, "UpfrontLayer() failed."); |
− | pMessage(msgLayer, |
+ | pMessage(msgLayer, "make Layer 2 the BehindLayer"); |
− | if (!BehindLayer(DUMMY, layer_array[2])) |
+ | if (!ILayers->BehindLayer(DUMMY, layer_array[2])) |
− | error(msgLayer, |
+ | error(msgLayer, "BehindLayer() failed."); |
− | pMessage(msgLayer, |
+ | pMessage(msgLayer, "Incrementally MoveLayers again..."); |
− | for(ktr = 0; ktr |
+ | for(ktr = 0; ktr < 30; ktr++) |
{ |
{ |
||
− | if (!MoveLayer(DUMMY, layer_array[1], 0, 1)) |
+ | if (!ILayers->MoveLayer(DUMMY, layer_array[1], 0, 1)) |
− | error(msgLayer, |
+ | error(msgLayer, "MoveLayer() failed."); |
− | if (!MoveLayer(DUMMY, layer_array[2], 0, 2)) |
+ | if (!ILayers->MoveLayer(DUMMY, layer_array[2], 0, 2)) |
− | error(msgLayer, |
+ | error(msgLayer, "MoveLayer() failed."); |
} |
} |
||
− | pMessage(msgLayer, |
+ | pMessage(msgLayer, "Refresh Simple Refresh Layer"); |
− | myLabelLayer(layer_array[2], BLUE_PEN, |
+ | myLabelLayer(layer_array[2], BLUE_PEN, "Simple"); |
− | pMessage(msgLayer, |
+ | pMessage(msgLayer, "Big MoveLayer"); |
− | for(ktr = 0; ktr |
+ | for(ktr = 0; ktr < 3; ktr++) |
{ |
{ |
||
− | if (!MoveLayer(DUMMY, layer_array[ktr], -layer_array[ktr]- |
+ | if (!ILayers->MoveLayer(DUMMY, layer_array[ktr], -layer_array[ktr]->bounds.MinX, 0)) |
− | error(msgLayer, |
+ | error(msgLayer, "MoveLayer() failed."); |
} |
} |
||
− | pMessage(msgLayer, |
+ | pMessage(msgLayer, "Incrementally increase size"); |
− | for(ktr = 0; ktr |
+ | for(ktr = 0; ktr < 5; ktr++) |
{ |
{ |
||
− | for(ktr_2 = 0; ktr_2 |
+ | for(ktr_2 = 0; ktr_2 < 3; ktr_2++) |
{ |
{ |
||
− | if (!SizeLayer(DUMMY, layer_array[ktr_2], 1, 1)) |
+ | if (!ILayers->SizeLayer(DUMMY, layer_array[ktr_2], 1, 1)) |
− | error(msgLayer, |
+ | error(msgLayer, "SizeLayer() failed."); |
} |
} |
||
} |
} |
||
− | pMessage(msgLayer, |
+ | pMessage(msgLayer, "Refresh Smart Refresh Layer"); |
− | myLabelLayer(layer_array[1], GREEN_PEN, |
+ | myLabelLayer(layer_array[1], GREEN_PEN, "Smart"); |
− | pMessage(msgLayer, |
+ | pMessage(msgLayer, "Refresh Simple Refresh Layer"); |
− | myLabelLayer(layer_array[2], BLUE_PEN, |
+ | myLabelLayer(layer_array[2], BLUE_PEN, "Simple"); |
− | pMessage(msgLayer, |
+ | pMessage(msgLayer, "Big SizeLayer"); |
− | for(ktr = 0; ktr |
+ | for(ktr = 0; ktr < 3; ktr++) |
{ |
{ |
||
− | if (!SizeLayer(DUMMY,layer_array[ktr], |
+ | if (!ILayers->SizeLayer(DUMMY,layer_array[ktr], |
− | SCREEN_W-(layer_array[ktr]- |
+ | SCREEN_W-(layer_array[ktr]->bounds.MaxX)-1,0)) |
− | error(msgLayer, |
+ | error(msgLayer, "SizeLayer() failed."); |
} |
} |
||
− | pMessage(msgLayer, |
+ | pMessage(msgLayer, "Refresh Smart Refresh Layer"); |
− | myLabelLayer(layer_array[1], GREEN_PEN, |
+ | myLabelLayer(layer_array[1], GREEN_PEN, "Smart"); |
− | pMessage(msgLayer, |
+ | pMessage(msgLayer, "Refresh Simple Refresh Layer"); |
− | myLabelLayer(layer_array[2], BLUE_PEN, |
+ | myLabelLayer(layer_array[2], BLUE_PEN, "Simple"); |
− | pMessage(msgLayer, |
+ | pMessage(msgLayer, "ScrollLayer down"); |
− | for(ktr = 0; ktr |
+ | for(ktr = 0; ktr < 30; ktr++) |
{ |
{ |
||
− | for(ktr_2 = 0; ktr_2 |
+ | for(ktr_2 = 0; ktr_2 < 3; ktr_2++) |
{ |
{ |
||
− | ScrollLayer(DUMMY, layer_array[ktr_2], 0, -1); |
+ | ILayers->ScrollLayer(DUMMY, layer_array[ktr_2], 0, -1); |
} |
} |
||
} |
} |
||
− | pMessage(msgLayer, |
+ | pMessage(msgLayer, "Refresh Smart Refresh Layer"); |
− | myLabelLayer(layer_array[1], GREEN_PEN, |
+ | myLabelLayer(layer_array[1], GREEN_PEN, "Smart"); |
− | pMessage(msgLayer, |
+ | pMessage(msgLayer, "Refresh Simple Refresh Layer"); |
− | myLabelLayer(layer_array[2], BLUE_PEN, |
+ | myLabelLayer(layer_array[2], BLUE_PEN, "Simple"); |
− | pMessage(msgLayer, |
+ | pMessage(msgLayer, "ScrollLayer up"); |
− | for(ktr = 0; ktr |
+ | for(ktr = 0; ktr < 30; ktr++) |
{ |
{ |
||
− | for(ktr_2 = 0; ktr_2 |
+ | for(ktr_2 = 0; ktr_2 < 3; ktr_2++) |
{ |
{ |
||
− | ScrollLayer(DUMMY, layer_array[ktr_2], 0, 1); |
+ | ILayers->ScrollLayer(DUMMY, layer_array[ktr_2], 0, 1); |
} |
} |
||
} |
} |
||
− | pMessage(msgLayer, |
+ | pMessage(msgLayer, "Refresh Smart Refresh Layer"); |
− | myLabelLayer(layer_array[1], GREEN_PEN, |
+ | myLabelLayer(layer_array[1], GREEN_PEN, "Smart"); |
− | pMessage(msgLayer, |
+ | pMessage(msgLayer, "Refresh Simple Refresh Layer"); |
− | myLabelLayer(layer_array[2], BLUE_PEN, |
+ | myLabelLayer(layer_array[2], BLUE_PEN, "Simple"); |
− | Delay(L_DELAY); |
+ | IDOS_>Delay(L_DELAY); |
} |
} |
||
Line 655: | Line 654: | ||
WORD ktr; |
WORD ktr; |
||
− | for (ktr = 0; ktr |
+ | for (ktr = 0; ktr < 3; ktr++) |
{ |
{ |
||
if (layer_array[ktr] != NULL) |
if (layer_array[ktr] != NULL) |
||
{ |
{ |
||
− | if (!DeleteLayer(DUMMY, layer_array[ktr])) |
+ | if (!ILayers->DeleteLayer(DUMMY, layer_array[ktr])) |
− | error(msgLayer, |
+ | error(msgLayer, "Error deleting layer"); |
} |
} |
||
} |
} |
||
Line 682: | Line 681: | ||
for (ktr = 0; |
for (ktr = 0; |
||
− | (ktr |
+ | (ktr < 3) && (create_layer_ok); |
ktr++) |
ktr++) |
||
{ |
{ |
||
− | pMessage(msgLayer, |
+ | pMessage(msgLayer, "Create BehindLayer"); |
if (ktr == 0) |
if (ktr == 0) |
||
{ |
{ |
||
− | if ((layer_array[ktr] = CreateBehindLayer(theLayerInfo, theBitMap, |
+ | if ((layer_array[ktr] = ILayers->CreateBehindLayer(theLayerInfo, theBitMap, |
W_L+(ktr*30), W_T+(ktr*30), W_R+(ktr*30), W_B+(ktr*30), |
W_L+(ktr*30), W_T+(ktr*30), W_R+(ktr*30), W_B+(ktr*30), |
||
theLayerFlags[ktr], super_bitmap)) == NULL) |
theLayerFlags[ktr], super_bitmap)) == NULL) |
||
Line 695: | Line 694: | ||
else |
else |
||
{ |
{ |
||
− | if ((layer_array[ktr] = CreateBehindLayer(theLayerInfo, theBitMap, |
+ | if ((layer_array[ktr] = ILayers->CreateBehindLayer(theLayerInfo, theBitMap, |
W_L+(ktr*30), W_T+(ktr*30), W_R+(ktr*30), W_B+(ktr*30), |
W_L+(ktr*30), W_T+(ktr*30), W_R+(ktr*30), W_B+(ktr*30), |
||
theLayerFlags[ktr], NULL)) == NULL) |
theLayerFlags[ktr], NULL)) == NULL) |
||
Line 703: | Line 702: | ||
if (create_layer_ok) |
if (create_layer_ok) |
||
{ |
{ |
||
− | pMessage(msgLayer, |
+ | pMessage(msgLayer, "Fill the RastPort"); |
− | SetRast(layer_array[ktr]- |
+ | IGraphics->SetRast(layer_array[ktr]->rp, ktr + 1); |
} |
} |
||
} |
} |
||
Line 726: | Line 725: | ||
if (NULL != bitmap) |
if (NULL != bitmap) |
||
{ |
{ |
||
− | for (ktr = 0; ktr |
+ | for (ktr = 0; ktr < depth; ktr++) |
{ |
{ |
||
− | if (NULL != bitmap- |
+ | if (NULL != bitmap->Planes[ktr]) |
− | FreeRaster(bitmap- |
+ | IGraphics->FreeRaster(bitmap->Planes[ktr], width, height); |
} |
} |
||
− | FreeMem(bitmap, sizeof(*bitmap)); |
+ | IExec->FreeMem(bitmap, sizeof(*bitmap)); |
} |
} |
||
} |
} |
||
Line 751: | Line 750: | ||
struct BitMap *bitmap = NULL; |
struct BitMap *bitmap = NULL; |
||
− | if (NULL != (bitmap = AllocMem(sizeof(*bitmap),NULL))) |
+ | if (NULL != (bitmap = IExec->AllocMem(sizeof(*bitmap),NULL))) |
{ |
{ |
||
− | InitBitMap(bitmap,depth,width,height); |
+ | IGraphics->InitBitMap(bitmap,depth,width,height); |
− | for (ktr = 0; ktr |
+ | for (ktr = 0; ktr < depth; ktr++) |
{ |
{ |
||
− | if (NULL == (bitmap- |
+ | if (NULL == (bitmap->Planes[ktr] = (PLANEPTR)IGraphics->AllocRaster(width,height))) |
bit_map_failed = TRUE; |
bit_map_failed = TRUE; |
||
else |
else |
||
− | BltClear(bitmap- |
+ | IGraphics->BltClear(bitmap->Planes[ktr], RASSIZE(width,height), 1); |
} |
} |
||
if (bit_map_failed) |
if (bit_map_failed) |
||
Line 780: | Line 779: | ||
struct Layer *theLayers[3] = { NULL, NULL, NULL, }; |
struct Layer *theLayers[3] = { NULL, NULL, NULL, }; |
||
− | if (NULL != (msgLayer = CreateUpfrontLayer(theLayerInfo, theBitMap, |
+ | if (NULL != (msgLayer = ILayers->CreateUpfrontLayer(theLayerInfo, theBitMap, |
M_L, M_T, M_R, M_B, LAYERSMART, NULL))) |
M_L, M_T, M_R, M_B, LAYERSMART, NULL))) |
||
{ |
{ |
||
− | pMessage(msgLayer, |
+ | pMessage(msgLayer, "Setting up Layers"); |
if (NULL != (theSuperBitMap = allocBitMap(SCREEN_D, SUPER_W, SUPER_H))) |
if (NULL != (theSuperBitMap = allocBitMap(SCREEN_D, SUPER_W, SUPER_H))) |
||
Line 795: | Line 794: | ||
disposeBitMap(theSuperBitMap, SCREEN_D, SUPER_W, SUPER_H); |
disposeBitMap(theSuperBitMap, SCREEN_D, SUPER_W, SUPER_H); |
||
} |
} |
||
− | if (!DeleteLayer(DUMMY, msgLayer)) |
+ | if (!ILayers->DeleteLayer(DUMMY, msgLayer)) |
− | error(msgLayer, |
+ | error(msgLayer, "Error deleting layer"); |
} |
} |
||
} |
} |
||
Line 808: | Line 807: | ||
** (other than the InstallClipRegion() call) is through Intuition windows. |
** (other than the InstallClipRegion() call) is through Intuition windows. |
||
** |
** |
||
− | ** See graphics primitives |
+ | ** See graphics primitives articles for details on creating and using the |
** low-level graphics calls. |
** low-level graphics calls. |
||
*/ |
*/ |
||
Line 824: | Line 823: | ||
/* save current view, to be restored when done */ |
/* save current view, to be restored when done */ |
||
− | if (NULL != (oldview = GfxBase- |
+ | if (NULL != (oldview = GfxBase->ActiView)) |
{ |
{ |
||
/* get a LayerInfo structure */ |
/* get a LayerInfo structure */ |
||
− | if (NULL != (theLayerInfo = NewLayerInfo())) |
+ | if (NULL != (theLayerInfo = ILayers->NewLayerInfo())) |
{ |
{ |
||
− | if (NULL != (theColorMap = GetColorMap(4))) |
+ | if (NULL != (theColorMap = IGraphics->GetColorMap(4))) |
{ |
{ |
||
− | colorpalette = (UWORD *)theColorMap- |
+ | colorpalette = (UWORD *)theColorMap->ColorTable; |
− | for(ktr = 0; ktr |
+ | for(ktr = 0; ktr < 4; ktr++) |
*colorpalette++ = colortable[ktr]; |
*colorpalette++ = colortable[ktr]; |
||
if (NULL != (theBitMap = allocBitMap(SCREEN_D, SCREEN_W, SCREEN_H))) |
if (NULL != (theBitMap = allocBitMap(SCREEN_D, SCREEN_W, SCREEN_H))) |
||
{ |
{ |
||
− | InitView(& |
+ | IGraphics->InitView(&theView); |
− | InitVPort(& |
+ | IGraphics->InitVPort(&theViewPort); |
− | theView.ViewPort = & |
+ | theView.ViewPort = &theViewPort; |
theViewPort.DWidth = SCREEN_W; |
theViewPort.DWidth = SCREEN_W; |
||
theViewPort.DHeight = SCREEN_H; |
theViewPort.DHeight = SCREEN_H; |
||
− | theViewPort.RasInfo = & |
+ | theViewPort.RasInfo = &theRasInfo; |
theViewPort.ColorMap = theColorMap; |
theViewPort.ColorMap = theColorMap; |
||
Line 852: | Line 851: | ||
theRasInfo.Next = NULL; |
theRasInfo.Next = NULL; |
||
− | MakeVPort(& |
+ | IGraphics->MakeVPort(&theView, &theViewPort); |
− | MrgCop(& |
+ | IGraphics->MrgCop(&theView); |
− | LoadView(& |
+ | IGraphics->LoadView(&theView); |
− | WaitTOF(); |
+ | IGraphics->WaitTOF(); |
startLayers(theLayerInfo, theBitMap); |
startLayers(theLayerInfo, theBitMap); |
||
Line 862: | Line 861: | ||
** active before freeing any of our display |
** active before freeing any of our display |
||
*/ |
*/ |
||
− | LoadView(oldview); |
+ | IGraphics->LoadView(oldview); |
− | WaitTOF(); |
+ | IGraphics->WaitTOF(); |
/* free dynamically created structures */ |
/* free dynamically created structures */ |
||
− | FreeVPortCopLists(& |
+ | IGraphics->FreeVPortCopLists(&theViewPort); |
− | FreeCprList(theView.LOFCprList); |
+ | IGraphics->FreeCprList(theView.LOFCprList); |
disposeBitMap(theBitMap, SCREEN_D, SCREEN_W, SCREEN_H); |
disposeBitMap(theBitMap, SCREEN_D, SCREEN_W, SCREEN_H); |
||
} |
} |
||
− | FreeColorMap(theColorMap); /* free the color map */ |
+ | IGraphics->FreeColorMap(theColorMap); /* free the color map */ |
} |
} |
||
− | DisposeLayerInfo(theLayerInfo); |
+ | ILayers->DisposeLayerInfo(theLayerInfo); |
} |
} |
||
} |
} |
||
Line 881: | Line 880: | ||
** Open the libraries used by the example. Clean up when done. |
** 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); |
||
− | if (NULL != (LayersBase = OpenLibrary("layers.library",33L))) |
||
+ | ILayers = (struct LayersIFace*)IExec->GetInterface(LayersBase, "main", 1, NULL); |
||
− | { |
||
+ | |||
+ | if (IGraphics != NULL && ILayers != NULL) |
||
+ | { |
||
runNewView(); |
runNewView(); |
||
− | |||
− | CloseLibrary((struct Library *)LayersBase); |
||
− | } |
||
− | CloseLibrary((struct Library *)GfxBase); |
||
} |
} |
||
− | }</pre> |
||
+ | IExec->DropInterface((struct Interface*)ILayers); |
||
− | == Regions == |
||
+ | IExec->DropInterface((struct Interface*)IGraphics); |
||
+ | IExec->CloseLibrary(LayersBase); |
||
+ | IExec->CloseLibrary(GfxBase); |
||
+ | return 0; |
||
− | 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). |
||
+ | } |
||
+ | </syntaxhighlight> |
||
+ | == Function Reference == |
||
− | 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. |
||
+ | The following are brief descriptions of the layers library functions. See the SDK for details on each function call. |
||
− | Functions Used with Regions |
||
{| class="wikitable" |
{| class="wikitable" |
||
+ | |+ Layers Library Functions |
||
− | ! Routine |
||
+ | ! Function |
||
− | ! Library |
||
! Description |
! Description |
||
|- |
|- |
||
+ | | NewLayerInfo() |
||
− | | InstallClipRegion() || Layers || Add a clipping region to a layer. |
||
+ | | Allocating a Layer_Info structure. |
||
|- |
|- |
||
+ | | DisposeLayerInfo() |
||
− | | NewRegion() || Graphics || Create a new, empty region. |
||
+ | | Deallocating a Layer_Info structure. |
||
|- |
|- |
||
+ | | CreateUpfrontLayer() |
||
− | | DisposeRegion() || Graphics || Dispose of an existing region and its rectangles. |
||
+ | | Make a new layer in front of others. |
||
|- |
|- |
||
+ | | CreateBehindLayer() |
||
− | | AndRectRegion() || Graphics || ''And'' a rectangle into a region. |
||
+ | | Make a new layer behind others. |
||
|- |
|- |
||
+ | | DeleteLayer() |
||
− | | OrRectRegion() || Graphics || ''Or'' a rectangle into a region. |
||
+ | | Remove and delete an existing layer. |
||
|- |
|- |
||
+ | | MoveLayer() |
||
− | | XorRectRegion() || Graphics || ''Exclusive-or'' a rectangle into a region. |
||
+ | | Change the position (not depth) of a layer. |
||
|- |
|- |
||
+ | | SizeLayer() |
||
− | | ClearRectRegion() || Graphics || Clear a rectangular portion of a region. |
||
+ | | Change the size of a layer. |
||
|- |
|- |
||
+ | | ScrollLayer() |
||
− | | AndRegionRegion() || Graphics || ''And'' two regions together. |
||
+ | | Change the internal coordinates of a layer. |
||
|- |
|- |
||
+ | | BehindLayer() |
||
− | | OrRegionRegion() || Graphics || ''Or'' two regions together. |
||
+ | | Depth arrange a layer behind others. |
||
|- |
|- |
||
+ | | UpfrontLayer() |
||
− | | XorRegionRegion() || Graphics || ''Exclusive-or'' two regions together. |
||
+ | | Depth arrange a layer in front of others. |
||
|- |
|- |
||
+ | | MoveLayerInFrontOf() |
||
− | | ClearRegion() || Graphics || Clear a region. |
||
+ | | 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. |
||
|} |
|} |
||
− | |||
− | 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. |
||
− | |||
− | {| class="wikitable" |
||
− | | ''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. |
||
− | |} |
||
− | |||
− | {| class="wikitable" |
||
− | | ''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. |
||
− | |||
− | <pre> |
||
− | struct Region *NewRegion( VOID ); |
||
− | </pre> |
||
− | |||
− | 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. |
||
− | |||
− | <pre> |
||
− | VOID DisposeRegion( struct Region *region ); |
||
− | </pre> |
||
− | |||
− | DisposeRegion() returns all memory associated with a region to the system and deallocates all rectangles that have been linked to it. |
||
− | |||
− | {| class="wikitable" |
||
− | | ''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. |
||
− | |||
− | <pre> |
||
− | struct Region *InstallClipRegion( struct Layer *layer, struct Region *region ); |
||
− | </pre> |
||
− | |||
− | 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. |
||
− | |||
− | <pre> |
||
− | /* |
||
− | ** 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) ; |
||
− | } |
||
− | </pre> |
||
− | |||
− | {| class="wikitable" |
||
− | | ''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. |
||
− | |} |
||
− | |||
− | <pre> |
||
− | 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) ; |
||
− | </pre> |
||
− | |||
− | === Changing a Region === |
||
− | |||
− | Regions may be modified by performing logical operations with rectangles, or with other regions. |
||
− | |||
− | {| class="wikitable" |
||
− | | ''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: |
||
− | |||
− | <pre> |
||
− | 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); |
||
− | } |
||
− | </pre> |
||
− | |||
− | ==== Rectangles and Regions ==== |
||
− | |||
− | There are four functions for changing a region through logical operations with a rectangle. |
||
− | |||
− | <pre> |
||
− | 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 ); |
||
− | </pre> |
||
− | |||
− | 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: |
||
− | |||
− | <pre> |
||
− | 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 ); |
||
− | </pre> |
||
− | |||
− | 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. |
||
− | |||
− | <pre>/* 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); |
||
− | } |
||
− | }</pre> |
||
− | |||
− | == 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 |
||
− | |||
− | <table> |
||
− | <tr class="header"> |
||
− | <th align="left">'''Function'''</th> |
||
− | <th align="left">'''Description'''</th> |
||
− | </tr> |
||
− | <tr class="odd"> |
||
− | <td align="left">NewLayerInfo()</td> |
||
− | <td align="left">Allocating a Layer_Info structure.</td> |
||
− | </tr> |
||
− | <tr class="even"> |
||
− | <td align="left">DisposeLayerInfo()</td> |
||
− | <td align="left">Deallocating a Layer_Info structure.</td> |
||
− | </tr> |
||
− | <tr class="odd"> |
||
− | <td align="left">CreateUpfrontLayer()</td> |
||
− | <td align="left">Make a new layer in front of others.</td> |
||
− | </tr> |
||
− | <tr class="even"> |
||
− | <td align="left">CreateBehindLayer()</td> |
||
− | <td align="left">Make a new layer behind others.</td> |
||
− | </tr> |
||
− | <tr class="odd"> |
||
− | <td align="left">DeleteLayer()</td> |
||
− | <td align="left">Remove and delete an existing layer.</td> |
||
− | </tr> |
||
− | <tr class="even"> |
||
− | <td align="left">MoveLayer()</td> |
||
− | <td align="left">Change the position (not depth) of a layer.</td> |
||
− | </tr> |
||
− | <tr class="odd"> |
||
− | <td align="left">SizeLayer()</td> |
||
− | <td align="left">Change the size of a layer.</td> |
||
− | </tr> |
||
− | <tr class="even"> |
||
− | <td align="left">ScrollLayer()</td> |
||
− | <td align="left">Change the internal coordinates of a layer.</td> |
||
− | </tr> |
||
− | <tr class="odd"> |
||
− | <td align="left">BehindLayer()</td> |
||
− | <td align="left">Depth arrange a layer behind others.</td> |
||
− | </tr> |
||
− | <tr class="even"> |
||
− | <td align="left">UpfrontLayer()</td> |
||
− | <td align="left">Depth arrange a layer in front of others.</td> |
||
− | </tr> |
||
− | <tr class="odd"> |
||
− | <td align="left">MoveLayerInFrontOf()</td> |
||
− | <td align="left">Depth arrange a layer to a specific position.</td> |
||
− | </tr> |
||
− | <tr class="even"> |
||
− | <td align="left">WhichLayer()</td> |
||
− | <td align="left">Find the frontmost layer at a position.</td> |
||
− | </tr> |
||
− | <tr class="odd"> |
||
− | <td align="left">SwapBitsRastPortClipRect()</td> |
||
− | <td align="left">Fast, non-layered and non-damaging display operation.</td> |
||
− | </tr> |
||
− | <tr class="even"> |
||
− | <td align="left">BeginUpdate()</td> |
||
− | <td align="left">Synchronize optimized refreshing for layer.</td> |
||
− | </tr> |
||
− | <tr class="odd"> |
||
− | <td align="left">EndUpdate()</td> |
||
− | <td align="left">End optimized layer refresh.</td> |
||
− | </tr> |
||
− | <tr class="even"> |
||
− | <td align="left">LockLayer()</td> |
||
− | <td align="left">Lock out rendering in a single layer.</td> |
||
− | </tr> |
||
− | <tr class="odd"> |
||
− | <td align="left">UnlockLayer()</td> |
||
− | <td align="left">Release LockLayer() lock.</td> |
||
− | </tr> |
||
− | <tr class="even"> |
||
− | <td align="left">LockLayers()</td> |
||
− | <td align="left">Lock out rendering in all layers of a display.</td> |
||
− | </tr> |
||
− | <tr class="odd"> |
||
− | <td align="left">UnlockLayers()</td> |
||
− | <td align="left">Release LockLayers() lock.</td> |
||
− | </tr> |
||
− | <tr class="even"> |
||
− | <td align="left">LockLayerInfo()</td> |
||
− | <td align="left">Gain exclusive access to the display‚Äôs layers.</td> |
||
− | </tr> |
||
− | <tr class="odd"> |
||
− | <td align="left">UnlockLayerInfo()</td> |
||
− | <td align="left">Release LockLayerInfo() lock.</td> |
||
− | </tr> |
||
− | <tr class="even"> |
||
− | <td align="left">InstallClipRegion()</td> |
||
− | <td align="left">Add a clipping region to a layer.</td> |
||
− | </tr> |
||
− | </table> |
||
− | |||
− | The following routines from graphics library are also required for certain layers library functions: |
||
− | |||
− | <table> |
||
− | <tr class="header"> |
||
− | <th align="left">'''Routine'''</th> |
||
− | <th align="left">'''Description'''</th> |
||
− | </tr> |
||
− | <tr class="odd"> |
||
− | <td align="left">LockLayerRom()</td> |
||
− | <td align="left">Same as LockLayer(), from layers library.</td> |
||
− | </tr> |
||
− | <tr class="even"> |
||
− | <td align="left">UnlockLayerRom()</td> |
||
− | <td align="left">Release LockLayerRom() lock.</td> |
||
− | </tr> |
||
− | <tr class="odd"> |
||
− | <td align="left">AttemptLockLayerRom()</td> |
||
− | <td align="left">Lock layer only if it is immediately available.</td> |
||
− | </tr> |
||
− | <tr class="even"> |
||
− | <td align="left">NewRegion()</td> |
||
− | <td align="left">Create a new, empty region.</td> |
||
− | </tr> |
||
− | <tr class="odd"> |
||
− | <td align="left">DisposeRegion()</td> |
||
− | <td align="left">Dispose of an existing region and its rectangles.</td> |
||
− | </tr> |
||
− | <tr class="even"> |
||
− | <td align="left">AndRectRegion()</td> |
||
− | <td align="left">AND a rectangle into a region.</td> |
||
− | </tr> |
||
− | <tr class="odd"> |
||
− | <td align="left">OrRectRegion()</td> |
||
− | <td align="left">OR a rectangle into a region.</td> |
||
− | </tr> |
||
− | <tr class="even"> |
||
− | <td align="left">XorRectRegion()</td> |
||
− | <td align="left">Exclusive-OR a rectangle into a region.</td> |
||
− | </tr> |
||
− | <tr class="odd"> |
||
− | <td align="left">ClearRectRegion()</td> |
||
− | <td align="left">Clear a region.</td> |
||
− | </tr> |
||
− | <tr class="even"> |
||
− | <td align="left">AndRegionRegion()</td> |
||
− | <td align="left">AND two regions together.</td> |
||
− | </tr> |
||
− | <tr class="odd"> |
||
− | <td align="left">OrRegionRegion()</td> |
||
− | <td align="left">OR two regions together.</td> |
||
− | </tr> |
||
− | <tr class="even"> |
||
− | <td align="left">XorRegionRegion()</td> |
||
− | <td align="left">Exclusive-OR two regions together.</td> |
||
− | </tr> |
||
− | <tr class="odd"> |
||
− | <td align="left">ClearRegion()</td> |
||
− | <td align="left">Clear a region.</td> |
||
− | </tr> |
||
− | </table> |
Latest revision as of 18:43, 4 November 2015
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 article 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 Graphics Library 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 articles 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. |