1188
|
1 /* OS-9 ViewGIF 2.0 Copyright (C) 1989 by Vaughn Cato */
|
|
2
|
|
3 /*
|
|
4 * This program was specifically written for OS-9 on the Tandy Color
|
|
5 * Computer 3 as its graphics routines will only work on that system.
|
|
6 * The GIF decoding routines were originally taken from the Apollo
|
|
7 * workstation version of viewgif by Ben Samit. As noted in the source
|
|
8 * code provided by Ben, most of his code was taken from a GIF to
|
|
9 * PostScript converter by Scott Hemphill. Because of their consideration
|
|
10 * in providing the source code with their respective programs I am doing
|
|
11 * the same.
|
|
12 *
|
|
13 * I encourage you to send any enhancements in the Color Computer version
|
|
14 * you wish to be publicly distributed to me so that I may update the
|
|
15 * program and re-release it. In this way, a standard version of the
|
|
16 * program can be maintained.
|
|
17 *
|
|
18 * My address is:
|
|
19 * Vaughn Cato
|
|
20 * 1244 E. Piedmont Rd. NE
|
|
21 * Marietta, Ga. 30062
|
|
22 */
|
|
23
|
|
24 /*
|
|
25 * Any portion of this program may be freely used in any software provided
|
|
26 * the source for that program is made freely available to the public and
|
|
27 * credit is given to me, Ben Samit, and Scott Hemphill.
|
|
28 */
|
|
29
|
|
30 #define EXTERN /* force a defining instance of global variables */
|
|
31
|
|
32 #include <string.h>
|
|
33 #include "viewgif.h"
|
|
34
|
|
35 void showdata();
|
|
36 char *mapgpb();
|
|
37 extern int errno;
|
|
38
|
|
39 DIRECT int pauselen = -1;
|
|
40 DIRECT bool global;
|
|
41
|
|
42 main(argc, argv)
|
|
43 int argc;
|
|
44 char *argv[];
|
|
45 {
|
|
46 register char *p;
|
|
47 register bool *cscan;
|
|
48 char opt;
|
|
49 bool quit;
|
|
50 int x, argnum;
|
|
51
|
|
52 dfactor = D_DITHER;
|
|
53 magfact = D_MAG;
|
|
54 britefac = D_BRITE;
|
|
55 infomode = D_INFO;
|
|
56 graytype = D_GRAY;
|
|
57 myheight = D_HEIGHT;
|
|
58
|
|
59 zapmap = aligned = realrand = vefon = FALSE;
|
|
60 flicker = newscrn = dispon = TRUE;
|
|
61
|
|
62 for (cscan = &coloruse[MGCLUT]; cscan > coloruse; )
|
|
63 *--cscan = TRUE;
|
|
64
|
|
65 screen[0].winpath = screen[1].winpath = -1;
|
|
66
|
|
67 for (argnum = 1; argnum < argc; ++argnum) {
|
|
68 if (argv[argnum][0] == '-') {
|
|
69 p = &argv[argnum][1];
|
|
70 while (opt = *p++) {
|
|
71 if (*p == '=')
|
|
72 ++p;
|
|
73 switch (opt) {
|
|
74 case 'd':
|
|
75 if (*p == '\0')
|
|
76 dfactor = 0;
|
|
77 else {
|
|
78 dfactor = atoi(p);
|
|
79 if (dfactor < -MAXTOL1 || dfactor > MAXDITH1)
|
|
80 error("Invalid dithering factor", 1);
|
|
81 }
|
|
82 break;
|
|
83 case 'u':
|
|
84 usefname = p;
|
|
85 break;
|
|
86 case 'm':
|
|
87 magfact = atoi(p);
|
|
88 if (magfact < MINMAG || magfact > MAXMAG)
|
|
89 error("Invalid magnification", 1);
|
|
90 break;
|
|
91 case 'x':
|
|
92 startx = atoi(p);
|
|
93 if (startx < MINCOORD || startx > MAXCOORD)
|
|
94 error("Invalid start x coordinate", 1);
|
|
95 break;
|
|
96 case 'y':
|
|
97 starty = atoi(p);
|
|
98 if (starty < MINCOORD || starty > MAXCOORD)
|
|
99 error("Invalid start y coordinate", 1);
|
|
100 break;
|
|
101 case 'g':
|
|
102 switch (*p) {
|
|
103 case '2':
|
|
104 graytype = MAX_GRAY;
|
|
105 break;
|
|
106 case '3':
|
|
107 graytype = NTSC_GRAY;
|
|
108 break;
|
|
109 default:
|
|
110 graytype = AVG_GRAY;
|
|
111 }
|
|
112 break;
|
|
113 case 'a':
|
|
114 aligned = TRUE;
|
|
115 continue;
|
|
116 case 'z':
|
|
117 dispon = zapmap = TRUE;
|
|
118 continue;
|
|
119 case 'v':
|
|
120 dispon = vefon = TRUE;
|
|
121 if (*p != '\0')
|
|
122 vefname = p;
|
|
123 break;
|
|
124 case 'r':
|
|
125 realrand = TRUE;
|
|
126 continue;
|
|
127 case 's':
|
|
128 infomode = NO_INFO;
|
|
129 continue;
|
|
130 case 'i':
|
|
131 if (newscrn)
|
|
132 infomode = MUCH_INFO;
|
|
133 continue;
|
|
134 case 'n':
|
|
135 if (vefname == NULL)
|
|
136 dispon = FALSE;
|
|
137 continue;
|
|
138 case 'p':
|
|
139 pauselen = atoi(p);
|
|
140 break;
|
|
141 case 'c':
|
|
142 newscrn = FALSE;
|
|
143 infomode = NO_INFO;
|
|
144 continue;
|
|
145 case 'f':
|
|
146 flicker = FALSE;
|
|
147 continue;
|
|
148 case 'b':
|
|
149 britefac = atoi(p);
|
|
150 if (britefac < MINBRITE || britefac > MAXBRITE)
|
|
151 error("Invalid brightness factor", 1);
|
|
152 break;
|
|
153 case '?':
|
|
154 usage();
|
|
155 default:
|
|
156 fatal("Unknown option");
|
|
157 }
|
|
158 break;
|
|
159 }
|
|
160 for (x = argnum + 1; x < argc; ++x)
|
|
161 argv[x - 1] = argv[x];
|
|
162 --argc;
|
|
163 --argnum;
|
|
164 }
|
|
165 }
|
|
166
|
|
167 if (argc < 2)
|
|
168 usage();
|
|
169
|
|
170 if ((infile = fopen(argv[1], "r")) == NULL)
|
|
171 error("Cannot open input file", errno);
|
|
172
|
|
173 if (flicker) {
|
|
174 maxdith = MAXDITH2;
|
|
175 minmod = SCALE2;
|
|
176 approx = approx2;
|
|
177 } else {
|
|
178 maxdith = MAXDITH1;
|
|
179 minmod = SCALE1;
|
|
180 approx = approx1;
|
|
181 }
|
|
182 if (dfactor > maxdith)
|
|
183 dfactor = maxdith;
|
|
184 low0 = minmod / 2;
|
|
185 up0 = low0 + 1;
|
|
186
|
|
187 checksig();
|
|
188 readscrn();
|
|
189 if (!realrand)
|
|
190 makerand();
|
|
191
|
|
192
|
|
193 quit = FALSE;
|
|
194 framenum = 0;
|
|
195 do {
|
|
196 switch (getc(infile)) {
|
|
197 case '\0':
|
|
198 break;
|
|
199 case ',':
|
|
200 ++framenum;
|
|
201 readimag();
|
|
202 waituser();
|
|
203 break;
|
|
204 case ';':
|
|
205 quit = TRUE;
|
|
206 break;
|
|
207 case '!':
|
|
208 readext();
|
|
209 break;
|
|
210 default:
|
|
211 quit = TRUE;
|
|
212 break;
|
|
213 }
|
|
214 if (!dispon && vefname == NULL && (usefname == NULL || !newuse))
|
|
215 break;
|
|
216 } while (!quit);
|
|
217
|
|
218 if (dispon) {
|
|
219 if (zapmap) {
|
|
220 if ((infile = freopen(argv[1], "r+", infile)) == NULL)
|
|
221 error("Cannot rewrite global map", errno);
|
|
222 else
|
|
223 zapglobmap();
|
|
224 }
|
|
225 killwind();
|
|
226 }
|
|
227
|
|
228 actwin = 1;
|
|
229 select();
|
|
230 flushwin();
|
|
231 }
|
|
232
|
|
233 makerand()
|
|
234 {
|
|
235 register char *rscan1, *rscan2;
|
|
236 int x, f2;
|
|
237 char temp;
|
|
238 bool oddrow, oddrc;
|
|
239
|
|
240 f2 = maxdith / 2;
|
|
241
|
|
242 /* initialize */
|
|
243 x = 256;
|
|
244 for (rscan2 = &randtab[16][0]; (rscan2 -= 16) >= &randtab[0][0]; )
|
|
245 for (rscan1 = rscan2 + 16; rscan1 > rscan2; )
|
|
246 *--rscan1 = (--x * f2) >> 8;
|
|
247
|
|
248 /*
|
|
249 * permute randomly (I don't think the original made all
|
|
250 * permutations equally likely, alas)
|
|
251 */
|
|
252 rscan1 = &randtab[0][0];
|
|
253 for (x = 256; x > 0; x--) {
|
|
254 rscan2 = rscan1 + (rand() % x);
|
|
255 temp = *rscan1;
|
|
256 *rscan1++ = *rscan2;
|
|
257 *rscan2 = temp;
|
|
258 }
|
|
259
|
|
260 oddrow = FALSE;
|
|
261 for (rscan2 = &randtab[16][0]; (rscan2 -= 16) >= &randtab[0][0]; ) {
|
|
262 oddrc = oddrow = !oddrow;
|
|
263 for (rscan1 = rscan2 + 16; --rscan1 >= rscan2; ) {
|
|
264 if (oddrc = !oddrc)
|
|
265 *rscan1 += maxdith;
|
|
266 if (oddrow)
|
|
267 *rscan1 += f2;
|
|
268 }
|
|
269 }
|
|
270 }
|
|
271
|
|
272 readuse()
|
|
273 {
|
|
274 char newname[64];
|
|
275 register char *ep;
|
|
276 int usefile;
|
|
277
|
|
278 getusename(newname);
|
|
279 if ((usefile = open(newname, 1)) == -1) {
|
|
280 for (ep = &coloruse[MGCLUT]; --ep >= coloruse; )
|
|
281 *ep = TRUE;
|
|
282 newuse = TRUE;
|
|
283 } else {
|
|
284 read(usefile, coloruse, MGCLUT * sizeof(bool));
|
|
285 close(usefile);
|
|
286 if (infomode != NO_INFO)
|
|
287 printf("Using usage file\n");
|
|
288 newuse = FALSE;
|
|
289 }
|
|
290 }
|
|
291
|
|
292 getusename(buffer)
|
|
293 {
|
|
294 if (framenum > 1)
|
|
295 sprintf(buffer, "%s%d", usefname, framenum);
|
|
296 else
|
|
297 strcpy(buffer, usefname);
|
|
298 }
|
|
299
|
|
300 writeuse()
|
|
301 {
|
|
302 register char *cp, *gp;
|
|
303 int usecount, usefile;
|
|
304 char newname[64];
|
|
305
|
|
306 usecount = 0;
|
|
307 for (gp = &globuse[globcolors], cp = &coloruse[globcolors];
|
|
308 --gp, --cp >= coloruse; )
|
|
309 {
|
|
310 if (*cp) {
|
|
311 *gp = TRUE;
|
|
312 ++usecount;
|
|
313 }
|
|
314 }
|
|
315 if (infomode != NO_INFO)
|
|
316 printf("%d out of %d colors used.\n", usecount, globcolors);
|
|
317 if (usefname != NULL) {
|
|
318 getusename(newname);
|
|
319 if (newuse) {
|
|
320 if ((usefile = creat(newname, 3)) == -1)
|
|
321 error("Cannot create usage file", errno);
|
|
322 else
|
|
323 write(usefile, coloruse, globcolors);
|
|
324 }
|
|
325 close(usefile);
|
|
326 }
|
|
327 }
|
|
328
|
|
329 zapglobmap()
|
|
330 {
|
|
331 register rgbcolor *gp, *used;
|
|
332 register int i;
|
|
333
|
|
334 for (i = 0; i < globcolors; i++) {
|
|
335 if (globuse[i]) {
|
|
336 used = &globclut[i];
|
|
337 for (gp = &globclut[i = globcolors]; --i, --gp >= globclut; )
|
|
338 {
|
|
339 if (!globuse[i]) {
|
|
340 gp->red = used->red;
|
|
341 gp->green = used->green;
|
|
342 gp->blue = used->blue;
|
|
343 }
|
|
344 }
|
|
345 fseek(infile, clutpos, 0);
|
|
346 fwrite(globclut, sizeof(rgbcolor), globcolors, infile);
|
|
347 return;
|
|
348 }
|
|
349 }
|
|
350 }
|
|
351
|
|
352 saveimag()
|
|
353 {
|
|
354 register cocoscreen *sscan;
|
|
355 char newname[64];
|
|
356 int file, x, scrnum, scrntype = 0;
|
|
357
|
|
358 for (scrnum = 0; scrnum <= flicker; ++scrnum) {
|
|
359 sscan = &screen[scrnum];
|
|
360 strcpy(newname, vefname);
|
|
361 if (framenum > 1)
|
|
362 sprintf(newname + strlen(newname), "%d", framenum);
|
|
363 if (scrnum == 1)
|
|
364 strcat(newname, ".2");
|
|
365 actwin = sscan->winpath;
|
|
366 select();
|
|
367 flushwin();
|
|
368 if ((file = creat(newname, 3)) == -1)
|
|
369 error("Cannot create vef file", errno);
|
|
370 else {
|
|
371 write(file, &scrntype, sizeof(scrntype));
|
|
372 write(file, sscan->pal, MCCLUT * sizeof(colorcode));
|
|
373 for (x = 0; x < 8; ++x)
|
|
374 write(file, gpbufptr, 160);
|
|
375 for (x = 0; x < MROWS; ++x) {
|
|
376 getblk(groupnum, bufnum, 0, x, MCOLS - 1, 1);
|
|
377 flushwin();
|
|
378 write(file, gpbufptr, 160);
|
|
379 }
|
|
380 close(file);
|
|
381 }
|
|
382 }
|
|
383 }
|
|
384
|
|
385 readext()
|
|
386 {
|
|
387 char buf[255];
|
|
388 int count;
|
|
389
|
|
390 (void) getc(infile);
|
|
391 while (count = getc(infile))
|
|
392 fread(buf, 1, count, infile);
|
|
393 }
|
|
394
|
|
395 DIRECT int real_x, real_y;
|
|
396 DIRECT int x_coord, y_coord;
|
|
397
|
|
398 typedef struct {
|
|
399 int ilv_r0; /* starting row */
|
|
400 int ilv_dr; /* step size */
|
|
401 } ilvspec;
|
|
402
|
|
403 static ilvspec ilvdat[] = {
|
|
404 {1, 2}, /* .|.|.|.|.|.|.|.|. */
|
|
405 {2, 4}, /* ..|...|...|...|.. */
|
|
406 {4, 8}, /* ....|.......|.... */
|
|
407 {0, 8}, /* |.......|.......| */
|
|
408 };
|
|
409
|
|
410 readimag()
|
|
411 {
|
|
412 BYTE buf[9];
|
|
413 unsigned left, top, width, height;
|
|
414 bool local, intrlevd;
|
|
415 int lclbits;
|
|
416 int row, rowoffset;
|
|
417 register int n;
|
|
418 int lineread, hold, xpos, x;
|
|
419 register ilvspec *ilvscan;
|
|
420
|
|
421 readuse();
|
|
422 newwind();
|
|
423
|
|
424 /* read header info */
|
|
425 fread(buf, sizeof(BYTE), sizeof(buf) / sizeof(BYTE), infile);
|
|
426 left = arith(buf[0]) | (buf[1] << 8);
|
|
427 top = arith(buf[2]) | (buf[3] << 8);
|
|
428 imagwid = width = arith(buf[4]) | (buf[5] << 8);
|
|
429 imaghigh = height = arith(buf[6]) | (buf[7] << 8);
|
|
430
|
|
431 if (infomode != NO_INFO)
|
|
432 printf("gif dimensions: %d x %d pixels\n", imagwid, imaghigh);
|
|
433
|
|
434 local = buf[8] & 0x80;
|
|
435 intrlevd = buf[8] & 0x40;
|
|
436
|
|
437 if (local) {
|
|
438 char tempbuf[3];
|
|
439
|
|
440 lclbits = (buf[8] & 0x7) + 1;
|
|
441 for (x = 1 << lclbits; --x >= 0; )
|
|
442 fread(tempbuf, 3, 1, infile);
|
|
443 } else if (!global)
|
|
444 fatal("no CLUT present for image");
|
|
445
|
|
446 ilevtab[MROWS] = ILEVEND;
|
|
447 for (x = MROWS; --x >= 0; )
|
|
448 ilevtab[x] = ILEVMISS;
|
|
449
|
|
450 if (!aligned)
|
|
451 n = myheight;
|
|
452 else {
|
|
453 for (n = imaghigh; n > 200; n /= 2)
|
|
454 ;
|
|
455 }
|
|
456 n *= magfact;
|
|
457
|
|
458 rowoffset = 3 * starty * magfact;
|
|
459 lineread = 0;
|
|
460 if (intrlevd) {
|
|
461 for (ilvscan = &ilvdat[elements(ilvdat)]; --ilvscan >= ilvdat; ) {
|
|
462 for (x = ilvscan->ilv_r0; x < imaghigh; x += ilvscan->ilv_dr) {
|
|
463 row = (long) x * n / imaghigh - rowoffset;
|
|
464 if (row >= 0 && row < MROWS)
|
|
465 ilevtab[row] = lineread;
|
|
466 ++lineread;
|
|
467 }
|
|
468 }
|
|
469 } else {
|
|
470 for (x = 0; x < imaghigh; ++x) {
|
|
471 row = (long) x * n / imaghigh - rowoffset;
|
|
472 if (row >= 0 && row < MROWS)
|
|
473 ilevtab[row] = lineread;
|
|
474 ++lineread;
|
|
475 }
|
|
476 }
|
|
477
|
|
478 x = startx * (imagwid / 64);
|
|
479 hold = xpos = 0;
|
|
480 while (xpos < mywidth) {
|
|
481 for (hold += mywidth * magfact; hold >= imagwid; hold -= imagwid)
|
|
482 xtab[xpos++] = x;
|
|
483 x++;
|
|
484 }
|
|
485
|
|
486 real_x = real_y = 0;
|
|
487 x_coord = y_coord = 0;
|
|
488
|
|
489 if (dispon || (usefname != NULL && newuse)) {
|
|
490 readrast(width, height);
|
|
491 writeuse();
|
|
492 if (vefname != NULL)
|
|
493 saveimag();
|
|
494 }
|
|
495 }
|
|
496
|
|
497 DIRECT int datum;
|
|
498 DIRECT int bits;
|
|
499 char buf[255];
|
|
500
|
|
501 readrast(width, height)
|
|
502 unsigned width, height;
|
|
503 {
|
|
504 register char *ch;
|
|
505 register codetype *cscan;
|
|
506 int count, code;
|
|
507
|
|
508 datasize = getc(infile);
|
|
509 codesize = datasize + 1;
|
|
510 codemask = (1 << codesize) - 1;
|
|
511 clear = 1 << datasize;
|
|
512 eoi = clear + 1;
|
|
513 bits = 16;
|
|
514
|
|
515 /* initialize code table */
|
|
516 for (cscan = &codetab[code = clear]; --cscan, --code >= 0; ) {
|
|
517 cscan->prefix = (codetype *) NULL;
|
|
518 cscan->first = cscan->suffix = code;
|
|
519 }
|
|
520
|
|
521 while ((count = getc(infile)) > 0) {
|
|
522 fread(buf, sizeof(*buf), count, infile);
|
|
523 for (ch = buf; --count >= 0; )
|
|
524 addbyte(*ch++);
|
|
525 }
|
|
526
|
|
527 datum >>= bits;
|
|
528 for (bits = 16 - bits; x_coord != 0 && bits >= codesize; bits -= codesize) {
|
|
529 process(datum & codemask);
|
|
530 datum >>= codesize;
|
|
531 }
|
|
532 }
|
|
533
|
|
534 addbyte(c)
|
|
535 char c;
|
|
536 {
|
|
537 /*
|
|
538 * datum += (long)(*ch & 0xff) << bits;
|
|
539 * bits += 8;
|
|
540 * while (bits >= codesize) {
|
|
541 * code = datum & codemask;
|
|
542 * datum >>= codesize;
|
|
543 * bits -= codesize;
|
|
544 * if (code == eoi)
|
|
545 * goto exitloop;
|
|
546 * process(code);
|
|
547 * }
|
|
548 */
|
|
549 #asm
|
|
550 ldb 5,s
|
|
551 lda <bits+1
|
|
552 suba #7
|
|
553 bls _addb3
|
|
554 sta <bits+1
|
|
555 lda <datum
|
|
556 sta <datum+1
|
|
557 stb <datum
|
|
558 lda #1
|
|
559 bra _addb4
|
|
560 _addb3
|
|
561 lda #8
|
|
562 _addb1
|
|
563 lsrb
|
|
564 ror <datum
|
|
565 ror <datum+1
|
|
566 _addb4
|
|
567 dec <bits+1
|
|
568 bne _addb2
|
|
569 * pshs d
|
|
570 tfr d,u
|
|
571 ldd <codesize
|
|
572 std <bits
|
|
573 ldd <datum
|
|
574 anda <codemask
|
|
575 andb <codemask+1
|
|
576 pshs d
|
|
577 lbsr process
|
|
578 leas 2,s
|
|
579 * puls d
|
|
580 tfr u,d
|
|
581 _addb2
|
|
582 deca
|
|
583 bne _addb1
|
|
584 #endasm
|
|
585 }
|
|
586
|
|
587 process(code)
|
|
588 int code;
|
|
589 {
|
|
590 register codetype *p, *cp;
|
|
591 static DIRECT int avail;
|
|
592 static DIRECT codetype *oldcp;
|
|
593
|
|
594 if (code == clear) {
|
|
595 /* clear table */
|
|
596 codesize = datasize + 1;
|
|
597 codemask = (1 << codesize) - 1;
|
|
598 avail = clear + 2;
|
|
599 oldcp = NULL;
|
|
600 } else if (code < avail) {
|
|
601 outcode(cp = &codetab[code]); /* output the code */
|
|
602 if (oldcp != NULL) {
|
|
603 /* add new entry */
|
|
604 p = &codetab[avail++];
|
|
605 /* prefix is previous code, first is prefix's first */
|
|
606 p->first = (p->prefix = oldcp)->first;
|
|
607 p->suffix = cp->first; /* suffix is first of current */
|
|
608 if ((avail & codemask) == 0 && avail < MCODE) {
|
|
609 /* increase code size */
|
|
610 codesize++;
|
|
611 codemask += avail;
|
|
612 }
|
|
613 }
|
|
614 oldcp = cp;
|
|
615 } else if (code == avail && oldcp != NULL) {
|
|
616 /* repeat of last code */
|
|
617 p = &codetab[avail++];
|
|
618 /* prefix is previous code, first is prefix's first */
|
|
619 p->first = (p->prefix = oldcp)->first;
|
|
620 p->suffix = p->first; /* Suffix is first of last */
|
|
621 outcode(p);
|
|
622 if ((avail & codemask) == 0 && avail < MCODE) {
|
|
623 /* increase code size */
|
|
624 codesize++;
|
|
625 codemask += avail;
|
|
626 }
|
|
627 oldcp = &codetab[code];
|
|
628 } else
|
|
629 fatal("illegal code in raster data");
|
|
630 }
|
|
631
|
|
632 /*
|
|
633 * outcode() -- we finally get the data out of the LZ decompression, and
|
|
634 * fill a buffer until we get a line's worth of data. The loop with x0
|
|
635 * and x is intended to take advantage of the mostly increasing nature
|
|
636 * of ilevtab[], replacing an O(n**2) loop that was there before. Timing,
|
|
637 * however, shows that the change doesn't affect display time, so the
|
|
638 * performance bottleneck must be elsewhere. Rats.
|
|
639 */
|
|
640 outcode(p)
|
|
641 codetype *p;
|
|
642 {
|
|
643 register BYTE *sp = &codestk[0];
|
|
644 register int x;
|
|
645 static DIRECT int x0 = 0;
|
|
646
|
|
647 for (; p; p = p->prefix)
|
|
648 *sp++ = p->suffix;
|
|
649
|
|
650 while (--sp >= &codestk[0]) {
|
|
651 coloruse[arith(*sp)] = TRUE;
|
|
652 if (real_x == 0) {
|
|
653 y_coord = -1;
|
|
654 x = x0;
|
|
655 do {
|
|
656 if (++x >= myheight)
|
|
657 x = 0;
|
|
658 if (ilevtab[x] == real_y) {
|
|
659 x0 = y_coord = x;
|
|
660 break;
|
|
661 }
|
|
662 } while (x != x0);
|
|
663 }
|
|
664 if (y_coord >= 0) {
|
|
665 while (xtab[x_coord] == real_x)
|
|
666 linestor[x_coord++] = arith(*sp);
|
|
667 }
|
|
668 if (++real_x >= imagwid) {
|
|
669 if (y_coord >= 0 && dispon) {
|
|
670 do {
|
|
671 doline();
|
|
672 } while (ilevtab[++y_coord] == ILEVMISS);
|
|
673 }
|
|
674 real_x = x_coord = 0;
|
|
675 ++real_y;
|
|
676 }
|
|
677 }
|
|
678 }
|
|
679
|
|
680 DIRECT int bitcount, pixperbyte;
|
|
681 DIRECT char *byteptr;
|
|
682
|
|
683 doline()
|
|
684 {
|
|
685 register xlate *p;
|
|
686 register char *rrow;
|
|
687 register int x, addval, scrnum;
|
|
688 cocoscreen *sscan;
|
|
689
|
|
690 rrow = &randtab[y_coord & 15][0];
|
|
691
|
|
692 for (sscan = &screen[scrnum = (flicker ? 2 : 1)]; --sscan, --scrnum >= 0;)
|
|
693 {
|
|
694 actwin = sscan->winpath;
|
|
695 bitcount = pixperbyte;
|
|
696 byteptr = gpbufptr;
|
|
697 if (dfactor > 0) {
|
|
698 for (x = 0; x < mywidth; ++x) {
|
|
699 addval = (realrand) ? rand85(y_coord + x)
|
|
700 : rrow[x & 15];
|
|
701 for (p = &transtab[linestor[x]][1]; p->addval <= addval; )
|
|
702 p++;
|
|
703 --p;
|
|
704 addpixel(p->clutval[scrnum]);
|
|
705 }
|
|
706 } else {
|
|
707 for (x = 0; x < mywidth; ++x)
|
|
708 addpixel(transtab[linestor[x]][0].clutval[scrnum]);
|
|
709 }
|
|
710 if (flicker)
|
|
711 select();
|
|
712 putblk(groupnum, bufnum, 0, y_coord);
|
|
713 flushwin();
|
|
714 }
|
|
715 }
|
|
716
|
|
717 addpixel(c)
|
|
718 {
|
|
719 /*
|
|
720 * *byteptr = (*byteptr << (gmode ? 2 : 4)) | c;
|
|
721 * if (--bitcount == 0) {
|
|
722 * byteptr++;
|
|
723 * bitcount = pixperbyte;
|
|
724 * }
|
|
725 *
|
|
726 * (The spelling discrepancy here is due to the 6809's chopping off
|
|
727 * identifier lengths at a different point than the assembler appears to!)
|
|
728 */
|
|
729 #asm
|
|
730 ldx <byteptr
|
|
731 ldb ,x
|
|
732 lda <gmode+1
|
|
733 bne _addpix1
|
|
734 lslb
|
|
735 lslb
|
|
736 _addpix1
|
|
737 lslb
|
|
738 lslb
|
|
739 orb 5,s
|
|
740 stb ,x
|
|
741 dec <bitcount+1
|
|
742 bne _addpix2
|
|
743 leax 1,x
|
|
744 stx <byteptr
|
|
745 lda <pixperby+1
|
|
746 sta <bitcount+1
|
|
747 _addpix2
|
|
748 #endasm
|
|
749 }
|
|
750
|
|
751 rand85(n)
|
|
752 int n;
|
|
753 {
|
|
754 register unsigned result;
|
|
755
|
|
756 result = rand() % maxdith;
|
|
757 if (n & 1)
|
|
758 result += maxdith + 1;
|
|
759 return result;
|
|
760 }
|
|
761
|
|
762 readscrn()
|
|
763 {
|
|
764 char buf[7];
|
|
765 int x;
|
|
766 register rgbcolor *rp;
|
|
767
|
|
768 fread(buf, sizeof(*buf), 7, infile);
|
|
769 imagwid = arith(buf[0]) | (buf[1] << 8);
|
|
770 imaghigh = arith(buf[2]) | (buf[3] << 8);
|
|
771 if (infomode != NO_INFO)
|
|
772 printf("%d x %d screen\n", imagwid, imaghigh);
|
|
773 global = (buf[4] & 0x80) != 0;
|
|
774 if (global) {
|
|
775 globbits = (buf[4] & 0x07) + 1;
|
|
776 globcolors = 1 << globbits;
|
|
777 if (infomode != NO_INFO)
|
|
778 printf("global bitmap: %d colors\n", globcolors);
|
|
779 clutpos = ftell(infile);
|
|
780 fread(globclut, 3, globcolors, infile);
|
|
781 if (infomode == MUCH_INFO) {
|
|
782 for (rp = globclut, x = 0; x < globcolors; rp++, x++) {
|
|
783 printf("color %d = %3d,%3d,%3d\n", x,
|
|
784 arith(rp->red), arith(rp->green), arith(rp->blue));
|
|
785 }
|
|
786 }
|
|
787 } else
|
|
788 fatal("cannot handle non-global bitmaps");
|
|
789 }
|
|
790
|
|
791 /*
|
|
792 * newwind() -- the big banana; determine the CoCo CLUT(s) that will
|
|
793 * best display the GIF image given the GIF CLUT.
|
|
794 */
|
|
795
|
|
796 newwind()
|
|
797 {
|
|
798 register cocoscreen *sscan;
|
|
799 register bool *bscan;
|
|
800 register colorcode *cscan;
|
|
801 rgbcolor *rgbp;
|
|
802 bool first;
|
|
803 char blip;
|
|
804 int x, hival, loval, midval;
|
|
805
|
|
806 fixgmap();
|
|
807
|
|
808 if (infomode != NO_INFO) {
|
|
809 printf("Analyzing..");
|
|
810 fflush(stdout);
|
|
811 }
|
|
812
|
|
813 loval = -MAXTOL1;
|
|
814 midval = hival = dfactor;
|
|
815
|
|
816 while (loval <= hival) {
|
|
817 dfactor = midval;
|
|
818 if (setmap()) {
|
|
819 loval = midval + 1;
|
|
820 blip = '+';
|
|
821 } else {
|
|
822 hival = midval - 1;
|
|
823 blip = '-';
|
|
824 }
|
|
825 if (infomode != NO_INFO) {
|
|
826 putchar(blip);
|
|
827 fflush(stdout);
|
|
828 }
|
|
829 midval = (loval + hival) / 2;
|
|
830 }
|
|
831
|
|
832 if (dfactor != hival) {
|
|
833 dfactor = hival;
|
|
834 setmap();
|
|
835 }
|
|
836
|
|
837 if (infomode != NO_INFO) {
|
|
838 putchar('\n');
|
|
839 showdata();
|
|
840 }
|
|
841
|
|
842 if (screen[0].clutsize <= 4 && !vefon) {
|
|
843 gmode = TRUE;
|
|
844 mywidth = 640;
|
|
845 pixperbyte = 4;
|
|
846 } else {
|
|
847 gmode = FALSE;
|
|
848 mywidth = 320;
|
|
849 pixperbyte = 2;
|
|
850 }
|
|
851
|
|
852 first = TRUE;
|
|
853 for (sscan = &screen[(flicker ? 2 : 1)]; --sscan >= screen; ) {
|
|
854 if (dispon)
|
|
855 sscan->winpath = initwin(first, sscan->winpath);
|
|
856 for (cscan = &sscan->pal[x = sscan->clutsize]; --cscan, --x >= 0; ) {
|
|
857 *cscan = colorval(&sscan->clut[x]);
|
|
858 if (dispon)
|
|
859 palette(x, *cscan);
|
|
860 }
|
|
861 if (dispon) {
|
|
862 border(0);
|
|
863 flushwin();
|
|
864 }
|
|
865 first = FALSE;
|
|
866 }
|
|
867 for (bscan = &coloruse[globcolors]; --bscan >= coloruse; )
|
|
868 *bscan = FALSE;
|
|
869 }
|
|
870
|
|
871 /* colorval() -- encode an RGB222 value the way the GIME likes it */
|
|
872
|
|
873 colorval(color)
|
|
874 register rgbcolor *color;
|
|
875 {
|
|
876 static char cocode[] = {'\000', '\001', '\010', '\011'};
|
|
877
|
|
878 return (((cocode[color->red & 3] << 1) |
|
|
879 cocode[color->green & 3]) << 1) | cocode[color->blue & 3];
|
|
880 }
|
|
881
|
|
882 /*
|
|
883 * showdata() -- display a bunch of information on the CLUTs used
|
|
884 * if it's been asked for
|
|
885 */
|
|
886 void
|
|
887 showdata()
|
|
888 {
|
|
889 register rgbcolor *rscan;
|
|
890 register cocoscreen *sscan;
|
|
891 int x, y;
|
|
892
|
|
893 if (dfactor > 0)
|
|
894 printf("Dithering factor = %d\n", dfactor);
|
|
895 else
|
|
896 printf("Color tolerance = %d\n", -dfactor);
|
|
897 fputs("Resulting coco CLUT: ", stdout);
|
|
898 printf("%d colors", screen[0].clutsize);
|
|
899 if (flicker)
|
|
900 printf(" + %d colors\n", screen[1].clutsize);
|
|
901 else
|
|
902 putchar('\n');
|
|
903 if (infomode == MUCH_INFO) {
|
|
904 for (x = 0; x < (flicker ? 1 : 2); x++) {
|
|
905 sscan = &screen[x];
|
|
906 for (rscan = sscan->clut, y = 0; y < sscan->clutsize; y++) {
|
|
907 printf("%2d:%d,%d,%d=%d\n", y,
|
|
908 rscan->red, rscan->green, rscan->blue, colorval(rscan));
|
|
909 rscan++;
|
|
910 }
|
|
911 putchar('\n');
|
|
912 }
|
|
913 fputs("Translation table:\n", stdout);
|
|
914 for (x = 0; x < globcolors; ++x) {
|
|
915 if (coloruse[x]) {
|
|
916 printf("%3d:", x);
|
|
917 for (y = 0; y < 4 && transtab[x][y].addval != BOGUSDITH; ++y) {
|
|
918 printf(" %3d=%3d",
|
|
919 transtab[x][y].addval, transtab[x][y].clutval[0]);
|
|
920 if (flicker)
|
|
921 printf(",%3d", transtab[x][y].clutval[1]);
|
|
922 }
|
|
923 putchar('\n');
|
|
924 }
|
|
925 }
|
|
926 }
|
|
927 }
|
|
928
|
|
929 /*
|
|
930 * fixgmap() -- scale colors in the GIF image global CLUT in accordance
|
|
931 * with the brightness specification, and in passing, convert to gray
|
|
932 * if requested (either using the average of the components or their
|
|
933 * maximum).
|
|
934 */
|
|
935 fixgmap()
|
|
936 {
|
|
937 register rgbcolor *rscan;
|
|
938 int x, r, g, b;
|
|
939
|
|
940 for (rscan = &globclut[x = globcolors]; --rscan, --x >= 0; ) {
|
|
941 if (coloruse[x]) {
|
|
942 r = arith(rscan->red);
|
|
943 g = arith(rscan->green);
|
|
944 b = arith(rscan->blue);
|
|
945 switch (graytype) {
|
|
946 case AVG_GRAY:
|
|
947 r = g = b = (r + g + b) / 3;
|
|
948 break;
|
|
949 case NTSC_GRAY:
|
|
950 r = g = b = (30 * r + 59 * g + 11 * b) / 100;
|
|
951 break;
|
|
952 case MAX_GRAY:
|
|
953 if (g > r)
|
|
954 r = g;
|
|
955 if (b > r)
|
|
956 r = b;
|
|
957 g = b = r;
|
|
958 break;
|
|
959 }
|
|
960 rscan->red = (britefac * r) >> 4;
|
|
961 rscan->green = (britefac * g) >> 4;
|
|
962 rscan->blue = (britefac * b) >> 4;
|
|
963 }
|
|
964 }
|
|
965 }
|
|
966
|
|
967 killwind()
|
|
968 {
|
|
969 mapgpb(screen[flicker].winpath, groupnum, bufnum, 0);
|
|
970 killbuf(groupnum, bufnum);
|
|
971 }
|
|
972
|
|
973 waituser()
|
|
974 {
|
|
975 char c;
|
|
976 int x;
|
|
977 register cocoscreen *sscan;
|
|
978
|
|
979 if (dispon) {
|
|
980 if (pauselen < 0) {
|
|
981 for (x = 5; --x >= 0; )
|
|
982 bell();
|
|
983 flushwin();
|
|
984 }
|
|
985 if (flicker) {
|
|
986 pauselen *= 30;
|
|
987 do {
|
|
988 for (sscan = &screen[2]; --sscan >= screen; ) {
|
|
989 actwin = sscan->winpath;
|
|
990 select();
|
|
991 flushwin();
|
|
992 sleep(2);
|
|
993 if (ready(actwin)) {
|
|
994 read(actwin, &c, 1);
|
|
995 if (c == '\n')
|
|
996 return;
|
|
997 }
|
|
998 }
|
|
999 } while (pauselen < 0 || --pauselen >= 0);
|
|
1000 } else if (pauselen > 0) {
|
|
1001 sleep(60 * pauselen);
|
|
1002 } else if (pauselen < 0) {
|
|
1003 do {
|
|
1004 read(screen[0].winpath, &c, 1);
|
|
1005 } while (c != '\n');
|
|
1006 }
|
|
1007 }
|
|
1008 }
|
|
1009
|
|
1010 ready(path)
|
|
1011 int path;
|
|
1012 {
|
|
1013 #asm
|
|
1014 lda 5,s
|
|
1015 ldb #SS.Ready
|
|
1016 os9 I$GetStt
|
|
1017 bcc _ready1
|
|
1018 ldd #0
|
|
1019 bra _ready2
|
|
1020 _ready1
|
|
1021 ldd #1
|
|
1022 _ready2
|
|
1023 #endasm
|
|
1024 }
|