From http://www.jwz.org/xscreensaver/xscreensaver-5.35.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 <inttypes.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 static const char * const demo_files[] = {
27 # include "m6502.h"
28 };
29
30
31 #ifndef HAVE_MOBILE
32 # define READ_FILES
33 #endif
34
35
36 /* We want to paint on a 32 by 32 grid of pixels. We will needed to
37    divided the screen up into chuncks */
38 enum {
39   SCREEN_W = ANALOGTV_VIS_LEN,
40   SCREEN_H = ANALOGTV_VISLINES,
41   NUM_PROGS = 9
42 };
43
44 struct state {
45   Display *dpy;
46   Window window;
47   
48   Bit8 pixels[32][32];
49
50   machine_6502 *machine;
51
52   analogtv *tv;
53   analogtv_input *inp;
54   analogtv_reception reception;
55   int pixw; /* pixel width */
56   int pixh;/* pixel height */
57   int topb;/* top boarder */
58   int field_ntsc[4];/* used for clearing the screen*/ 
59   int dt;/* how long to wait before changing the demo*/
60   int which;/* the program to run*/
61   int demos;/* number of demos included */
62   struct timeval start_time; 
63   int reset_p;
64 };
65
66 static void
67 plot6502(Bit8 x, Bit8 y, Bit8 color, void *closure)
68 {
69   struct state *st = (struct state *) closure;
70   st->pixels[x][y] = color;
71 }
72
73 #undef countof
74 #define countof(x) (sizeof((x))/sizeof((*x)))
75
76
77 static void 
78 start_rand_bin_prog(machine_6502 *machine, struct state *st){
79   int n = st->which;
80   while(n == st->which)
81     n = random() % st->demos;
82   st->which = n;
83   m6502_start_eval_string(machine, demo_files[st->which], plot6502, st);
84 }
85
86 \f
87 /*
88  * get_time ()
89  *
90  * returns the total time elapsed since the beginning of the demo
91  */
92 static double get_time(struct state *st) {
93   struct timeval t;
94   float f;
95 #if GETTIMEOFDAY_TWO_ARGS
96   gettimeofday(&t, NULL);
97 #else
98   gettimeofday(&t);
99 #endif
100   t.tv_sec -= st->start_time.tv_sec;
101   f = ((double)t.tv_sec) + t.tv_usec*1e-6;
102   return f;
103 }
104
105 /*
106  * init_time ()
107  *
108  * initialises the timing structures
109  */
110 static void init_time(struct state *st) {
111 #if GETTIMEOFDAY_TWO_ARGS
112   gettimeofday(&st->start_time, NULL);
113 #else
114   gettimeofday(&st->start_time);
115 #endif
116 }
117
118 static void *
119 m6502_init (Display *dpy, Window window)
120 {
121   struct state *st = (struct state *) calloc (1, sizeof(*st));
122   unsigned int x, y;
123   int n = get_integer_resource(dpy, "displaytime", "Displaytime");
124   int dh;
125   st->demos = countof(demo_files);
126   st->which = random() % st->demos;
127   st->dt = n;
128   st->dpy = dpy;
129   st->window = window;
130   st->tv=analogtv_allocate(st->dpy, st->window);
131   analogtv_set_defaults(st->tv, "");
132   
133   st->machine = m6502_build();
134   st->inp=analogtv_input_allocate();
135   analogtv_setup_sync(st->inp, 1, 0);
136   
137   st->reception.input = st->inp;
138   st->reception.level = 2.0;
139   st->reception.ofs=0;
140   
141   st->reception.multipath=0.0;
142   st->pixw = SCREEN_W / 32;
143   st->pixh = SCREEN_H / 32;
144   dh = SCREEN_H % 32;
145   st->topb = dh / 2;
146
147   init_time(st);
148   
149   {
150 #ifdef READ_FILES
151     char *s = get_string_resource (dpy, "file", "File");
152     if (strlen(s) > 0)
153       m6502_start_eval_file(st->machine,s, plot6502, st);
154   else
155 #endif
156     start_rand_bin_prog(st->machine,st);
157   }
158
159   analogtv_lcp_to_ntsc(ANALOGTV_BLACK_LEVEL, 0.0, 0.0, st->field_ntsc);
160
161   analogtv_draw_solid(st->inp,
162                       ANALOGTV_VIS_START, ANALOGTV_VIS_END,
163                       ANALOGTV_TOP, ANALOGTV_BOT,
164                       st->field_ntsc);
165
166   for(x = 0; x < 32; x++)
167     for(y = 0; y < 32; y++)
168       st->pixels[x][y] = 0;
169
170   return st;
171 }
172
173 static void
174 paint_pixel(struct state *st, int x, int y, int idx)
175 {
176   double clr_tbl[16][3] = {
177     {  0,   0,   0},
178     {255, 255, 255},
179     {136,   0,   0},
180     {170, 255, 238},
181     {204,  68, 204},
182     {  0, 204,  85},
183     {  0,   0, 170},
184     {238, 238, 119},
185     {221, 136,  85},
186     {102,  68,   0},
187     {255, 119, 119},
188     { 51,  51,  51},
189     {119, 119, 119},
190     {170, 255, 102},
191     {  0, 136, 255},
192     {187, 187, 187}
193   };
194   int ntsc[4], i;
195   int rawy,rawi,rawq;
196   /* RGB conversion taken from analogtv draw xpm */
197   rawy=( 5*clr_tbl[idx][0] + 11*clr_tbl[idx][1] + 2*clr_tbl[idx][2]) / 64;
198   rawi=(10*clr_tbl[idx][0] -  4*clr_tbl[idx][1] - 5*clr_tbl[idx][2]) / 64;
199   rawq=( 3*clr_tbl[idx][0] -  8*clr_tbl[idx][1] + 5*clr_tbl[idx][2]) / 64;
200
201   ntsc[0]=rawy+rawq;
202   ntsc[1]=rawy-rawi;
203   ntsc[2]=rawy-rawq;
204   ntsc[3]=rawy+rawi;
205
206   for (i=0; i<4; i++) {
207     if (ntsc[i]>ANALOGTV_WHITE_LEVEL) ntsc[i]=ANALOGTV_WHITE_LEVEL;
208     if (ntsc[i]<ANALOGTV_BLACK_LEVEL) ntsc[i]=ANALOGTV_BLACK_LEVEL;
209   }
210
211       
212   x *= st->pixw;
213   y *= st->pixh;
214   y += st->topb;
215   analogtv_draw_solid(st->inp,
216                       ANALOGTV_VIS_START + x, ANALOGTV_VIS_START + x + st->pixw,
217                       ANALOGTV_TOP + y, ANALOGTV_TOP + y + st->pixh, ntsc);                           
218 }
219
220 static unsigned long
221 m6502_draw (Display *dpy, Window window, void *closure)
222 {
223   struct state *st = (struct state *) closure;
224   unsigned int x = 0, y = 0;
225   double te;
226   const analogtv_reception *reception = &st->reception;
227
228   m6502_next_eval(st->machine,500);
229
230   for (x = 0; x < 32; x++)
231     for (y = 0; y < 32; y++)
232       paint_pixel(st,x,y,st->pixels[x][y]);
233   
234   analogtv_reception_update(&st->reception);
235   analogtv_draw(st->tv, 0.04, &reception, 1);
236   te = get_time(st);
237   
238   if (st->reset_p || te > st->dt){ /* do something more interesting here XXX */
239     st->reset_p = 0;
240     for(x = 0; x < 32; x++)
241       for(y = 0; y < 32; y++)
242         st->pixels[x][y] = 0;
243     init_time(st);
244     start_rand_bin_prog(st->machine,st);
245   }
246
247 #ifdef HAVE_MOBILE
248   return 0;
249 #else
250   return 5000;
251 #endif
252 }
253
254
255 \f
256
257 static const char *m6502_defaults [] = {
258   ".background:      black",
259   ".foreground:      white",
260   "*file:",
261   "*displaytime:     20",
262   ANALOGTV_DEFAULTS
263   0
264 };
265
266 static XrmOptionDescRec m6502_options [] = {
267   { "-file",           ".file",     XrmoptionSepArg, 0 },
268   { "-displaytime",    ".displaytime", XrmoptionSepArg, 0},
269   ANALOGTV_OPTIONS
270   { 0, 0, 0, 0 }
271 };
272
273 static void
274 m6502_reshape (Display *dpy, Window window, void *closure, 
275                  unsigned int w, unsigned int h)
276 {
277   struct state *st = (struct state *) closure;
278   analogtv_reconfigure (st->tv);
279 }
280
281 static Bool
282 m6502_event (Display *dpy, Window window, void *closure, XEvent *event)
283 {
284   struct state *st = (struct state *) closure;
285   if (screenhack_event_helper (dpy, window, event))
286     {
287       st->reset_p = 1;
288       return True;
289     }
290   return False;
291 }
292
293 static void
294 m6502_free (Display *dpy, Window window, void *closure)
295 {
296   struct state *st = (struct state *) closure;
297   analogtv_release(st->tv);
298   free (st);
299 }
300
301 XSCREENSAVER_MODULE ("m6502", m6502)