
/******************************************************************************
*                                                                             *
*   example_code -- specifying the new V1.4 ViewPort Modes to graphics.       *
*                                                                             *
*   Requires V1.4 KickStart and the new ECS chip set to display new modes.    *
*                                                                             *
******************************************************************************/


/*  this file consists of example code for the program ViewPortDemo, 
    included with this release; detailed comments  and includes can 
    be found in the companion file "tutorial", available on disk  */


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

#define V1_POINT_4      36

struct GfxBase  *GfxBase = NULL;

extern iterate_modes( );
extern mode_info( );

main()
{
    int error = FALSE;

    if( GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",V1_POINT_4) )
    {
        iterate_modes();         /* display every available mode */
        CloseLibrary( GfxBase ); /* clean up and exit */
    }
    else
    {
        error = TRUE;
    }

    exit(error);
}



struct DisplayInfo   queryinfo;
struct MonitorInfo   querymntr;
struct DimensionInfo querydims;

iterate_modes()
{
    /* start with speical begin/end-of-list ID */

    ULONG       ID = INVALID_ID; 

    /* get next ID until there are no more */

    while((ID = NextDisplayInfo( ID )) != INVALID_ID)
    {
        /* query each ID returned by next() for mode information */

        if( mode_info( ID ) ) 
        {
            /* use the information to open a view/viewport in that mode */

            open_mode( ID );
        }
    }
}


mode_info( ID )
ULONG ID;
{
    int    info = FALSE;
    int    mntr = FALSE;
    int    dims = FALSE;
    int    success = FALSE;

    if( info=GetDisplayInfoData(NULL,&queryinfo,sizeof(queryinfo),DTAG_DISP,ID))
    {
        mntr=GetDisplayInfoData(NULL,&querymntr,sizeof(querymntr),DTAG_MNTR,ID);
        dims=GetDisplayInfoData(NULL,&querydims,sizeof(querydims),DTAG_DIMS,ID);

        if(!(queryinfo.NotAvailable)) success= TRUE; 
    }

    return( (info && mntr && dims)? success : FALSE );
}



#include <exec/memory.h>
#include <graphics/gfxbase.h>
#include <graphics/gfx.h>
#include <graphics/rastport.h>
#include <graphics/view.h>
#include <libraries/dos.h>

/* forward references */

extern                 create_display( ); /* draw a recognizable testpattern */
extern struct RastPort *create_rp    ( ); /* allocate and init a rastport    */
extern struct RasInfo  *create_ri    ( ); /* allocate and init a rasinfo     */
extern struct BitMap   *create_bm    ( ); /* allocate and init a bitmap      */
extern struct ViewPort *create_vp    ( ); /* allocate and init a viewport    */
extern struct View     *create_view  ( ); /* allocate and init a view        */

extern                  dispose_ri   ( ); /* deallocate a rasinfo            */
extern                  dispose_bm   ( ); /* deallocate a bitmap             */
extern                  dispose_vp   ( ); /* deallocate a viewport           */
extern                  dispose_view ( ); /* deallocate a view               */



open_mode( ID )
ULONG ID;
{
    struct MonitorSpec *mspc, *OpenMonitor();
    struct View        *view;
    struct ViewPort    *vp;
    struct RasInfo     *ri;
    struct RasPort     *rp;

    if( ( mspc = OpenMonitor( NULL, ID ) ) 
    &&  ( view = create_view( mspc ) )     
    &&  ( vp   = create_vp( view, ID ) ) ) 
    {
        view->ViewPort = vp; 

        if( ri = create_ri( vp ) )
        {
            vp->RasInfo = ri;

            if( rp = create_rp( ri ) )
            {
                struct View *restore_view = GfxBase->ActiView;

                create_display( vp, rp );

                MakeVPort( view, vp );
                MrgCop( view );
                LoadView( view );          

                Wait(SIGBREAKF_CTRL_C);    
                
                LoadView( restore_view );  

                dispose_rp( rp );
            }   
            if( ri ) dispose_ri( ri );
        }   
        if( vp )dispose_vp( vp );          
        if( view )  dispose_view( view );  
        CloseMonitor( mspc );              
    } 
}


#include <graphics/monitor.h>
#include <graphics/videocontrol.h>

struct TagItem vc[] =
{
    { VTAG_ATTACH_CM_SET, NULL },       
    { VTAG_VIEWPORTEXTRA_SET, NULL },   
    { VTAG_NORMAL_DISP_SET, NULL },     
    { VTAG_END_CM, NULL }               
};

struct ViewPort *create_vp( view, ID )
struct View *view;
ULONG ID;
{
    struct ViewPort  *vp       = NULL;
    struct ViewPortExtra *vpx  = NULL;  /* new for V1.4 */

    if( vp = (struct ViewPort *) AllocMem(sizeof(*vp),MEMF_PUBLIC|MEMF_CLEAR) )
    {
        struct Rectangle *oscan    = &querydims.Nominal;
        ULONG  WIDTH   = oscan->MaxX - oscan->MinX + 1 ;
        ULONG  HEIGHT  = oscan->MaxY - oscan->MinY + 1 ;

        InitVPort( vp );

        vp->Modes    = (ID & 0xFFFF); 

        vp->DxOffset = 0;       vp->DyOffset = 0; 
        vp->DWidth   = WIDTH;   vp->DHeight  = HEIGHT;

        if( vpx = (struct ViewPortExtra *) GfxNew( VIEWPORT_EXTRA_TYPE ) )
        {
            vpx->DisplayClip.MinX = oscan->MinX;
            vpx->DisplayClip.MinY = oscan->MinY;
            vpx->DisplayClip.MaxX = oscan->MaxX;
            vpx->DisplayClip.MaxY = oscan->MaxY;
        }

        vc[0].ti_Data = (ULONG) vp;
        vc[1].ti_Data = (ULONG) vpx; 
        vc[2].ti_Data = (ULONG) FindDisplayInfo( ID );

        VideoControl( GetColorMap(32), vc );

        view->Modes |= ((DIPF_IS_LACE & queryinfo.PropertyFlags)? LACE: 0);
    }

    return( vp ); 
}


struct TagItem end_vc[] =
{
    { VTAG_VIEWPORTEXTRA_GET, NULL }, 
    { VTAG_END_CM, NULL }             
};

dispose_vp( vp)
struct ViewPort *vp;
{
    struct ViewPortExtra *vpx;
    int error = FALSE;

    if( vp )
    {
        error = VideoControl( vp->ColorMap, end_vc ); 

        if(!error)
        {
            if(vpx = (struct ViewPortExtra *)end_vc[0].ti_Data)
            {
                GfxFree( vpx );         
            }
        }

        if ( vp->ColorMap )
        {
            FreeColorMap( vp->ColorMap );
        }

        FreeVPortCopLists( vp );
        FreeMem( vp, sizeof(*vp) );
    }
}


struct View *create_view( mspc )
struct MonitorSpec *mspc;
{
    struct View *view;
    struct ViewExtra *vx;


    if( view = (struct View *)AllocMem(sizeof(*view),MEMF_PUBLIC|MEMF_CLEAR) )
    {
        InitView( view );

        if( vx = (struct ViewExtra *)GfxNew( VIEW_EXTRA_TYPE ) )
        {
            vx->Monitor = mspc;
            GfxAssociate( view, vx );
            view->Modes |= EXTEND_VSTRUCT;
        }

        view->DxOffset = querymntr.ViewPosition.x ;
        view->DyOffset = querymntr.ViewPosition.y ;
    }
    return( view );
}

dispose_view( view)
struct View *view;
{
    if( view )
    {
        if (view->Modes & EXTEND_VSTRUCT)
        {
            struct ViewExtra *vx;     

            if( vx = (struct ViewExtra *) GfxLookUp( view ) )
            {
                GfxFree( vx );
            }
        }
        if ( view->LOFCprList ) FreeCprList ( view->LOFCprList );
        if ( view->SHFCprList ) FreeCprList ( view->SHFCprList );

        FreeMem( view, sizeof(*view) );
    }
}

create_display( vp, rp )
struct ViewPort *vp;
struct RastPort *rp;
{
    int i,j,k;
    char text[1];
    WORD x_center = vp->DWidth  >> 1; 
    WORD y_center = vp->DHeight >> 1; 
    WORD width  =   vp->DWidth  >> 2; 
    WORD height =  
    (( ( LONG )( width * queryinfo.Resolution.x ) ) / queryinfo.Resolution.y );

    if(vp && rp)
    {
        SetAPen(  rp,  -1 );
        SetDrMd(  rp,  JAM1 );

        /* "circle" in the center, 1/4 width of the screen  */
        DrawEllipse( rp, x_center, y_center, width, height );

        /* outline the edge of the display with a rectangle */
        Move( rp, 0,            0 ); 
        Draw( rp, 0,            vp->DHeight-1);
        Draw( rp, vp->DWidth-1, vp->DHeight-1);
        Draw( rp, vp->DWidth-1, 0);
        Draw( rp, 0,            0);

        /* indicate diagonals */
        Move( rp, 0,            0 );
        Draw( rp, vp->DWidth-1, vp->DHeight-1);
        Move( rp, 0,            vp->DHeight-1);
        Draw( rp, vp->DWidth-1, 0);

        /* dimension counters along the top and left edges  */
        for(i=0; i < vp->DWidth; i+=(1<<4))
        {
            Move( rp, i, 0 ); Draw( rp, i, vp->DHeight-1);
            if(!i) for(k=0; k+12 < vp->DHeight; k+=(1<<4))
            {
                *text = '0'+((k>>4)%10);
                Move( rp, i+4, k+12 ); Text( rp, text, 1);
            }
        }
        for(j=0; j < vp->DHeight; j+=(1<<4))
        {
            Move( rp, 0, j ); Draw( rp, vp->DWidth-1, j);
            if(!j) for(k=0; k < vp->DWidth; k+=(1<<4))
            {
                *text = '0'+((k>>4)%10);
                Move( rp, k+4, j+12 ); Text( rp, text, 1);
            }
        }
    }
}

struct RasInfo  *create_ri( vp )
struct ViewPort *vp;
{
    struct RasInfo *ri  = NULL;
    struct BitMap  *bm  = NULL;
    struct RasInfo *ri2 = NULL;
    struct BitMap  *bm2 = NULL;
    int    depth        = querydims.MaxDepth;
    int    depth2       = depth / 2;
    int    error        = FALSE;

    if( queryinfo.PropertyFlags & DIPF_IS_DUALPF )
    {
        if( depth2 )
        {
            depth -= depth2;

            if( bm2 = create_bm( vp, depth2 ) )
            {
                if( ri2 =  
                (struct RasInfo *)AllocMem(sizeof(*ri2),MEMF_PUBLIC|MEMF_CLEAR))
                {
                    ri2->BitMap = bm2;
                }
                else error = TRUE;
            }
            else error = TRUE;
        }
    }

    if( !error )
    {
        if( bm = create_bm( vp, depth ) )
        {
            if(ri = 
              (struct RasInfo *)AllocMem(sizeof(*ri),MEMF_PUBLIC|MEMF_CLEAR) )
            {
                ri->BitMap = bm;
                ri->Next   = ri2;
            }
            else error = TRUE;
        }
        else error = TRUE;
    }

    if( error )
    {
            if( bm  ) dispose_bm( bm  );
            if( ri2 ) dispose_ri( ri2 );
            if( bm2 ) dispose_bm( bm2 );
    }

    return( ri );
}


struct RastPort *create_rp( ri )
struct RasInfo  *ri;
{
    struct RastPort *rp = NULL;
    struct BitMap   *bm = ri->BitMap;

    if( bm 
    &&( rp = (struct RastPort *)AllocMem(sizeof(*rp),MEMF_PUBLIC|MEMF_CLEAR) ) )
    {
        InitRastPort( rp );
        rp->BitMap = bm;
    }
    return( rp );
}

dispose_rp( rp )
struct RastPort *rp;
{
    if( rp )
    {
        FreeMem( rp, sizeof(*rp));
    }
}

dispose_ri( ri )
struct RasInfo *ri;
{
    if( ri->Next ) dispose_ri( ri->Next ); /* recurse for dual playfield */

    if( ri )
    {
        dispose_bm( ri->BitMap );
        FreeMem( ri, sizeof(*ri) );
    }
}



struct BitMap *create_bm( vp, depth )
struct ViewPort *vp;
int    depth;
{
    struct BitMap  *bm = NULL;
    int i;

    if( vp && depth )
    {
        if( bm = (struct BitMap *) AllocMem(sizeof(*bm),MEMF_PUBLIC|MEMF_CLEAR))
        {
            InitBitMap(bm, depth, vp->DWidth, vp->DHeight );

            for (i = 0; i < bm->Depth; i++)
            {
                if( bm->Planes[i] = (PLANEPTR) /* allocate chip memory planes */
                AllocMem( RASSIZE(vp->DWidth,vp->DHeight),MEMF_CHIP|MEMF_CLEAR))
                {
                    continue;
                }
                else bm->Depth = i; dispose_bm( bm ); return( NULL );
            }
        }
    }

    return( bm ); 
}

dispose_bm( bm )
struct BitMap *bm;
{
    if( bm )
    {
        int i;

        for(i=0; i < bm->Depth; i++)
        {
            if(bm->Planes[i]) FreeMem( bm->Planes[i], bm->BytesPerRow*bm->Rows);
        }
        FreeMem( bm, sizeof(*bm));
    }
}



