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