
ECS Display Modes and ILBM CAMG

by Carolyn Scheppner

Under previous versions of the Amiga operating system and hardware,
the available display modes such as HIRES, LACE, HAM, HALFBRITE,
DUALPF, and assorted combinations of these display modes could all be
described in a 16-bit ViewPort mode field (often referred to as a
viewmode).

The 1.3 procedure for storing an Amiga viewmode in an ILBM was to take
the 16-bit viewmode, mask out the undesirable bits GENLOCK_AUDIO,
GENLOCK_VIDEO, VP_HIDE, and SPRITES, and store the result as a long
(32-bit) value in a CAMG chunk (the upper 16 bits of the long would be
0).

The 1.3 procedure for reading ILBM CAMG chunk was to read the 32-bit
value, mask out the undesirable bits mentioned above, and then use the
low word of the result as a 16-bit value for ViewPort.Modes or
NewScreen.Modes when opening a display.

The 2.0 operating system and the ECS chips support an extensible
number of display modes - too many to be specified by the previous
method where individual bits mapped to a limited number of specific
display characteristics.  Under 2.0, display modes are now specified
by a 32-bit ModeID which is not stored in the ViewPort, but is instead
held in private graphics lists of extended display information linked
into an extension of the ColorMap structure.  System functions are
provided for accessing this extended display information.  A simple
2.0 function is provided for getting the new 32-bit ModeID for any
ViewPort:

      ULONG modeID = GetVPModeID(struct ViewPort *vp);


The 2.0 scheme for CAMG is to save the entire 32-bit ModeID,
untouched, in the CAMG chunk.

Although ModeIDs are numeric values rather than bit masks, the current
2.0 ModeIDs have been specially designed to contain compatible
old-style bits in their low word for the matching (or closest match)
of an old ViewPort mode.

For example, the 2.0 ModeID for a Hires-Interlace display has the
HIRES and LACE bits set in its low word.  And the 2.0 ModeID for
Productivity-Interlace also has the HIRES and LACE bits set in its low
word.  This is because on a non-ECS or non-2.0 system, Hires-Interlace
is the closest old viewmode available for attempting to display a
Productivity-Interlace image.

By storing the entire 32-bit ModeID in the CAMG chunk under 2.0, new
reader applications can attempt to redisplay the image in its intended
display mode when possible (i.e., when running under 2.0 on a system
capable of the display mode).  Old readers will not be able to use the
new display modes, but their existing code will truncate the new
32-bit ModeID into a 16-bit viewmode which will generally provide an
old mode capable of displaying the image in some fashion.

New ILBM readers and readers revised for 2.0 can apply logic such as
the following when supporting new display modes: 



struct Screen *openidscreen(ULONG modeid,SHORT wide, SHORT high, SHORT deep)
{
extern struct Libary *GfxBase;
struct Screen *screen;

if(GfxBase->lib_Version >= 36)
    {
    /* if mode is not available, try a fallback mode */
    if(ModeNotAvailable(modeid))    modeid = fallbackmode(modeid).

    if(!(ModeNotAvailable(modeid))) /* if mode is available */
        {
        /* We have an available mode id
        Here you may wish to create a custom, or centered, or overscan
        display clip based on the size of the image.  Or just use
        one of the standard clips.

        The 2.0 Display program uses QueryOverscan to get the settings
        of this modeid's OSCAN_TEXT, OSCAN_STANDARD, and OSCAN_MAX.
        Display centers the screen (via TopEdge and LeftEdge) within
        the user's OSCAN_STANDARD settings, and creates a display clip
        by using the same values and then clipping the values to be
        within OSCAN_MAX limits.  If the centered screen ends up lower
        than user's OSCAN_TEXT settings, I move it up to same MinY as his
        OSCAN_TEXT --- otherwise his Workbench might peek over the top.
        */

        /*
        Now use extended OpenScreen or OpenScreenTags for this modeid.
        (this gives you the benefit of system-supported overscan, etc.)
        */
        }
    }


if no display opened yet  (either not 2.0 or mode not available or can't open)
    {
    Try an old-style OpenScreen with NewScreen.Modes = mode & VPMODEMASK;
    }

return(screen);
}



/*
 * fallbackmodeid - passed an unavailable modeid, attempts to provide an
 *                  available replacement modeid to use instead
 */

#define VPMODEMASK (~(GENLOCK_AUDIO|GENLOCK_VIDEO|VP_HIDE|SPRITES))

ULONG fallbackmodeid(ULONG modeid, SHORT wide, SHORT high, SHORT deep)
{
extern struct Library *GfxBase;
ULONG newmodeid;

    /* if it's an old 1.3-style mode, mask out inappropriate bits
     */
    if(!(modeid & MONITOR_ID_MASK)) newmodeid = modeid & VPMODEMASK;

    else newmodeid = modeid;  /* else start with what was passed */

    if(GfxBase->lib_Version >= 36)
        {
            if(ModeNotAvailable(newmodeid))
            {
            /* Here you should either be asking the user what mode they want
            * OR searching the display database and choosing an appropriate
            * replacement mode based on what you or the user deem important
            * (colors, or aspect, or size, etc.).  You could also use a built
            * in table for modes you know about, and substitute mode you wish
            * to use when the desired mode is not available.
            */

            newmodeid = ??? 
            } 
        }

#ifdef DEBUG
        printf ("Trying 0x%08lx instead of 0x%08lx\n",newmodeid,modeid);
#endif
    return(newmodeid);
}
