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