home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Developer CD v1.2
/
amidev_cd_12.iso
/
devcon
/
sanfrancisco_1989
/
sf-devcon89.1
/
graphics
/
tutorial.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-08-27
|
29KB
|
834 lines
/******************************************************************************
*
* $Header: tut,v 36.1 89/05/22 13:52:04 bart Exp $
*
******************************************************************************/
/* this file is a tutorial on the use some of the new features of V1.4 .
it consists of example code for the program ViewPortDemo, included with
this release; in addition to detailed comments and included information */
#include <exec/types.h>
#include <graphics/displayinfo.h>
/* the 1.2 release was 33, the 1.3 release was 34, but the 1.4 release is 36 */
/* this is because of the interim "jumpstart" release to support the A2024 . */
#define V1_POINT_4 36
struct GfxBase *GfxBase = NULL;
/* each 1.4 mode is associated with a DisplayInfoRecord in the new graphics
database. in order to use these modes, some of which are new for V1.4
it is useful to do two things: iterate through all known modes and get
information about their qualities, current parameters and availability */
extern iterate_modes( );
extern mode_info( );
/* here is the main routine: its function is to quarantee that we are indeed
running V1.4, and to call the iteration procedure to display every available
mode that can be obtained from the graphics DisplayInfo database. */
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);
}
/* let's take a closer look at the data structures defined in displayinfo.h */
#ifndef GRAPHICS_DISPLAYINFO_H
#define GRAPHICS_DISPLAYINFO_H
/* the "public" handle to a DisplayInfoRecord. this handle is obtained via
the new graphics function handle = FindDisplayInfo(ID) . the ID passed
to FindDisplayInfo is a "composite key" which is a unique 32bit numnber
associated with a particular display Mode such as lores, hires, etc. */
typedef APTR DisplayInfoHandle;
/* DisplayInfoRecord IDentifiers -- the invalid ID is special. you may call
ID = NextDisplayInfo(INVALID_ID) to obtain the first composite key in the
graphics DisplayInfo database. after obtaining the first_id: you repeat
ID = NextDisplayInfo(ID) to iterate through all available composite keys
until ID == INVALID_ID again. thus INVALID_ID functions as both the
start-of-list and end-of-list marker.... */
#define INVALID_ID ~0
/* the following 20 composite keys are for Modes on the default Monitor */
/* ntsc & pal "flavors" of these particular keys may be made by or'ing */
/* the ntsc or pal MONITOR_ID with the desired MODE_KEY... */
#define LORES_KEY 0x00000000
#define HIRES_KEY 0x00008000
#define SUPER_KEY 0x00008020
#define HAM_KEY 0x00000800
#define LORESLACE_KEY 0x00000004
#define HIRESLACE_KEY 0x00008004
#define SUPERLACE_KEY 0x00008024
#define HAMLACE_KEY 0x00000804
#define LORESDPF_KEY 0x00000400
#define HIRESDPF_KEY 0x00008400
#define SUPERDPF_KEY 0x00008420
#define LORESLACEDPF_KEY 0x00000404
#define HIRESLACEDPF_KEY 0x00008404
#define SUPERLACEDPF_KEY 0x00008424
#define LORESDPF2_KEY 0x00000440
#define HIRESDPF2_KEY 0x00008440
#define SUPERDPF2_KEY 0x00008460
#define LORESLACEDPF2_KEY 0x00000444
#define HIRESLACEDPF2_KEY 0x00008444
#define SUPERLACEDPF2_KEY 0x00008464
#define DEFAULT_MONITOR_ID 0x00000000
#define NTSC_MONITOR_ID 0x00011000
#define PAL_MONITOR_ID 0x00021000
/* vga IDentifiers -- these are modes running at 31.5khz (doublescan ) rates.
one of these is "special" : that is the VGAPRODUCT_KEY which identifies
the "Productivity" Mode, which we expect will be the most frequently used.
ALL of these modes require the ECS chipset (both agnus and denise) in
addition to a having a currently available multi-sync or bi-sync monitor */
#define VGAEXTRALORES_KEY 0x00031004
#define VGALORES_KEY 0x00039004
#define VGAPRODUCT_KEY 0x00039024
#define VGAHAM_KEY 0x00031804
#define VGAEXTRALORESLACE_KEY 0x00031005
#define VGALORESLACE_KEY 0x00039005
#define VGAPRODUCTLACE_KEY 0x00039025
#define VGAHAMLACE_KEY 0x00031805
#define VGAEXTRALORESDPF_KEY 0x00031404
#define VGALORESDPF_KEY 0x00039404
#define VGAPRODUCTDPF_KEY 0x00039424
#define VGAEXTRALORESLACEDPF_KEY 0x00031405
#define VGALORESLACEDPF_KEY 0x00039405
#define VGAPRODUCTLACEDPF_KEY 0x00039425
#define VGAEXTRALORESDPF2_KEY 0x00031444
#define VGALORESDPF2_KEY 0x00039444
#define VGAPRODUCTDPF2_KEY 0x00039464
#define VGAEXTRALORESLACEDPF2_KEY 0x00031445
#define VGALORESLACEDPF2_KEY 0x00039445
#define VGAPRODUCTLACEDPF2_KEY 0x00039465
#define VGA_MONITOR_ID 0x00031000
/* a2024 IDentifiers --these are the two different refresh rates at which
you may run an a2024 display. these modes are available in ROM for V1.4
without requiring the RCS chipset. they do, however require an a2024. */
#define A2024TENHERTZ_KEY 0x00041000
#define A2024FIFTEENHERTZ_KEY 0x00049000
#define A2024_MONITOR_ID 0x00041000
/* once you have obtained a handle to a DisplayInfoRecord via FindDisplayInfo()
you may use GetDisplayInfoData() to query the DisplayInfoRecord about its
current settings. Each datachunk inquiy will copy bytes into your querybuf:
beggining with the queryheader and followed by data for the chunk type.
TAG_DISP: (DisplayInfo) - properties and availability information.
TAG_DIMS: (DimensionInfo) - default dimensions and overscan info.
TAG_MNTR: (MonitorInfo) - type, position, scanrate, and compatibility.
TAG_NAME: (NameInfo) - a user friendly way to refer to this mode. */
/* datachunk types */
#define DTAG_DISP 0x80000000
#define DTAG_DIMS 0x80001000
#define DTAG_MNTR 0x80002000
#define DTAG_NAME 0x80003000
/* when calling GetDisplayInfoData(handle,querybuf,bufsize,tagID,[ID]) then
bufsize bytes will be copied into your buffer. bufsize must be at least
sizeof(struct QueryHeader) : querybuf should be at least bufsize bytes */
struct QueryHeader
{
ULONG StructID; /* datachunk type IDentifier */
ULONG DisplayID; /* copy of display record key */
ULONG StructIgnore; /* TAG_IGNORE -- see tagitems.h */
ULONG Length; /* length of local data in tagitems */
/* each tagitem is a double-longword */
};
/* note that though a DisplayInfoRecord for a given key may be found in the
database, this mode may not be "currently" available: reasons for this
can include NOCHIPS (mode requires the ECS chipset, which has not been
installed) and NOMONITOR (mode requires a monitor which is not attached) */
struct DisplayInfo
{
struct QueryHeader Header;
UWORD NotAvailable; /* if NULL available, else see defines */
ULONG PropertyFlags; /* Properties of this mode see defines */
Point Resolution; /* ticks-per-pixel X/Y */
UWORD PixelSpeed; /* aproximation in nanoseconds */
UWORD NumStdSprites; /* number of standard amiga sprites */
UWORD PaletteRange; /* distinguishable shades available */
Point SpriteResolution; /* std sprite ticks-per-pixel X/Y */
UBYTE pad[4];
ULONG reserved[2]; /* terminator */
};
/* availability */
#define DI_AVAIL_NOCHIPS 0x0001
#define DI_AVAIL_NOMONITOR 0x0002
/* mode properties */
#define DIPF_IS_LACE 0x00000001
#define DIPF_IS_DUALPF 0x00000002
#define DIPF_IS_PF2PRI 0x00000004
#define DIPF_IS_HAM 0x00000008
#define DIPF_IS_ECS 0x00000010
#define DIPF_IS_PAL 0x00000020
#define DIPF_IS_SPRITES 0x00000040
#define DIPF_IS_GENLOCK 0x00000080
#define DIPF_IS_WB 0x00000100
#define DIPF_IS_DRAGGABLE 0x00000200
#define DIPF_IS_PANELLED 0x00000400
#define DIPF_IS_BEAMSYNC 0x00000800
/* the raster sizes are the maximum bitmap sizes that are available for
graphics operations. the ECS chipset, if installed, allows for blits
up to ~32k x 32k in size. otherwise, blits may only be ~1k x 1k big.
note that beginning with V1.4, the raster may be much larger than the
displayable portion of a screen and intuition will allow you to scroll
this larger raster about your displayclip rectangle */
/* the overscan rectangles represent the displayable dimensions for this mode.
nominal is the default viewport height and width for this mode
max is the maximum display region which software displayclip will handle
video is the absolute largest display that the hardware clipping will allow
txt is the region within which all text rendering will be visible
std is the region which extends "just" to the edges of the bezel */
struct DimensionInfo
{
struct QueryHeader Header;
UWORD MaxDepth; /* log2( max number of colors ) */
UWORD MinRasterWidth; /* minimum width in pixels */
UWORD MinRasterHeight; /* minimum height in pixels */
UWORD MaxRasterWidth; /* maximum width in pixels */
UWORD MaxRasterHeight; /* maximum height in pixels */
struct Rectangle Nominal; /* "standard" dimensions */
struct Rectangle MaxOScan; /* fixed, hardware dependant */
struct Rectangle VideoOScan; /* fixed, hardware dependant */
struct Rectangle TxtOScan; /* editable via preferences */
struct Rectangle StdOScan; /* editable via preferences */
UBYTE pad[14];
ULONG reserved[2]; /* terminator */
};
/* the compatibility criteria in the monitorinfo structure indicates which
modes may be combined in a display, both with others of thier own ilk,
and others whose natural "monitor" may be incompatible with this display. */
struct MonitorInfo
{
struct QueryHeader Header;
struct MonitorSpec *Mspc; /* pointer to monitor specification */
Point ViewPosition; /* editable via preferences */
Point ViewResolution; /* standard monitor ticks-per-pixel */
struct Rectangle ViewPositionRange; /* fixed, hardware dependant */
UWORD TotalRows; /* display height in scanlines */
UWORD TotalColorClocks; /* scanline width in 280 ns units */
UWORD MinRow; /* absolute minimum active scanline */
WORD Compatibility; /* how this coexists with others */
UBYTE pad[36];
ULONG reserved[2]; /* terminator */
};
/* monitor compatibility */
#define MCOMPAT_MIXED 0 /* can share display with other MCOMPAT_MIXED */
#define MCOMPAT_SELF 1 /* can share only within same monitor */
#define MCOMPAT_NOBODY -1 /* only one viewport at a time */
/* the name (optionally) associated with a DisplayInfoRecord is bound to
this record at run time, either from the startup-sequence or by the user.
thus you may build a "mode requester" for in the current natural language */
#define DISPLAYNAMELEN 32
struct NameInfo
{
struct QueryHeader Header;
UBYTE Name[DISPLAYNAMELEN];
ULONG reserved[2]; /* terminator */
};
#endif /* GRAPHICS_DISPLAYINFO_H */
/* here we reserve query_buffers to store the data that mode_info() will fill */
struct DisplayInfo queryinfo;
struct MonitorInfo querymntr;
struct DimensionInfo querydims;
/* ok, now that we've gotten the preliminaries out of the way, lets see what
composite mode keys are in the DisplayInfo database... */
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 takes a composite key and return a boolean value: TRUE if all the
information necessary to open a mode is available and has been copied into
the appropriate buffers or FALSE if some copy did not succeed. */
mode_info( ID )
ULONG ID;
{
int info = FALSE;
int mntr = FALSE;
int dims = FALSE;
int success = FALSE;
/* GetDisplayInfoData() takes either a handle to a DisplayInfoRecord
or a "composite key" ID if no handle is passed in... in this case we
skip handle = FindDisplayInfo(ID) and pass a handle of NULL relying
on GetDisplayInfoData() searching for the key in the database, which
incurs a little overhead... */
if( info=GetDisplayInfoData(NULL,&queryinfo,sizeof(queryinfo),DTAG_DISP,ID))
{
/* if we reach here then "info" bytes were copied from the datachunk
into the queryinfo buffer: now fill the monitor and dimension bufs */
mntr=GetDisplayInfoData(NULL,&querymntr,sizeof(querymntr),DTAG_MNTR,ID);
dims=GetDisplayInfoData(NULL,&querydims,sizeof(querydims),DTAG_DIMS,ID);
/* we have copied the available information: lets see if there
any reasons why we shold not try to display it at this time */
if(!(queryinfo.NotAvailable)) success= TRUE;
}
/* return the "availability" of the mode associated with the argument ID */
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 */
/* ok, lets actually create and display some view/viewport with this mode ID */
open_mode( ID )
ULONG ID;
{
struct MonitorSpec *mspc, *OpenMonitor();
struct View *view;
struct ViewPort *vp;
struct RasInfo *ri;
struct RasPort *rp;
/* mspc is a handle to a graphics internal Monitor Specification structure.
every composite mode key ID is associated with a graphics MonitorSpec
even thought all modes on the same monitor share the same MonitorSpec.
in order to obtain this mspc pointer and make it available to your view,
you must call OpenMonitor(...,ID) in order to obtain a "blind" handle.
never deference this handle yourself, it's strictly graphics private! */
if( ( mspc = OpenMonitor( NULL, ID ) ) /* open the monitorspec handle */
&& ( view = create_view( mspc ) ) /* allocate and init your view */
&& ( vp = create_vp( view, ID ) ) ) /* allocate and init your vp */
{
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 ); /* show this modeID display */
Wait(SIGBREAKF_CTRL_C); /* and wait for a signal... */
LoadView( restore_view ); /* begin clean up procedure */
dispose_rp( rp );
}
if( ri ) dispose_ri( ri );
}
if( vp )dispose_vp( vp ); /* deallocate your viewport */
if( view ) dispose_view( view ); /* deallocate your view */
CloseMonitor( mspc ); /* dont forget to close mspc */
}
}
/* we need to include the file monitor.h in order to set the DisplayClip
rectangle in the ViewPortExtra structure to limit the display region... */
#include <graphics/monitor.h>
/* here is the viewportextra structure - this structure is obtained via GfxNew.
the DisplayClip rectangle specifies the edges of the actively displayed part
of this viewport's bitmap in its own pixel resolution, relative to the view
origin. note that for 1.4, since the ECS allows blits to very large bitmaps,
the raster may be much larger than the "onscreen" display area. this is why
larger screens may now scroll left/right and up/down without restriction and
still have smoothly "clipped" edges on the display: for smooth clipping.
for smooth clipping make certain that your displayclip is wholly contained
within DimensionInfo.MaxOScan...
struct ViewPortExtra
{
struct ExtendedNode n;
struct ViewPort *ViewPort; /* backwards link
struct Rectangle DisplayClip; /* makevp display clipping information
}; */
/* we need to include the file videocontrol.h in order to associate a particular
DisplayInfoRecord with the viewport that we are going create... the interface
to use for this association is the new graphics function VideoControl(). */
#include <graphics/videocontrol.h>
/* the videocontrol commands that we will use operate on a ColorMap structure */
/* each videocommand is a TagItem:
struct TagItem /* as defined in intuition/tagitems.h
{
ULONG ti_Tag; /* identifies the type of this item
ULONG ti_Data; /* type-specific data, can be a pointer
};
/* we will need these commands:
1) attach a ColorMap obtained via GetColorMap() to our new viewport
2) set some extra viewport information to displayclip this viewport
3) associate the displayinforecord for this mode with this viewport
/* here are the commands we will use to set up the viewport's colormap: */
struct TagItem vc[] =
{
{ VTAG_ATTACH_CM_SET, NULL }, /* overwrite NULL with viewport */
{ VTAG_VIEWPORTEXTRA_SET, NULL }, /* overwrite NULL with viewportextra */
{ VTAG_NORMAL_DISP_SET, NULL }, /* overwrite NULL with displayinfo */
{ VTAG_END_CM, NULL } /* end-of-command list terminator */
};
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 );
/* the composite key mode ID's have been cleverly selected to obtain
maximum 1.2/1.3 compatibility when their bottom 16 bits are used
as templates for the vp->Modes field of your viewport... since
old iff readers/writers may be saving these modes to disk based
files, we have no guarantee that when they read them back that
the ECS will be available on the target machine... */
vp->Modes = (ID & 0xFFFF);
vp->DxOffset = 0; vp->DyOffset = 0;
vp->DWidth = WIDTH; vp->DHeight = HEIGHT;
/* allocate a viewportextra & initialize displayclip for viewport */
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;
}
/* pass new information to the system via VideoControl interface */
vc[0].ti_Data = (ULONG)vp;
vc[1].ti_Data = (ULONG)vpx;
vc[2].ti_Data = (ULONG) FindDisplayInfo( ID );
/* get a full colormap and execute the videocommands for this cm */
VideoControl( GetColorMap(32), vc );
/* set the global lace */
view->Modes |= ((DIPF_IS_LACE & queryinfo.PropertyFlags)? LACE: 0);
}
return( vp );
}
/* videocontrol commands that we will use to cleanup on closing the display */
/* we will need these commands: */
struct TagItem end_vc[] =
{
{ VTAG_VIEWPORTEXTRA_GET, NULL }, /* <--- this field will be filled in */
{ VTAG_END_CM, NULL } /* below by viewportextra_get to vpx */
};
dispose_vp( vp)
struct ViewPort *vp;
{
struct ViewPortExtra *vpx;
int error = FALSE;
if( vp )
{
error = VideoControl( vp->ColorMap, end_vc ); /* fetch the vpx ptr */
if(!error)
{
if(vpx = (struct ViewPortExtra *)end_vc[0].ti_Data)
{
GfxFree( vpx ); /* free the viewportextra structure */
}
}
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 );
/* viewextra is new for V1.4 -- it is used to pass the mspc for this
view to the graphics display routines such as makevp, mrgcop, and
loadview... as well as others. it is allocated with GfxNew( ) and
freed with GfxFree( ). since there is no field in the view to
point to this viewextra information, you must call the hashing
function GfxAssociate( view, vx ) which creates a soft "link"
between the view and the viewextra. after hashing, set the
EXTEND_VSTRUCT bit in the view->Modes to let the sytem know
when a hash GfxLookup() needs to be performed... */
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 ); /* gfxfree will inactivate and deallocate 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; /* center of the display, x dimension */
WORD y_center = vp->DHeight >> 1; /* center of the display, y dimension */
WORD width = vp->DWidth >> 2; /* width of ellipse 1/4 width display */
WORD height = /* ellipse height, adjusted for aspect ratio of the mode */
(( ( 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));
}
}