[Contents] [Index] [Help] [Retrace] [browse <] [Browse >]

/* screen.c - 2.0 screen module for Display
 * based on scdemo, oscandemo, looki
 */

/*
Copyright (c) 1989-1999 Amiga, Inc.

Executables based on this information may be used in software
for Amiga computers. All other rights reserved.
This information is provided "as is"; no warranties are made.
All use is at your own risk, and no liability or responsibility
is assumed.
*/

#include "iffp/ilbmapp.h"

BOOL   VideoControlTags(struct ColorMap *,ULONG tags, ...);

extern struct Library *GfxBase;
extern struct Library *IntuitionBase;

struct TextAttr SafeFont = { (UBYTE *) "topaz.font", 8, 0, 0, };
UWORD  penarray[] = {~0};

/* default new window if none supplied in ilbm->nw */
struct   NewWindow      defnw = {
   0, 0,                                  /* LeftEdge and TopEdge */
   0, 0,                                  /* Width and Height */
   -1, -1,                                /* DetailPen and BlockPen */
   VANILLAKEY|MOUSEBUTTONS,               /* IDCMP Flags with Flags below */
   BACKDROP|BORDERLESS|SMART_REFRESH|NOCAREREFRESH|ACTIVATE|RMBTRAP,
   NULL, NULL,                            /* Gadget and Image pointers */
   NULL,                                  /* Title string */
   NULL,                                  /* Screen ptr null till opened */
   NULL,                                  /* BitMap pointer */
   50, 20,                                /* MinWidth and MinHeight */
   0 , 0,                                 /* MaxWidth and MaxHeight */
   CUSTOMSCREEN                           /* Type of window */
   };


/* opendisplay - passed ILBMInfo, dimensions, modeID
 *
 *    Attempts to open correct 2.0 modeID screen and window,
 *    else an old 1.3 mode screen and window.
 *
 * Returns *window or NULL.
 */

struct Window *opendisplay(struct ILBMInfo *ilbm,
                           SHORT wide, SHORT high, SHORT deep,
                           ULONG mode)
    {
    struct NewWindow newwin, *nw;

    closedisplay(ilbm);
    if(ilbm->scr = openidscreen(ilbm, wide, high, deep, mode))
        {
        nw = &newwin;
        if(ilbm->windef) *nw = *(ilbm->windef);
        else *nw = *(&defnw);
        nw->Screen = ilbm->scr;

        D(bug("sizes: scr= %ld x %ld  passed= %ld x %ld\n",
                ilbm->scr->Width,ilbm->scr->Height,wide,high));

        nw->Width  = wide;
        nw->Height = high;
        if (!(ilbm->win = OpenWindow(nw)))
            {
            closedisplay(ilbm);
            D(bug("Failed to open window."));
            }
        else
            {
            if(ilbm->win->Flags & BACKDROP)
                {
                ShowTitle(ilbm->scr, FALSE);
                ilbm->TBState = FALSE;
                }
            }
        }

    if(ilbm->scr)  /* nulled out by closedisplay if OpenWindow failed */
        {
        ilbm->vp  = &ilbm->scr->ViewPort;
        ilbm->srp = &ilbm->scr->RastPort;
        ilbm->wrp = ilbm->win->RPort;
        }
    return(ilbm->win);
    }


void closedisplay(struct ILBMInfo *ilbm)
    {
    if(ilbm)
        {
        if (ilbm->win)     CloseWindow(ilbm->win), ilbm->win = NULL;
        if (ilbm->scr)     CloseScreen(ilbm->scr), ilbm->scr = NULL;
        ilbm->vp  = NULL;
        ilbm->srp = ilbm->wrp = NULL;
        }
    }



