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