1 /*  Sarien - A Sierra AGI resource interpreter engine
2  *  Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka
3  *
4  *  $Id: hirespic.c,v 1.18 2001/09/12 16:57:21 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 #ifdef USE_HIRES
12 
put_hires_pixel(int x,int y)13 static void put_hires_pixel (int x, int y)
14 {
15 	UINT8 *p;
16 
17 	if (x < 0 || y < 0 || x >= (_WIDTH * 2) || y >= _HEIGHT)
18 		return;
19 
20 	p = &game.hires[y * (_WIDTH * 2) + x];
21 
22 	if (pri_on) *p = (pri_colour << 4) | (*p & 0x0f);
23 	if (scr_on) *p = scr_colour | (*p & 0xf0);
24 }
25 
fix_pixel_bothsides(int x,int y)26 static void fix_pixel_bothsides (int x, int y)
27 {
28 	UINT8 *p, *s;
29 
30 	/* Sometimes a solid color area in the lo-res pic is made
31 	 * with lines, and we want to keep this  effect in the
32 	 * hi-res pic.
33 	 */
34 	p = &game.hires[y * (_WIDTH * 2) + x];
35 	if ((*(p - 2) & 0x0f) == scr_colour)
36 		put_hires_pixel (x - 1, y);
37 	if ((*(p + 2) & 0x0f) == scr_colour)
38 		put_hires_pixel (x + 1, y);
39 
40 	/* If two lines are contiguous in the lo-res pic, make them
41 	 * contiguous in the hi-res pic. This condition is needed
42 	 * in some scenes like in front of Lefty's in LSL1, to draw
43 	 * the pole. Note: it adds artifacts in some cases.
44 	 */
45 	s = &game.sbuf[y * _WIDTH + x / 2];
46 	if ((*(p - 1) & 0x0f) != (*(s - 1) & 0x0f))
47 		put_hires_pixel (x - 1, y);
48 }
49 
50 
51 /**************************************************************************
52 ** drawline
53 ** Draws an AGI line.
54 **
55 ** line drawing routine sent to me by joshua neal
56 ** modified by stuart george, fixed >>2 to >>1 and some other bugs
57 ** like x1 instead of y1, etc
58 **************************************************************************/
draw_hires_line(int x1,int y1,int x2,int y2)59 static void draw_hires_line (int x1, int y1, int x2, int y2)
60 {
61 	int i, x, y, deltaX, deltaY, stepX, stepY, errorX, errorY, detdelta;
62 
63 	/* CM: Do clipping */
64 #define clip(x, y) if((x)>=(y)) (x)=(y)
65 	clip (x1, (_WIDTH * 2) - 1);
66 	clip (x2, (_WIDTH * 2) - 1);
67 	clip (y1, _HEIGHT - 1);
68 	clip (y2, _HEIGHT - 1);
69 
70 	/* Vertical line */
71 
72 	if (x1 == x2) {
73 		if(y1 > y2) {
74 			y = y1;
75 			y1 = y2;
76 			y2 = y;
77 		}
78 
79 		for ( ; y1 <= y2; y1++) {
80 			put_hires_pixel (x1, y1);
81 			fix_pixel_bothsides (x1, y1);
82 		}
83 
84 		return;
85 	}
86 
87 	/* Horizontal line */
88 
89 	if (y1 == y2) {
90 		if (x1 > x2) {
91 			x = x1;
92 			x1 = x2;
93 			x2 = x;
94 		}
95 
96 		fix_pixel_bothsides (x1, y1);
97 
98    		for( ; x1 < x2; x1++)
99 			put_hires_pixel (x1, y1);
100 
101 		put_hires_pixel (x1, y1);
102 		fix_pixel_bothsides (x1, y1);
103 
104 		return;
105 	}
106 
107 	y = y1;
108   	x = x1;
109 
110 	stepY = 1;
111 	deltaY = y2-y1;
112 	if (deltaY < 0) {
113 		stepY = -1;
114 		deltaY = -deltaY;
115 	}
116 
117 	stepX = 1;
118 	deltaX = x2 - x1;
119 	if (deltaX < 0) {
120 		stepX = -1;
121 		deltaX = -deltaX;
122 	}
123 
124 	if(deltaY > deltaX) {
125 		i=deltaY;
126 		detdelta=deltaY;
127 		errorX=deltaY/2;
128 		errorY=0;
129 	} else {
130 		i=deltaX;
131 		detdelta=deltaX;
132 		errorX=0;
133 		errorY=deltaX/2;
134 	}
135 
136 	put_hires_pixel (x, y);
137 	fix_pixel_bothsides (x, y);
138 
139 	do {
140 		errorY += deltaY;
141 		if (errorY >= detdelta) {
142 			errorY -= detdelta;
143 			y += stepY;
144 		}
145 
146 		errorX += deltaX;
147 		if (errorX >= detdelta) {
148 			errorX -= detdelta;
149 			x += stepX;
150 		}
151 
152 		put_hires_pixel (x, y);
153 		fix_pixel_bothsides (x, y);
154 		i--;
155 	} while (i > 0);
156 
157 	put_hires_pixel (x, y);
158 	fix_pixel_bothsides (x, y);
159 }
160 
161 /**************************************************************************
162 ** relativeDraw
163 **
164 ** Draws short lines relative to last position.  (drawing action 0xF7)
165 **************************************************************************/
dynamic_hires_line()166 static void dynamic_hires_line ()
167 {
168 	int x1, y1, disp, dx, dy;
169 
170 	x1 = 2 * next_byte;
171 	y1 = next_byte;
172 
173 	put_hires_pixel (x1, y1);
174 
175 	while (42) {
176 		if ((disp = next_byte) >= 0xf0)
177 			break;
178 
179 		dx= ((disp & 0xf0) >> 4) & 0x0f;
180 		dy= (disp & 0x0f);
181 
182 	      	if (dx & 0x08)
183 			dx = -(dx & 0x07);
184 
185 	      	if (dy & 0x08)
186 			dy = -(dy & 0x07);
187 
188 		dx *= 2;
189 
190 		draw_hires_line (x1, y1, x1 + dx, y1 + dy);
191 		x1 += dx;
192 		y1 += dy;
193 	}
194 	foffs--;
195 }
196 
197 /**************************************************************************
198 ** absoluteLine
199 **
200 ** Draws long lines to actual locations (cf. relative) (drawing action 0xF6)
201 **************************************************************************/
absolute_hires_line()202 static void absolute_hires_line ()
203 {
204 	int x1, y1, x2, y2;
205 
206 	x1 = 2 * next_byte;
207 	y1 = next_byte;
208 	put_hires_pixel (x1, y1);
209 
210 	while (42) {
211 		if ((x2 = next_byte) >= 0xf0)
212 			break;
213 
214 		if ((y2 = next_byte) >= 0xf0)
215 			break;
216 
217 		x2 *= 2;
218 
219 		draw_hires_line (x1, y1, x2, y2);
220 		x1 = x2;
221 		y1 = y2;
222 	}
223 	foffs--;
224 }
225 
226 
227 /**************************************************************************
228 ** okToFill
229 **************************************************************************/
hires_fill_here(int x,int y)230 static INLINE int hires_fill_here (int x, int y)
231 {
232 	UINT8 *p, *s;
233 
234 	if (!scr_on && !pri_on)
235 		return FALSE;
236 
237 	p = &game.hires[y * (_WIDTH * 2) + x * 2];
238 	s = &game.sbuf[y * _WIDTH + x];
239 
240 	if (scr_on) {
241 		if (scr_colour == 0x0f)
242 			return FALSE;
243 		if ((*p & 0x0f) != 0x0f || (*(p + 1) & 0x0f) != 0x0f)
244 			return FALSE;
245 		if ((*s & 0x0f) != scr_colour)
246 			return FALSE;
247 	}
248 
249 	if (pri_on) {
250 		if (pri_colour == 0x04)
251 			return FALSE;
252 		if ((*p >> 4) != 0x04 || (*(p + 1) >> 4) != 0x04)
253 			return FALSE;
254 		if ((*s >> 4) != pri_colour)
255 			return FALSE;
256 	}
257 
258 
259 	return TRUE;
260 }
261 
262 
fix_pixel_left(int x,int y)263 static void fix_pixel_left (int x, int y)
264 {
265 	UINT8 *p;
266 
267 	if (!scr_on)
268 		return;
269 
270 	p = &game.hires[y * (_WIDTH * 2) + x * 2 + 1];
271 	if ((*p & 0x0f) == 0x0f)
272 		put_hires_pixel (2 * x + 1, y);
273 	else if ((*p & 0x0f) == (*(p - 1) & 0x0f))
274 		put_hires_pixel (2 * x + 1, y);
275 }
276 
fix_pixel_right(int x,int y)277 static void fix_pixel_right (int x, int y)
278 {
279 	UINT8 p;
280 
281 	p = game.hires[y * (_WIDTH * 2) + x * 2];
282 	if (scr_on && (p & 0x0f) == 0x0f)
283 		put_hires_pixel (2 * x, y);
284 }
285 
fix_pixel_here(int x,int y)286 static void fix_pixel_here (int x, int y)
287 {
288 	UINT8 p;
289 
290 	p = game.hires[y * (_WIDTH * 2) + x * 2 + 1];
291 	if (scr_on && (p & 0x0f) == 0x0f)
292 		put_hires_pixel (2 * x + 1, y);
293 }
294 
295 
296 /**************************************************************************
297 ** agiFill
298 **************************************************************************/
hiresFill(int x,int y)299 static void hiresFill (int x, int y)
300 {
301 	struct point_xy c;
302 
303 	c.x = x;
304 	c.y = y;
305 	_PUSH (&c);
306 
307 	while (42) {
308 		_POP(&c);
309 
310 		/* Exit if stack is empty */
311 		if (c.x == 0xffff || c.y == 0xffff)
312 			break;
313 
314 		if (hires_fill_here (c.x, c.y)) {
315 			put_hires_pixel (2 * c.x, c.y);
316 			fix_pixel_here (c.x, c.y);
317 
318 			if (c.x > 0) {
319 				if (hires_fill_here (c.x - 1, c.y)) {
320 					c.x--; _PUSH (&c); c.x++;
321     				} else {
322 					fix_pixel_left (c.x - 1, c.y);
323 				}
324 			}
325 			if (c.x < _WIDTH - 1) {
326 				if (hires_fill_here (c.x + 1, c.y)) {
327 					c.x++; _PUSH (&c); c.x--;
328  				} else {
329 					fix_pixel_right (c.x + 1, c.y);
330 				}
331 			}
332 			if (c.y < _HEIGHT - 1 && hires_fill_here (c.x, c.y + 1)) {
333 				c.y++; _PUSH (&c); c.y--;
334     			}
335 			if (c.y > 0 && hires_fill_here (c.x, c.y - 1)) {
336 				c.y--; _PUSH (&c); c.y++;
337     			}
338 		}
339 	}
340 
341 	stack_ptr = 0;
342 	stack_seg = 0;
343 }
344 
345 /**************************************************************************
346 ** xCorner
347 **
348 ** Draws an xCorner  (drawing action 0xF5)
349 **************************************************************************/
hires_x_corner()350 static void hires_x_corner ()
351 {
352 	int x1, x2, y1, y2;
353 
354 	x1 = 2 * next_byte;
355 	y1 = next_byte;
356    	put_hires_pixel (x1, y1);
357 
358 	while (42) {
359 		x2 = next_byte;
360 
361 		if (x2 >= 0xf0)
362 			break;
363 
364 		x2 *= 2;
365 
366 		draw_hires_line (x1, y1, x2, y1);
367 		x1 = x2;
368 		y2 = next_byte;
369 
370 		if (y2 >= 0xf0)
371 			break;
372 
373 		draw_hires_line (x1, y1, x1, y2);
374 		y1 = y2;
375 	}
376 	foffs--;
377 }
378 
379 
380 /**************************************************************************
381 ** yCorner
382 **
383 ** Draws an yCorner  (drawing action 0xF4)
384 **************************************************************************/
hires_y_corner()385 static void hires_y_corner ()
386 {
387 	int x1, x2, y1, y2;
388 
389 	x1 = 2 * next_byte;
390 	y1 = next_byte;
391 	put_hires_pixel (x1, y1);
392 
393 	while (42) {
394 		y2 = next_byte;
395 
396 		if (y2 >= 0xF0)
397 			break;
398 
399 		draw_hires_line (x1, y1, x1, y2);
400 		y1 = y2;
401 		x2 = next_byte;
402 
403 		if (x2 >= 0xf0)
404 			break;
405 
406 		x2 *= 2;
407 
408 		draw_hires_line (x1, y1, x2, y1);
409 		x1 = x2;
410 	}
411 
412 	foffs--;
413 }
414 
415 /**************************************************************************
416 ** fill
417 **
418 ** AGI flood fill.  (drawing action 0xF8)
419 **************************************************************************/
hires_fill()420 static void hires_fill ()
421 {
422 	int x1, y1;
423 
424 	while ((x1 = next_byte) < 0xf0 && (y1 = next_byte) < 0xf0) {
425 		hiresFill (x1, y1);
426 	}
427 
428 	foffs--;
429 }
430 
431 /* Extra randomness added to brush fill, and double width to single
432  * pixels (makes MUMG and others look a lot nicer).
433  */
434 
435 #define plotHiresPatternPoint() do {					\
436 	if (patCode & 0x20) {						\
437 		if ((splatterMap[bitPos>>3] >> (7-(bitPos&7))) & 1) {	\
438 			if (rnd(4)) put_hires_pixel(x1*2, y1);		\
439 			if (!rnd(4))put_hires_pixel(x1*2+1, y1);	\
440 		}							\
441 		bitPos++;						\
442 		if (bitPos == 0xff)					\
443 			bitPos=0;					\
444 	} else { put_hires_pixel(x1*2,y1); put_hires_pixel(x1*2+1,y1); }\
445 } while (0)
446 
447 /**************************************************************************
448 ** plotPattern
449 **
450 ** Draws pixels, circles, squares, or splatter brush patterns depending
451 ** on the pattern code.
452 **************************************************************************/
plot_hires_pattern(UINT8 x,UINT8 y)453 static void plot_hires_pattern(UINT8 x, UINT8 y)
454 {
455 	static UINT8 circles[][15] = {		/* agi circle bitmaps */
456 		{ 0x80 },
457 		{ 0xfc },
458 		{ 0x5f, 0xf4 },
459 		{ 0x66, 0xff, 0xf6, 0x60 },
460 		{ 0x23, 0xbf, 0xff, 0xff, 0xee, 0x20 },
461 		{ 0x31, 0xe7, 0x9e, 0xff, 0xff, 0xde, 0x79, 0xe3, 0x00 },
462 		{ 0x38, 0xf9, 0xf3, 0xef, 0xff, 0xff,
463 		  0xff, 0xfe, 0xf9, 0xf3, 0xe3, 0x80 },
464 		{ 0x18, 0x3c, 0x7e, 0x7e, 0x7e, 0xff, 0xff,
465 		  0xff, 0xff, 0xff, 0x7e, 0x7e, 0x7e, 0x3c, 0x18 }
466 	};
467 
468 	static UINT8 splatterMap[32] = {	/* splatter brush bitmaps */
469 		0x20, 0x94, 0x02, 0x24, 0x90, 0x82, 0xa4, 0xa2,
470 		0x82, 0x09, 0x0a, 0x22, 0x12, 0x10, 0x42, 0x14,
471 		0x91, 0x4a, 0x91, 0x11, 0x08, 0x12, 0x25, 0x10,
472 		0x22, 0xa8, 0x14, 0x24, 0x00, 0x50, 0x24, 0x04
473 	};
474 
475 	static UINT8 splatterStart[128] = {	/* starting bit position */
476 		0x00, 0x18, 0x30, 0xc4, 0xdc, 0x65, 0xeb, 0x48,
477 		0x60, 0xbd, 0x89, 0x05, 0x0a, 0xf4, 0x7d, 0x7d,
478 		0x85, 0xb0, 0x8e, 0x95, 0x1f, 0x22, 0x0d, 0xdf,
479 		0x2a, 0x78, 0xd5, 0x73, 0x1c, 0xb4, 0x40, 0xa1,
480 		0xb9, 0x3c, 0xca, 0x58, 0x92, 0x34, 0xcc, 0xce,
481 		0xd7, 0x42, 0x90, 0x0f, 0x8b, 0x7f, 0x32, 0xed,
482 		0x5c, 0x9d, 0xc8, 0x99, 0xad, 0x4e, 0x56, 0xa6,
483 		0xf7, 0x68, 0xb7, 0x25, 0x82, 0x37, 0x3a, 0x51,
484 		0x69, 0x26, 0x38, 0x52, 0x9e, 0x9a, 0x4f, 0xa7,
485 		0x43, 0x10, 0x80, 0xee, 0x3d, 0x59, 0x35, 0xcf,
486 		0x79, 0x74, 0xb5, 0xa2, 0xb1, 0x96, 0x23, 0xe0,
487 		0xbe, 0x05, 0xf5, 0x6e, 0x19, 0xc5, 0x66, 0x49,
488 		0xf0, 0xd1, 0x54, 0xa9, 0x70, 0x4b, 0xa4, 0xe2,
489 		0xe6, 0xe5, 0xab, 0xe4, 0xd2, 0xaa, 0x4c, 0xe3,
490 		0x06, 0x6f, 0xc6, 0x4a, 0xa4, 0x75, 0x97, 0xe1
491 	};
492 
493 	SINT32 circlePos = 0;
494 	UINT32 x1, y1, penSize, bitPos = splatterStart[patNum];
495 
496 	penSize = (patCode & 7);
497 
498 	if (x < penSize)
499 		x = penSize-1;
500 	if (y < penSize)
501 		y = penSize;
502 
503 	for (y1 = y - penSize; y1 <= y + penSize; y1++) {
504 		for (x1 = x - (penSize+1)/2; x1<=x + penSize/2; x1++) {
505 			if (patCode & 0x10) {		/* Square */
506 				plotHiresPatternPoint();
507 			} else {			/* Circle */
508 				if ((circles[patCode&7][circlePos>>3] >> (7-(circlePos&7)))&1)
509 					plotHiresPatternPoint();
510 				circlePos++;
511 			}
512 		}
513 	}
514 }
515 
516 /**************************************************************************
517 ** plotBrush
518 **
519 ** Plots points and various brush patterns.
520 **************************************************************************/
plot_hires_brush()521 static void plot_hires_brush ()
522 {
523 	UINT8 x1, y1;
524 
525 	while (42) {
526 		if (patCode & 0x20) {
527 			if ((patNum = next_byte) >= 0xF0)
528 				break;
529 			patNum = (patNum >> 1) & 0x7f;
530 		}
531 
532 		if ((x1 = next_byte) >= 0xf0)
533 			break;
534 
535 		if ((y1 = next_byte) >= 0xf0)
536 			break;
537 
538 		plot_hires_pattern (x1, y1);
539    	}
540 
541    	foffs--;
542 }
543 
544 /**
545  * Show AGI picture.
546  * This function copies a ``hidden'' AGI picture to the output device.
547  */
show_hires_pic()548 void show_hires_pic ()
549 {
550 	int i, y;
551 	int offset;
552 
553 	i = 0;
554 	offset = game.line_min_print * CHAR_LINES;
555 	for (y = 0; y < _HEIGHT; y++) {
556 		put_pixels_hires (0, y + offset, _WIDTH * 2,
557 			&game.hires[i]);
558 		i += _WIDTH * 2;
559 	}
560 
561 	flush_screen ();
562 }
563 
fix_hires_picture()564 void fix_hires_picture ()
565 {
566 	UINT8 *p, *b;
567 	int i;
568 
569 	p = game.hires;
570 	b = game.sbuf;
571 
572 	for (i = 0; p < &game.hires[_WIDTH * _HEIGHT * 2] - 1; p++, i++) {
573 /*
574 		if ((*p & 0x0f) == 0x0f && (*(p + 1) & 0x0f) != 0x0f)
575 			*p = *(p + 1);
576 		else if ((*p & 0x0f) == 0x0f && (*b & 0x0f) != 0x0f)
577 			*p = *b;
578 */
579 		if ((*p & 0x0f) == 0x0f && (*b & 0x0f) != 0x0f) {
580 			if ((*(p + 1) & 0x0f) != 0x0f)
581 				*p = *(p + 1);
582 			else
583 				*p = *b;
584 		}
585 		if ((*p >> 4) == 4 && (*b >> 4) != 4 &&
586 			(*(b + 1) >> 4) != 4)
587 		{
588 			*p = (*p & 0x0f) | (*b & 0xf0);
589 		}
590 		b += (i & 1);
591 	}
592 }
593 
594 #endif /* USE_HIRES */
595 
596 /* end: hirespic.c */
597 
598