/* openidscreen - ILBMInfo, dimensions, modeID
 *
 *    Attempts to open correct 2.0 modeID screen with centered
 *    overscan based on user's prefs,
 *    else old 1.3 mode screen.
 *
 * If ilbm->stype includes CUSTOMBITMAP, ilbm->brbitmap will be
 *      used as the screen's bitmap.
 * If ilbm->stags is non-NULL, these tags will be added to the
 *      end of the taglist.
 *
 * Returns *screen or NULL.
 */

struct Screen *openidscreen(struct ILBMInfo *ilbm,
                            SHORT wide, SHORT high, SHORT deep,
                            ULONG mode)
    {
    struct NewScreen ns;                        /* for old style OpenScreen */
    struct Rectangle spos, dclip, txto, stdo, maxo, uclip;  /* display rectangles */
    struct Rectangle *uclipp;
    struct Screen   *scr = NULL;
    LONG   error, trynew;
    ULONG  bitmaptag, passedtags;
    BOOL   vctl;

    if (trynew = ((((struct Library *)GfxBase)->lib_Version >= 36)&&
          (((struct Library *)IntuitionBase)->lib_Version >= 36)))
        {
        /* if >= v36, see if mode is available */
        if(error = ModeNotAvailable(mode))
            {
            D(bug("Mode $%08lx not available, error=%ld:\n",mode,error));
            /* if not available, try fall back mode */
            mode = modefallback(mode,wide,high,deep);
            error = ModeNotAvailable(mode);

            D(bug("$%08lx ModeNotAvailable=%ld:\n",mode,error));
            }

        if(error) trynew = FALSE;
        else trynew=((QueryOverscan(mode,&txto,OSCAN_TEXT))&&
                        (QueryOverscan(mode,&stdo,OSCAN_STANDARD))&&
                            (QueryOverscan(mode,&maxo,OSCAN_MAX)));
        }

    D(bug("\nILBM: w=%ld, h=%ld, d=%ld, mode=0x%08lx\n",
                wide,high,deep,mode));
    D(bug("OPEN: %s.\n",
        trynew  ? "Is >= 2.0 and mode available, trying OpenScreenTags"
                : "Not 2.0, doing old OpenScreen"));

    if(trynew)
        {
        /* If user clip type specified and available, use it */
        if(ilbm->Video) ilbm->ucliptype = OSCAN_VIDEO;
        if((ilbm->ucliptype)&&(QueryOverscan(mode,&uclip,ilbm->ucliptype)))
                uclipp = &uclip;
        else uclipp = NULL;

        clipit(wide,high,&spos,&dclip,&txto,&stdo,&maxo,uclipp);

        D(bug("Using dclip  %ld,%ld  to  %ld,%ld... width=%ld height=%ld\n",
                        dclip.MinX,dclip.MinY,dclip.MaxX,dclip.MaxY,
                        dclip.MaxX-dclip.MinX+1,dclip.MaxY-dclip.MinY+1));
        D(bug("spos->minx = %ld, spos->miny = %ld\n",spos.MinX,spos.MinY));
        D(bug("DEBUG: About to attempt OpenScreenTags\n"));

        bitmaptag = ((ilbm->brbitmap)&&(ilbm->stype & CUSTOMBITMAP)) ?
                SA_BitMap : TAG_IGNORE;
        passedtags = ilbm->stags ? TAG_MORE : TAG_IGNORE;

        scr=(struct Screen *)OpenScreenTags((struct NewScreen *)NULL,
                SA_DisplayID,   mode,
                SA_Type,        ilbm->stype,
                SA_Behind,      TRUE,
                SA_Top,         spos.MinY,
                SA_Left,        spos.MinX,
                SA_Width,       wide,
                SA_Height,      high,
                SA_Depth,       deep,
                SA_DClip,       &dclip,
                SA_AutoScroll,  ilbm->Autoscroll ? TRUE : FALSE,
                SA_Title,       ilbm->stitle,
                SA_Font,        &SafeFont,
                SA_Pens,        penarray,
                SA_ErrorCode,   &error,
                bitmaptag,      ilbm->brbitmap,
                passedtags,     ilbm->stags,
                TAG_DONE
                );

            D(bug("DEBUG: OpenScreenTags scr at 0x%lx\n",scr));

            if(scr)
                {
                if(ilbm->Notransb)
                    {
                    vctl=VideoControlTags(scr->ViewPort.ColorMap,
                                VTAG_BORDERNOTRANS_SET, TRUE,
                                TAG_DONE);

        D(bug("VideoControl to set bordernotrans, error = %ld\n",vctl));

                    MakeScreen(scr);
                    RethinkDisplay();
                    }
                }
            else modeErrorMsg(mode,error);
        }

    if(!scr)
        {
        /* ns initialization for 1.3 old style OpenScreen only
         */
        ns.LeftEdge = ns.TopEdge = 0;
        ns.Width        =       wide;
        ns.Height       =       high;
        ns.Depth        =       deep;
        ns.ViewModes    =       modefallback(mode,wide,high,deep);
        ns.DetailPen    =       0;
        ns.BlockPen     =       1;
        ns.Gadgets      =       NULL;
        ns.CustomBitMap =       ((ilbm->brbitmap)&&(ilbm->stype & CUSTOMBITMAP))
                                        ? ilbm->brbitmap : NULL;
        ns.Font         =       &SafeFont;
        ns.DefaultTitle =       ilbm->stitle;
        ns.Type         =       ilbm->stype & 0x01FF;  /* allow only 1.3 types */

        scr=(struct Screen *)OpenScreen(&ns);

        D(bug("DEBUG: ns.ViewModes=0x%lx, vp->Modes=0x%lx\n",
                 ns.ViewModes,scr->ViewPort.Modes));
        D(bug("DEBUG: non-extended scr at 0x%lx (0=failure)\n",scr));
        }
    return(scr);
    }


