Copyright (c) Hyperion Entertainment and contributors.

Classic Intuition Screens

From AmigaOS Documentation Wiki
Revision as of 21:21, 9 November 2015 by Steven Solie (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Classic Intuition Screens

This sections contains information regarding programming Amiga screens which is no longer in use or apply only to the Classic Amiga platform's ECS/AGA chip set. See Intuition Screens for the current methods used to manipulate Intuition screens.

Screen Data Structures

The Amiga uses color registers and bitplane organization as its internal representation of display data. Screens require a color table and display raster memory for each bitplane. This is the memory where imagery is rendered and later translated by the hardware into the actual video display. This information is contained in data structures from the Amiga's graphics library.

A ViewPort is the main data structure used by the graphics library to represent a screen. Pointers to each of the screen's bitplanes are stored in the graphics library BitMap structure. Color table information is stored in a graphics structure called a ColorMap. And the screen's drawing and font information is stored in the RastPort structure.

The graphics RastPort structure is a general-purpose handle that the graphics library uses for drawing operations. Many Intuition drawing functions also take a RastPort address as a parameter. This makes sense since the RastPort structure contains drawing variables as well as a pointer to the BitMap telling where to draw. See Graphics Primitives for more information on these structures and how they are used.

The Intuition Screen Data Structure

The structures mentioned above are unified along with other information in Intuition's Screen data structure defined in the include file <intuition/screens.h>. Notice that the Screen structure contains instances of a ViewPort, RastPort and BitMap.

struct Screen
    {
    struct Screen *NextScreen;
    struct Window *FirstWindow;
    WORD LeftEdge, TopEdge, Width, Height;
    WORD MouseY, MouseX;
    UWORD Flags;
    UBYTE *Title, *DefaultTitle;
    BYTE BarHeight, BarVBorder, BarHBorder, MenuVBorder, MenuHBorder;
    BYTE WBorTop, WBorLeft, WBorRight, WBorBottom;
    struct TextAttr *Font;
    struct ViewPort ViewPort;
    struct RastPort RastPort;
    struct BitMap BitMap;
    struct Layer_Info LayerInfo;
    struct Gadget *FirstGadget;
    UBYTE DetailPen, BlockPen;
    UWORD SaveColor0;
    struct Layer *BarLayer;
    UBYTE *ExtData, *UserData;
    };

In general, applications don't need to access the fields in the Screen structure directly; they use Intuition functions to manipulate the screen instead. Likewise, applications do not set up the Screen themselves; they use one of the OpenScreen() calls (see below). Here is a description of some of the more interesting members of the Screen structure (it is not meant to be a complete description of all the fields).

LeftEdge, TopEdge
The LeftEdge and TopEdge variables give the position of the screen relative to the upper left corner of the monitor's visible display (as set by the user in the Overscan preferences editor). If it is positioned down or to the right, the values are positive. If the screen is positioned up or to the left, the values are negative. The values are in screen resolution pixels.
The screen position may be set when the screen is opened or later by calling the MoveScreen() function.
Note that the screen's actual display position may not exactly equal the coordinates given in the LeftEdge and TopEdge fields of the Screen structure. This can cause a window which is opened in the visible part of the screen to be incorrectly positioned by a few pixels in each direction. This complication is due to hardware constraints that limit the fineness of screen positioning. For instance, high resolution screens can only be positioned in low resolution pixel coordinates, yet the values in the LeftEdge and TopEdge use high resolution pixel coordinates. So when the screen is displayed, its position is rounded to a position available for the monitor.
MouseX, MouseY
Position of the mouse with respect to the upper left corner of the screen.
ViewPort, RastPort, BitMap, LayerInfo
Actual instances of the graphics library data structures associated with this screen (not pointers to structures). For normal use of custom screens, these structures may be ignored.
BarLayer
A pointer to the Layer structure for the screen's title bar.
WBorTop, WBorLeft, WBorRight, WBorBottom
Window border values, see the Intuition Windows for information on pre-calculating the size of window borders for windows that open in this screen.
Font
The default screen font, this can be used to pre-calculate the size of the window borders for windows that open in this screen.
UserData
Free for application use.

Other Screen structure members provide information on the title bar layer, and attributes of menus and windows opened in the screen. Of particular interest are the values that allow precalculation of window border size. These variables will be discussed in Intuition Windows.

Other Screen Data Structures

In addition to the Screen structure, Intuition uses some other supporting structures defined in the include file <intuition/screens.h> and in <utility/tagitems.h>. (See the SDK for a complete listing.)

Structure Name Description Defined in Include File
Screen Main Intuition structure that defines a screen (see above) <intuition/screens.h>
DrawInfo Holds the screen's pen, font and aspect data for Intuition <intuition/screens.h>
TagItem General purpose parameter structure used to set up screens in V36 <utility/tagitem.h>
NewScreen Parameter structure used to create a screen in V34 <intuition/screens.h>
ExtNewScreen An extension to the NewScreen structure used in V37 for backward compatibility with older systems <intuition/screens.h>

As previously mentioned, there is an Intuition Screen structure (and a corresponding graphics ViewPort) for every screen in memory. Whenever a new screen is created, Intuition also creates an auxiliary data structure called a DrawInfo.

The DrawInfo structure is similar to a RastPort in that it holds drawing information. But where a RastPort is used at the lower graphics level, the DrawInfo structure is used at the higher Intuition level. Specifically, DrawInfo contains data needed to support the New Look of Intuition. (See the section below, "DrawInfo and the 3D Look" for more information.)

With screens, tag items are used to describe the attributes an application wants for a new, custom screen. Tag items replace the NewScreen structure, the set of parameters used in older versions of the OS to set up a screen.

Applications should use tag items to set up a new screen instead of the NewScreen structure since tag items are often more convenient. For the sake of backwards compatibility, the ExtNewScreen structure is available. ExtNewScreen combines the NewScreen method used to define screens in older versions of the OS with the tag item method. The examples listed in the next section show how these various data structures can be used to set up a new screen.

Custom Screen Functions

All applications require a screen to work in. This can be an existing, public screen or a new, custom screen created by the application itself. To create a new, custom screen to work with, you call OpenScreen().

Creating a new Custom Screen

The old OpenScreen() call relied on a fixed size data structure (NewScreen) which made little allowance for extensions and growth. The new calls are tag based, allowing for the addition of new features without modification of existing structures and applications. The "Screen Attributes" section below contains a complete list of all the tag options available for setting up an Intuition screen. For a general description of tag items, see Utility Library.

The NewScreen structure used with OpenScreen() has been extended with a tag list in V36 to form an ExtNewScreen. This is done by setting the NS_EXTENDED bit in the Type field of the NewScreen structure and adding a pointer to an array of tags to the end of the structure. The NS_EXTENDED bit is ignored in older versions of the operating system, so the tags can be transparently added to existing applications and the features will appear when executed in a system running V36 or greater. See the OpenScreen() Autodocs and the include file <intuition/screens.h> for more information on NS_EXTENDED and the ExtNewScreen structure.

Intuition Screens and the Graphics Library

An Intuition screen is related to a number of underlying graphics library structures.

Screen Functions that integrate Intuition and Graphics

These functions, normally used only by the system, integrate high-level Intuition structures with the lower-level constructs used by the graphics library to create the display.

Screen Functions That Integrate Intuition and Graphics
MakeScreen() Update a single screen's copper list
RethinkDisplay() Merge copper lists from all screens to form a View
RemakeDisplay() Update all screen copper lists then merge them to form a View

Advanced Intuition programmers may use these functions to achieve special screen effects such as double-buffering or dual-playfield Intuition screens. For examples of these see the next section.

MakeScreen() updates, but does not install, a screen's Copper list. This function is the Intuition equivalent of the low-level MakeVPort() graphics library function. MakeScreen() performs the MakeVPort() call, synchronized with Intuition's own use of the screen's ViewPort. Call RethinkDisplay() after MakeScreen() to allow the new Copper list for the screen to take effect. The MakeScreen() function takes one argument, a pointer to the Screen that contains the Copper list to be updated.

RethinkDisplay() combines all the screen's copper lists into a single view. This procedure performs the Intuition global display reconstruction, which includes massaging some of Intuition's internal state data, rethinking all of the Intuition screen ViewPorts and their relationship to one another, and, finally, reconstructing the entire display by merging the new screens into the graphics View structure. Custom screens that handle their own Copper instructions, use this call to install the Copper list previously updated with MakeScreen(). RethinkDisplay() calls lower-level graphics primitives MrgCop() and LoadView() to install the Copper list. This function takes no arguments.

RemakeDisplay() remakes the entire Intuition display. It is equivalent to calling MakeScreen() for each screen in the system, then calling RethinkDisplay(). This routine performs a MakeVPort() (graphics primitive) on every Intuition screen and then calls RethinkDisplay() to recreate the View. It takes no arguments.

Both RemakeDisplay() and RethinkDisplay() take several milliseconds to run and lock out all other tasks while they run. This can seriously degrade system performance, so do not use these routines lightly.

Advanced Screen Programming

This section discusses how to create a dual-playfield Intuition screen and other advanced topics.

Dual-Playfield Screen Example

This example shows how to create a dual-playfield display. Note that this technique is only valid for screen modes which support dual-playfield, do not try to convert other modes.

Setting up dual playfield mode in the OpenScreen() call is not the best method of obtaining a dual playfield viewport for a screen. It is better to open a standard screen, passing to Intuition (or letting Intuition create) only one of the playfield bitmaps (the front one). Next allocate and set up a second bitmap, its bitplanes, and a RasInfo structure installing these into the new screen's viewport. Update the viewport modes to include DUALPF and call MakeScreen() and RethinkDisplay(). This method, shown in the example below, keeps Intuition rendering (gadgets, menus, windows) in a single playfield.

/* dualplayfield.c
** Shows how to turn on dual-playfield mode in a screen.
**
** SAS/C 5.10a
** lc -b1 -cfist -v -y dualplayfield
** blink FROM LIB:c.o dualplayfield.o TO dualplayfield LIB LIB:lc.lib LIB:amiga.lib
*/

#define INTUI_V36_NAMES_ONLY

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

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

VOID doDualPF ( struct Window * );
BOOL installDualPF( struct Screen *, struct RastInfo * );
VOID drawSomething( struct RastPort * );
VOID handleIDCMP ( struct Window * );
VOID removeDualPF( struct Screen *s );

struct Library *IntuitionBase;
struct Library *GfxBase;

VOID main(int argc, char **argv)
{
struct Window *win;
struct Screen *scr;

IntuitionBase = OpenLibrary("intuition.library",37);
if (IntuitionBase != NULL)
    {
    GfxBase = OpenLibrary("graphics.library", 37);
    if (GfxBase != NULL)
        {
        scr = OpenScreenTags(NULL,
                             SA_Depth,     2,
                             SA_DisplayID, HIRES_KEY,
                             SA_Title,     "Dual Playfield Test Screen",
                             TAG_END);
        if ( scr != NULL )
            {
            win = OpenWindowTags(NULL,
                                 WA_Title,        "Dual Playfield Mode",
                                 WA_IDCMP,        IDCMP_CLOSEWINDOW,
                                 WA_Width,        200,
                                 WA_Height,       100,
                                 WA_DragBar,      TRUE,
                                 WA_CloseGadget,  TRUE,
                                 WA_CustomScreen, scr,
                                 TAG_END);
            if ( win != NULL )
                {
                doDualPF(win);

                CloseWindow(win);
                }
            CloseScreen(scr);
            }
        CloseLibrary(GfxBase);
        }
    CloseLibrary(IntuitionBase);
    }
}


/*
** Allocate all of the stuff required to add dual playfield to a screen.
*/
VOID doDualPF(struct Window *win)
{
struct Screen   *myscreen;
struct RasInfo  *rinfo2;
struct BitMap   *bmap2;
struct RastPort *rport2;

myscreen = win->WScreen;   /* Find the window's screen */

/* Allocate the second playfield's rasinfo, bitmap, and bitplane */
rinfo2 = (struct RasInfo *) AllocMem(sizeof(struct RasInfo), MEMF_PUBLIC | MEMF_CLEAR);
if ( rinfo2 != NULL )
    {
    /* Get a rastport, and set it up for rendering into bmap2 */
    rport2 = (struct RastPort *) AllocMem(sizeof(struct RastPort), MEMF_PUBLIC );
    if (rport2 != NULL )
        {
        bmap2 = (struct BitMap *) AllocMem(sizeof(struct BitMap), MEMF_PUBLIC | MEMF_CLEAR);
        if (bmap2 != NULL )
            {
            InitBitMap(bmap2, 1, myscreen->Width, myscreen->Height);

            /* extra playfield will only use one bitplane here. */
            bmap2->Planes[0] = (PLANEPTR) AllocRaster(myscreen->Width, myscreen->Height);
            if (bmap2->Planes[0] != NULL )
                {
                InitRastPort(rport2);
                rport2->BitMap = rinfo2->BitMap = bmap2;

                SetRast(rport2, 0);

                if (installDualPF(myscreen,rinfo2))
                    {
                    /* Set foreground color; color 9 is color 1 for
                    ** second playfield of hi-res viewport
                    */
                    SetRGB4(&myscreen->ViewPort, 9, 0, 0xF, 0);

                    drawSomething(rport2);

                    handleIDCMP(win);

                    removeDualPF(myscreen);
                    }
                FreeRaster(bmap2->Planes[0], myscreen->Width, myscreen->Height);
                }
            FreeMem(bmap2, sizeof(struct BitMap));
            }
        FreeMem(rport2, sizeof(struct RastPort));
        }
    FreeMem(rinfo2, sizeof(struct RasInfo));
    }
}


/*
** Manhandle the viewport:
** install second playfield and change modes
*/
BOOL installDualPF(struct Screen *scrn, struct RastInfo *rinfo2)
{
ULONG screen_modeID;
BOOL return_code = FALSE;

screen_modeID = GetVPModeID(&(scrn->ViewPort));
if( screen_modeID != INVALID_ID )
    {
    /* you can only play with the bits in the Modes field
    ** if the upper half of the screen mode ID is zero!!!
    */
    if ( (screen_modeID & 0xFFFF0000L) == 0L )
        {
        return_code = TRUE;

        Forbid();

        /* Install rinfo for viewport's second playfield */
        scrn->ViewPort.RasInfo->Next = rinfo2;
        scrn->ViewPort.Modes |= DUALPF;

        Permit();

        /* Put viewport change into effect */
        MakeScreen(scrn);
        RethinkDisplay();
        }
    }
return(return_code);
}

/*
** Draw some lines in a rast port...This is used to get some data into
** the second playfield.  The windows on the screen will move underneath
** these graphics without disturbing them.
*/
VOID drawSomething(struct RastPort *rp)
{
int width, height;
int r, c;

width = rp->BitMap->BytesPerRow * 8;
height = rp->BitMap->Rows;

SetAPen(rp, 1);

for (r = 0; r < height; r += 40)
    {
    for (c = 0; c < width; c += 40)
        {
        Move(rp, 0L, r);
        Draw(rp, c, 0L);
        }
    }
}

/*
** simple event loop to wait for the user to hit the close gadget
** on the window.
*/
VOID handleIDCMP(struct Window *win)
{
BOOL done = FALSE;
struct IntuiMessage *message = NULL;
ULONG class;
ULONG signals;

while (!done)
    {
    signals = Wait(1L << win->UserPort->mp_SigBit);
    if (signals & (1L << win->UserPort->mp_SigBit))
        {
        while ((!done) &&
               (message = (struct IntuiMessage *)GetMsg(win->UserPort)))
            {
            class = message->Class;
            ReplyMsg((struct Message *)message);

            switch (class)
                {
                case IDCMP_CLOSEWINDOW:
                    done = TRUE;
                    break;
                }
            }
        }
    }
}

/*
** remove the effects of installDualPF().
** only call if installDualPF() succeeded.
*/
VOID removeDualPF(struct Screen *scrn)
{
Forbid();

scrn->ViewPort.RasInfo->Next = NULL;
scrn->ViewPort.Modes &= ~DUALPF;

Permit();

MakeScreen(scrn);
RethinkDisplay();
}