http://www.jwz.org/xscreensaver/xscreensaver-5.13.tar.gz
[xscreensaver] / hacks / m6502.c
1 /* -*- indent-tabs-mode:nil -*-
2  * Copyright (c) 2007 Jeremy English <jhe@jeremyenglish.org>
3  * 
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation.  No representations are made about the suitability of this
9  * software for any purpose.  It is provided "as is" without express or 
10  * implied warranty.
11  * 
12  * Created: 07-May-2007 
13  */
14
15 #include <stdint.h> 
16 #include <string.h>
17 #include "screenhack.h"
18 #include "analogtv.h"
19 #include "asm6502.h"
20
21 # ifdef __GNUC__
22   __extension__  /* don't warn about "string length is greater than the length
23                     ISO C89 compilers are required to support" when includng
24                     the following data file... */
25 # endif
26 const char * const demo_files[] = {
27 # include "m6502.h"
28 };
29
30
31 /* We want to paint on a 32 by 32 grid of pixels. We will needed to
32    divided the screen up into chuncks */
33 enum {
34   SCREEN_W = ANALOGTV_VIS_LEN,
35   SCREEN_H = ANALOGTV_VISLINES,
36   NUM_PROGS = 9
37 };
38
39 struct state {
40   Display *dpy;
41   Window window;
42   
43   Bit8 pixels[32][32];
44
45   machine_6502 *machine;
46
47   analogtv *tv;
48   analogtv_input *inp;
49   analogtv_reception reception;
50   int pixw; /* pixel width */
51   int pixh;/* pixel height */
52   int topb;/* top boarder */
53   int field_ntsc[4];/* used for clearing the screen*/ 
54   int dt;/* how long to wait before changing the demo*/
55   int which;/* the program to run*/
56   int demos;/* number of demos included */
57   struct timeval start_time; 
58 };
59
60 static void
61 plot6502(Bit8 x, Bit8 y, Bit8 color, void *closure)
62 {
63   struct state *st = (struct state *) closure;
64   st->pixels[x][y] = color;
65 }
66
67 #undef countof
68 #define countof(x) (sizeof((x))/sizeof((*x)))
69
70
71 static void 
72 start_rand_bin_prog(machine_6502 *machine, struct state *st){
73   int n = st->which;
74   while(n == st->which)
75     n = random() % st->demos;
76   st->which = n;
77   start_eval_string(machine, demo_files[st->which], plot6502, st);
78 }
79
80 \f
81 /*
82  * get_time ()
83  *
84  * returns the total time elapsed since the beginning of the demo
85  */
86 static double get_time(struct state *st) {
87   struct timeval t;
88   float f;
89 #if GETTIMEOFDAY_TWO_ARGS
90   gettimeofday(&t, NULL);
91 #else
92   gettimeofday(&t);
93 #endif
94   t.tv_sec -= st->start_time.tv_sec;
95   f = ((double)t.tv_sec) + t.tv_usec*1e-6;
96   return f;
97 }
98
99 /*
100  * init_time ()
101  *
102  * initialises the timing structures
103  */
104 static void init_time(struct state *st) {
105 #if GETTIMEOFDAY_TWO_ARGS
106   gettimeofday(&st->start_time, NULL);
107 #else
108   gettimeofday(&st->start_time);
109 #endif
110 }
111
112 static void *
113 m6502_init (Display *dpy, Window window)
114 {
115   struct state *st = (struct state *) calloc (1, sizeof(*st));
116   unsigned int x, y;
117   char *s = get_string_resource (dpy, "file", "File");
118   int n = get_integer_resource(dpy, "displaytime", "Displaytime");
119   int dh;
120   st->demos = countof(demo_files);
121   st->which = random() % st->demos;
122   st->dt = n;
123   st->dpy = dpy;
124   st->window = window;
125   st->tv=analogtv_allocate(st->dpy, st->window);
126   analogtv_set_defaults(st->tv, "");
127   
128   st->machine = build6502();
129   st->inp=analogtv_input_allocate();
130   analogtv_setup_sync(st->inp, 1, 0);
131   
132   st->reception.input = st->inp;
133   st->reception.level = 2.0;
134   st->reception.ofs=0;
135   
136   st->reception.multipath=0.0;
137   st->pixw = SCREEN_W / 32;
138   st->pixh = SCREEN_H / 32;
139   dh = SCREEN_H % 32;
140   st->topb = dh / 2;
141
142   init_time(st);
143   
144   if (strlen(s) > 0)
145     start_eval_file(st->machine,s, plot6502, st);
146   else
147     start_rand_bin_prog(st->machine,st);
148
149   analogtv_lcp_to_ntsc(ANALOGTV_BLACK_LEVEL, 0.0, 0.0, st->field_ntsc);
150
151   analogtv_draw_solid(st->inp,
152                       ANALOGTV_VIS_START, ANALOGTV_VIS_END,
153                       ANALOGTV_TOP, ANALOGTV_BOT,
154                       st->field_ntsc);
155
156   for(x = 0; x < 32; x++)
157     for(y = 0; y < 32; y++)
158       st->pixels[x][y] = 0;
159
160   return st;
161 }
162
163 static void
164 paint_pixel(struct state *st, int x, int y, int idx)
165 {
166   double clr_tbl[16][3] = {
167     {  0,   0,   0},
168     {255, 255, 255},
169     {136,   0,   0},
170     {170, 255, 238},
171     {204,  68, 204},
172     {  0, 204,  85},
173     {  0,   0, 170},
174     {238, 238, 119},
175     {221, 136,  85},
176     {102,  68,   0},
177     {255, 119, 119},
178     { 51,  51,  51},
179     {119, 119, 119},
180     {170, 255, 102},
181     {  0, 136, 255},
182     {187, 187, 187}
183   };
184   int ntsc[4], i;
185   int rawy,rawi,rawq;
186   /* RGB conversion taken from analogtv draw xpm */
187   rawy=( 5*clr_tbl[idx][0] + 11*clr_tbl[idx][1] + 2*clr_tbl[idx][2]) / 64;
188   rawi=(10*clr_tbl[idx][0] -  4*clr_tbl[idx][1] - 5*clr_tbl[idx][2]) / 64;
189   rawq=( 3*clr_tbl[idx][0] -  8*clr_tbl[idx][1] + 5*clr_tbl[idx][2]) / 64;
190
191   ntsc[0]=rawy+rawq;
192   ntsc[1]=rawy-rawi;
193   ntsc[2]=rawy-rawq;
194   ntsc[3]=rawy+rawi;
195
196   for (i=0; i<4; i++) {
197     if (ntsc[i]>ANALOGTV_WHITE_LEVEL) ntsc[i]=ANALOGTV_WHITE_LEVEL;
198     if (ntsc[i]<ANALOGTV_BLACK_LEVEL) ntsc[i]=ANALOGTV_BLACK_LEVEL;
199   }
200
201       
202   x *= st->pixw;
203   y *= st->pixh;
204   y += st->topb;
205   analogtv_draw_solid(st->inp,
206                       ANALOGTV_VIS_START + x, ANALOGTV_VIS_START + x + st->pixw,
207                       ANALOGTV_TOP + y, ANALOGTV_TOP + y + st->pixh, ntsc);                           
208 }
209
210 static unsigned long
211 m6502_draw (Display *dpy, Window window, void *closure)
212 {
213   struct state *st = (struct state *) closure;
214   unsigned int x = 0, y = 0;
215   double te;
216
217   next_eval(st->machine,500);
218
219   for (x = 0; x < 32; x++)
220     for (y = 0; y < 32; y++)
221       paint_pixel(st,x,y,st->pixels[x][y]);
222   
223   analogtv_init_signal(st->tv, 0.04);
224   analogtv_reception_update(&st->reception);
225   analogtv_add_signal(st->tv, &st->reception);
226   analogtv_draw(st->tv);
227   te = get_time(st);
228   
229   if (te > st->dt){ /* do something more interesting here XXX */
230     for(x = 0; x < 32; x++)
231       for(y = 0; y < 32; y++)
232         st->pixels[x][y] = 0;
233     init_time(st);
234     start_rand_bin_prog(st->machine,st);
235   }
236
237   return 10000;
238 }
239
240
241 \f
242
243 static const char *m6502_defaults [] = {
244   ".background:      black",
245   ".foreground:      white",
246   "*file:",
247   "*displaytime:     20",
248   ANALOGTV_DEFAULTS
249   "*TVContrast:      150",
250   0
251 };
252
253 static XrmOptionDescRec m6502_options [] = {
254   { "-file",           ".file",     XrmoptionSepArg, 0 },
255   { "-displaytime",    ".displaytime", XrmoptionSepArg, 0},
256   ANALOGTV_OPTIONS
257   { 0, 0, 0, 0 }
258 };
259
260 static void
261 m6502_reshape (Display *dpy, Window window, void *closure, 
262                  unsigned int w, unsigned int h)
263 {
264   struct state *st = (struct state *) closure;
265   analogtv_reconfigure (st->tv);
266 }
267
268 static Bool
269 m6502_event (Display *dpy, Window window, void *closure, XEvent *event)
270 {
271   return False;
272 }
273
274 static void
275 m6502_free (Display *dpy, Window window, void *closure)
276 {
277   struct state *st = (struct state *) closure;
278   analogtv_release(st->tv);
279   free (st);
280 }
281
282 XSCREENSAVER_MODULE ("m6502", m6502)