/*
 * modefallback - passed a mode id, attempts to provide a
 *                suitable old mode to use instead
 */

/* for old 1.3 screens */
#define MODE_ID_MASK (LACE|HIRES|HAM|EXTRA_HALFBRITE)

ULONG modefallback(ULONG mode, SHORT wide, SHORT high, SHORT deep)
{
ULONG newmode;

    /* For now, simply masks out everything but old mode bits.
     * This is just a cheap way to get some kind of display open
     *   and may be totally invalid for future modes.
     * Should search the display database for a suitable mode
     * based on the specific needs of your application.
     */
    newmode = mode & MODE_ID_MASK;

    D(bug("Try 0x%08lx instead of 0x%08lx\n",newmode,mode));
    return(newmode);
}


/*
 * clipit - passed width and height of a display, and the text, std, and
 *          max overscan rectangles for the mode, clipit fills in the
 *          spos (screen pos) and dclip rectangles to use in centering.
 *          Centered around smallest containing user-editable oscan pref,
 *          with dclip confined to legal maxoscan limits.
 *          Screens which center such that their top is below text
 *          oscan top, will be moved up.
 *          If a non-null uclip is passed, that clip is used instead.
 */
void clipit(SHORT wide, SHORT high,
            struct Rectangle *spos, struct Rectangle *dclip,
            struct Rectangle *txto, struct Rectangle *stdo,
            struct Rectangle *maxo, struct Rectangle *uclip)
{
struct  Rectangle *besto;
SHORT   minx, maxx, miny, maxy;
SHORT   txtw, txth, stdw, stdh, maxw, maxh, bestw, besth;

    /* get the txt, std and max widths and heights */
    txtw = txto->MaxX - txto->MinX + 1;
    txth = txto->MaxY - txto->MinY + 1;
    stdw = stdo->MaxX - stdo->MinX + 1;
    stdh = stdo->MaxY - stdo->MinY + 1;
    maxw = maxo->MaxX - maxo->MinX + 1;
    maxh = maxo->MaxY - maxo->MinY + 1;

