1 /*  Sarien - A Sierra AGI resource interpreter engine
2  *  Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka
3  *
4  *  $Id: picture.c,v 1.44 2001/10/31 00:27:26 cmatsuoka Exp $
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; see docs/COPYING for further details.
9  */
10 
11 #include <stdio.h>
12 #include <string.h>
13 #include <assert.h>
14 #include "sarien.h"
15 #include "agi.h"
16 #include "graphics.h"
17 #include "rand.h"
18 #include "savegame.h"
19 
20 #define next_byte data[foffs++]
21 
22 static UINT8	*data;
23 static UINT32	flen;
24 static UINT32	foffs;
25 
26 static UINT8	patCode;
27 static UINT8	patNum;
28 static UINT8	pri_on;
29 static UINT8	scr_on;
30 static UINT8	scr_colour;
31 static UINT8	pri_colour;
32 
33 
put_virt_pixel(int x,int y)34 static void put_virt_pixel (int x, int y)
35 {
36 	UINT8 *p;
37 
38 	if (x >= _WIDTH || y >= _HEIGHT)
39 		return;
40 
41 	p = &game.sbuf[y * _WIDTH + x];
42 
43 	if (pri_on) *p = (pri_colour << 4) | (*p & 0x0f);
44 	if (scr_on) *p = scr_colour | (*p & 0xf0);
45 }
46 
47 
48 /* For the flood fill routines */
49 
50 #define STACK_SEG_SIZE 0x1000
51 
52 struct point_xy {
53 	struct point_xy *next;
54 	unsigned int x, y;
55 };
56 
57 #define MAX_STACK_SEGS 16
58 static unsigned int stack_num_segs;
59 static unsigned int stack_seg;
60 static unsigned int stack_ptr;
61 
62 static struct point_xy *stack[MAX_STACK_SEGS];
63 
_PUSH(struct point_xy * c)64 static INLINE void _PUSH (struct point_xy *c)
65 {
66 	if (stack_ptr >= STACK_SEG_SIZE) {
67 		/* Allocate new stack segment */
68 
69 		assert (stack_num_segs < MAX_STACK_SEGS);
70 
71 		if (stack_num_segs <= ++stack_seg) {
72 			_D ("new stack (#%d)", stack_num_segs);
73 			stack[stack_num_segs] = malloc (sizeof (struct point_xy)
74 				* STACK_SEG_SIZE);
75 			assert (stack[stack_num_segs] != NULL);
76 			stack_num_segs++;
77 		}
78 		stack_ptr = 0;
79 	}
80 
81 	stack[stack_seg][stack_ptr].x = c->x;
82 	stack[stack_seg][stack_ptr].y = c->y;
83 	stack_ptr++;
84 }
85 
86 
_POP(struct point_xy * c)87 static INLINE void _POP (struct point_xy *c)
88 {
89 	if (stack_ptr == 0) {
90 		if (stack_seg == 0) {
91 			c->x = c->y = 0xffff;
92 		} else {
93 			stack_seg--;
94 			 stack_ptr = STACK_SEG_SIZE - 1;
95 		}
96 
97 		return;
98 	}
99 
100 	stack_ptr--;
101 	c->x = stack[stack_seg][stack_ptr].x;
102 	c->y = stack[stack_seg][stack_ptr].y;
103 }
104 
105 
106 /**************************************************************************
107 ** drawline
108 ** Draws an AGI line.
109 **
110 ** line drawing routine sent to me by joshua neal
111 ** modified by stuart george, fixed >>2 to >>1 and some other bugs
112 ** like x1 instead of y1, etc
113 **************************************************************************/
draw_line(int x1,int y1,int x2,int y2)114 static void draw_line (int x1, int y1, int x2, int y2)
115 {
116 	int i, x, y, deltaX, deltaY, stepX, stepY, errorX, errorY, detdelta;
117 
118 	/* CM: Do clipping */
119 #define clip(x, y) if((x)>=(y)) (x)=(y)
120 	clip (x1, _WIDTH-1);
121 	clip (x2, _WIDTH-1);
122 	clip (y1, _HEIGHT-1);
123 	clip (y2, _HEIGHT-1);
124 
125 	/* Vertical line */
126 
127 	if (x1 == x2) {
128 		if(y1 > y2) {
129 			y = y1;
130 			y1 = y2;
131 			y2 = y;
132 		}
133 
134 		for ( ; y1 <= y2; y1++)
135 			put_virt_pixel (x1, y1);
136 
137 		return;
138 	}
139 
140 	/* Horizontal line */
141 
142 	if (y1 == y2) {
143 		if (x1 > x2) {
144 			x = x1;
145 			x1 = x2;
146 			x2 = x;
147 		}
148 
149    		for( ; x1 <= x2; x1++)
150    			put_virt_pixel (x1, y1);
151 
152 		return;
153 	}
154 
155 	y = y1;
156   	x = x1;
157 
158 	stepY = 1;
159 	deltaY = y2-y1;
160 	if (deltaY < 0) {
161 		stepY = -1;
162 		deltaY = -deltaY;
163 	}
164 
165 	stepX = 1;
166 	deltaX = x2 - x1;
167 	if (deltaX < 0) {
168 		stepX = -1;
169 		deltaX = -deltaX;
170 	}
171 
172 	if(deltaY > deltaX) {
173 		i=deltaY;
174 		detdelta=deltaY;
175 		errorX=deltaY/2;
176 		errorY=0;
177 	} else {
178 		i=deltaX;
179 		detdelta=deltaX;
180 		errorX=0;
181 		errorY=deltaX/2;
182 	}
183 
184 	put_virt_pixel (x, y);
185 
186 	do {
187 		errorY += deltaY;
188 		if (errorY >= detdelta) {
189 			errorY -= detdelta;
190 			y += stepY;
191 		}
192 
193 		errorX += deltaX;
194 		if (errorX >= detdelta) {
195 			errorX -= detdelta;
196 			x += stepX;
197 		}
198 
199 		put_virt_pixel(x, y);
200 		i--;
201 	} while (i > 0);
202 
203 	/* put_virt_pixel (x, y); */
204 }
205 
206 /**************************************************************************
207 ** relativeDraw
208 **
209 ** Draws short lines relative to last position.  (drawing action 0xF7)
210 **************************************************************************/
dynamic_draw_line()211 static void dynamic_draw_line ()
212 {
213 	int x1, y1, disp, dx, dy;
214 
215 	x1 = next_byte;
216 	y1 = next_byte;
217 
218 	put_virt_pixel (x1, y1);
219 
220 	while (42) {
221 		if ((disp = next_byte) >= 0xf0)
222 			break;
223 
224 		dx= ((disp & 0xf0) >> 4) & 0x0f;
225 		dy= (disp & 0x0f);
226 
227 	      	if (dx & 0x08)
228 			dx = -(dx & 0x07);
229 
230 	      	if (dy & 0x08)
231 			dy = -(dy & 0x07);
232 
233 		draw_line (x1, y1, x1 + dx, y1 + dy);
234 		x1 += dx;
235 		y1 += dy;
236 	}
237 	foffs--;
238 }
239 
240 /**************************************************************************
241 ** absoluteLine
242 **
243 ** Draws long lines to actual locations (cf. relative) (drawing action 0xF6)
244 **************************************************************************/
absolute_draw_line()245 static void absolute_draw_line ()
246 {
247 	int x1, y1, x2, y2;
248 
249 	x1 = next_byte;
250 	y1 = next_byte;
251 	put_virt_pixel (x1, y1);
252 
253 	while (42) {
254 		if ((x2 = next_byte) >= 0xf0)
255 			break;
256 
257 		if ((y2 = next_byte) >= 0xf0)
258 			break;
259 
260 		draw_line (x1, y1, x2, y2);
261 		x1 = x2;
262 		y1 = y2;
263 	}
264 	foffs--;
265 }
266 
267 
268 /**************************************************************************
269 ** okToFill
270 **************************************************************************/
is_ok_fill_here(int x,int y)271 static INLINE int is_ok_fill_here (int x, int y)
272 {
273 	unsigned int i;
274 	UINT8 p;
275 
276 	if (!scr_on && !pri_on)
277 		return FALSE;
278 
279 	i = y * _WIDTH + x;
280 	p = game.sbuf[i];
281 
282 	if (!pri_on && scr_on && scr_colour != 15)
283 		return (p & 0x0f) == 15;
284 
285 	if (pri_on && !scr_on && pri_colour != 4)
286 		return (p >> 4) == 4;
287 
288 	return (scr_on && (p & 0x0f) == 15 && scr_colour != 15);
289 }
290 
291 /**************************************************************************
292 ** agiFill
293 **************************************************************************/
agiFill(int x,int y)294 static void agiFill (int x, int y)
295 {
296 	struct point_xy c;
297 
298 	c.x = x;
299 	c.y = y;
300 	_PUSH (&c);
301 
302 	while (42) {
303 		_POP(&c);
304 
305 		/* Exit if stack is empty */
306 		if (c.x == 0xffff || c.y == 0xffff)
307 			break;
308 
309 		if (is_ok_fill_here (c.x, c.y)) {
310 			put_virt_pixel (c.x, c.y);
311 			if (c.x > 0 && is_ok_fill_here (c.x - 1, c.y)) {
312 				c.x--; _PUSH (&c); c.x++;
313     			}
314 			if (c.x < _WIDTH - 1 && is_ok_fill_here (c.x + 1, c.y)) {
315 				c.x++; _PUSH (&c); c.x--;
316  			}
317 			if (c.y < _HEIGHT - 1 && is_ok_fill_here (c.x, c.y + 1)) {
318 				c.y++; _PUSH (&c); c.y--;
319     			}
320 			if (c.y > 0 && is_ok_fill_here (c.x, c.y - 1)) {
321 				c.y--; _PUSH (&c); c.y++;
322     			}
323 		}
324 	}
325 
326 	stack_ptr = 0;
327 	stack_seg = 0;
328 }
329 
330 /**************************************************************************
331 ** xCorner
332 **
333 ** Draws an xCorner  (drawing action 0xF5)
334 **************************************************************************/
x_corner()335 static void x_corner ()
336 {
337 	int x1, x2, y1, y2;
338 
339 	x1 = next_byte;
340 	y1 = next_byte;
341    	put_virt_pixel (x1, y1);
342 
343 	while (42) {
344 		x2=next_byte;
345 
346 		if (x2 >= 0xf0)
347 			break;
348 
349 		draw_line (x1, y1, x2, y1);
350 		x1 = x2;
351 		y2 = next_byte;
352 
353 		if (y2 >= 0xF0)
354 			break;
355 
356 		draw_line (x1, y1, x1, y2);
357 		y1 = y2;
358 	}
359 	foffs--;
360 }
361 
362 
363 /**************************************************************************
364 ** yCorner
365 **
366 ** Draws an yCorner  (drawing action 0xF4)
367 **************************************************************************/
y_corner()368 static void y_corner ()
369 {
370 	int x1, x2, y1, y2;
371 
372 	x1 = next_byte;
373 	y1 = next_byte;
374 	put_virt_pixel (x1, y1);
375 
376 	while (42) {
377 		y2 = next_byte;
378 
379 		if (y2 >= 0xF0)
380 			break;
381 
382 		draw_line (x1, y1, x1, y2);
383 		y1 = y2;
384 		x2 = next_byte;
385 
386 		if (x2 >= 0xF0)
387 			break;
388 
389 		draw_line (x1, y1, x2, y1);
390 		x1 = x2;
391 	}
392 
393 	foffs--;
394 }
395 
396 /**************************************************************************
397 ** fill
398 **
399 ** AGI flood fill.  (drawing action 0xF8)
400 **************************************************************************/
fill()401 static void fill ()
402 {
403 	int x1, y1;
404 
405 	while ((x1 = next_byte) < 0xF0 && (y1 = next_byte) < 0xF0)
406 		agiFill (x1, y1);
407 
408 	foffs--;
409 }
410 
411 
412 #define plotPatternPoint() do {						\
413 	if (patCode & 0x20) {						\
414 		if ((splatterMap[bitPos>>3] >> (7-(bitPos&7))) & 1)	\
415 			put_virt_pixel(x1, y1);				\
416 		bitPos++;						\
417 		if (bitPos == 0xff)					\
418 			bitPos=0;					\
419 	} else put_virt_pixel(x1, y1);					\
420 } while (0)
421 
422 /**************************************************************************
423 ** plotPattern
424 **
425 ** Draws pixels, circles, squares, or splatter brush patterns depending
426 ** on the pattern code.
427 **************************************************************************/
plotPattern(unsigned int x,unsigned int y)428 void plotPattern(unsigned int x, unsigned int y)
429 {
430 	static UINT8 circles[][15] = {		/* agi circle bitmaps */
431 		{ 0x80 },
432 		{ 0xfc },
433 		{ 0x5f, 0xf4 },
434 		{ 0x66, 0xff, 0xf6, 0x60 },
435 		{ 0x23, 0xbf, 0xff, 0xff, 0xee, 0x20 },
436 		{ 0x31, 0xe7, 0x9e, 0xff, 0xff, 0xde, 0x79, 0xe3, 0x00 },
437 		{ 0x38, 0xf9, 0xf3, 0xef, 0xff, 0xff,
438 		  0xff, 0xfe, 0xf9, 0xf3, 0xe3, 0x80 },
439 		{ 0x18, 0x3c, 0x7e, 0x7e, 0x7e, 0xff, 0xff,
440 		  0xff, 0xff, 0xff, 0x7e, 0x7e, 0x7e, 0x3c, 0x18 }
441 	};
442 
443 	static UINT8 splatterMap[32] = {	/* splatter brush bitmaps */
444 		0x20, 0x94, 0x02, 0x24, 0x90, 0x82, 0xa4, 0xa2,
445 		0x82, 0x09, 0x0a, 0x22, 0x12, 0x10, 0x42, 0x14,
446 		0x91, 0x4a, 0x91, 0x11, 0x08, 0x12, 0x25, 0x10,
447 		0x22, 0xa8, 0x14, 0x24, 0x00, 0x50, 0x24, 0x04
448 	};
449 
450 	static UINT8 splatterStart[128] = {	/* starting bit position */
451 		0x00, 0x18, 0x30, 0xc4, 0xdc, 0x65, 0xeb, 0x48,
452 		0x60, 0xbd, 0x89, 0x05, 0x0a, 0xf4, 0x7d, 0x7d,
453 		0x85, 0xb0, 0x8e, 0x95, 0x1f, 0x22, 0x0d, 0xdf,
454 		0x2a, 0x78, 0xd5, 0x73, 0x1c, 0xb4, 0x40, 0xa1,
455 		0xb9, 0x3c, 0xca, 0x58, 0x92, 0x34, 0xcc, 0xce,
456 		0xd7, 0x42, 0x90, 0x0f, 0x8b, 0x7f, 0x32, 0xed,
457 		0x5c, 0x9d, 0xc8, 0x99, 0xad, 0x4e, 0x56, 0xa6,
458 		0xf7, 0x68, 0xb7, 0x25, 0x82, 0x37, 0x3a, 0x51,
459 		0x69, 0x26, 0x38, 0x52, 0x9e, 0x9a, 0x4f, 0xa7,
460 		0x43, 0x10, 0x80, 0xee, 0x3d, 0x59, 0x35, 0xcf,
461 		0x79, 0x74, 0xb5, 0xa2, 0xb1, 0x96, 0x23, 0xe0,
462 		0xbe, 0x05, 0xf5, 0x6e, 0x19, 0xc5, 0x66, 0x49,
463 		0xf0, 0xd1, 0x54, 0xa9, 0x70, 0x4b, 0xa4, 0xe2,
464 		0xe6, 0xe5, 0xab, 0xe4, 0xd2, 0xaa, 0x4c, 0xe3,
465 		0x06, 0x6f, 0xc6, 0x4a, 0xa4, 0x75, 0x97, 0xe1
466 	};
467 
468 	SINT32 circlePos = 0;
469 	UINT32 x1, y1, penSize, bitPos = splatterStart[patNum];
470 
471 	penSize = (patCode & 7);
472 
473 	if (x < penSize)
474 		x = penSize-1;
475 	if (y < penSize)
476 		y = penSize;
477 
478 	for (y1 = y - penSize; y1 <= y + penSize; y1++) {
479 		for (x1 = x-(penSize+1)/2; x1<=x+penSize/2; x1++) {
480 			if (patCode & 0x10) {		/* Square */
481 				plotPatternPoint();
482 			} else {			/* Circle */
483 				if ((circles[patCode&7][circlePos>>3] >> (7-(circlePos&7)))&1)
484 					plotPatternPoint();
485 				circlePos++;
486 			}
487 		}
488 	}
489 }
490 
491 /**************************************************************************
492 ** plotBrush
493 **
494 ** Plots points and various brush patterns.
495 **************************************************************************/
plot_brush()496 static void plot_brush ()
497 {
498 	int x1, y1;
499 
500 	while (42) {
501 		if (patCode & 0x20) {
502 			if ((patNum = next_byte) >= 0xF0)
503 				break;
504 			patNum = (patNum >> 1) & 0x7f;
505 		}
506 
507 		if ((x1 = next_byte) >= 0xf0)
508 			break;
509 
510 		if ((y1 = next_byte) >= 0xf0)
511 			break;
512 
513 		plotPattern (x1, y1);
514    	}
515 
516    	foffs--;
517 }
518 
519 #ifdef USE_HIRES
520 #include "hirespic.c"
521 #endif
522 
draw_picture()523 static void draw_picture ()
524 {
525 	UINT8 act;
526 	unsigned int i;
527 	int drawing;
528 #ifdef USE_HIRES
529 	int save_foffs;
530 #endif
531 
532  	patCode = 0;
533  	patNum = 0;
534  	pri_on = scr_on = FALSE;
535  	scr_colour = 0xf;
536  	pri_colour = 0x4;
537 
538 	drawing = 1;
539 
540 	stack[0] = calloc (sizeof (struct point_xy), STACK_SEG_SIZE);
541 	stack_ptr = stack_seg = 0;
542 	stack_num_segs = 1;
543 
544 	_D (_D_WARN "Drawing picture");
545 	for (drawing = 1; drawing && foffs < flen; ) {
546 
547 #ifdef USE_HIRES
548 		save_foffs = foffs;
549 #endif
550 
551 		act = next_byte;
552 		switch(act) {
553 		case 0xf0:			/* set colour on screen */
554 			scr_colour = next_byte;
555 			scr_colour &= 0xF;	/* for v3 drawing diff */
556 			scr_on = TRUE;
557 			break;
558 		case 0xf1:			/* disable screen drawing */
559 			scr_on = FALSE;
560 			break;
561 		case 0xf2:			/* set colour on priority */
562 			pri_colour = next_byte;
563 			pri_colour &= 0xf;	/* for v3 drawing diff */
564 			pri_on = TRUE;
565 			break;
566 		case 0xf3:			/* disable priority screen */
567 			pri_on = FALSE;
568 			break;
569 		case 0xf4:			/* y-corner */
570 			y_corner ();
571 			break;
572 		case 0xf5:			/* x-corner */
573 			x_corner ();
574 			break;
575 		case 0xf6:			/* absolute draw lines */
576 			absolute_draw_line ();
577 			break;
578 		case 0xf7:			/* dynamic draw lines */
579 			dynamic_draw_line ();
580 			break;
581 		case 0xf8:			/* fill */
582 			fill ();
583 			break;
584 		case 0xf9:			/* set pattern */
585 			patCode = next_byte;
586 			break;
587 		case 0xfA:			/* plot brush */
588 			plot_brush ();
589 			break;
590 		case 0xFF:			/* end of pic data */
591 		default:
592 			drawing = 0;
593 			break;
594 		}
595 
596 #ifdef USE_HIRES
597 		foffs = save_foffs;
598 
599 		act = next_byte;
600 		switch(act) {
601 		case 0xf0:			/* set colour on screen */
602 			scr_colour = next_byte;
603 			scr_colour &= 0xF;	/* for v3 drawing diff */
604 			scr_on = TRUE;
605 			break;
606 		case 0xf1:			/* disable screen drawing */
607 			scr_on = FALSE;
608 			break;
609 		case 0xf2:			/* set colour on priority */
610 			pri_colour = next_byte;
611 			pri_colour &= 0xf;	/* for v3 drawing diff */
612 			pri_on = TRUE;
613 			break;
614 		case 0xf3:			/* disable priority screen */
615 			pri_on = FALSE;
616 			break;
617 		case 0xf4:			/* y-corner */
618 			hires_y_corner ();
619 			break;
620 		case 0xf5:			/* x-corner */
621 			hires_x_corner ();
622 			break;
623 		case 0xf6:			/* absolute draw lines */
624 			absolute_hires_line ();
625 			break;
626 		case 0xf7:			/* dynamic draw lines */
627 			dynamic_hires_line ();
628 			break;
629 		case 0xf8:			/* fill */
630 			hires_fill ();
631 			break;
632 		case 0xf9:			/* set pattern */
633 			patCode = next_byte;
634 			break;
635 		case 0xfA:			/* plot brush */
636 			plot_hires_brush ();
637 			break;
638 		case 0xFF:			/* end of pic data */
639 		default:
640 			drawing = 0;
641 			break;
642 		}
643 #endif
644 	}
645 
646 	for (i = 0; i < stack_num_segs; i++)
647 		free (stack[i]);
648 }
649 
650 /*
651  * Public functions
652  */
653 
654 /**
655  *
656  */
convert_v3_pic(UINT8 * data,UINT32 len)657 UINT8* convert_v3_pic (UINT8 *data, UINT32 len)
658 {
659 	UINT8	d, old = 0, x, *in, *xdata, *out, mode = 0;
660 	UINT32	i, ulen;
661 
662 	xdata = malloc (len + len / 2);
663 
664 	out = xdata;
665 	in = data;
666 
667 	for (i = ulen = 0; i < len; i++, ulen++) {
668 		d = *in++;
669 
670 		*out++ = x = mode ? ((d & 0xF0) >> 4) + ((old & 0x0F) << 4) : d;
671 
672 		if (x == 0xFF) {
673 			ulen++;
674 			break;
675 		}
676 
677 		if (x == 0xf0 || x == 0xf2) {
678 			if (mode) {
679 				*out++ = d & 0x0F;
680 				ulen++;
681 			} else {
682 				d = *in++;
683 				*out++ = (d & 0xF0) >> 4;
684 				i++, ulen++;
685 			}
686 
687 			mode = !mode;
688 		}
689 
690 		old = d;
691 	}
692 
693 	free (data);
694 	xdata = realloc (xdata, ulen);
695 
696 	return xdata;
697 }
698 
699 /**
700  * Decode an AGI picture resource.
701  * This function decodes an AGI picture resource into the correct slot
702  * and draws it on the AGI screen, optionally cleaning the screen before
703  * drawing.
704  * @param n      AGI picture resource number
705  * @param clear  clear AGI screen before drawing
706  */
decode_picture(int n,int clear)707 int decode_picture (int n, int clear)
708 {
709 	_D (_D_WARN "(%d)", n);
710 
711 	patCode = 0;
712 	patNum = 0;
713 	pri_on = scr_on = FALSE;
714 	scr_colour = 0xF;
715 	pri_colour = 0x4;
716 
717 	data = game.pictures[n].rdata;
718 	flen = game.dir_pic[n].len;
719 	foffs = 0;
720 
721 	if (clear) {
722 		memset (game.sbuf, 0x4f, _WIDTH * _HEIGHT);
723 #ifdef USE_HIRES
724 		memset (game.hires, 0x4f, _WIDTH * 2 * _HEIGHT);
725 #endif
726 	}
727 
728 	draw_picture ();
729 
730 #ifdef USE_HIRES
731 	fix_hires_picture ();
732 #endif
733 
734 	if(clear)
735 		clear_image_stack();
736 	record_image_stack_call(ADD_PIC, n, clear, 0, 0, 0, 0, 0);
737 
738 	return err_OK;
739 }
740 
741 
742 /**
743  * Unload an AGI picture resource.
744  * This function unloads an AGI picture resource and deallocates
745  * resource data.
746  * @param n AGI picture resource number
747  */
unload_picture(int n)748 int unload_picture (int n)
749 {
750 	/* remove visual buffer & priority buffer if they exist */
751 	if (game.dir_pic[n].flags & RES_LOADED) {
752 		free (game.pictures[n].rdata);
753 		game.dir_pic[n].flags &= ~RES_LOADED;
754 	}
755 
756 	return err_OK;
757 }
758 
759 /**
760  * Show AGI picture.
761  * This function copies a ``hidden'' AGI picture to the output device.
762  */
show_pic()763 void show_pic ()
764 {
765 	int i, y;
766 	int offset;
767 
768 #ifdef USE_HIRES
769 	if (opt.hires) {
770 		show_hires_pic ();
771 		return;
772 	}
773 #endif
774 
775 	i = 0;
776 	offset = game.line_min_print * CHAR_LINES;
777 	for (y = 0; y < _HEIGHT; y++) {
778 		put_pixels_a (0, y + offset, _WIDTH, &game.sbuf[i]);
779 		i += _WIDTH;
780 	}
781 
782 #if 0
783 	/* Amiga/IIgs transitions. Too slow, and annoying after a few rooms.
784 	 * Also doesn't work well with console.
785 	 */
786 #define BRICK_W 4
787 #define BRICK_H 2
788 	for (i = 0; i < 20000; i++) {
789 		int bx = rnd (GFX_WIDTH / BRICK_W) * BRICK_W;
790 		int by = rnd (GFX_HEIGHT / BRICK_H) * BRICK_H;
791 		flush_block (bx, by, bx + BRICK_W - 1, by + BRICK_H - 1);
792 		do_update ();
793 	}
794 #endif
795 
796 	flush_screen ();
797 }
798 
799 
800 /* end: picture.c */
801