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