    if((wide <= txtw)&&(high <= txth))
        {
        besto = txto;
        bestw = txtw;
        besth = txth;

        D(bug("Best clip is txto\n"));
        }
    else
        {
        besto = stdo;
        bestw = stdw;
        besth = stdh;

        D(bug("Best clip is stdo\n"));
        }

    D(bug("TXTO: mnx=%ld mny=%ld mxx=%ld mxy=%ld  stdw=%ld stdh=%ld\n",
                txto->MinX,txto->MinY,txto->MaxX,txto->MaxY,txtw,txth));
    D(bug("STDO: mnx=%ld mny=%ld mxx=%ld mxy=%ld  stdw=%ld stdh=%ld\n",
                stdo->MinX,stdo->MinY,stdo->MaxX,stdo->MaxY,stdw,stdh));
    D(bug("MAXO: mnx=%ld mny=%ld mxx=%ld mxy=%ld  maxw=%ld maxh=%ld\n",
                maxo->MinX,maxo->MinY,maxo->MaxX,maxo->MaxY,maxw,maxh));

    if(uclip)
        {
        *dclip = *uclip;
        spos->MinX = uclip->MinX;
        spos->MinY = uclip->MinY;

        D(bug("UCLIP: mnx=%ld mny=%ld maxx=%ld maxy=%ld\n",
                        dclip->MinX,dclip->MinY,dclip->MaxX,dclip->MaxY));
        }
    else
        {
        /* CENTER the screen based on best oscan prefs
        * but confine dclip within max oscan limits
        *
        * FIX MinX first */
        spos->MinX = minx = besto->MinX - ((wide - bestw) >> 1);
        maxx = wide + minx - 1;
        if(maxx > maxo->MaxX)  maxx = maxo->MaxX;        /* too right */
        if(minx < maxo->MinX)  minx = maxo->MinX;        /* too left  */

        D(bug("DCLIP: minx adjust from %ld to %ld\n",spos->MinX,minx));

        /* FIX MinY */
        spos->MinY = miny = besto->MinY - ((high - besth) >> 1);
        /* if lower than top of txto, move up */
        spos->MinY = miny = MIN(spos->MinY,txto->MinY);
        maxy = high + miny - 1;
        if(maxy > maxo->MaxY)  maxy = maxo->MaxY;        /* too down  */
        if(miny < maxo->MinY)  miny = maxo->MinY;        /* too up    */

        D(bug("DCLIP: miny adjust from %ld to %ld\n",spos->MinY,miny));

        /* SET up dclip */
        dclip->MinX = minx;
        dclip->MinY = miny;
        dclip->MaxX = maxx;
        dclip->MaxY = maxy;

        D(bug("CENTER: mnx=%ld mny=%ld maxx=%ld maxy=%ld\n",
                        dclip->MinX,dclip->MinY,dclip->MaxX,dclip->MaxY));
        }
}


void modeErrorMsg(ULONG mode, ULONG errorcode)
   {
   UBYTE *s=NULL;

        D(bug("DEBUG: Can't open mode ID 0x%08lx screen: ",mode));

        switch ( errorcode )
        {
        case OSERR_NOMEM:
            s="Not enough memory.";
            break;
        case OSERR_NOCHIPMEM:
            s="Not enough chip memory.";
            break;
#ifdef DEBUG
        case OSERR_NOMONITOR:
            s="monitor not available.";
            break;

        case OSERR_NOCHIPS:
            s="new chipset not available.";
            break;

        case OSERR_PUBNOTUNIQUE:
            s="public screen already open.";
            break;
        case OSERR_UNKNOWNMODE:
            s="mode ID is unknown.";
            break;
        default:
            message("unknown mode error %ld\n",errorcode);
#endif
        }
    if(s) message("%s\n",s);
    }


/*----------------------------------------------------------------------*/

BOOL VideoControlTags(struct ColorMap *cm, ULONG tags, ...)
    {
    return (VideoControl(cm, (struct TagItem *)&tags));
    }


/*----------------------------------------------------------------------*/