1 /*    SCCS Id: @(#)winchar.c     3.1    93/07/22			*/
2 /*    Copyright (c) Olaf Seibert (KosmoSoft), 1989, 1992	  */
3 /*    Copyright (c) Kenneth Lorber, Bethesda, Maryland 1993	  */
4 /*    Copyright (c) Gregg Wonderly, Naperville Illinois, 1994.		*/
5 /*    NetHack may be freely redistributed.  See license for details.	*/
6 
7 #include <exec/types.h>
8 #include <libraries/iffparse.h>
9 #include <graphics/scale.h>
10 #ifndef _DCC
11 #include <proto/iffparse.h>
12 #endif
13 
14 #ifdef TESTING
15 # include "hack.h"
16 #else
17 # include "NH:src/tile.c"
18 #endif
19 
20 #include "NH:win/share/tile.h"
21 
22 #include "NH:sys/amiga/windefs.h"
23 #include "NH:sys/amiga/winext.h"
24 #include "NH:sys/amiga/winproto.h"
25 
26 #ifdef OPT_DISPMAP
27 # define DISPMAP		/* use display_map() from dispmap.s */
28 #endif
29 
30 /* NH:sys/amiga/winvchar.c */
31 int main ( int  , char ** );
32 struct BitMap *MyAllocBitMap ( int  , int  , int  , long  );
33 void MyFreeBitMap ( struct BitMap * );
34 void FreeImageFiles ( char **, struct BitMap ** );
35 void amiv_flush_glyph_buffer ( struct Window * );
36 void amiv_lprint_glyph ( winid  , int  , int  );
37 void amii_lprint_glyph ( winid  , int  , int  );
38 void amiv_start_glyphout ( winid  );
39 void amii_end_glyphout ( winid  );
40 void SetMazeType ( MazeType  );
41 int GlyphToIcon ( int  );
42 void amii_start_glyphout ( winid  );
43 void amii_end_glyphout ( winid  );
44 void amii_flush_glyph_buffer( struct Window * );
45 
46 int amii_extraplanes = 0;
47 extern int reclip;
48 
49 struct BitMap *MyAllocBitMap( int xsize, int ysize, int depth, long mflags );
50 void MyFreeBitMap( struct BitMap *bmp );
51 
52 #ifdef DISPMAP
53 extern void display_map( struct Window * );
54 #endif
55 
56 /*
57  *  These values will be available from tile.c source
58  *
59  * #define MAXMONTILE 335
60  * #define MAXOBJTILE 722
61  * #define MAXOTHTILE 841
62  */
63 
64 #define	IMGROWS		12
65 #define IMGCOLUMNS	20
66 #define IMGPAGESIZE	(IMGROWS*IMGCOLUMNS)
67 
68 #define ID_BMAP		MAKE_ID('B','M','A','P')	/* The type of form we use */
69 #define ID_BMHD		MAKE_ID('B','M','H','D')	/* The ILBM bitmap header */
70 #define ID_CAMG		MAKE_ID('C','A','M','G')	/* The ILBM camg (ignored) */
71 #define ID_CMAP		MAKE_ID('C','M','A','P')	/* Standard ILBM color map */
72 #define ID_PLNE		MAKE_ID('P','L','N','E')	/* The plane data */
73 #define ID_PDAT		MAKE_ID('P','D','A','T')	/* The PDAT structure below */
74 
75 struct PDAT pictdata;
76 
77 #define NUMTILEIMAGES	3
78 char *tileimages[] =
79 {
80 #define TBLMONTILE	0
81 	"NetHack:tiles/monsters.iff",
82 #define TBLOBJTILE	1
83 	"NetHack:tiles/objects.iff",
84 #define TBLOTHTILE	2
85 	"NetHack:tiles/other.iff",
86 	0,
87 };
88 
89 struct BitMap *ifftimg[ NUMTILEIMAGES ], *tile;
90 
91 #ifdef TESTING
92 short pens[NUMDRIPENS] = { 8, 3, 15, 0, 15, 7, 7, 8, 0 };
main(int argc,char ** argv)93 main( int argc, char **argv )
94 {
95     BitMapHeader bmhd;
96     struct IntuiMessage *imsg;
97     long code, class;
98     char buf[100];
99     int i, x, y, tbl, done = 0, num;
100     struct Window *w;
101     struct Screen *scr;
102 
103     bmhd = ReadTileImageFiles( );
104 
105     scr = OpenScreenTags( NULL,
106 	SA_Depth, pictdata.nplanes + amii_extraplanes,
107 	SA_DisplayID, DBLNTSC_MONITOR_ID|HIRESLACE_KEY,
108 	SA_Overscan, OSCAN_TEXT,
109 	SA_Top, 0,
110 	SA_Left, 0,
111 	SA_Width, STDSCREENWIDTH,
112 	SA_Height, STDSCREENHEIGHT,
113 	SA_Type, CUSTOMSCREEN,
114 	SA_DetailPen, 0,
115 	SA_BlockPen, 1,
116 	SA_Title, "NetHack Chars",
117 	SA_Pens, pens,
118 	TAG_DONE
119 	);
120     if( scr == NULL )
121     {
122     	printf( "no screen\n" );
123 #undef exit
124     	exit( 1 );
125     }
126 
127     w = OpenWindowTags( 0,
128 		WA_CustomScreen, scr,
129     		WA_Flags, WFLG_DRAGBAR|WFLG_SIZEGADGET|WFLG_DEPTHGADGET|WFLG_CLOSEGADGET,
130     		WA_IDCMP, IDCMP_CLOSEWINDOW|IDCMP_NEWSIZE|IDCMP_MOUSEBUTTONS,
131 		WA_Left, 0,
132 		WA_Top, scr->WBorTop + 1 + 13,
133 		WA_MinWidth, 100,
134 		WA_MinHeight, 100,
135 		WA_MaxWidth, 700,
136 		WA_MaxHeight, 1000,
137 		WA_Width, 640,
138 		WA_Height, 340,
139 		WA_SmartRefresh, TRUE,
140 		TAG_DONE );
141     if( w )
142     {
143 	while( !done )
144 	{
145 	    for( i = 0; i < NUMTILEIMAGES * IMGPAGESIZE; ++i )
146 	    {
147 		int dx, dy;
148 		tbl = i/IMGPAGESIZE;
149 		x = i % IMGPAGESIZE;
150 		y = x / IMGCOLUMNS;
151 		x = x % IMGCOLUMNS;
152 		dx = i % (IMGCOLUMNS*2);
153 		dy = i / (IMGCOLUMNS*2);
154 		BltBitMapRastPort( ifftimg[ tbl ],
155 				x * pictdata.xsize, y * pictdata.ysize,
156 				w->RPort,
157 				w->BorderLeft + 1 + dx*pictdata.xsize,
158 				w->BorderTop + 1 + dy*pictdata.ysize,
159 				pictdata.xsize, pictdata.ysize, 0xc0 );
160 	    }
161 	    WaitPort( w->UserPort );
162 	    while( imsg = (struct IntuiMessage *)GetMsg( w->UserPort ) )
163 	    {
164 	    	class = imsg->Class;
165 	    	code = imsg->Code;
166 	    	ReplyMsg( (struct Message *)imsg );
167 	    	switch( class )
168 		{
169 		case IDCMP_MOUSEBUTTONS:
170 		    {
171 			x = imsg->MouseX - w->BorderLeft;
172 			y = imsg->MouseY - w->BorderTop;
173 			num = ((y/pictdata.ysize)*IMGCOLUMNS*2)+(x/pictdata.xsize);
174 			sprintf( buf, "Char #%d", num );
175 			SetWindowTitles( w, buf, buf );
176 		    }
177 		    break;
178 		case IDCMP_CLOSEWINDOW:
179 		    done = 1;
180 		    break;
181 		}
182 	    }
183 	}
184 	CloseWindow( w );
185 	CloseScreen( scr );
186     }
187 
188     FreeImageFiles(tileimages, ifftimg );
189 
190     return(0);
191 }
192 #endif
193 
194 BitMapHeader
ReadTileImageFiles()195 ReadTileImageFiles(){
196     char *errstr = NULL;
197     BitMapHeader ret = ReadImageFiles(tileimages, ifftimg, &errstr);
198     if(errstr){
199 	panic(errstr);
200     }
201     return ret;
202 }
203 
204 BitMapHeader
ReadImageFiles(char ** filenames,struct BitMap ** iffimg,char ** errstrp)205 ReadImageFiles(char **filenames, struct BitMap **iffimg, char **errstrp )
206 {
207     BitMapHeader *bmhd = NULL, bmhds;
208     unsigned char *cmap;
209     extern int errno;
210     register int i, j;
211     struct IFFHandle *iff;
212     struct StoredProperty *prop;
213 
214     IFFParseBase = OpenLibrary( "iffparse.library", 0L );
215     if( !IFFParseBase )
216     {
217 	*errstrp = "No iffparse.library";
218 	return bmhds;
219     }
220 
221 /*
222     for( i = 0; filenames[i]; ++i )
223 	memset( iffimg[i], 0, sizeof( struct BitMap ) );
224 */
225     for( i = 0; filenames[i]; ++i )
226     {
227 	iff = AllocIFF();
228 	if( !iff )
229 	{
230 	    FreeImageFiles(filenames, iffimg );
231 	    *errstrp = "can't start IFF processing";
232 	    return bmhds;
233 	}
234 	iff->iff_Stream = Open( filenames[i], MODE_OLDFILE );
235 	if( iff->iff_Stream == 0 )
236 	{
237 	    char *buf = malloc(100+strlen(filenames[i]));
238 	    FreeImageFiles( filenames, iffimg );
239 	    sprintf(buf, "Can't open %s: %s", filenames[i], strerror( errno ));
240 	    *errstrp = buf;
241 	    return bmhds;
242 	}
243 	InitIFFasDOS( iff );
244 	OpenIFF( iff, IFFF_READ );
245 	PropChunk( iff, ID_BMAP, ID_BMHD );
246 	PropChunk( iff, ID_BMAP, ID_CMAP );
247 	PropChunk( iff, ID_BMAP, ID_CAMG );
248 	PropChunk( iff, ID_BMAP, ID_PDAT );
249 	StopChunk( iff, ID_BMAP, ID_PLNE );
250 	if( ( j = ParseIFF( iff, IFFPARSE_SCAN ) ) != 0 )
251 	{
252 	    char *buf = malloc(100);
253 	    FreeImageFiles( filenames, iffimg );
254 	    sprintf(buf,"ParseIFF failed for image %d, failure code: %d",i,j);
255 	    *errstrp = buf;
256 	    return bmhds;
257 	}
258 
259 	if( prop = FindProp( iff, ID_BMAP, ID_BMHD ) )
260 	{
261 	    bmhd = (BitMapHeader *)prop->sp_Data;
262 	}
263 	else
264 	{
265 	    FreeImageFiles(filenames, iffimg);
266 	    CloseIFF( iff );
267 	    Close( iff->iff_Stream );
268 	    FreeIFF( iff );
269 	    *errstrp = "No BMHD CHUNK in file";
270 	    return bmhds;
271 	}
272 
273 	if( prop = FindProp( iff, ID_BMAP, ID_CMAP ) )
274 	{
275 	    cmap = prop->sp_Data;
276 	    for( j = 0; j < (1L << bmhd->nPlanes)*3; j+=3 )
277 	    {
278 #if 0
279 		/* Some day we will want to use the larger palette
280 		 * resolution available under v39 and later.  i.e.
281 		 * 32 instead of 12 bits of color.  Ususally this
282 		 * just means shifting the color left by 16-20 bits
283 		 * depending on what intensity looks best.  Experience
284 		 * says that the higher values are better intensities.
285 		 *
286 		 * For now though we won't do this. The color table
287 		 * structure is incompatible with earlier versions of
288 		 * intuition.  We would have to do some funny things
289 		 * to make 3*AMII_MAXCOLORS longs work like 3*AMII_MAXCOLORS
290 		 * UWORD's at run time...  A union would help, but...
291 		 */
292 		if( IntuitionBase->LibNode.lib_Version >= 39 )
293 		{
294 		    /* 8 bits of color, so shift to left end. */
295 		    amiv_init_map[ j+0 ] = cmap[j+0]<<24;
296 		    amiv_init_map[ j+1 ] = cmap[j+1]<<24;
297 		    amiv_init_map[ j+2 ] = cmap[j+2]<<24;
298 		}
299 		else
300 #endif
301 		{
302 		    /* We can only use 4 bits of the 8 that are stored in the
303 		     * cmap, so mask them and then shift them into position
304 		     * for the UWORD value to store.
305 		     */
306 #ifndef TESTING
307 		    amii_initmap[ j/3 ] =
308 		    amiv_init_map[ j/3 ] =
309 					((cmap[j+0]>>4)<<8)|
310 					((cmap[j+1]>>4)<<4)|
311 					(cmap[j+2]>>4);
312 #endif
313 		}
314 	    }
315 	}
316 	else
317 	{
318 	    FreeImageFiles(filenames, iffimg);
319 	    CloseIFF( iff );
320 	    Close( iff->iff_Stream );
321 	    FreeIFF( iff );
322 	    *errstrp = "No CMAP CHUNK in file";
323 	    return bmhds;
324 	}
325 
326 	if( prop = FindProp( iff, ID_BMAP, ID_PDAT ) )
327 	{
328 	    struct PDAT *pp;
329 
330 	    pp = (struct PDAT *)prop->sp_Data;
331 	    pictdata = *pp;
332 	}
333 	else
334 	{
335 	    FreeImageFiles(filenames, iffimg);
336 	    CloseIFF( iff );
337 	    Close( iff->iff_Stream );
338 	    FreeIFF( iff );
339 	    *errstrp = "No PDAT CHUNK in file";
340 	    return bmhds;
341 	}
342 
343 	iffimg[ i ] = MyAllocBitMap( bmhd->w, bmhd->h,
344 		pictdata.nplanes + amii_extraplanes, MEMF_CHIP|MEMF_CLEAR );
345 	if( iffimg[ i ] == NULL )
346 	{
347 	    char *buf = malloc(80);
348 	    FreeImageFiles(filenames, iffimg);
349 	    sprintf(buf, "Can't allocate bitmap for image %d\n", i );
350 	    *errstrp = buf;
351 	    return bmhds;
352 	}
353 	for( j = 0; j < pictdata.nplanes + amii_extraplanes; ++j )
354 	{
355 	    ReadChunkBytes( iff, iffimg[i]->Planes[j], RASSIZE( bmhd->w, bmhd->h ) );
356 	}
357 	bmhds = *bmhd;
358 	CloseIFF( iff );
359 	Close( iff->iff_Stream );
360 	FreeIFF( iff );
361     }
362     CloseLibrary( IFFParseBase );
363 
364     tile = MyAllocBitMap( pictdata.xsize, pictdata.ysize,
365 	    pictdata.nplanes + amii_extraplanes, MEMF_CHIP|MEMF_CLEAR );
366     if( tile == NULL )
367     {
368 	FreeImageFiles(filenames, iffimg);
369 	*errstrp = "Can't allocate tile bitmap for scaling";
370     }
371     return( bmhds );
372 }
373 
374 struct MyBitMap
375 {
376 	struct BitMap bm;
377 	long mflags;
378 	USHORT xsize, ysize;
379 };
380 
381 struct BitMap *
MyAllocBitMap(int xsize,int ysize,int depth,long mflags)382 MyAllocBitMap( int xsize, int ysize, int depth, long mflags )
383 {
384     int j;
385     struct MyBitMap *bm;
386 
387     bm = (struct MyBitMap *)alloc( sizeof( *bm ) );
388     if( !bm )
389 	return( NULL );
390 
391     bm->xsize = xsize;
392     bm->ysize = ysize;
393     InitBitMap( &bm->bm, depth, xsize, ysize );
394     for( j = 0; j < depth; ++j )
395     {
396 	if( mflags & MEMF_CHIP )
397 	    bm->bm.Planes[ j ] = AllocRaster( xsize, ysize );
398 	else
399 	    bm->bm.Planes[ j ] = AllocMem( RASSIZE( xsize, ysize ), mflags );
400 
401 	if( bm->bm.Planes[ j ] == 0 )
402 	{
403 	    MyFreeBitMap( &bm->bm );
404 	    return( NULL );
405 	}
406 	if( mflags & MEMF_CLEAR )
407 	    memset( bm->bm.Planes[ j ], 0, RASSIZE( xsize, ysize ) );
408     }
409     return( &bm->bm );
410 }
411 
412 void
MyFreeBitMap(struct BitMap * bmp)413 MyFreeBitMap( struct BitMap *bmp )
414 {
415     int j;
416     struct MyBitMap *bm = (struct MyBitMap *)bmp;
417 
418     for( j = 0; j < bm->bm.Depth; ++j )
419     {
420 	if( bm->bm.Planes[j] )
421 	{
422 	    if( bm->mflags & MEMF_CHIP )
423 		FreeRaster( bm->bm.Planes[j], bm->xsize, bm->ysize );
424 	    else
425 		FreeMem( bm->bm.Planes[j], RASSIZE( bm->xsize, bm->ysize ) );
426 	}
427     }
428     free( bm );
429 }
430 
431 #ifdef	TESTING
432 void
panic(s,a1,a2,a3,a4)433 panic(s,a1,a2,a3,a4)
434 	char *s;
435 {
436     printf( s, a1, a2, a3, a4 );
437     putchar('\n');
438 }
439 long *
alloc(unsigned int x)440 alloc(unsigned int x){
441 	long *p = (long *)malloc(x);
442 	if(!p){panic("malloc failed"); exit(1);}
443 	return p;
444 }
445 #endif
446 
447 void
FreeTileImageFiles()448 FreeTileImageFiles(){
449 	FreeImageFiles(tileimages,ifftimg);
450 }
451 
452 void
FreeImageFiles(char ** filenames,struct BitMap ** img)453 FreeImageFiles(char **filenames, struct BitMap **img )
454 {
455     register int i;
456 
457     for( i = 0; filenames[i]; ++i )
458     {
459 	if( img[ i ] )
460 	    MyFreeBitMap( img[ i ] );
461     }
462 
463 	/* REALLY ugly hack alert! */
464     if( tile && img==ifftimg)
465 	MyFreeBitMap( tile );
466 }
467 
468 #ifndef TESTING
469 /*
470  * Define some stuff for our special glyph drawing routines
471  */
472 unsigned short glyph_node_index, glyph_buffer_index;
473 #define NUMBER_GLYPH_NODES  80
474 #define GLYPH_BUFFER_SIZE   512
475 struct amiv_glyph_node {
476     short	odstx, odsty;
477     short	srcx, srcy, dstx, dsty;
478     struct BitMap	*bitmap;
479 };
480 struct amiv_glyph_node amiv_g_nodes[NUMBER_GLYPH_NODES];
481 static char amiv_glyph_buffer[GLYPH_BUFFER_SIZE];
482 
483 void
flush_glyph_buffer(vw)484 flush_glyph_buffer( vw )
485     struct Window *vw;
486 {
487     if( WINVERS_AMIV )
488 	amiv_flush_glyph_buffer ( vw );
489     else
490 	amii_flush_glyph_buffer ( vw );
491 }
492 
493 /*
494  * Routine to flush whatever is buffered
495  */
496 void
amiv_flush_glyph_buffer(vw)497 amiv_flush_glyph_buffer( vw )
498     struct Window *vw;
499 {
500 #if !defined(DISPMAP) || defined(OPT_DISPMAP)
501     int xsize, ysize, x, y;
502     struct BitScaleArgs bsa;
503     struct BitScaleArgs bsm;
504     struct RastPort rast;
505     struct Window *w = NULL;
506     struct BitMap *imgbm = 0, *bm = 0;
507     int i, k;
508     int scaling_needed;
509     register struct RastPort *rp = vw->RPort;
510 #endif
511 
512     /* If nothing is buffered, return before we do anything */
513     if(glyph_node_index == 0)
514 	return;
515 
516     cursor_off( WIN_MAP );
517     amiv_start_glyphout( WIN_MAP );
518 
519 #ifdef OPT_DISPMAP
520     if(flags.fast_map){
521 #endif
522 #ifdef DISPMAP
523 	display_map( vw );
524 #endif
525 #ifdef OPT_DISPMAP
526     } else {
527 #endif
528 #if !defined(DISPMAP) || defined(OPT_DISPMAP)
529 /* XXX fix indent */
530     /* This is a dynamic value based on this relationship. */
531     scaling_needed = ( pictdata.xsize != mxsize || pictdata.ysize != mysize );
532 
533     /* If overview window is up, set up to render the correct scale there */
534     if( WIN_OVER != WIN_ERR && ( w = amii_wins[ WIN_OVER ]->win ) != NULL )
535     {
536 	InitRastPort( &rast );
537 
538 	/* Calculate the x and y size of each tile for a ROWNO by COLNO map */
539 	xsize = (w->Width - w->BorderLeft - w->BorderRight) / COLNO;
540 	ysize = (w->Height - w->BorderTop - w->BorderBottom) / ROWNO;
541 
542 	/* Get a chip memory bitmap to blit out of */
543 	bm = MyAllocBitMap( pictdata.xsize, pictdata.ysize,
544 	    pictdata.nplanes + amii_extraplanes, MEMF_CLEAR|MEMF_CHIP );
545 	if( bm == NULL )
546 	{
547 	    amii_putstr( WIN_MESSAGE, 0, "Can't allocate bitmap for scaling overview window" );
548 	}
549 
550 	rast.BitMap = bm;
551 
552 	memset( &bsa, 0, sizeof( bsa ) );
553 	bsa.bsa_SrcX = bsa.bsa_SrcY = 0;
554 	bsa.bsa_SrcBitMap = tile;
555 	bsa.bsa_SrcWidth = pictdata.xsize;
556 	bsa.bsa_SrcHeight = pictdata.ysize;
557 	bsa.bsa_XSrcFactor = pictdata.xsize;
558 	bsa.bsa_YSrcFactor = pictdata.ysize;
559 	bsa.bsa_DestX = 0;
560 	bsa.bsa_DestY = 0;
561 	bsa.bsa_DestWidth = xsize;
562 	bsa.bsa_DestHeight = ysize;
563 	bsa.bsa_XDestFactor = xsize;
564 	bsa.bsa_YDestFactor = ysize;
565 	bsa.bsa_DestBitMap = bm;
566     }
567 
568     if( scaling_needed )
569     {
570 	/* Fill in scaling data for map rendering */
571 	memset( &bsm, 0, sizeof( bsm ) );
572 	bsm.bsa_SrcX = bsm.bsa_SrcY = 0;
573 	bsm.bsa_SrcBitMap = tile;
574 
575 	bsm.bsa_SrcWidth = pictdata.xsize;
576 	bsm.bsa_SrcHeight = pictdata.ysize;
577 
578 	bsm.bsa_XSrcFactor = pictdata.xsize;
579 	bsm.bsa_YSrcFactor = pictdata.ysize;
580 
581 	bsm.bsa_DestWidth = mxsize;
582 	bsm.bsa_DestHeight = mysize;
583 
584 	bsm.bsa_XDestFactor = mxsize;
585 	bsm.bsa_YDestFactor = mysize;
586 	bsm.bsa_DestBitMap = rp->BitMap;
587 	bsm.bsa_DestY = bsm.bsa_DestX = 0;
588 
589 	imgbm = MyAllocBitMap( mxsize, mysize,
590 	    pictdata.nplanes + amii_extraplanes, MEMF_CLEAR|MEMF_CHIP );
591 	if( imgbm == NULL )
592 	{
593 	    amii_putstr( WIN_MESSAGE, 0,
594 		"Can't allocate scaling bitmap for map window" );
595 	}
596 	else
597 	    bsm.bsa_DestBitMap = imgbm;
598     }
599 
600     /* Go ahead and start dumping the stuff */
601     for( i=0; i<glyph_node_index; ++i )
602     {
603 	/* Do it */
604 	register int offx, offy, j;
605 	struct BitMap *nodebm = amiv_g_nodes[ i ].bitmap;
606 
607 	/* Get the unclipped coordinates */
608 	x = amiv_g_nodes[ i ].odstx;
609 	y = amiv_g_nodes[ i ].odsty;
610 
611 	/* If image is not in CHIP. copy each plane into tile line by line */
612 
613 	offx = amiv_g_nodes[ i ].srcx / 8;	/* 8 is bits per byte */
614 	offy = amiv_g_nodes[ i ].srcy * nodebm->BytesPerRow;
615 	for( j = 0; j < pictdata.nplanes + amii_extraplanes; ++j )
616 	{
617 	    for( k = 0; k < pictdata.ysize; ++k )
618 	    {
619 
620 	    	/* For a 16x16 tile, this could just be short assignments, but
621 	    	 * this code is generalized to handle any size tile image...
622 	    	 */
623 	    	memcpy( tile->Planes[ j ] + ( ( k * pictdata.ysize ) / 8 ),
624 			nodebm->Planes[ j ] + offx + offy + ( nodebm->BytesPerRow * k ),
625 			pictdata.ysize/8 );
626 	    }
627 	}
628 
629 	if( !clipping ||
630 		( x >= clipx    && y >= clipy &&
631 		  x <  clipxmax && y <  clipymax ) )
632 	{
633 	    /* scaling is needed, do it */
634 	    if( scaling_needed )
635 	    {
636 		BitMapScale( &bsm );
637 		BltBitMapRastPort( imgbm, 0, 0,
638 		    rp, amiv_g_nodes[ i ].dstx, amiv_g_nodes[ i ].dsty,
639 		    mxsize, mysize, 0xc0 );
640 	    }
641 	    else
642 	    {
643 		BltBitMapRastPort( tile, 0, 0,
644 		    rp, amiv_g_nodes[ i ].dstx, amiv_g_nodes[ i ].dsty,
645 		    pictdata.xsize, pictdata.ysize, 0xc0 );
646 	    }
647 	}
648 	/* Draw the overview window unless we are scrolling the map raster around */
649 	if( bm && w && reclip != 2 )
650 	{
651 	    BitMapScale( &bsa );
652 	    BltBitMapRastPort( rast.BitMap, 0, 0,
653 		    w->RPort,
654 		    w->BorderLeft + amiv_g_nodes[ i ].odstx*xsize,
655 		    w->BorderTop + amiv_g_nodes[ i ].odsty*ysize,
656 		    xsize, ysize, 0xc0 );
657 	}
658     }
659 
660     if( imgbm ) MyFreeBitMap( imgbm );
661     if( bm ) MyFreeBitMap( bm );
662 #endif /* DISPMAP */
663 #ifdef OPT_DISPMAP
664     }
665 #endif
666 
667     amii_end_glyphout( WIN_MAP );
668 
669     /* Clean up */
670     glyph_node_index = glyph_buffer_index = 0;
671 }
672 
673 /*
674  * Glyph buffering routine.  Called instead of WindowPuts().
675  */
676 void
amiv_lprint_glyph(window,color_index,glyph)677 amiv_lprint_glyph(window,color_index, glyph)
678     winid window;
679     int color_index, glyph;
680 {
681     int base;
682     struct amii_WinDesc *cw;
683     struct Window *w;
684     int curx;
685     int cury;
686     int tbl, icon;
687     register int xoff, yoff;
688 
689     /* Get the real icon index */
690     if( glyph != NO_GLYPH )
691 	icon = GlyphToIcon( glyph );
692 
693     if( ( cw=amii_wins[window] ) == (struct amii_WinDesc *)NULL )
694 	panic("bad winid in amiv_lprint_glyph: %d", window );
695 
696     w = cw->win;
697 
698     if( glyph != NO_GLYPH && glyph < 10000)
699     {
700 	/* decide on which image has the needed picture */
701 	if( icon <= MAXMONTILE )
702 	{
703 	    tbl = TBLMONTILE;
704 	    base = 0;
705 	}
706 	else if( icon <= MAXOBJTILE )
707 	{
708 	    tbl = TBLOBJTILE;
709 	    base = MAXMONTILE+1;
710 	}
711 	else if( icon <= MAXOTHTILE )
712 	{
713 	    tbl = TBLOTHTILE;
714 	    base = MAXOBJTILE+1;
715 	}
716 	else
717 	    panic( "Bad icon #%d, glyph #%d, only %d icons known\n", icon, glyph, MAXOTHTILE );
718 
719 	/* Get the relative offset in the page */
720 
721 	/* How many pixels to account for y distance down */
722 	yoff = ((icon-base) / pictdata.across) * pictdata.ysize;
723 
724 	/* How many pixels to account for x distance across */
725 	xoff = ((icon-base) % pictdata.across) * pictdata.xsize;
726     }
727 
728     if(glyph >= 10000){
729 	/* Run a single ASCII character out to the rastport right now */
730 	char c= glyph-10000;
731 	int xxx,xxy;
732 	struct RastPort *rp = w->RPort;
733 
734 	Move(rp, xxx=(((cw->curx-clipx)*rp->TxWidth) + w->BorderLeft),
735 	  xxy=(w->BorderTop + (((cw->cury-clipy)+1)* rp->TxHeight)+1));
736 	Text(rp,&c,1);
737 		/* XXX this shouldn't be necessary: */
738 	if(cw->cursx == xxx && cw->cursy == xxy){
739 	    cw->wflags &= ~FLMAP_CURSUP;
740 	}
741 	cw->curx += rp->TxWidth;	/* keep things in sync */
742 	return;
743     }
744 
745     if( cw->type == NHW_MAP )
746     {
747 	curx = cw->curx - clipx;
748 	cury = cw->cury - clipy;
749 
750 	/* See if we're out of glyph nodes */
751 	if(glyph_node_index >= NUMBER_GLYPH_NODES)
752 	    amiv_flush_glyph_buffer( w );
753 
754 	/* Fill in the node. */
755 	amiv_g_nodes[glyph_node_index].dsty = min( w->BorderTop + (cury * mysize),
756 						w->Height - 1 );
757 
758 #ifdef OPT_DISPMAP
759 	if(flags.fast_map){
760 #endif /* keni */
761 #ifdef	DISPMAP
762 	/* display_map() needs byte-aligned destinations, and we don't want to
763 	 * overwrite the window border.
764 	 */
765 	amiv_g_nodes[glyph_node_index].dstx =
766 				(w->BorderLeft + 8 + (curx * mxsize)) & -8;
767 #endif
768 #ifdef OPT_DISPMAP
769 } else {
770 #endif
771 #if !defined(DISPMAP) || defined(OPT_DISPMAP)
772 	amiv_g_nodes[glyph_node_index].dstx = min( w->BorderLeft + (curx * mxsize),
773 						w->Width - 1 );
774 #endif
775 #ifdef OPT_DISPMAP
776 }
777 #endif
778 	amiv_g_nodes[glyph_node_index].odsty = cw->cury;
779 	amiv_g_nodes[glyph_node_index].odstx = cw->curx;
780 	amiv_g_nodes[glyph_node_index].srcx = xoff;
781 	amiv_g_nodes[glyph_node_index].srcy = yoff;
782 	amiv_g_nodes[glyph_node_index].bitmap = ifftimg[ tbl ];
783 	++glyph_node_index;
784     }
785     else
786     {
787 	/* Do it */
788 	register int j, k, x, y, apen;
789 	struct RastPort *rp = w->RPort;
790 	x = rp->cp_x - pictdata.xsize - 3;
791 #ifdef OPT_DISPMAP
792 	if(flags.fast_map){
793 #endif
794 #ifdef DISPMAP
795 		x &= -8;
796 		if(x==0) x = 8;
797 #endif
798 #ifdef OPT_DISPMAP
799 	}
800 #endif
801 
802 	y = rp->cp_y - pictdata.ysize + 1;
803 
804 	if( glyph != NO_GLYPH )
805 	{
806 	    struct BitMap *bm = ifftimg[ tbl ];
807 
808 	    /* 8 bits per byte */
809 	    xoff /= 8;
810 	    yoff *= bm->BytesPerRow;
811 	    for( j = 0; j < pictdata.nplanes; ++j )
812 	    {
813 		for( k = 0; k < pictdata.ysize; ++k )
814 		{
815 		    memcpy( tile->Planes[ j ] + ( ( k * pictdata.ysize ) / 8 ),
816 			    bm->Planes[ j ] + xoff + yoff + ( bm->BytesPerRow * k ),
817 			    pictdata.ysize/8 );
818 		}
819 	    }
820 
821 	    BltBitMapRastPort( tile, 0, 0,
822 		rp, x, y,
823 		pictdata.xsize, pictdata.ysize, 0xc0 );
824 
825 	    apen = rp->FgPen;
826 	    SetAPen( rp, flags.amii_dripens[ SHINEPEN ] );
827 	    Move( rp, x-1, y + pictdata.ysize );
828 	    Draw( rp, x-1, y - 1 );
829 	    Draw( rp, x + pictdata.xsize, y - 1 );
830 	    SetAPen( rp, flags.amii_dripens[ SHADOWPEN ] );
831 	    Move( rp, x + pictdata.xsize, y );
832 	    Draw( rp, x + pictdata.xsize, y + pictdata.ysize );
833 	    Draw( rp, x, y + pictdata.ysize );
834 	    SetAPen( rp, apen );
835 	}
836 	else if( x > w->BorderLeft )
837 	{
838 	    int apen, bpen;
839 	    apen = rp->FgPen;
840 	    bpen = rp->BgPen;
841 	    SetAPen( rp, amii_menuBPen );
842 	    SetBPen( rp, amii_menuBPen );
843 	    RectFill( rp, x-1, y-1, x + pictdata.xsize, y + pictdata.ysize );
844 	    SetAPen( rp, apen );
845 	    SetBPen( rp, bpen );
846 	}
847     }
848 }
849 
850 /*
851  * Define some variables which will be used to save context when toggling
852  * back and forth between low level text and console I/O.
853  */
854 static long xsave, ysave, modesave, apensave, bpensave;
855 static int usecolor;
856 
857 /*
858  * The function is called before any glyphs are driven to the screen.  It
859  * removes the cursor, saves internal state of the window, then returns.
860  */
861 
862 void
amiv_start_glyphout(window)863 amiv_start_glyphout(window)
864     winid window;
865 {
866     struct amii_WinDesc *cw;
867     struct Window *w;
868 
869     if( ( cw=amii_wins[window] ) == (struct amii_WinDesc *)NULL )
870 	panic( "bad winid %d in start_glyphout()", window );
871 
872     if( cw->wflags & FLMAP_INGLYPH )
873 	return;
874 
875     if( !(w = cw->win ) )
876 	panic( "bad winid %d, no window ptr set", window );
877 
878     /*
879      * Save the context of the window
880      */
881     xsave = w->RPort->cp_x;
882     ysave = w->RPort->cp_y;
883     modesave = w->RPort->DrawMode;
884     apensave = w->RPort->FgPen;
885     bpensave = w->RPort->BgPen;
886 
887     /*
888      * Set the mode, and be done with it
889      */
890     usecolor = iflags.use_color;
891     iflags.use_color = FALSE;
892     cw->wflags |= FLMAP_INGLYPH;
893 }
894 
895 /*
896  * General cleanup routine -- flushes and restores cursor
897  */
898 void
amii_end_glyphout(window)899 amii_end_glyphout(window)
900     winid window;
901 {
902     struct amii_WinDesc *cw;
903     struct Window *w;
904 
905     if( ( cw = amii_wins[ window ] ) == (struct amii_WinDesc *)NULL )
906 	panic("bad window id %d in amii_end_glyphout()", window );
907 
908     if( ( cw->wflags & FLMAP_INGLYPH ) == 0 )
909 	return;
910     cw->wflags &= ~(FLMAP_INGLYPH);
911 
912     if( !(w = cw->win ) )
913 	panic( "bad winid %d, no window ptr set", window );
914 
915     /*
916      * Clean up whatever is left in the buffer
917      */
918     iflags.use_color = usecolor;
919 
920     /*
921      * Reset internal data structs
922      */
923     SetAPen(w->RPort, apensave);
924     SetBPen(w->RPort, bpensave);
925     SetDrMd(w->RPort, modesave);
926 
927     Move(w->RPort, xsave, ysave);
928 }
929 
930 static maze_type=COL_MAZE_BRICK;
931 
SetMazeType(MazeType t)932 void SetMazeType(MazeType t)
933 {
934     maze_type=t;
935 }
936 
GlyphToIcon(int glyph)937 int GlyphToIcon(int glyph)
938 {
939     if(glyph>10000)return glyph;
940     return( glyph2tile[glyph] );
941 }
942 #endif
943 
944 #ifdef AMII_GRAPHICS
945 # ifdef TESTING
946 /*
947  * Define some stuff for our special glyph drawing routines
948  */
949 static unsigned short glyph_node_index, glyph_buffer_index;
950 #  define NUMBER_GLYPH_NODES  80
951 #  define GLYPH_BUFFER_SIZE   512
952 # endif /* TESTING */
953 
954 struct amii_glyph_node {
955     short	x;
956     short	y;
957     short	len;
958     unsigned char   bg_color;
959     unsigned char   fg_color;
960     char	*buffer;
961 };
962 static struct amii_glyph_node amii_g_nodes[NUMBER_GLYPH_NODES];
963 static char amii_glyph_buffer[GLYPH_BUFFER_SIZE];
964 
965 #ifdef TEXTCOLOR
966 /*
967  * Map our amiga-specific colormap into the colormap specified in color.h.
968  * See winami.c for the amiga specific colormap.
969  */
970 
971 int foreg[AMII_MAXCOLORS] = { 0, 7, 4, 2, 6, 5, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
972 int backg[AMII_MAXCOLORS] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 7, 4, 1, 6, 5, 3, 1 };
973 #if 0
974 	#define CLR_BLACK	0
975 	#define CLR_RED		1
976 	#define CLR_GREEN	2
977 	#define CLR_BROWN	3	/* on IBM, low-intensity yellow is brown */
978 	#define CLR_BLUE	4
979 	#define CLR_MAGENTA 	5
980 	#define CLR_CYAN	6
981 	#define CLR_GRAY	7	/* low-intensity white */
982 	#define NO_COLOR	8
983 	#define CLR_ORANGE	9
984 	#define CLR_BRIGHT_GREEN 10
985 	#define CLR_YELLOW	11
986 	#define CLR_BRIGHT_BLUE	12
987 	#define CLR_BRIGHT_MAGENTA 13
988 	#define CLR_BRIGHT_CYAN	14
989 	#define CLR_WHITE	15
990 	#define CLR_MAX		16
991 #endif
992 #endif
993 
994 #ifndef TESTING
995 /*
996  * Begin Revamped Text display routines
997  *
998  * Up until version 3.1, the only method for displaying text on the playing
999  * field was by using the console.device.  This was nice for a number of
1000  * reasons, the most signifigant of which was a lot of the nuts and bolts was
1001  * done for you via escape sequences interpreted by said device.  This did
1002  * not come without a price however.  And that price was speed. It has now
1003  * come to a point where the speed has now been deemed unacceptable.
1004  *
1005  * The following series of routines are designed to drop into the current
1006  * nethack display code, using hooks provided for such a measure. It works
1007  * on similar principals as the WindowPuts(), buffering I/O internally
1008  * until either an explicit flush or internal buffering is exceeded, thereby
1009  * forcing the flush.  The output (or glyphs) does not go to the
1010  * console.device, however.  It is driven directly to the rasterport of the
1011  * nethack window via the low-level Text() calls, increasing the speed by
1012  * a very signifigant factor.
1013  */
1014 /*
1015  * Routine to simply flush whatever is buffered
1016  */
1017 void
amii_flush_glyph_buffer(w)1018 amii_flush_glyph_buffer( w )
1019     struct Window *w;
1020 {
1021     short i, x, y;
1022     register struct RastPort *rp = w->RPort;
1023 
1024     /* If nothing is buffered, return before we do anything */
1025     if(glyph_node_index == 0)
1026 	return;
1027 
1028     cursor_off( WIN_MAP );
1029     amii_start_glyphout( WIN_MAP );
1030 
1031     /* Set up the drawing mode */
1032     SetDrMd( rp, JAM2);
1033 
1034     /* Go ahead and start dumping the stuff */
1035     for(i=0; i<glyph_node_index; ++i) {
1036 	/* These coordinate calculations must be synced with the
1037 	 * code in amii_curs() in winfuncs.c.  curs_on_u() calls amii_curs()
1038 	 * to draw the cursor on top of the player
1039 	 */
1040 	y = w->BorderTop + (amii_g_nodes[i].y-2) * rp->TxHeight +
1041 	    rp->TxBaseline + 1;
1042 	x = amii_g_nodes[i].x * rp->TxWidth + w->BorderLeft;
1043 
1044 	/* Move pens to correct location */
1045 	Move( rp, (long)x, (long)y);
1046 
1047 	/* Setup the colors */
1048 	SetAPen( rp, (long)amii_g_nodes[i].fg_color);
1049 	SetBPen( rp, (long)amii_g_nodes[i].bg_color);
1050 
1051 	/* Do it */
1052 	Text( rp, amii_g_nodes[i].buffer, amii_g_nodes[i].len);
1053     }
1054 
1055     amii_end_glyphout( WIN_MAP );
1056     /* Clean up */
1057     glyph_node_index = glyph_buffer_index = 0;
1058 }
1059 void
amiga_print_glyph(window,color_index,glyph)1060 amiga_print_glyph(window,color_index, glyph)
1061     winid window;
1062     int color_index, glyph;
1063 {
1064     if( WINVERS_AMIV )
1065 	amiv_lprint_glyph(window,color_index, glyph);
1066     else
1067 	amii_lprint_glyph(window,color_index, glyph);
1068 }
1069 
1070 /*
1071  * Glyph buffering routine.  Called instead of WindowPuts().
1072  */
1073 void
amii_lprint_glyph(window,color_index,glyph)1074 amii_lprint_glyph(window,color_index, glyph)
1075     winid window;
1076     int color_index, glyph;
1077 {
1078     int fg_color, bg_color;
1079     struct amii_WinDesc *cw;
1080     struct Window *w;
1081     int curx;
1082     int cury;
1083 
1084     if( ( cw=amii_wins[window] ) == (struct amii_WinDesc *)NULL )
1085 	panic("bad winid in amii_lprint_glyph: %d", window );
1086 
1087     w = cw->win;
1088     curx=cw->curx;
1089     cury=cw->cury;
1090 
1091 #ifdef TEXTCOLOR
1092     fg_color = foreg[color_index];
1093     bg_color = backg[color_index];
1094 #else
1095     fg_color = 1;
1096     bg_color = 0;
1097 #endif /* TEXTCOLOR */
1098 
1099     /* See if we have enough character buffer space... */
1100     if(glyph_buffer_index  >= GLYPH_BUFFER_SIZE)
1101 	amii_flush_glyph_buffer( w );
1102 
1103     /*
1104      * See if we can append it to the current active node of glyph buffer. It
1105      * must satisfy the following conditions:
1106      *
1107      *    * background colors are the same, AND
1108      *    * foreground colors are the same, AND
1109      *    * they are precisely side by side
1110      */
1111     if((glyph_buffer_index != 0) &&
1112        (fg_color == amii_g_nodes[glyph_node_index-1].fg_color) &&
1113        (bg_color == amii_g_nodes[glyph_node_index-1].bg_color) &&
1114        (amii_g_nodes[glyph_node_index-1].x+
1115 	amii_g_nodes[glyph_node_index-1].len == curx) &&
1116        (amii_g_nodes[glyph_node_index-1].y == cury)) {
1117 	/*
1118 	 * Add it to the end of the buffer
1119 	 */
1120 	amii_glyph_buffer[glyph_buffer_index++] = glyph;
1121 	amii_g_nodes[glyph_node_index-1].len ++;
1122      } else {
1123 	/* See if we're out of glyph nodes */
1124 	if(glyph_node_index >= NUMBER_GLYPH_NODES)
1125 	    amii_flush_glyph_buffer( w );
1126 	amii_g_nodes[glyph_node_index].len = 1;
1127 	amii_g_nodes[glyph_node_index].x = curx;
1128 	amii_g_nodes[glyph_node_index].y = cury;
1129 	amii_g_nodes[glyph_node_index].fg_color = fg_color;
1130 	amii_g_nodes[glyph_node_index].bg_color = bg_color;
1131 	amii_g_nodes[glyph_node_index].buffer = &amii_glyph_buffer[glyph_buffer_index];
1132 	amii_glyph_buffer[glyph_buffer_index] = glyph;
1133 	++glyph_buffer_index;
1134 	++glyph_node_index;
1135     }
1136 }
1137 #endif /* !TESTING */
1138 
1139 #ifdef TESTING
1140 /*
1141  * Define some variables which will be used to save context when toggling
1142  * back and forth between low level text and console I/O.
1143  */
1144 static long xsave, ysave, modesave, apensave, bpensave;
1145 static int usecolor;
1146 #endif /* TESTING */
1147 
1148 #ifndef TESTING
1149 /*
1150  * The function is called before any glyphs are driven to the screen.  It
1151  * removes the cursor, saves internal state of the window, then returns.
1152  */
1153 
1154 void
amii_start_glyphout(window)1155 amii_start_glyphout(window)
1156     winid window;
1157 {
1158     struct amii_WinDesc *cw;
1159     struct Window *w;
1160 
1161     if( ( cw=amii_wins[window] ) == (struct amii_WinDesc *)NULL )
1162 	panic( "bad winid %d in start_glyphout()", window );
1163 
1164     if( cw->wflags & FLMAP_INGLYPH )
1165 	return;
1166 
1167     if( !(w = cw->win ) )
1168 	panic( "bad winid %d, no window ptr set", window );
1169 
1170     /*
1171      * Save the context of the window
1172      */
1173     xsave = w->RPort->cp_x;
1174     ysave = w->RPort->cp_y;
1175     modesave = w->RPort->DrawMode;
1176     apensave = w->RPort->FgPen;
1177     bpensave = w->RPort->BgPen;
1178 
1179     /*
1180      * Set the mode, and be done with it
1181      */
1182     usecolor = iflags.use_color;
1183     iflags.use_color = FALSE;
1184     cw->wflags |= FLMAP_INGLYPH;
1185 }
1186 #endif /* !TESTING */
1187 
1188 # if 0
1189 /*
1190  * General cleanup routine -- flushes and restores cursor
1191  */
1192 void
1193 amii_end_glyphout(window)
1194     winid window;
1195 {
1196     struct amii_WinDesc *cw;
1197     struct Window *w;
1198 
1199     if( ( cw = amii_wins[ window ] ) == (struct amii_WinDesc *)NULL )
1200 	panic("bad window id %d in amii_end_glyphout()", window );
1201 
1202     if( ( cw->wflags & FLMAP_INGLYPH ) == 0 )
1203 	return;
1204     cw->wflags &= ~(FLMAP_INGLYPH);
1205 
1206     if( !(w = cw->win ) )
1207 	panic( "bad winid %d, no window ptr set", window );
1208 
1209     /*
1210      * Clean up whatever is left in the buffer
1211      */
1212     iflags.use_color = usecolor;
1213 
1214     /*
1215      * Reset internal data structs
1216      */
1217     SetAPen(w->RPort, apensave);
1218     SetBPen(w->RPort, bpensave);
1219     SetDrMd(w->RPort, modesave);
1220 
1221     Move(w->RPort, xsave, ysave);
1222 }
1223 # endif
1224 #endif
1225 
1226 #ifndef TESTING
1227 # ifdef OPT_DISPMAP
1228 /* don't use dispmap unless x & y are 8,16,24,32,48 and equal */
1229 void
dispmap_sanity()1230 dispmap_sanity(){
1231 	if(
1232 	    mxsize != mysize ||
1233 	    dispmap_sanity1(mxsize) ||
1234 	    dispmap_sanity1(mysize)){
1235 		flags.fast_map = 0;
1236 	}
1237 }
1238 int
dispmap_sanity1(x)1239 dispmap_sanity1(x)
1240 	int x;
1241 {
1242 	static unsigned char valid[] = {8,16,24,32,48,0};
1243 	return !!strchr(valid,x);
1244 }
1245 # endif /* OPT_DISPMAP */
1246 #endif /* TESTING */
1247