Files
nethack/sys/amiga/winchar.c

1249 lines
31 KiB
C

/* NetHack 3.5 winchar.c $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ */
/* NetHack 3.5 winchar.c $Date: 2009/05/06 10:48:33 $ $Revision: 1.4 $ */
/* SCCS Id: @(#)winchar.c 3.5 1993/07/22 */
/* Copyright (c) Olaf Seibert (KosmoSoft), 1989, 1992 */
/* Copyright (c) Kenneth Lorber, Bethesda, Maryland 1993 */
/* Copyright (c) Gregg Wonderly, Naperville Illinois, 1994. */
/* NetHack may be freely redistributed. See license for details. */
#include <exec/types.h>
#include <libraries/iffparse.h>
#include <graphics/scale.h>
#ifndef _DCC
#include <proto/iffparse.h>
#endif
#ifdef TESTING
# include "hack.h"
#else
# include "NH:src/tile.c"
#endif
#include "NH:win/share/tile.h"
#include "NH:sys/amiga/windefs.h"
#include "NH:sys/amiga/winext.h"
#include "NH:sys/amiga/winproto.h"
#ifdef OPT_DISPMAP
# define DISPMAP /* use display_map() from dispmap.s */
#endif
/* NH:sys/amiga/winvchar.c */
int main ( int , char ** );
struct BitMap *MyAllocBitMap ( int , int , int , long );
void MyFreeBitMap ( struct BitMap * );
void FreeImageFiles ( char **, struct BitMap ** );
void amiv_flush_glyph_buffer ( struct Window * );
void amiv_lprint_glyph ( winid , int , int );
void amii_lprint_glyph ( winid , int , int );
void amiv_start_glyphout ( winid );
void amii_end_glyphout ( winid );
void SetMazeType ( MazeType );
int GlyphToIcon ( int );
void amii_start_glyphout ( winid );
void amii_end_glyphout ( winid );
void amii_flush_glyph_buffer( struct Window * );
int amii_extraplanes = 0;
extern int reclip;
struct BitMap *MyAllocBitMap( int xsize, int ysize, int depth, long mflags );
void MyFreeBitMap( struct BitMap *bmp );
#ifdef DISPMAP
extern void display_map( struct Window * );
#endif
/*
* These values will be available from tile.c source
*
* #define MAXMONTILE 335
* #define MAXOBJTILE 722
* #define MAXOTHTILE 841
*/
#define IMGROWS 12
#define IMGCOLUMNS 20
#define IMGPAGESIZE (IMGROWS*IMGCOLUMNS)
#define ID_BMAP MAKE_ID('B','M','A','P') /* The type of form we use */
#define ID_BMHD MAKE_ID('B','M','H','D') /* The ILBM bitmap header */
#define ID_CAMG MAKE_ID('C','A','M','G') /* The ILBM camg (ignored) */
#define ID_CMAP MAKE_ID('C','M','A','P') /* Standard ILBM color map */
#define ID_PLNE MAKE_ID('P','L','N','E') /* The plane data */
#define ID_PDAT MAKE_ID('P','D','A','T') /* The PDAT structure below */
struct PDAT pictdata;
#define NUMTILEIMAGES 3
char *tileimages[] =
{
#define TBLMONTILE 0
"NetHack:tiles/monsters.iff",
#define TBLOBJTILE 1
"NetHack:tiles/objects.iff",
#define TBLOTHTILE 2
"NetHack:tiles/other.iff",
0,
};
struct BitMap *ifftimg[ NUMTILEIMAGES ], *tile;
#ifdef TESTING
short pens[NUMDRIPENS] = { 8, 3, 15, 0, 15, 7, 7, 8, 0 };
main( int argc, char **argv )
{
BitMapHeader bmhd;
struct IntuiMessage *imsg;
long code, class;
char buf[100];
int i, x, y, tbl, done = 0, num;
struct Window *w;
struct Screen *scr;
bmhd = ReadTileImageFiles( );
scr = OpenScreenTags( NULL,
SA_Depth, pictdata.nplanes + amii_extraplanes,
SA_DisplayID, DBLNTSC_MONITOR_ID|HIRESLACE_KEY,
SA_Overscan, OSCAN_TEXT,
SA_Top, 0,
SA_Left, 0,
SA_Width, STDSCREENWIDTH,
SA_Height, STDSCREENHEIGHT,
SA_Type, CUSTOMSCREEN,
SA_DetailPen, 0,
SA_BlockPen, 1,
SA_Title, "NetHack Chars",
SA_Pens, pens,
TAG_DONE
);
if( scr == NULL )
{
printf( "no screen\n" );
#undef exit
exit( 1 );
}
w = OpenWindowTags( 0,
WA_CustomScreen, scr,
WA_Flags, WFLG_DRAGBAR|WFLG_SIZEGADGET|WFLG_DEPTHGADGET|WFLG_CLOSEGADGET,
WA_IDCMP, IDCMP_CLOSEWINDOW|IDCMP_NEWSIZE|IDCMP_MOUSEBUTTONS,
WA_Left, 0,
WA_Top, scr->WBorTop + 1 + 13,
WA_MinWidth, 100,
WA_MinHeight, 100,
WA_MaxWidth, 700,
WA_MaxHeight, 1000,
WA_Width, 640,
WA_Height, 340,
WA_SmartRefresh, TRUE,
TAG_DONE );
if( w )
{
while( !done )
{
for( i = 0; i < NUMTILEIMAGES * IMGPAGESIZE; ++i )
{
int dx, dy;
tbl = i/IMGPAGESIZE;
x = i % IMGPAGESIZE;
y = x / IMGCOLUMNS;
x = x % IMGCOLUMNS;
dx = i % (IMGCOLUMNS*2);
dy = i / (IMGCOLUMNS*2);
BltBitMapRastPort( ifftimg[ tbl ],
x * pictdata.xsize, y * pictdata.ysize,
w->RPort,
w->BorderLeft + 1 + dx*pictdata.xsize,
w->BorderTop + 1 + dy*pictdata.ysize,
pictdata.xsize, pictdata.ysize, 0xc0 );
}
WaitPort( w->UserPort );
while( imsg = (struct IntuiMessage *)GetMsg( w->UserPort ) )
{
class = imsg->Class;
code = imsg->Code;
ReplyMsg( (struct Message *)imsg );
switch( class )
{
case IDCMP_MOUSEBUTTONS:
{
x = imsg->MouseX - w->BorderLeft;
y = imsg->MouseY - w->BorderTop;
num = ((y/pictdata.ysize)*IMGCOLUMNS*2)+(x/pictdata.xsize);
sprintf( buf, "Char #%d", num );
SetWindowTitles( w, buf, buf );
}
break;
case IDCMP_CLOSEWINDOW:
done = 1;
break;
}
}
}
CloseWindow( w );
CloseScreen( scr );
}
FreeImageFiles(tileimages, ifftimg );
return(0);
}
#endif
BitMapHeader
ReadTileImageFiles(){
char *errstr = NULL;
BitMapHeader ret = ReadImageFiles(tileimages, ifftimg, &errstr);
if(errstr){
panic(errstr);
}
return ret;
}
BitMapHeader
ReadImageFiles(char **filenames, struct BitMap **iffimg, char **errstrp )
{
BitMapHeader *bmhd = NULL, bmhds;
unsigned char *cmap;
extern int errno;
register int i, j;
struct IFFHandle *iff;
struct StoredProperty *prop;
IFFParseBase = OpenLibrary( "iffparse.library", 0L );
if( !IFFParseBase )
{
*errstrp = "No iffparse.library";
return bmhds;
}
/*
for( i = 0; filenames[i]; ++i )
memset( iffimg[i], 0, sizeof( struct BitMap ) );
*/
for( i = 0; filenames[i]; ++i )
{
iff = AllocIFF();
if( !iff )
{
FreeImageFiles(filenames, iffimg );
*errstrp = "can't start IFF processing";
return bmhds;
}
iff->iff_Stream = Open( filenames[i], MODE_OLDFILE );
if( iff->iff_Stream == 0 )
{
char *buf = malloc(100+strlen(filenames[i]));
FreeImageFiles( filenames, iffimg );
sprintf(buf, "Can't open %s: %s", filenames[i], strerror( errno ));
*errstrp = buf;
return bmhds;
}
InitIFFasDOS( iff );
OpenIFF( iff, IFFF_READ );
PropChunk( iff, ID_BMAP, ID_BMHD );
PropChunk( iff, ID_BMAP, ID_CMAP );
PropChunk( iff, ID_BMAP, ID_CAMG );
PropChunk( iff, ID_BMAP, ID_PDAT );
StopChunk( iff, ID_BMAP, ID_PLNE );
if( ( j = ParseIFF( iff, IFFPARSE_SCAN ) ) != 0 )
{
char *buf = malloc(100);
FreeImageFiles( filenames, iffimg );
sprintf(buf,"ParseIFF failed for image %d, failure code: %d",i,j);
*errstrp = buf;
return bmhds;
}
if( prop = FindProp( iff, ID_BMAP, ID_BMHD ) )
{
bmhd = (BitMapHeader *)prop->sp_Data;
}
else
{
FreeImageFiles(filenames, iffimg);
CloseIFF( iff );
Close( iff->iff_Stream );
FreeIFF( iff );
*errstrp = "No BMHD CHUNK in file";
return bmhds;
}
if( prop = FindProp( iff, ID_BMAP, ID_CMAP ) )
{
cmap = prop->sp_Data;
for( j = 0; j < (1L << bmhd->nPlanes)*3; j+=3 )
{
#if 0
/* Some day we will want to use the larger palette
* resolution available under v39 and later. i.e.
* 32 instead of 12 bits of color. Ususally this
* just means shifting the color left by 16-20 bits
* depending on what intensity looks best. Experience
* says that the higher values are better intensities.
*
* For now though we won't do this. The color table
* structure is incompatible with earlier versions of
* intuition. We would have to do some funny things
* to make 3*AMII_MAXCOLORS longs work like 3*AMII_MAXCOLORS
* UWORD's at run time... A union would help, but...
*/
if( IntuitionBase->LibNode.lib_Version >= 39 )
{
/* 8 bits of color, so shift to left end. */
amiv_init_map[ j+0 ] = cmap[j+0]<<24;
amiv_init_map[ j+1 ] = cmap[j+1]<<24;
amiv_init_map[ j+2 ] = cmap[j+2]<<24;
}
else
#endif
{
/* We can only use 4 bits of the 8 that are stored in the
* cmap, so mask them and then shift them into position
* for the UWORD value to store.
*/
#ifndef TESTING
amii_initmap[ j/3 ] =
amiv_init_map[ j/3 ] =
((cmap[j+0]>>4)<<8)|
((cmap[j+1]>>4)<<4)|
(cmap[j+2]>>4);
#endif
}
}
}
else
{
FreeImageFiles(filenames, iffimg);
CloseIFF( iff );
Close( iff->iff_Stream );
FreeIFF( iff );
*errstrp = "No CMAP CHUNK in file";
return bmhds;
}
if( prop = FindProp( iff, ID_BMAP, ID_PDAT ) )
{
struct PDAT *pp;
pp = (struct PDAT *)prop->sp_Data;
pictdata = *pp;
}
else
{
FreeImageFiles(filenames, iffimg);
CloseIFF( iff );
Close( iff->iff_Stream );
FreeIFF( iff );
*errstrp = "No PDAT CHUNK in file";
return bmhds;
}
iffimg[ i ] = MyAllocBitMap( bmhd->w, bmhd->h,
pictdata.nplanes + amii_extraplanes, MEMF_CHIP|MEMF_CLEAR );
if( iffimg[ i ] == NULL )
{
char *buf = malloc(80);
FreeImageFiles(filenames, iffimg);
sprintf(buf, "Can't allocate bitmap for image %d\n", i );
*errstrp = buf;
return bmhds;
}
for( j = 0; j < pictdata.nplanes + amii_extraplanes; ++j )
{
ReadChunkBytes( iff, iffimg[i]->Planes[j], RASSIZE( bmhd->w, bmhd->h ) );
}
bmhds = *bmhd;
CloseIFF( iff );
Close( iff->iff_Stream );
FreeIFF( iff );
}
CloseLibrary( IFFParseBase );
tile = MyAllocBitMap( pictdata.xsize, pictdata.ysize,
pictdata.nplanes + amii_extraplanes, MEMF_CHIP|MEMF_CLEAR );
if( tile == NULL )
{
FreeImageFiles(filenames, iffimg);
*errstrp = "Can't allocate tile bitmap for scaling";
}
return( bmhds );
}
struct MyBitMap
{
struct BitMap bm;
long mflags;
USHORT xsize, ysize;
};
struct BitMap *
MyAllocBitMap( int xsize, int ysize, int depth, long mflags )
{
int j;
struct MyBitMap *bm;
bm = (struct MyBitMap *)alloc( sizeof( *bm ) );
if( !bm )
return( NULL );
bm->xsize = xsize;
bm->ysize = ysize;
InitBitMap( &bm->bm, depth, xsize, ysize );
for( j = 0; j < depth; ++j )
{
if( mflags & MEMF_CHIP )
bm->bm.Planes[ j ] = AllocRaster( xsize, ysize );
else
bm->bm.Planes[ j ] = AllocMem( RASSIZE( xsize, ysize ), mflags );
if( bm->bm.Planes[ j ] == 0 )
{
MyFreeBitMap( &bm->bm );
return( NULL );
}
if( mflags & MEMF_CLEAR )
memset( bm->bm.Planes[ j ], 0, RASSIZE( xsize, ysize ) );
}
return( &bm->bm );
}
void
MyFreeBitMap( struct BitMap *bmp )
{
int j;
struct MyBitMap *bm = (struct MyBitMap *)bmp;
for( j = 0; j < bm->bm.Depth; ++j )
{
if( bm->bm.Planes[j] )
{
if( bm->mflags & MEMF_CHIP )
FreeRaster( bm->bm.Planes[j], bm->xsize, bm->ysize );
else
FreeMem( bm->bm.Planes[j], RASSIZE( bm->xsize, bm->ysize ) );
}
}
free( bm );
}
#ifdef TESTING
void
panic(s,a1,a2,a3,a4)
char *s;
{
printf( s, a1, a2, a3, a4 );
putchar('\n');
}
long *
alloc(unsigned int x){
long *p = (long *)malloc(x);
if(!p){panic("malloc failed"); exit(1);}
return p;
}
#endif
void
FreeTileImageFiles(){
FreeImageFiles(tileimages,ifftimg);
}
void
FreeImageFiles(char **filenames, struct BitMap **img )
{
register int i;
for( i = 0; filenames[i]; ++i )
{
if( img[ i ] )
MyFreeBitMap( img[ i ] );
}
/* REALLY ugly hack alert! */
if( tile && img==ifftimg)
MyFreeBitMap( tile );
}
#ifndef TESTING
/*
* Define some stuff for our special glyph drawing routines
*/
unsigned short glyph_node_index, glyph_buffer_index;
#define NUMBER_GLYPH_NODES 80
#define GLYPH_BUFFER_SIZE 512
struct amiv_glyph_node {
short odstx, odsty;
short srcx, srcy, dstx, dsty;
struct BitMap *bitmap;
};
struct amiv_glyph_node amiv_g_nodes[NUMBER_GLYPH_NODES];
static char amiv_glyph_buffer[GLYPH_BUFFER_SIZE];
void
flush_glyph_buffer( vw )
struct Window *vw;
{
if( WINVERS_AMIV )
amiv_flush_glyph_buffer ( vw );
else
amii_flush_glyph_buffer ( vw );
}
/*
* Routine to flush whatever is buffered
*/
void
amiv_flush_glyph_buffer( vw )
struct Window *vw;
{
#if !defined(DISPMAP) || defined(OPT_DISPMAP)
int xsize, ysize, x, y;
struct BitScaleArgs bsa;
struct BitScaleArgs bsm;
struct RastPort rast;
struct Window *w = NULL;
struct BitMap *imgbm = 0, *bm = 0;
int i, k;
int scaling_needed;
register struct RastPort *rp = vw->RPort;
#endif
/* If nothing is buffered, return before we do anything */
if(glyph_node_index == 0)
return;
cursor_off( WIN_MAP );
amiv_start_glyphout( WIN_MAP );
#ifdef OPT_DISPMAP
if(sysflags.fast_map){
#endif
#ifdef DISPMAP
display_map( vw );
#endif
#ifdef OPT_DISPMAP
} else {
#endif
#if !defined(DISPMAP) || defined(OPT_DISPMAP)
/* XXX fix indent */
/* This is a dynamic value based on this relationship. */
scaling_needed = ( pictdata.xsize != mxsize || pictdata.ysize != mysize );
/* If overview window is up, set up to render the correct scale there */
if( WIN_OVER != WIN_ERR && ( w = amii_wins[ WIN_OVER ]->win ) != NULL )
{
InitRastPort( &rast );
/* Calculate the x and y size of each tile for a ROWNO by COLNO map */
xsize = (w->Width - w->BorderLeft - w->BorderRight) / COLNO;
ysize = (w->Height - w->BorderTop - w->BorderBottom) / ROWNO;
/* Get a chip memory bitmap to blit out of */
bm = MyAllocBitMap( pictdata.xsize, pictdata.ysize,
pictdata.nplanes + amii_extraplanes, MEMF_CLEAR|MEMF_CHIP );
if( bm == NULL )
{
amii_putstr( WIN_MESSAGE, 0, "Can't allocate bitmap for scaling overview window" );
}
rast.BitMap = bm;
memset( &bsa, 0, sizeof( bsa ) );
bsa.bsa_SrcX = bsa.bsa_SrcY = 0;
bsa.bsa_SrcBitMap = tile;
bsa.bsa_SrcWidth = pictdata.xsize;
bsa.bsa_SrcHeight = pictdata.ysize;
bsa.bsa_XSrcFactor = pictdata.xsize;
bsa.bsa_YSrcFactor = pictdata.ysize;
bsa.bsa_DestX = 0;
bsa.bsa_DestY = 0;
bsa.bsa_DestWidth = xsize;
bsa.bsa_DestHeight = ysize;
bsa.bsa_XDestFactor = xsize;
bsa.bsa_YDestFactor = ysize;
bsa.bsa_DestBitMap = bm;
}
if( scaling_needed )
{
/* Fill in scaling data for map rendering */
memset( &bsm, 0, sizeof( bsm ) );
bsm.bsa_SrcX = bsm.bsa_SrcY = 0;
bsm.bsa_SrcBitMap = tile;
bsm.bsa_SrcWidth = pictdata.xsize;
bsm.bsa_SrcHeight = pictdata.ysize;
bsm.bsa_XSrcFactor = pictdata.xsize;
bsm.bsa_YSrcFactor = pictdata.ysize;
bsm.bsa_DestWidth = mxsize;
bsm.bsa_DestHeight = mysize;
bsm.bsa_XDestFactor = mxsize;
bsm.bsa_YDestFactor = mysize;
bsm.bsa_DestBitMap = rp->BitMap;
bsm.bsa_DestY = bsm.bsa_DestX = 0;
imgbm = MyAllocBitMap( mxsize, mysize,
pictdata.nplanes + amii_extraplanes, MEMF_CLEAR|MEMF_CHIP );
if( imgbm == NULL )
{
amii_putstr( WIN_MESSAGE, 0,
"Can't allocate scaling bitmap for map window" );
}
else
bsm.bsa_DestBitMap = imgbm;
}
/* Go ahead and start dumping the stuff */
for( i=0; i<glyph_node_index; ++i )
{
/* Do it */
register int offx, offy, j;
struct BitMap *nodebm = amiv_g_nodes[ i ].bitmap;
/* Get the unclipped coordinates */
x = amiv_g_nodes[ i ].odstx;
y = amiv_g_nodes[ i ].odsty;
/* If image is not in CHIP. copy each plane into tile line by line */
offx = amiv_g_nodes[ i ].srcx / 8; /* 8 is bits per byte */
offy = amiv_g_nodes[ i ].srcy * nodebm->BytesPerRow;
for( j = 0; j < pictdata.nplanes + amii_extraplanes; ++j )
{
for( k = 0; k < pictdata.ysize; ++k )
{
/* For a 16x16 tile, this could just be short assignments, but
* this code is generalized to handle any size tile image...
*/
memcpy( tile->Planes[ j ] + ( ( k * pictdata.ysize ) / 8 ),
nodebm->Planes[ j ] + offx + offy + ( nodebm->BytesPerRow * k ),
pictdata.ysize/8 );
}
}
if( !clipping ||
( x >= clipx && y >= clipy &&
x < clipxmax && y < clipymax ) )
{
/* scaling is needed, do it */
if( scaling_needed )
{
BitMapScale( &bsm );
BltBitMapRastPort( imgbm, 0, 0,
rp, amiv_g_nodes[ i ].dstx, amiv_g_nodes[ i ].dsty,
mxsize, mysize, 0xc0 );
}
else
{
BltBitMapRastPort( tile, 0, 0,
rp, amiv_g_nodes[ i ].dstx, amiv_g_nodes[ i ].dsty,
pictdata.xsize, pictdata.ysize, 0xc0 );
}
}
/* Draw the overview window unless we are scrolling the map raster around */
if( bm && w && reclip != 2 )
{
BitMapScale( &bsa );
BltBitMapRastPort( rast.BitMap, 0, 0,
w->RPort,
w->BorderLeft + amiv_g_nodes[ i ].odstx*xsize,
w->BorderTop + amiv_g_nodes[ i ].odsty*ysize,
xsize, ysize, 0xc0 );
}
}
if( imgbm ) MyFreeBitMap( imgbm );
if( bm ) MyFreeBitMap( bm );
#endif /* DISPMAP */
#ifdef OPT_DISPMAP
}
#endif
amii_end_glyphout( WIN_MAP );
/* Clean up */
glyph_node_index = glyph_buffer_index = 0;
}
/*
* Glyph buffering routine. Called instead of WindowPuts().
*/
void
amiv_lprint_glyph(window,color_index, glyph)
winid window;
int color_index, glyph;
{
int base;
struct amii_WinDesc *cw;
struct Window *w;
int curx;
int cury;
int tbl, icon;
register int xoff, yoff;
/* Get the real icon index */
if( glyph != NO_GLYPH )
icon = GlyphToIcon( glyph );
if( ( cw=amii_wins[window] ) == (struct amii_WinDesc *)NULL )
panic("bad winid in amiv_lprint_glyph: %d", window );
w = cw->win;
if( glyph != NO_GLYPH && glyph < 10000)
{
/* decide on which image has the needed picture */
if( icon <= MAXMONTILE )
{
tbl = TBLMONTILE;
base = 0;
}
else if( icon <= MAXOBJTILE )
{
tbl = TBLOBJTILE;
base = MAXMONTILE+1;
}
else if( icon <= MAXOTHTILE )
{
tbl = TBLOTHTILE;
base = MAXOBJTILE+1;
}
else
panic( "Bad icon #%d, glyph #%d, only %d icons known\n", icon, glyph, MAXOTHTILE );
/* Get the relative offset in the page */
/* How many pixels to account for y distance down */
yoff = ((icon-base) / pictdata.across) * pictdata.ysize;
/* How many pixels to account for x distance across */
xoff = ((icon-base) % pictdata.across) * pictdata.xsize;
}
if(glyph >= 10000){
/* Run a single ASCII character out to the rastport right now */
char c= glyph-10000;
int xxx,xxy;
struct RastPort *rp = w->RPort;
Move(rp, xxx=(((cw->curx-clipx)*rp->TxWidth) + w->BorderLeft),
xxy=(w->BorderTop + (((cw->cury-clipy)+1)* rp->TxHeight)+1));
Text(rp,&c,1);
/* XXX this shouldn't be necessary: */
if(cw->cursx == xxx && cw->cursy == xxy){
cw->wflags &= ~FLMAP_CURSUP;
}
cw->curx += rp->TxWidth; /* keep things in sync */
return;
}
if( cw->type == NHW_MAP )
{
curx = cw->curx - clipx;
cury = cw->cury - clipy;
/* See if we're out of glyph nodes */
if(glyph_node_index >= NUMBER_GLYPH_NODES)
amiv_flush_glyph_buffer( w );
/* Fill in the node. */
amiv_g_nodes[glyph_node_index].dsty = min( w->BorderTop + (cury * mysize),
w->Height - 1 );
#ifdef OPT_DISPMAP
if(sysflags.fast_map){
#endif /* keni */
#ifdef DISPMAP
/* display_map() needs byte-aligned destinations, and we don't want to
* overwrite the window border.
*/
amiv_g_nodes[glyph_node_index].dstx =
(w->BorderLeft + 8 + (curx * mxsize)) & -8;
#endif
#ifdef OPT_DISPMAP
} else {
#endif
#if !defined(DISPMAP) || defined(OPT_DISPMAP)
amiv_g_nodes[glyph_node_index].dstx = min( w->BorderLeft + (curx * mxsize),
w->Width - 1 );
#endif
#ifdef OPT_DISPMAP
}
#endif
amiv_g_nodes[glyph_node_index].odsty = cw->cury;
amiv_g_nodes[glyph_node_index].odstx = cw->curx;
amiv_g_nodes[glyph_node_index].srcx = xoff;
amiv_g_nodes[glyph_node_index].srcy = yoff;
amiv_g_nodes[glyph_node_index].bitmap = ifftimg[ tbl ];
++glyph_node_index;
}
else
{
/* Do it */
register int j, k, x, y, apen;
struct RastPort *rp = w->RPort;
x = rp->cp_x - pictdata.xsize - 3;
#ifdef OPT_DISPMAP
if(sysflags.fast_map){
#endif
#ifdef DISPMAP
x &= -8;
if(x==0) x = 8;
#endif
#ifdef OPT_DISPMAP
}
#endif
y = rp->cp_y - pictdata.ysize + 1;
if( glyph != NO_GLYPH )
{
struct BitMap *bm = ifftimg[ tbl ];
/* 8 bits per byte */
xoff /= 8;
yoff *= bm->BytesPerRow;
for( j = 0; j < pictdata.nplanes; ++j )
{
for( k = 0; k < pictdata.ysize; ++k )
{
memcpy( tile->Planes[ j ] + ( ( k * pictdata.ysize ) / 8 ),
bm->Planes[ j ] + xoff + yoff + ( bm->BytesPerRow * k ),
pictdata.ysize/8 );
}
}
BltBitMapRastPort( tile, 0, 0,
rp, x, y,
pictdata.xsize, pictdata.ysize, 0xc0 );
apen = rp->FgPen;
SetAPen( rp, sysflags.amii_dripens[ SHINEPEN ] );
Move( rp, x-1, y + pictdata.ysize );
Draw( rp, x-1, y - 1 );
Draw( rp, x + pictdata.xsize, y - 1 );
SetAPen( rp, sysflags.amii_dripens[ SHADOWPEN ] );
Move( rp, x + pictdata.xsize, y );
Draw( rp, x + pictdata.xsize, y + pictdata.ysize );
Draw( rp, x, y + pictdata.ysize );
SetAPen( rp, apen );
}
else if( x > w->BorderLeft )
{
int apen, bpen;
apen = rp->FgPen;
bpen = rp->BgPen;
SetAPen( rp, amii_menuBPen );
SetBPen( rp, amii_menuBPen );
RectFill( rp, x-1, y-1, x + pictdata.xsize, y + pictdata.ysize );
SetAPen( rp, apen );
SetBPen( rp, bpen );
}
}
}
/*
* Define some variables which will be used to save context when toggling
* back and forth between low level text and console I/O.
*/
static long xsave, ysave, modesave, apensave, bpensave;
static int usecolor;
/*
* The function is called before any glyphs are driven to the screen. It
* removes the cursor, saves internal state of the window, then returns.
*/
void
amiv_start_glyphout(window)
winid window;
{
struct amii_WinDesc *cw;
struct Window *w;
if( ( cw=amii_wins[window] ) == (struct amii_WinDesc *)NULL )
panic( "bad winid %d in start_glyphout()", window );
if( cw->wflags & FLMAP_INGLYPH )
return;
if( !(w = cw->win ) )
panic( "bad winid %d, no window ptr set", window );
/*
* Save the context of the window
*/
xsave = w->RPort->cp_x;
ysave = w->RPort->cp_y;
modesave = w->RPort->DrawMode;
apensave = w->RPort->FgPen;
bpensave = w->RPort->BgPen;
/*
* Set the mode, and be done with it
*/
usecolor = iflags.use_color;
iflags.use_color = FALSE;
cw->wflags |= FLMAP_INGLYPH;
}
/*
* General cleanup routine -- flushes and restores cursor
*/
void
amii_end_glyphout(window)
winid window;
{
struct amii_WinDesc *cw;
struct Window *w;
if( ( cw = amii_wins[ window ] ) == (struct amii_WinDesc *)NULL )
panic("bad window id %d in amii_end_glyphout()", window );
if( ( cw->wflags & FLMAP_INGLYPH ) == 0 )
return;
cw->wflags &= ~(FLMAP_INGLYPH);
if( !(w = cw->win ) )
panic( "bad winid %d, no window ptr set", window );
/*
* Clean up whatever is left in the buffer
*/
iflags.use_color = usecolor;
/*
* Reset internal data structs
*/
SetAPen(w->RPort, apensave);
SetBPen(w->RPort, bpensave);
SetDrMd(w->RPort, modesave);
Move(w->RPort, xsave, ysave);
}
static maze_type=COL_MAZE_BRICK;
void SetMazeType(MazeType t)
{
maze_type=t;
}
int GlyphToIcon(int glyph)
{
if(glyph>10000)return glyph;
return( glyph2tile[glyph] );
}
#endif
#ifdef AMII_GRAPHICS
# ifdef TESTING
/*
* Define some stuff for our special glyph drawing routines
*/
static unsigned short glyph_node_index, glyph_buffer_index;
# define NUMBER_GLYPH_NODES 80
# define GLYPH_BUFFER_SIZE 512
# endif /* TESTING */
struct amii_glyph_node {
short x;
short y;
short len;
unsigned char bg_color;
unsigned char fg_color;
char *buffer;
};
static struct amii_glyph_node amii_g_nodes[NUMBER_GLYPH_NODES];
static char amii_glyph_buffer[GLYPH_BUFFER_SIZE];
#ifdef TEXTCOLOR
/*
* Map our amiga-specific colormap into the colormap specified in color.h.
* See winami.c for the amiga specific colormap.
*/
int foreg[AMII_MAXCOLORS] = { 0, 7, 4, 2, 6, 5, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
int backg[AMII_MAXCOLORS] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 7, 4, 1, 6, 5, 3, 1 };
#if 0
#define CLR_BLACK 0
#define CLR_RED 1
#define CLR_GREEN 2
#define CLR_BROWN 3 /* on IBM, low-intensity yellow is brown */
#define CLR_BLUE 4
#define CLR_MAGENTA 5
#define CLR_CYAN 6
#define CLR_GRAY 7 /* low-intensity white */
#define NO_COLOR 8
#define CLR_ORANGE 9
#define CLR_BRIGHT_GREEN 10
#define CLR_YELLOW 11
#define CLR_BRIGHT_BLUE 12
#define CLR_BRIGHT_MAGENTA 13
#define CLR_BRIGHT_CYAN 14
#define CLR_WHITE 15
#define CLR_MAX 16
#endif
#endif
#ifndef TESTING
/*
* Begin Revamped Text display routines
*
* Up until version 3.1, the only method for displaying text on the playing
* field was by using the console.device. This was nice for a number of
* reasons, the most signifigant of which was a lot of the nuts and bolts was
* done for you via escape sequences interpreted by said device. This did
* not come without a price however. And that price was speed. It has now
* come to a point where the speed has now been deemed unacceptable.
*
* The following series of routines are designed to drop into the current
* nethack display code, using hooks provided for such a measure. It works
* on similar principals as the WindowPuts(), buffering I/O internally
* until either an explicit flush or internal buffering is exceeded, thereby
* forcing the flush. The output (or glyphs) does not go to the
* console.device, however. It is driven directly to the rasterport of the
* nethack window via the low-level Text() calls, increasing the speed by
* a very signifigant factor.
*/
/*
* Routine to simply flush whatever is buffered
*/
void
amii_flush_glyph_buffer( w )
struct Window *w;
{
short i, x, y;
register struct RastPort *rp = w->RPort;
/* If nothing is buffered, return before we do anything */
if(glyph_node_index == 0)
return;
cursor_off( WIN_MAP );
amii_start_glyphout( WIN_MAP );
/* Set up the drawing mode */
SetDrMd( rp, JAM2);
/* Go ahead and start dumping the stuff */
for(i=0; i<glyph_node_index; ++i) {
/* These coordinate calculations must be synced with the
* code in amii_curs() in winfuncs.c. curs_on_u() calls amii_curs()
* to draw the cursor on top of the player
*/
y = w->BorderTop + (amii_g_nodes[i].y-2) * rp->TxHeight +
rp->TxBaseline + 1;
x = amii_g_nodes[i].x * rp->TxWidth + w->BorderLeft;
/* Move pens to correct location */
Move( rp, (long)x, (long)y);
/* Setup the colors */
SetAPen( rp, (long)amii_g_nodes[i].fg_color);
SetBPen( rp, (long)amii_g_nodes[i].bg_color);
/* Do it */
Text( rp, amii_g_nodes[i].buffer, amii_g_nodes[i].len);
}
amii_end_glyphout( WIN_MAP );
/* Clean up */
glyph_node_index = glyph_buffer_index = 0;
}
void
amiga_print_glyph(window,color_index, glyph)
winid window;
int color_index, glyph;
{
if( WINVERS_AMIV )
amiv_lprint_glyph(window,color_index, glyph);
else
amii_lprint_glyph(window,color_index, glyph);
}
/*
* Glyph buffering routine. Called instead of WindowPuts().
*/
void
amii_lprint_glyph(window,color_index, glyph)
winid window;
int color_index, glyph;
{
int fg_color, bg_color;
struct amii_WinDesc *cw;
struct Window *w;
int curx;
int cury;
if( ( cw=amii_wins[window] ) == (struct amii_WinDesc *)NULL )
panic("bad winid in amii_lprint_glyph: %d", window );
w = cw->win;
curx=cw->curx;
cury=cw->cury;
#ifdef TEXTCOLOR
fg_color = foreg[color_index];
bg_color = backg[color_index];
#else
fg_color = 1;
bg_color = 0;
#endif /* TEXTCOLOR */
/* See if we have enough character buffer space... */
if(glyph_buffer_index >= GLYPH_BUFFER_SIZE)
amii_flush_glyph_buffer( w );
/*
* See if we can append it to the current active node of glyph buffer. It
* must satisfy the following conditions:
*
* * background colors are the same, AND
* * foreground colors are the same, AND
* * they are precisely side by side
*/
if((glyph_buffer_index != 0) &&
(fg_color == amii_g_nodes[glyph_node_index-1].fg_color) &&
(bg_color == amii_g_nodes[glyph_node_index-1].bg_color) &&
(amii_g_nodes[glyph_node_index-1].x+
amii_g_nodes[glyph_node_index-1].len == curx) &&
(amii_g_nodes[glyph_node_index-1].y == cury)) {
/*
* Add it to the end of the buffer
*/
amii_glyph_buffer[glyph_buffer_index++] = glyph;
amii_g_nodes[glyph_node_index-1].len ++;
} else {
/* See if we're out of glyph nodes */
if(glyph_node_index >= NUMBER_GLYPH_NODES)
amii_flush_glyph_buffer( w );
amii_g_nodes[glyph_node_index].len = 1;
amii_g_nodes[glyph_node_index].x = curx;
amii_g_nodes[glyph_node_index].y = cury;
amii_g_nodes[glyph_node_index].fg_color = fg_color;
amii_g_nodes[glyph_node_index].bg_color = bg_color;
amii_g_nodes[glyph_node_index].buffer = &amii_glyph_buffer[glyph_buffer_index];
amii_glyph_buffer[glyph_buffer_index] = glyph;
++glyph_buffer_index;
++glyph_node_index;
}
}
#endif /* !TESTING */
#ifdef TESTING
/*
* Define some variables which will be used to save context when toggling
* back and forth between low level text and console I/O.
*/
static long xsave, ysave, modesave, apensave, bpensave;
static int usecolor;
#endif /* TESTING */
#ifndef TESTING
/*
* The function is called before any glyphs are driven to the screen. It
* removes the cursor, saves internal state of the window, then returns.
*/
void
amii_start_glyphout(window)
winid window;
{
struct amii_WinDesc *cw;
struct Window *w;
if( ( cw=amii_wins[window] ) == (struct amii_WinDesc *)NULL )
panic( "bad winid %d in start_glyphout()", window );
if( cw->wflags & FLMAP_INGLYPH )
return;
if( !(w = cw->win ) )
panic( "bad winid %d, no window ptr set", window );
/*
* Save the context of the window
*/
xsave = w->RPort->cp_x;
ysave = w->RPort->cp_y;
modesave = w->RPort->DrawMode;
apensave = w->RPort->FgPen;
bpensave = w->RPort->BgPen;
/*
* Set the mode, and be done with it
*/
usecolor = iflags.use_color;
iflags.use_color = FALSE;
cw->wflags |= FLMAP_INGLYPH;
}
#endif /* !TESTING */
# if 0
/*
* General cleanup routine -- flushes and restores cursor
*/
void
amii_end_glyphout(window)
winid window;
{
struct amii_WinDesc *cw;
struct Window *w;
if( ( cw = amii_wins[ window ] ) == (struct amii_WinDesc *)NULL )
panic("bad window id %d in amii_end_glyphout()", window );
if( ( cw->wflags & FLMAP_INGLYPH ) == 0 )
return;
cw->wflags &= ~(FLMAP_INGLYPH);
if( !(w = cw->win ) )
panic( "bad winid %d, no window ptr set", window );
/*
* Clean up whatever is left in the buffer
*/
iflags.use_color = usecolor;
/*
* Reset internal data structs
*/
SetAPen(w->RPort, apensave);
SetBPen(w->RPort, bpensave);
SetDrMd(w->RPort, modesave);
Move(w->RPort, xsave, ysave);
}
# endif
#endif
#ifndef TESTING
# ifdef OPT_DISPMAP
/* don't use dispmap unless x & y are 8,16,24,32,48 and equal */
void
dispmap_sanity(){
if(
mxsize != mysize ||
dispmap_sanity1(mxsize) ||
dispmap_sanity1(mysize)){
sysflags.fast_map = 0;
}
}
int
dispmap_sanity1(x)
int x;
{
static unsigned char valid[] = {8,16,24,32,48,0};
return !!strchr(valid,x);
}
# endif /* OPT_DISPMAP */
#endif /* TESTING */