source: trunk/third/xscreensaver/hacks/apple2.c @ 20148

Revision 20148, 21.6 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20147, which included commits to RCS files with non-trunk default branches.
Line 
1/* xscreensaver, Copyright (c) 1998-2003 Jamie Zawinski <jwz@jwz.org>
2 *
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation.  No representations are made about the suitability of this
8 * software for any purpose.  It is provided "as is" without express or
9 * implied warranty.
10 *
11 * Apple ][ CRT simulator, by Trevor Blackwell <tlb@tlb.org>
12 * with additional work by Jamie Zawinski <jwz@jwz.org>
13 */
14
15#include <math.h>
16#include "screenhack.h"
17#include "apple2.h"
18#include <time.h>
19#include <sys/time.h>
20#include <X11/Intrinsic.h>
21
22#ifdef HAVE_XSHM_EXTENSION
23#include "xshm.h"
24#endif
25
26#define DEBUG
27
28extern XtAppContext app;
29
30/*
31 * Implementation notes
32 *
33 * The A2 had 3 display modes: text, lores, and hires. Text was 40x24, and it
34 * disabled color in the TV. Lores gave you 40x48 graphics blocks, using the
35 * same memory as the text screen. Each could be one of 16 colors. Hires gave
36 * you 280x192 pixels. Odd pixels were blue or purple, and even pixels were
37 * orange or green depending on the setting of the high bit in each byte.
38 *
39 * The graphics modes could also have 4 lines of text at the bottom. This was
40 * fairly unreadable if you had a color monitor.
41 *
42 * Each mode had 2 different screens using different memory space. In hires
43 * mode this was sometimes used for double buffering, but more often the lower
44 * screen was full of code/data and the upper screen was used for display, so
45 * you got random garbage on the screen.
46 *
47 * The text font is based on X's standard 6x10 font, with a few tweaks like
48 * putting a slash across the zero.
49 *
50 * To use this, you'll call apple2(display, window, duration,
51 * controller) where the function controller defines what will happen.
52 * See bsod.c and apple2-main.c for example controllers. The
53 * controller function gets called whenever the machine ready to start
54 * something new. By setting sim->printing or sim->typing, it'll be
55 * busy for some time spitting characters out one at a time. By
56 * setting *next_actiontime+=X.X, it'll pause and just update the screen
57 * for that long before calling the controller function again.
58 *
59 * By setting stepno to A2CONTROLLER_DONE, the loop will end. It will also end
60 * after the time specified by the delay parameter. In either case, it calls
61 * the controller with stepno==A2CONTROLLER_FREE to allow it to release any
62 * memory.
63 *
64 * The void* apple2_sim_t::controller_data is for the use of the controller.
65 * It will be initialize to NULL, and the controller can store its own state
66 * there.
67 *
68 */
69
70void
71a2_scroll(apple2_state_t *st)
72{
73  int i;
74  for (i=0; i<23; i++) {
75    memcpy(st->textlines[i],st->textlines[i+1],40);
76  }
77  memset(st->textlines[23],0xe0,40);
78}
79
80void
81a2_printc(apple2_state_t *st, char c)
82{
83  st->textlines[st->cursy][st->cursx] |= 0xc0; /* turn off blink */
84
85  if (c == '\n')                      /* ^J == NL */
86    {
87      if (st->cursy==23)
88        {
89          a2_scroll(st);
90        }
91      else
92        {
93          st->cursy++;
94        }
95      st->cursx=0;
96    }
97  else if (c == 014)                  /* ^L == CLS, Home */
98    {
99      a2_cls(st);
100      a2_goto(st,0,0);
101    }
102  else if (c == '\t')                 /* ^I == tab */
103    {
104      a2_goto(st, st->cursy, (st->cursx+8)&~7);
105    }
106  else if (c == 010)                  /* ^H == backspace */
107    {
108      st->textlines[st->cursy][st->cursx]=0xe0;
109      a2_goto(st, st->cursy, st->cursx-1);
110    }
111  else if (c == '\r')                 /* ^M == CR */
112    {
113      st->cursx=0;
114    }
115  else
116    {
117      st->textlines[st->cursy][st->cursx]=c ^ 0xc0;
118      st->cursx++;
119      if (st->cursx==40) {
120        if (st->cursy==23) {
121          a2_scroll(st);
122        } else {
123          st->cursy++;
124        }
125        st->cursx=0;
126      }
127    }
128
129  st->textlines[st->cursy][st->cursx] &= 0x7f; /* turn on blink */
130}
131
132void
133a2_prints(apple2_state_t *st, char *s)
134{
135  while (*s) a2_printc(st, *s++);
136}
137
138void
139a2_goto(apple2_state_t *st, int r, int c)
140{
141  st->textlines[st->cursy][st->cursx] |= 0xc0; /* turn off blink */
142  st->cursy=r;
143  st->cursx=c;
144  st->textlines[st->cursy][st->cursx] &= 0x7f; /* turn on blink */
145}
146
147void
148a2_cls(apple2_state_t *st)
149{
150  int i;
151  for (i=0; i<24; i++) {
152    memset(st->textlines[i],0xe0,40);
153  }
154}
155
156void
157a2_clear_gr(apple2_state_t *st)
158{
159  int i;
160  for (i=0; i<24; i++) {
161    memset(st->textlines[i],0x00,40);
162  }
163}
164
165void
166a2_clear_hgr(apple2_state_t *st)
167{
168  int i;
169  for (i=0; i<192; i++) {
170    memset(st->hireslines[i],0,40);
171  }
172}
173
174void
175a2_invalidate(apple2_state_t *st)
176{
177}
178
179void
180a2_poke(apple2_state_t *st, int addr, int val)
181{
182
183  if (addr>=0x400 && addr<0x800) {
184    /* text memory */
185    int row=((addr&0x380)/0x80) + ((addr&0x7f)/0x28)*8;
186    int col=(addr&0x7f)%0x28;
187    if (row<24 && col<40) {
188      st->textlines[row][col]=val;
189      if (!(st->gr_mode&(A2_GR_HIRES)) ||
190          (!(st->gr_mode&(A2_GR_FULL)) && row>=20)) {
191      }
192    }
193  }
194  else if (addr>=0x2000 && addr<0x4000) {
195    int row=(((addr&0x1c00) / 0x400) * 1 +
196             ((addr&0x0380) / 0x80) * 8 +
197             ((addr&0x0078) / 0x28) * 64);
198    int col=((addr&0x07f)%0x28);
199    if (row<192 && col<40) {
200      st->hireslines[row][col]=val;
201      if (st->gr_mode&A2_GR_HIRES) {
202      }
203    }
204  }
205}
206
207void
208a2_hplot(apple2_state_t *st, int hcolor, int x, int y)
209{
210  int highbit,run;
211
212  highbit=((hcolor<<5)&0x80) ^ 0x80; /* capture bit 2 into bit 7 */
213
214  if (y<0 || y>=192 || x<0 || x>=280) return;
215
216  for (run=0; run<2 && x<280; run++) {
217    u_char *vidbyte = &st->hireslines[y][x/7];
218    u_char whichbit=1<<(x%7);
219    int masked_bit;
220
221    *vidbyte = (*vidbyte & 0x7f) | highbit;
222
223    /* use either bit 0 or 1 of hcolor for odd or even pixels */
224    masked_bit = (hcolor>>(1-(x&1)))&1;
225
226    /* Set whichbit to 1 or 0 depending on color */
227    *vidbyte = (*vidbyte & ~whichbit) | (masked_bit ? whichbit : 0);
228
229    x++;
230  }
231}
232
233void
234a2_hline(apple2_state_t *st, int hcolor, int x1, int y1, int x2, int y2)
235{
236  int dx,dy,incx,incy,x,y,balance;
237
238  /* Bresenham's line drawing algorithm */
239
240  if (x2>=x1) {
241    dx=x2-x1;
242    incx=1;
243  } else {
244    dx=x1-x2;
245    incx=-1;
246  }
247  if (y2>=y1) {
248    dy=y2-y1;
249    incy=1;
250  } else {
251    dy=y1-y2;
252    incy=-1;
253  }
254
255  x=x1; y=y1;
256
257  if (dx>=dy) {
258    dy*=2;
259    balance=dy-dx;
260    dx*=2;
261    while (x!=x2) {
262      a2_hplot(st, hcolor, x, y);
263      if (balance>=0) {
264        y+=incy;
265        balance-=dx;
266      }
267      balance+=dy;
268      x+=incx;
269    }
270    a2_hplot(st, hcolor, x, y);
271  } else {
272    dx*=2;
273    balance=dx-dy;
274    dy*=2;
275    while (y!=y2) {
276      a2_hplot(st, hcolor, x, y);
277      if (balance>=0) {
278        x+=incx;
279        balance-=dy;
280      }
281      balance+=dx;
282      y+=incy;
283    }
284    a2_hplot(st, hcolor, x, y);
285  }
286}
287
288void
289a2_plot(apple2_state_t *st, int color, int x, int y)
290{
291  int textrow=y/2;
292  u_char byte;
293
294  if (x<0 || x>=40 || y<0 || y>=48) return;
295
296  byte=st->textlines[textrow][x];
297  if (y&1) {
298    byte = (byte&0xf0) | (color&0x0f);
299  } else {
300    byte = (byte&0x0f) | ((color&0x0f)<<4);
301  }
302  st->textlines[textrow][x]=byte;
303}
304
305void
306a2_display_image_loading(apple2_state_t *st, unsigned char *image,
307                         int lineno)
308{
309  /*
310    When loading images,it would normally just load the big binary
311    dump into screen memory while you watched. Because of the way
312    screen memory was laid out, it wouldn't load from the top down,
313    but in a funny interleaved way. You should call this with lineno
314    increasing from 0 thru 191 over a period of a few seconds.
315  */
316
317  int row=(((lineno / 24) % 8) * 1 +
318           ((lineno / 3 ) % 8) * 8 +
319           ((lineno / 1 ) % 3) * 64);
320
321  memcpy (st->hireslines[row], &image[row * 40], 40);
322}
323
324/*
325  Simulate plausible initial memory contents for running a program.
326*/
327void
328a2_init_memory_active(apple2_sim_t *sim)
329{
330  int i,j,x,y,c;
331  int addr=0;
332  apple2_state_t *st=sim->st;
333
334  while (addr<0x4000) {
335    int n;
336
337    switch (random()%4) {
338    case 0:
339    case 1:
340      n=random()%500;
341      for (i=0; i<n && addr<0x4000; i++) {
342        u_char rb=((random()%6==0 ? 0 : random()%16) |
343                   ((random()%5==0 ? 0 : random()%16)<<4));
344        a2_poke(st, addr++, rb);
345      }
346      break;
347
348    case 2:
349      /* Simulate shapes stored in memory. We use the font since we have it.
350         Unreadable, since rows of each character are stored in consecutive
351         bytes. It was typical to store each of the 7 possible shifts of
352         bitmaps, for fastest blitting to the screen. */
353      x=random()%(sim->text_im->width);
354      for (i=0; i<100; i++) {
355        for (y=0; y<8; y++) {
356          c=0;
357          for (j=0; j<8; j++) {
358            c |= XGetPixel(sim->text_im, (x+j)%sim->text_im->width, y)<<j;
359          }
360          a2_poke(st, addr++, c);
361        }
362        x=(x+1)%(sim->text_im->width);
363      }
364      break;
365
366    case 3:
367      if (addr>0x2000) {
368        n=random()%200;
369        for (i=0; i<n && addr<0x4000; i++) {
370          a2_poke(st, addr++, 0);
371        }
372      }
373      break;
374
375    }
376  }
377}
378
379
380/* This table lists fixes for characters that differ from the standard 6x10
381   font. Each encodes a pixel, as (charindex*7 + x) + (y<<10) + (value<<15)
382   where value is 0 for white and 1 for black. */
383static unsigned short a2_fixfont[] = {
384  /* Fix $ */  0x8421, 0x941d,
385  /* Fix % */  0x8024, 0x0028, 0x8425, 0x0426, 0x0825, 0x1027, 0x1426, 0x9427,
386               0x1824, 0x9828,
387  /* Fix * */  0x8049, 0x8449, 0x8849, 0x0c47, 0x0c48, 0x0c4a, 0x0c4b, 0x9049,
388               0x9449, 0x9849,
389  /* Fix , */  0x9057, 0x1458, 0x9856, 0x1857, 0x1c56,
390  /* Fix . */  0x1465, 0x1864, 0x1866, 0x1c65,
391  /* Fix / */  0x006e, 0x186a,
392  /* Fix 0 */  0x8874, 0x8c73, 0x9072,
393  /* Fix 1 */  0x0878, 0x1878, 0x187c,
394  /* Fix 5 */  0x8895, 0x0c94, 0x0c95,
395  /* Fix 6 */  0x809f, 0x8c9c, 0x109c,
396  /* Fix 7 */  0x8ca4, 0x0ca5, 0x90a3, 0x10a4,
397  /* Fix 9 */  0x08b3, 0x8cb3, 0x98b0,
398  /* Fix : */  0x04b9, 0x08b8, 0x08ba, 0x0cb9, 0x90b9, 0x14b9, 0x18b8, 0x18b9,
399               0x18ba, 0x1cb9,
400  /* Fix ; */  0x04c0, 0x08bf, 0x08c1, 0x0cc0, 0x90c0, 0x14c1, 0x98bf, 0x18c0,
401               0x1cbf,
402  /* Fix < */  0x80c8, 0x00c9, 0x84c7, 0x04c8, 0x88c6, 0x08c7, 0x8cc5, 0x0cc6,
403               0x90c6, 0x10c7,
404               0x94c7, 0x14c8, 0x98c8, 0x18c9,
405  /* Fix > */  0x80d3, 0x00d4, 0x84d4, 0x04d5, 0x88d5, 0x08d6, 0x8cd6, 0x0cd7,
406               0x90d5, 0x10d6,
407               0x94d4, 0x14d5, 0x98d3, 0x18d4,
408  /* Fix @ */  0x88e3, 0x08e4, 0x8ce4, 0x98e5,
409  /* Fix B */  0x84ef, 0x04f0, 0x88ef, 0x08f0, 0x8cef, 0x90ef, 0x10f0, 0x94ef,
410               0x14f0,
411  /* Fix D */  0x84fd, 0x04fe, 0x88fd, 0x08fe, 0x8cfd, 0x0cfe, 0x90fd, 0x10fe,
412               0x94fd, 0x14fe,
413  /* Fix G */  0x8116, 0x0516, 0x9916,
414  /* Fix J */  0x0129, 0x012a, 0x052a, 0x852b, 0x092a, 0x892b, 0x0d2a, 0x8d2b,
415               0x112a, 0x912b,
416               0x152a, 0x952b, 0x992a,
417  /* Fix M */  0x853d, 0x853f, 0x093d, 0x893e, 0x093f,
418  /* Fix Q */  0x915a, 0x155a, 0x955b, 0x155c, 0x195b, 0x995c, 0x1d5c,
419  /* Fix V */  0x8d7b, 0x0d7c, 0x0d7e, 0x8d7f, 0x917b, 0x117c, 0x117e, 0x917f,
420  /* Fix [ */  0x819e, 0x81a2, 0x859e, 0x899e, 0x8d9e, 0x919e, 0x959e, 0x999e,
421               0x99a2,
422  /* Fix \ */  0x01a5, 0x19a9,
423  /* Fix ] */  0x81ac, 0x81b0, 0x85b0, 0x89b0, 0x8db0, 0x91b0, 0x95b0, 0x99ac,
424               0x99b0,
425  /* Fix ^ */  0x01b5, 0x05b4, 0x05b6, 0x09b3, 0x89b5, 0x09b7, 0x8db4, 0x8db6,
426               0x91b3, 0x91b7,
427  /* Fix _ */  0x9db9, 0x9dbf,
428  0,
429};
430
431static void
432a2_make_font(apple2_sim_t *sim)
433{
434  /*
435    Generate the font. It used a 5x7 font which looks a lot like the standard X
436    6x10 font, with a few differences. So we render up all the uppercase
437    letters of 6x10, and make a few tweaks (like putting a slash across the
438    zero) according to fixfont.
439   */
440
441  int i;
442  const char *def_font="6x10";
443  XFontStruct *font;
444  Pixmap text_pm;
445  GC gc;
446  XGCValues gcv;
447
448  font = XLoadQueryFont (sim->dpy, def_font);
449  if (!font) {
450    fprintf(stderr, "%s: can't load font %s\n", progname, def_font);
451    abort();
452  }
453
454  text_pm=XCreatePixmap(sim->dpy, sim->window, 64*7, 8, sim->dec->xgwa.depth);
455
456  memset(&gcv, 0, sizeof(gcv));
457  gcv.foreground=1;
458  gcv.background=0;
459  gcv.font=font->fid;
460  gc=XCreateGC(sim->dpy, text_pm, GCFont|GCBackground|GCForeground, &gcv);
461
462  XSetForeground(sim->dpy, gc, 0);
463  XFillRectangle(sim->dpy, text_pm, gc, 0, 0, 64*7, 8);
464  XSetForeground(sim->dpy, gc, 1);
465  for (i=0; i<64; i++) {
466    char c=32+i;
467    int x=7*i+1;
468    int y=7;
469    if (c=='0') {
470      c='O';
471      XDrawString(sim->dpy, text_pm, gc, x, y, &c, 1);
472    } else {
473      XDrawString(sim->dpy, text_pm, gc, x, y, &c, 1);
474    }
475  }
476  sim->text_im = XGetImage(sim->dpy, text_pm, 0, 0, 64*7, 8, ~0L, ZPixmap);
477  XFreeGC(sim->dpy, gc);
478  XFreePixmap(sim->dpy, text_pm);
479
480  for (i=0; a2_fixfont[i]; i++) {
481    XPutPixel(sim->text_im, a2_fixfont[i]&0x3ff,
482              (a2_fixfont[i]>>10)&0xf,
483              (a2_fixfont[i]>>15)&1);
484  }
485}
486
487
488void
489apple2(Display *dpy, Window window, int delay,
490       void (*controller)(apple2_sim_t *sim,
491                          int *stepno,
492                          double *next_actiontime))
493{
494  int i,textrow,row,col,stepno;
495  int c;
496  double next_actiontime;
497  apple2_sim_t *sim;
498
499  sim=(apple2_sim_t *)calloc(1,sizeof(apple2_state_t));
500  sim->dpy = dpy;
501  sim->window = window;
502  sim->delay = delay;
503
504  sim->st = (apple2_state_t *)calloc(1,sizeof(apple2_state_t));
505  sim->dec = analogtv_allocate(dpy, window);
506  sim->dec->event_handler = screenhack_handle_event;
507  sim->inp = analogtv_input_allocate();
508
509  sim->reception.input = sim->inp;
510  sim->reception.level = 1.0;
511
512  sim->prompt=']';
513
514  if (random()%4==0 && !sim->dec->use_cmap && sim->dec->use_color && sim->dec->visbits>=8) {
515    sim->dec->flutter_tint=1;
516  }
517  else if (random()%3==0) {
518    sim->dec->flutter_horiz_desync=1;
519  }
520  sim->typing_rate = 1.0;
521
522  analogtv_set_defaults(sim->dec, "");
523  sim->dec->squish_control=0.05;
524  analogtv_setup_sync(sim->inp, 1, 0);
525
526
527  a2_make_font(sim);
528
529  stepno=0;
530  a2_goto(sim->st,23,0);
531
532  if (random()%2==0) sim->basetime_tv.tv_sec -= 1; /* random blink phase */
533  next_actiontime=0.0;
534
535  sim->curtime=0.0;
536  next_actiontime=sim->curtime;
537  (*controller)(sim, &stepno, &next_actiontime);
538
539# ifdef GETTIMEOFDAY_TWO_ARGS
540  gettimeofday(&sim->basetime_tv, NULL);
541# else
542  gettimeofday(&sim->basetime_tv);
543# endif
544
545  while (1) {
546    double blinkphase;
547
548    {
549      struct timeval curtime_tv;
550# ifdef GETTIMEOFDAY_TWO_ARGS
551      struct timezone tzp;
552      gettimeofday(&curtime_tv, &tzp);
553# else
554      gettimeofday(&curtime_tv);
555# endif
556      sim->curtime=(curtime_tv.tv_sec - sim->basetime_tv.tv_sec) +
557        0.000001*(curtime_tv.tv_usec - sim->basetime_tv.tv_usec);
558      if (sim->curtime > sim->dec->powerup)
559        sim->dec->powerup=sim->curtime;
560    }
561
562    if (analogtv_handle_events(sim->dec)) {
563      sim->typing=NULL;
564      sim->printing=NULL;
565      stepno=A2CONTROLLER_FREE;
566      next_actiontime = sim->curtime;
567      (*controller)(sim, &stepno, &next_actiontime);
568      stepno=0;
569      sim->controller_data=NULL;
570      sim->st->gr_mode=0;
571      continue;
572    }
573
574    blinkphase=sim->curtime/0.8;
575
576    /* The blinking rate was controlled by 555 timer with a resistor/capacitor
577       time constant. Because the capacitor was electrolytic, the flash rate
578       varied somewhat between machines. I'm guessing 1.6 seconds/cycle was
579       reasonable. (I soldered a resistor in mine to make it blink faster.) */
580    i=sim->st->blink;
581    sim->st->blink=((int)blinkphase)&1;
582    if (sim->st->blink!=i && !(sim->st->gr_mode&A2_GR_FULL)) {
583      int downcounter=0;
584      /* For every row with blinking text, set the changed flag. This basically
585         works great except with random screen garbage in text mode, when we
586         end up redrawing the whole screen every second */
587      for (row=(sim->st->gr_mode ? 20 : 0); row<24; row++) {
588        for (col=0; col<40; col++) {
589          c=sim->st->textlines[row][col];
590          if ((c & 0xc0) == 0x40) {
591            downcounter=4;
592            break;
593          }
594        }
595        if (downcounter>0) {
596          downcounter--;
597        }
598      }
599    }
600
601    if (sim->printing) {
602      int nlcnt=0;
603      while (*sim->printing) {
604        if (*sim->printing=='\001') { /* pause */
605          sim->printing++;
606          break;
607        }
608        else if (*sim->printing=='\n') {
609          a2_printc(sim->st,*sim->printing);
610          sim->printing++;
611          nlcnt++;
612          if (nlcnt>=2) break;
613        }
614        else {
615          a2_printc(sim->st,*sim->printing);
616          sim->printing++;
617        }
618      }
619      if (!*sim->printing) sim->printing=NULL;
620    }
621    else if (sim->curtime >= next_actiontime) {
622      if (sim->typing) {
623
624        int c;
625        /* If we're in the midst of typing a string, emit a character with
626           random timing. */
627        c =*sim->typing++;
628        if (c==0) {
629          sim->typing=NULL;
630        }
631        else {
632          a2_printc(sim->st, c);
633          if (c=='\r' || c=='\n') {
634            next_actiontime = sim->curtime;
635          }
636          else if (c==010) {
637            next_actiontime = sim->curtime + 0.1;
638          }
639          else {
640            next_actiontime = (sim->curtime +
641                               (((random()%1000)*0.001 + 0.3) *
642                                sim->typing_rate));
643          }
644        }
645      } else {
646        next_actiontime=sim->curtime;
647
648        (*controller)(sim, &stepno, &next_actiontime);
649        if (stepno==A2CONTROLLER_DONE) goto finished;
650
651      }
652    }
653
654
655    analogtv_setup_sync(sim->inp, sim->st->gr_mode? 1 : 0, 0);
656    analogtv_setup_frame(sim->dec);
657
658    for (textrow=0; textrow<24; textrow++) {
659      for (row=textrow*8; row<textrow*8+8; row++) {
660
661        /* First we generate the pattern that the video circuitry shifts out
662           of memory. It has a 14.something MHz dot clock, equal to 4 times
663           the color burst frequency. So each group of 4 bits defines a color.
664           Each character position, or byte in hires, defines 14 dots, so odd
665           and even bytes have different color spaces. So, pattern[0..600]
666           gets the dots for one scan line. */
667
668        char *pp=&sim->inp->signal[row+ANALOGTV_TOP+4][ANALOGTV_PIC_START+100];
669
670        if ((sim->st->gr_mode&A2_GR_HIRES) &&
671            (row<160 || (sim->st->gr_mode&A2_GR_FULL))) {
672
673          /* Emulate the mysterious pink line, due to a bit getting
674             stuck in a shift register between the end of the last
675             row and the beginning of this one. */
676          if ((sim->st->hireslines[row][0] & 0x80) &&
677              (sim->st->hireslines[row][39]&0x40)) {
678            pp[-1]=ANALOGTV_WHITE_LEVEL;
679          }
680
681          for (col=0; col<40; col++) {
682            u_char b=sim->st->hireslines[row][col];
683            int shift=(b&0x80)?0:1;
684
685            /* Each of the low 7 bits in hires mode corresponded to 2 dot
686               clocks, shifted by one if the high bit was set. */
687            for (i=0; i<7; i++) {
688              pp[shift+1] = pp[shift] = (((b>>i)&1)
689                                         ?ANALOGTV_WHITE_LEVEL
690                                         :ANALOGTV_BLACK_LEVEL);
691              pp+=2;
692            }
693          }
694        }
695        else if ((sim->st->gr_mode&A2_GR_LORES) &&
696                 (row<160 || (sim->st->gr_mode&A2_GR_FULL))) {
697          for (col=0; col<40; col++) {
698            u_char nib=((sim->st->textlines[textrow][col] >> (((row/4)&1)*4))
699                        & 0xf);
700            /* The low or high nybble was shifted out one bit at a time. */
701            for (i=0; i<14; i++) {
702              *pp = (((nib>>((col*14+i)&3))&1)
703                     ?ANALOGTV_WHITE_LEVEL
704                     :ANALOGTV_BLACK_LEVEL);
705              pp++;
706            }
707          }
708        }
709        else {
710          for (col=0; col<40; col++) {
711            int rev;
712            c=sim->st->textlines[textrow][col]&0xff;
713            /* hi bits control inverse/blink as follows:
714               0x00: inverse
715               0x40: blink
716               0x80: normal
717               0xc0: normal */
718            rev=!(c&0x80) && (!(c&0x40) || sim->st->blink);
719
720            for (i=0; i<7; i++) {
721              unsigned long pix=XGetPixel(sim->text_im,
722                                          ((c&0x3f)^0x20)*7+i,
723                                          row%8);
724              pp[1] = pp[2] = ((pix^rev)
725                               ?ANALOGTV_WHITE_LEVEL
726                               :ANALOGTV_BLACK_LEVEL);
727              pp+=2;
728            }
729          }
730        }
731      }
732    }
733    analogtv_init_signal(sim->dec, 0.02);
734    analogtv_reception_update(&sim->reception);
735    analogtv_add_signal(sim->dec, &sim->reception);
736    analogtv_draw(sim->dec);
737  }
738
739 finished:
740
741  stepno=A2CONTROLLER_FREE;
742  (*controller)(sim, &stepno, &next_actiontime);
743
744  XSync(sim->dpy, False);
745  XClearWindow(sim->dpy, sim->window);
746}
747
748void
749a2controller_test(apple2_sim_t *sim, int *stepno, double *next_actiontime)
750{
751  int row,col;
752
753  switch(*stepno) {
754  case 0:
755    a2_invalidate(sim->st);
756    /*
757      For testing color rendering. The spec is:
758      red grn blu
759      0  black       0   0   0
760      1  red       227  30  96
761      2  dk blue    96  78 189
762      3  purple    255  68 253
763      4  dk green    0 163  96
764      5  gray      156 156 156
765      6  med blue   20 207 253
766      7  lt blue   208 195 255
767      8  brown      96 114   3
768      9  orange    255 106  60
769      10 grey      156 156 156
770      11 pink      255 160 208
771      12 lt green   20 245  60
772      13 yellow    208 221 141
773      14 aqua      114 255 208
774      15 white     255 255 255
775    */
776    sim->st->gr_mode=A2_GR_LORES;
777    for (row=0; row<24; row++) {
778      for (col=0; col<40; col++) {
779        sim->st->textlines[row][col]=(row&15)*17;
780      }
781    }
782    *next_actiontime+=0.4;
783    *stepno=99;
784    break;
785
786  case 99:
787    if (sim->curtime > 10) *stepno=-1;
788    break;
789  }
790}
Note: See TracBrowser for help on using the repository browser.