]> Shamusworld >> Repos - thunder/blob - src/gui.cpp
Initial conversion to SDL 2.
[thunder] / src / gui.cpp
1 //
2 // Thunder Graphic User Interface
3 //
4 // by James Hammons
5 // (c) 2004, 2014 Underground Software
6 //
7 // JLH = James Hammons <jlhamm@acm.org>
8 //
9 // WHO  WHEN        WHAT
10 // ---  ----------  -----------------------------------------------------------
11 // JLH  07/23/2009  Added changelog ;-)
12 //
13
14 #include "gui.h"
15
16 #include <string>
17 #include <fstream>       // Needed for tracelog
18 #include "screen.h"
19 #include "resource.h"    // Thunder graphics & sounds
20
21 using namespace std;
22
23 // External shit
24
25 extern SDL_Surface * screen;
26
27 extern uint8_t my_scr[0x14000];         // Screen buffer...
28 extern uint8_t gram1[];                         // Game RAM (do here??)
29 extern uint8_t hScrollOffset;           // Horizontal scroll offset
30 extern uint8_t vScrollOffset;           // Vertical scroll offset
31 extern uint32_t voffsets[8];
32 extern uint8_t voice_rom[];                     // PCM data pointer
33 extern fstream tr;                                      // Tracelog
34
35 // Global shit
36
37 uint16_t text_life;                             // How long text is visible
38 bool show_text;                                 // Whether or not to show text
39 uint16_t show_which_msg;                // Which message to show
40 bool show_gui;                                  // Whether or not to show GUI
41 uint16_t selection;                             // Which GUI item currently selected
42 uint16_t snd_num;
43 uint16_t gui_debounce;                  // GUI key debounce value
44 uint16_t num_coins;                             // Number of coins dropped
45 uint16_t blink = 0;                             // Used to blink player 1 & 2 start buttons
46 uint16_t flash = 23;                    // Used to flash GUI lights
47 uint16_t iline = 0;                             // Used to roll line
48 uint16_t dcurcol = 179;                 // dipswitch cursor color
49 int  dcurdir = 1;                               // Initially going up...
50 bool blink_on = false;
51 bool game_refresh;                              // Refresh rate user set
52 bool do_decrement;                              // Flag to handle decrement...
53 bool user_selected_something;   // Flag for well, you know...
54 uint16_t dswitch;                               // Which dipswitch is selected...
55
56 // The following are global for the sound routines...
57
58 const float sampleBase = 22050.0/6000.0;  // Btwn 5512.5 and 6000
59 bool snd_go = false;
60 bool chan1_go = false, chan2_go = false, chan3_go = false;
61 bool chan4_go = false, chan5_go = false, chan6_go = false;
62 uint8_t * sndp1, * sndp2, * sndp3, * sndp4, * sndp5, * sndp6;
63 uint32_t rom_pos, end_pos;
64 uint32_t spos1, end_pos1;
65 uint32_t spos2, end_pos2;
66 uint32_t spos3, end_pos3;
67 uint32_t spos4, end_pos4;
68 uint32_t spos5, end_pos5;
69 uint32_t spos6, end_pos6;
70 float sample1;
71 uint8_t prevSamp1;
72 int8_t delta_x1;
73 float sample2;
74 uint8_t prevSamp2;
75 int8_t delta_x2;
76
77 uint8_t * snd_array[3] = { sunknown, scya, scamera }; // From RESOURCE.H
78 uint32_t snd_lens[3]   = { sunknownlen, scyalen, scameralen };
79
80 // Bitmaps
81
82 uint8_t bmp1[] = {
83   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
84   0,0,1,1,0,0,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,
85   0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,1,1,1,1,0,
86   0,1,1,1,0,0,1,0,0,1,0,1,1,1,1,0,0,0,1,0,0,
87   0,1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,
88   0,0,1,1,0,0,0,1,1,0,0,1,0,0,1,0,1,1,1,1,0,
89   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
90   };
91 uint8_t bmp2[] = {
92   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
93   0,1,1,1,0,0,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,
94   0,0,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,1,1,1,0,
95   0,0,1,1,0,0,1,0,0,1,0,1,1,1,1,0,0,0,1,0,0,
96   0,0,0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,
97   0,1,1,1,0,0,0,1,1,0,0,1,0,0,1,0,1,1,1,1,0,
98   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
99   };
100 uint8_t bmp3[] = {
101   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
102   0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
103   0,1,0,0,0,0,1,1,1,0,0,0,1,1,0,0,1,1,1,0,0,
104   0,0,1,1,0,0,1,0,0,1,0,0,0,0,1,0,1,0,0,1,0,
105   0,0,0,0,1,0,1,0,0,1,0,1,1,1,1,0,1,0,0,1,0,
106   0,1,1,1,0,0,1,0,0,1,0,0,1,1,1,0,1,1,1,0,0,
107   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0
108   };
109 uint8_t boptions[] = { // 35x9
110   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
111   0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
112   0,1,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
113   0,1,0,0,1,0,1,1,1,0,0,1,1,1,1,0,1,1,0,0,0,1,1,0,0,1,1,1,0,0,0,1,1,0,0,
114   0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,1,0,0,0,0,
115   0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,1,0,0,
116   0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,0,0,1,0,
117   0,0,1,1,0,0,1,1,1,0,0,0,0,1,1,0,1,1,1,0,0,1,1,0,0,1,0,0,1,0,0,1,1,0,0,
118   0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
119   };
120 uint8_t bn0[] = {
121   0,0,0,0,0,0,
122   0,0,1,1,0,0,
123   0,1,0,0,1,0,
124   0,1,0,0,1,0,
125   0,1,0,0,1,0,
126   0,0,1,1,0,0,
127   0,0,0,0,0,0
128   };
129 uint8_t bn1[] = {
130   0,0,0,0,0,0,
131   0,0,1,0,0,0,
132   0,1,1,0,0,0,
133   0,0,1,0,0,0,
134   0,0,1,0,0,0,
135   0,1,1,1,0,0,
136   0,0,0,0,0,0
137   };
138 uint8_t bn2[] = {
139   0,0,0,0,0,0,
140   0,1,1,1,0,0,
141   0,0,0,0,1,0,
142   0,0,1,1,0,0,
143   0,1,0,0,0,0,
144   0,1,1,1,1,0,
145   0,0,0,0,0,0
146   };
147 uint8_t bn3[] = {
148   0,0,0,0,0,0,
149   0,1,1,1,0,0,
150   0,0,0,0,1,0,
151   0,1,1,1,0,0,
152   0,0,0,0,1,0,
153   0,1,1,1,0,0,
154   0,0,0,0,0,0
155   };
156 uint8_t bn4[] = {
157   0,0,0,0,0,0,
158   0,0,0,1,0,0,
159   0,1,0,1,0,0,
160   0,1,0,1,0,0,
161   0,1,1,1,1,0,
162   0,0,0,1,0,0,
163   0,0,0,0,0,0
164   };
165 uint8_t bn5[] = {
166   0,0,0,0,0,0,
167   0,1,1,1,1,0,
168   0,1,0,0,0,0,
169   0,1,1,1,0,0,
170   0,0,0,0,1,0,
171   0,1,1,1,0,0,
172   0,0,0,0,0,0
173   };
174 uint8_t bn6[] = {
175   0,0,0,0,0,0,
176   0,0,1,1,0,0,
177   0,1,0,0,0,0,
178   0,1,1,1,0,0,
179   0,1,0,0,1,0,
180   0,0,1,1,0,0,
181   0,0,0,0,0,0
182   };
183 uint8_t bn7[] = {
184   0,0,0,0,0,0,
185   0,1,1,1,1,0,
186   0,0,0,0,1,0,
187   0,0,0,1,0,0,
188   0,0,1,0,0,0,
189   0,0,1,0,0,0,
190   0,0,0,0,0,0
191   };
192 uint8_t bn8[] = {
193   0,0,0,0,0,0,
194   0,0,1,1,0,0,
195   0,1,0,0,1,0,
196   0,0,1,1,0,0,
197   0,1,0,0,1,0,
198   0,0,1,1,0,0,
199   0,0,0,0,0,0
200   };
201 uint8_t bn9[] = {
202   0,0,0,0,0,0,
203   0,0,1,1,0,0,
204   0,1,0,0,1,0,
205   0,0,1,1,1,0,
206   0,0,0,0,1,0,
207   0,0,1,1,0,0,
208   0,0,0,0,0,0
209   };
210 uint8_t bnA[] = {
211   0,0,0,0,0,0,
212   0,0,1,1,0,0,
213   0,1,0,0,1,0,
214   0,1,1,1,1,0,
215   0,1,0,0,1,0,
216   0,1,0,0,1,0,
217   0,0,0,0,0,0
218   };
219 uint8_t bnB[] = {
220   0,0,0,0,0,0,
221   0,1,1,1,0,0,
222   0,1,0,0,1,0,
223   0,1,1,1,0,0,
224   0,1,0,0,1,0,
225   0,1,1,1,0,0,
226   0,0,0,0,0,0
227   };
228 uint8_t bnC[] = {
229   0,0,0,0,0,0,
230   0,0,1,1,0,0,
231   0,1,0,0,1,0,
232   0,1,0,0,0,0,
233   0,1,0,0,1,0,
234   0,0,1,1,0,0,
235   0,0,0,0,0,0
236   };
237 uint8_t bnD[] = {
238   0,0,0,0,0,0,
239   0,1,1,1,0,0,
240   0,1,0,0,1,0,
241   0,1,0,0,1,0,
242   0,1,0,0,1,0,
243   0,1,1,1,0,0,
244   0,0,0,0,0,0
245   };
246 uint8_t bnE[] = {
247   0,0,0,0,0,0,
248   0,1,1,1,1,0,
249   0,1,0,0,0,0,
250   0,1,1,1,1,0,
251   0,1,0,0,0,0,
252   0,1,1,1,1,0,
253   0,0,0,0,0,0
254   };
255 uint8_t bnF[] = {
256   0,0,0,0,0,0,
257   0,1,1,1,1,0,
258   0,1,0,0,0,0,
259   0,1,1,1,0,0,
260   0,1,0,0,0,0,
261   0,1,0,0,0,0,
262   0,0,0,0,0,0
263   };
264
265
266   //
267 // Initialize GUI
268 //
269 void InitGUI(void)
270 {
271         num_coins = 0;
272         gui_debounce = 0;
273         user_selected_something = false;
274 }
275
276
277 //
278 // Handle key debounce
279 //
280 void HandleGUIDebounce(void)
281 {
282         if (gui_debounce)
283                 gui_debounce--;   // Debounce GUI keys...
284
285         do_decrement = !do_decrement;        // Called at 60Hz, so skip decrementing blink
286
287         if (do_decrement)
288         {
289                 if (blink)
290                         blink--;  // Handle blinking stuff (Should prb go in DrawGUI)
291
292                 flash -= 2;  // Handle flashing stuff (Should prb go in DrawGUI)
293
294                 if (flash == 0xFFFF)
295                         flash = 23;
296
297                 iline++;
298
299                 if (iline > 30)
300                         iline = 0;  // 30 pixels high, going past by 1
301
302                 dcurcol += dcurdir;
303
304                 if (dcurcol == 186)
305                         dcurdir = -1;
306
307                 if (dcurcol == 179)
308                         dcurdir = 1;
309         }
310 }
311
312
313 //
314 // Set the refresh rate (30/60 Hz)
315 //
316 void SetRefreshRate(bool refresh)
317 {
318         game_refresh = refresh;
319 }
320
321
322 //
323 // Whether or not GUI is showing
324 //
325 bool ShowGUI(void)
326 {
327         return show_gui;
328 }
329
330
331 //
332 // Turn the GUI on
333 //
334 void ActivateGUI(void)
335 {
336         show_gui = true;
337 }
338
339
340 //
341 // Turn the GUI off
342 //
343 void DeactivateGUI(void)
344 {
345         show_gui = false;
346 }
347
348
349 //
350 // Draw the small icons...
351 //
352 void DrawSmallIcons(uint16_t icon_not_to_draw)
353 {
354         uint8_t * iconmem;
355         uint8_t xl, yl;
356         uint8_t * sIcons[12] = { inoguis, icoinus, ipl1sts, ipl2sts, ii30hzs,
357                 ii60hzs, idipsws, ichecks, ikeycns, isnapss, iresets, ibyebys };
358         uint8_t xlens[12] = { 31, 18, 32, 35, 37, 37, 29, 23, 28, 32, 19, 19 };
359         uint8_t ylens[12] = { 31, 18, 19, 19, 21, 21, 23, 20, 16, 17, 20, 23 };
360         uint8_t xpos[11] = { 33, 48, 63, 78, 104, 0, 184, 210, 225, 240, 255 };
361         uint8_t iconidx[11] = { 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 6 };
362
363         if (game_refresh)
364                 iconidx[9] = 5;       // 60 Hz...
365
366         // Draw small icons 1 to 5 on left, then 11 to 7 on right.
367
368         for(int i=0; i<5; i++)
369         {
370                 uint16_t idx = i + icon_not_to_draw;    // Get correct start pos.
371
372                 if (idx > 10)
373                         idx -= 11;
374
375                 iconmem = sIcons[iconidx[idx]];
376                 xl = xlens[iconidx[idx]];
377                 yl = ylens[iconidx[idx]];
378
379                 uint32_t scadr = hScrollOffset + voffsets[vScrollOffset];
380                 scadr += 320 * ((224 - yl) / 2);                // Center vertically
381                 scadr += xpos[i] - (xl / 2);                    // Center around horiz. pos.
382                 uint16_t bmpptr = 0;
383
384                 for(int yy=0; yy<yl; yy++)
385                 {
386                         for(int xx=0; xx<xl; xx++)
387                         {
388                                 uint8_t b = iconmem[bmpptr++];
389
390                                 if (b)
391                                         my_scr[scadr + xx + yy * 320] = b;
392                         }
393                 }
394         }
395
396         for(int i=10; i>5; i--)
397         {
398                 uint16_t idx = i + icon_not_to_draw;    // Get correct start pos.
399
400                 if (idx > 10)
401                         idx -= 11;
402
403                 iconmem = sIcons[iconidx[idx]];
404                 xl = xlens[iconidx[idx]];
405                 yl = ylens[iconidx[idx]];
406
407                 uint32_t scadr = hScrollOffset + voffsets[vScrollOffset];
408                 scadr += 320 * ((224 - yl) / 2);                // Center vertically
409                 scadr += xpos[i] - (xl / 2);                    // Center around horiz. pos.
410                 uint16_t bmpptr = 0;
411
412                 for(int yy=0; yy<yl; yy++)
413                 {
414                         for(int xx=0; xx<xl; xx++)
415                         {
416                                 uint8_t b = iconmem[bmpptr++];
417
418                                 if (b)
419                                         my_scr[scadr + xx + yy * 320] = b;
420                         }
421                 }
422         }
423 }
424
425
426 //
427 // Draw the large (selected) icon
428 //
429 void DrawLargeIcon(uint16_t icon)
430 {
431         uint8_t * iconmem;
432         uint8_t xl, yl;
433         uint8_t * lIcons[11] = { inoguib, icoinub, ipl1stb, ipl2stb, ii30hzb,
434                 ii60hzb, idipswb, ikeycnb, isnapsb, iresetb, ibyebyb };
435         uint8_t xlens[11] = { 44, 45, 50, 52, 59, 59, 42, 45, 48, 58, 42 };
436         uint8_t ylens[11] = { 44, 40, 33, 29, 52, 52, 34, 45, 37, 40, 50 };
437
438         uint8_t gsubs1[24] = { 21, 21, 20, 19, 168, 168, 31, 155, 68, 68, 67, 66,
439                                                 36, 36, 35, 34, 188, 188, 183, 181, 81, 81, 85, 80 },
440                 gsubs2[24] = { 20, 20, 19, 19, 31,  31,  155, 155, 67, 67, 66, 66,
441                                                 35, 35, 34, 34, 183, 183, 181, 181, 85, 85, 80, 80 },
442                 gsubs3[24] = { 35, 34, 188, 188, 183, 181, 81, 81, 85, 80, 21, 21,
443                                                 20, 19, 168, 168, 31, 155, 68, 68, 67, 66, 36, 36 },
444                 gsubs4[24] = { 34, 34, 183, 183, 181, 181, 85, 85, 80, 80, 20, 20,
445                                                 19, 19, 31,  31,  155, 155, 67, 67, 66, 66, 35, 35 },
446                 gsubs5[24] = { 20, 20, 183, 183, 31, 31, 85, 85, 67, 67, 20, 20,
447                                                 35, 35, 31, 31, 183, 183, 67, 67, 85, 85, 35, 35 };
448
449         iconmem = lIcons[icon];
450         xl = xlens[icon];
451         yl = ylens[icon];
452
453         if (icon == OPTIONS)
454         {
455                 iconmem = boptions;
456                 xl = 35;
457                 yl = 9;
458         }
459
460         if ((icon == REFRESH) && game_refresh)
461         {
462                 iconmem = lIcons[5];
463                 xl = xlens[5];
464                 yl = ylens[5];
465         }
466
467         if (icon == DIPSWITCH)
468         {
469                 iconmem = lIcons[6];
470                 xl = xlens[6];
471                 yl = ylens[6];
472         }
473
474         uint32_t scadr = hScrollOffset + voffsets[vScrollOffset];
475         scadr += 320 * ((224 - yl) / 2);                // Center vertically
476         scadr += (288 - xl) / 2;                      // Center horizontally
477         uint16_t bmpptr = 0;
478
479         for(int yy=0; yy<yl; yy++)
480         {
481                 for(int xx=0; xx<xl; xx++)
482                 {
483                         uint8_t b = iconmem[bmpptr++];
484
485                         if (b)
486                         {
487                                 if ((icon == PL1START) && (b == 235) && (num_coins) && !blink_on)
488                                 b = 125;                        // Light ON color
489                 /*noguib: 44x44 [Green (hi/lo): 36/235 Orange: 168/31 Neutral:12]
490                 Rainbow (ROYGBP, hi/med/lo): 21,20,19; 168, 31,155; 68,67,66;
491                                                                                 36,35,34; 188,183,181; 81,85,80 */
492                                 if (icon == NOGUI)
493                                 {
494                                         uint8_t fln = (23 - flash) + 1; // Want to go forward (maybe fix it?)
495                                         switch (b)
496                                         {
497                                                 case 36:   { b = gsubs1[fln];  break; }
498                                                 case 235:  { b = gsubs2[fln];  break; }
499                                                 case 168:  { b = gsubs3[fln];  break; }
500                                                 case 31:   { b = gsubs4[fln];  break; }
501                                                 case 12:   { b = gsubs5[fln];  break; }
502                                         }
503                                 }
504
505                                 if ((icon == REFRESH) && (iline == yy) && (b == 50))
506                                         b = 188;
507
508                                 my_scr[scadr+xx+yy*320] = b;
509                         }
510                 }
511         }
512
513         if (!blink)    // Should go here???
514         {
515                 blink_on = !blink_on;        // Switch blink state
516
517                 if (blink_on)
518                         blink = 12;
519                 else
520                         blink = 6;
521         }
522   //if (flash == 1)  flash = 23;       // Reset flash value
523 }
524
525
526 //
527 // Draw the dipswitch portion of the GUI
528 //
529 void DrawDipswitch(void)
530 {
531         uint8_t dseloff[16] = { 0, 1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10, 11, 11, 12 };
532         uint8_t * dtxt[13] = { idstext1, idstext2, idstext3, idstext4, idstext5,
533                 idstext2, idstext6, idstext7, idstext8, idstext9, idstext10, idstext11,
534                 idstext12 };
535
536         uint8_t dtx[13] = { 48, 80, 96, 82, 60, 80, 76, 57, 33, 50, 62, 65, 63 },
537                 dty[13] = { 7, 9, 7, 9, 7, 9, 7, 7, 7, 9, 7, 9, 7 };
538         uint32_t dtxtoff[13] = { 4*320+24, 14*320-78, 25*320+24, 32*320-80,
539                 39*320+24, 49*320-78,  4*320+24, 11*320-55, 18*320+24, 25*320-48,
540                 32*320+24, 42*320-63, 53*320+24 };
541         uint32_t scadr, bmpptr;
542         //dsx = //26x65
543
544         uint32_t dbase = hScrollOffset + voffsets[vScrollOffset];
545         dbase += (288 - 26) / 2;                 // Center horizontally
546         dbase += 320 * ((224 - ((65 * 2) + 8)) / 2);   // Center vertically
547
548         scadr = dbase;   // Reset screen address
549         bmpptr = 0;
550
551         for(int yy=0; yy<65; yy++)
552         {
553                 for(int xx=0; xx<26; xx++)
554                 {
555                         uint8_t b = idswitch[bmpptr++];
556
557                         if (b)
558                                 my_scr[scadr + xx + yy * 320] = b;
559                 }
560         }
561
562         scadr = dbase + (320*73);   // Reset screen address
563         bmpptr = 0;
564
565         for(int yy=0; yy<65; yy++)
566         {
567                 for(int xx=0; xx<26; xx++)
568                 {
569                         uint8_t b = idswitch[bmpptr++];
570
571                         if (b)
572                                 my_scr[scadr + xx + yy * 320] = b;
573                 }
574         }
575
576         for(int i=0; i<16; i++)
577         {
578                 scadr = dbase + (5 * 320 + 5) + i * 7 * 320;
579
580                 if (i > 7)
581                         scadr += 17*320;   // Adjust for DSW #2
582
583                 bmpptr = 0;
584
585                 if (gram1[0x423D + (i << 1)])
586                         scadr += 12; // Adjust position if ON
587
588                 for(int yy=0; yy<5; yy++)
589                 {
590                         for(int xx=0; xx<5; xx++)
591                         {
592                                 my_scr[scadr++] = idsbutton[bmpptr++];
593                         }
594
595                         scadr += 315; // Adjust position...
596                 }
597         }
598
599         uint8_t dselected_text = dseloff[dswitch];
600
601         for(int i=0; i<13; i++)
602         {
603                 if (dselected_text != i)
604                 {
605                         scadr = dbase + dtxtoff[i];
606
607                         if (i > 5)
608                                 scadr += (73 * 320);
609
610                         bmpptr = 0;
611
612                         for(int yy=0; yy<dty[i]; yy++)
613                         {
614                                 for(int xx=0; xx<dtx[i]; xx++)
615                                 {
616                                         uint8_t b = dtxt[i][bmpptr++];
617
618                                         if (b)
619                                                 my_scr[scadr] = b;
620
621                                         scadr++;
622                                 }
623
624                                 scadr += (320 - dtx[i]); // Adjust position...
625                         }
626                 }
627         }
628
629         scadr = dbase + dtxtoff[dselected_text];
630
631         if (dselected_text>5)
632                 scadr += (73 * 320);
633
634         bmpptr = 0;
635
636         for(int yy=0; yy<dty[dselected_text]; yy++)
637         {
638                 for(int xx=0; xx<dtx[dselected_text]; xx++)
639                 {
640                         uint8_t b = dtxt[dselected_text][bmpptr++];
641
642                         if (b)
643                                 my_scr[scadr] = 125;
644
645                         scadr++;
646                 }
647
648                 scadr += (320 - dtx[dselected_text]); // Adjust position...
649         }
650
651         if (dswitch != 16)                   // Draw cursor
652         {
653                 scadr = dbase + (4 * 320 + 4) + dswitch * 7 * 320;
654
655                 if (dswitch>7)
656                         scadr += 17 * 320;   // Adjust for DSW #2
657
658                 for(int xx=0; xx<19; xx++)
659                         my_scr[scadr++] = dcurcol;
660
661                 scadr += 301;
662
663                 for(int xx=0; xx<5; xx++)
664                 {
665                         my_scr[scadr] = dcurcol;
666                         scadr += 18;
667                         my_scr[scadr] = dcurcol;
668                         scadr += 302;
669                 }
670
671                 for(int xx=0; xx<19; xx++)
672                         my_scr[scadr++] = dcurcol;
673         }
674 }
675
676
677 //
678 // The actual GUI display routine
679 //
680 void DrawGUI(void)
681 {
682         if (!user_selected_something)  // i.e. we're not inside a selection...
683         {
684                 DrawSmallIcons(selection);  // 'selection' is icon *not* to draw
685                 DrawLargeIcon(selection);
686         }
687         else
688         {
689                 if (selection == DIPSWITCH)
690                         DrawDipswitch();
691         }
692 }
693
694
695 //
696 // User pressed left arrow handler
697 //
698 void SelectLeft(void)
699 {
700         if (!gui_debounce)
701         {
702                 gui_debounce = 6;
703
704                 if (!user_selected_something)
705                 {
706                         selection++;
707
708                         if (selection > 10)
709                                 selection = 0;
710                 }
711                 else
712                 {
713                         if (gram1[0x423D + (dswitch << 1)])       // It's switchable...
714                         {}  //SpawnSound(USERSOUND, SCLICK);
715                         else
716                         {}  //SpawnSound(USERSOUND, SUNGH);
717
718                         gram1[0x423D + (dswitch << 1)] = 0;       // & turn it off
719                 }
720         }
721 }
722
723
724 //
725 // User pressed right arrow handler
726 //
727 void SelectRight(void)
728 {
729         if (!gui_debounce)
730         {
731                 gui_debounce = 6;
732
733                 if (!user_selected_something)
734                 {
735                         selection--;
736
737                         if (selection > 10)
738                                 selection = 10;  // Unsigned compare
739                 }
740                 else
741                 {
742                         if (!gram1[0x423D + (dswitch << 1)])       // It's switchable...
743                         {}  //SpawnSound(USERSOUND, SCLICK);
744                         else
745                         {}  //SpawnSound(USERSOUND, SUNGH);
746
747                         gram1[0x423D+(dswitch<<1)] = 1;       // & turn it on
748                 }
749         }
750 }
751
752
753 //
754 // User pressed Up arrow handler
755 //
756 void SelectUp(void)
757 {
758         if (!gui_debounce)
759         {
760                 gui_debounce = 6;
761
762                 if (user_selected_something)
763                 {
764                         if (selection == DIPSWITCH)
765                         {
766                                 dswitch--;
767
768                                 if (dswitch > 16)
769                                         dswitch = 16;  // Wrap non-int
770                                 //snd_num = dswitch;  SpawnMsg(MSHOWNUMS); // Temp...
771                         }
772                 }
773         }
774 }
775
776
777 //
778 // User pressed down arrow handler
779 //
780 void SelectDown(void)
781 {
782         if (!gui_debounce)
783         {
784                 gui_debounce = 6;
785
786                 if (user_selected_something)
787                 {
788                         if (selection == DIPSWITCH)
789                         {
790                                 dswitch++;
791
792                                 if (dswitch > 16)
793                                         dswitch = 0;
794                                 //snd_num = dswitch;  SpawnMsg(MSHOWNUMS); // Temp...
795                         }
796                 }
797         }
798 }
799
800
801 //
802 // User selected something! Handle it!
803 //
804 uint8_t UserSelectedSomething(void)
805 {
806         //extern uint8_t * gram1;
807
808         if (!gui_debounce)
809         {
810                 gui_debounce = 6;
811
812                 if (!user_selected_something)  // Inside a selection? no...
813                 {
814
815                         if (selection == NOGUI)     // Turn off GUI
816                         {
817                                 show_gui = false;
818                         }
819
820                         if (selection == COINUP)    // Coin up machine
821                         {
822                                 gram1[0x41A5]++;          // Add one coin... (prob. need sep. counter)
823                                 num_coins++;
824                                 gram1[0x4189] = num_coins / 10; // Should be in THUNDER.CPP?
825                                 gram1[0x418A] = num_coins - (gram1[0x4189] * 10);
826                         }
827
828                         if (selection == PL1START)  // 1 Player start
829                         {
830                                 if (num_coins)
831                                 {
832                                         num_coins--;
833                                         show_gui = false;       // Shut off GUI only if coined up
834                                 }
835
836                                 gram1[0x418C] = 1;        // Strobe start location
837                         }
838
839                         if (selection == PL2START)  // 2 Player start
840                         {
841                                 if (num_coins > 1)
842                                 {
843                                         num_coins -= 2;
844                                         show_gui = false;
845                                 }
846                         }
847
848                         if (selection == REFRESH)   // Toggle refresh rate
849                         {
850                                 //SpawnSound(USERSOUND, SCLICK);
851                         }
852
853                         if (selection == DIPSWITCH) // Edit game settings
854                         {
855                                 //SpawnSound(USERSOUND, SBLAH);
856                                 user_selected_something = true;
857                                 dswitch = 0;              // Set at first dipswitch
858                         }
859
860                         if (selection == OPTIONS)   // Edit emulator settings
861                         {
862                         }
863
864                         if (selection == KEYCONFIG) // Edit game keys
865                         {
866                         }
867
868                         if (selection == SNAPSHOT)  // Snapshot
869                         {
870                                 SpawnSound(USERSOUND, SCAMERA);
871                                 SnapPCX(screen);
872                         }
873
874                         if (selection == RESET)     // Reset machine
875                         {
876                                 //SpawnSound(USERSOUND, SRESET);
877                         }
878
879                         if (selection == EXIT)
880                         {
881                                 SpawnSound(USERSOUND, SCYA);
882                         }
883
884                         return selection;
885                 }
886                 else           // Selected something inside selection...
887                 {
888                         if (selection == DIPSWITCH)
889                         {
890                                 if (dswitch == 16)  // Selected 'back to GUI'
891                                 {
892                                         //SpawnSound(USERSOUND, SBLAH2);
893                                         user_selected_something = false;
894                                 }
895                                 else
896                                 {
897                                         //SpawnSound(USERSOUND, SCLICK);
898                                         gram1[0x423D + (dswitch << 1)] = !gram1[0x423D + (dswitch << 1)];
899                                 }
900                         }
901
902                         return 0xFF;  // Nothing for main to do...
903                 }
904         }
905         else
906                 return 0xFF;  // Wasn't debounced, so return invalid
907 }
908
909
910 //
911 // Show byte passed to it
912 //
913 void ShowNumbers(int number)
914 {
915         uint8_t * bnarray[16] = { bn0, bn1, bn2, bn3, bn4, bn5, bn6, bn7, bn8, bn9,
916                 bnA, bnB, bnC, bnD, bnE, bnF };
917 //      uint32_t scadr = hScrollOffset + voffsets[vScrollOffset] + 642 + 2560;
918         uint32_t scadr = ((2 * 288) + 2) + (8 * 288);
919         uint16_t bmpptr = 0;
920
921         uint8_t first_dig = number >> 4, second_dig = number & 0x0F;
922
923         for(int y=0; y<7; y++)
924         {
925                 for(int x=0; x<6; x++)
926                 {
927                         if (bnarray[first_dig][bmpptr++] == 1)
928 //                              my_scr[scadr + x + y * 320] = 7;
929                                 my_scr[scadr + x + y * 288] = 7;
930                         else
931 //                              my_scr[scadr + x + y * 320] = 0;
932                                 my_scr[scadr + x + y * 288] = 0;
933                 }
934         }
935
936         bmpptr = 0;
937         scadr += 6;
938
939         for(int y=0; y<7; y++)
940         {
941                 for(int x=0; x<6; x++)
942                 {
943                         if (bnarray[second_dig][bmpptr++] == 1)
944 //                              my_scr[scadr + x + y * 320] = 7;
945                                 my_scr[scadr + x + y * 288] = 7;
946                         else
947 //                              my_scr[scadr + x + y * 320] = 0;
948                                 my_scr[scadr + x + y * 288] = 0;
949                 }
950         }
951 }
952
953
954 //
955 // Spawn a message
956 //
957 void SpawnMsg(uint8_t msg)
958 {
959         text_life = 60;                 // 1 second...
960         show_text = true;               // Show the damn thing...
961         show_which_msg = msg;   // And tell it which message to show...
962 }
963
964
965 //
966 // Draw text message
967 //
968 void DrawText(void)
969 {
970         // Kill text if it's time
971         if (!text_life)
972         {
973                 show_text = false;
974                 return;
975         }
976
977         // Your life force is running out...
978         text_life--;
979
980         // Draw the message here...
981 //      uint32_t scadr = hScrollOffset + voffsets[vScrollOffset] + 642;
982         uint32_t scadr = (288 * 2) + 2;
983         uint16_t bmpptr = 0;
984
985         for(int y=0; y<7; y++)
986         {
987                 for(int x=0; x<21; x++)
988                 {
989                         if (show_which_msg == M60FPS)
990                         {
991                                 if (bmp1[bmpptr++] == 1)
992 //                                      my_scr[scadr + x + y * 320] = 7;
993                                         my_scr[scadr + x + y * 288] = 7;
994                                 else
995 //                                      my_scr[scadr + x + y * 320] = 0;
996                                         my_scr[scadr + x + y * 288] = 0;
997                         }
998                         else if (show_which_msg == M30FPS)
999                         {
1000                                 if (bmp2[bmpptr++] == 1)
1001 //                                      my_scr[scadr + x + y * 320] = 7;
1002                                         my_scr[scadr + x + y * 288] = 7;
1003                                 else
1004 //                                      my_scr[scadr + x + y * 320] = 0;
1005                                         my_scr[scadr + x + y * 288] = 0;
1006                         }
1007                         else if (show_which_msg == MSNAPSHOT)
1008                         {
1009                                 if (bmp3[bmpptr++] == 1)
1010 //                                      my_scr[scadr + x + y * 320] = 7;
1011                                         my_scr[scadr + x + y * 288] = 7;
1012                                 else
1013 //                                      my_scr[scadr + x + y * 320] = 0;
1014                                         my_scr[scadr + x + y * 288] = 0;
1015                         }
1016                 }
1017         }
1018
1019         if (show_which_msg == MSHOWNUMS)
1020                 ShowNumbers(snd_num);
1021 }
1022
1023
1024 //
1025 // Sound stuff (Will go elsewhere??? Perhaps in sound.cpp?)
1026 //
1027 void SpawnSound(int type, int snd, int channel/* = 0*/)
1028 {
1029         extern uint32_t psg_lens[16];
1030         extern uint8_t * psg_adrs[16];
1031         extern uint32_t voc_lens[32];
1032         extern uint8_t * voc_adrs[32];
1033         extern uint32_t fm_lens[14];
1034         extern uint8_t * fm_adrs[14];
1035
1036         snd_num = snd;
1037         SpawnMsg(MSHOWNUMS);
1038
1039         if (type == GAMESOUND)
1040         {
1041                 snd--;                                                                                  // Will that do it???  Yes!!!
1042
1043                 if (channel == 0)
1044                 {
1045                         // 00 nn ss (nn # of repeats of sample ss)
1046                         uint32_t st = 0;
1047
1048                         if (snd & 0x40)
1049                         {
1050                                 st = 0x10000;
1051                                 snd &= 0x0F;
1052                         }
1053
1054                         spos1 = (voice_rom[st + (snd << 1)] << 8) | voice_rom[st + (snd << 1) + 1];
1055                         spos1 += st;                                                            // Need to add start somewhere...
1056                         prevSamp1 = 128;
1057                         sample1 = 0;
1058                         chan1_go = true;
1059                 }
1060                 else
1061                 {
1062                         uint32_t st = 0;
1063
1064                         if (snd & 0x40)
1065                         {
1066                                 st = 0x10000;
1067                                 snd &= 0x0F;
1068                         }
1069
1070                         spos2 = (voice_rom[st + (snd << 1)] << 8) | voice_rom[st + (snd << 1) + 1];
1071                         spos2 += st;                                                            // Need to add start somewhere...
1072                         prevSamp2 = 128;
1073                         sample2 = 0;
1074                         chan2_go = true;
1075                 }
1076         }
1077         else if (type == PSGSOUND)
1078         {
1079                 if (snd_num & 0x10)                                                             // Second channel?
1080                 {
1081                         spos3 = 0;
1082                         end_pos3 = psg_lens[snd_num & 0x0F];
1083                         sndp3 = psg_adrs[snd_num & 0x0F];
1084                         chan3_go = true;
1085
1086                         if (spos3 == end_pos3)
1087                                 chan3_go = false;                                               // No sound loaded, so don't do it!
1088                 }
1089                 else                                                                                    // First channel
1090                 {
1091                         spos4 = 0;
1092                         end_pos4 = psg_lens[snd_num & 0x0F];
1093                         sndp4 = psg_adrs[snd_num & 0x0F];
1094                         chan4_go = true;
1095
1096                         if (spos4 == end_pos4)
1097                                 chan4_go = false;                                               // No sound loaded, so don't do it!
1098                 }
1099         }
1100         else if (type == FMSOUND)
1101         {
1102                 spos5 = 0;
1103                 end_pos5 = fm_lens[snd_num];
1104                 sndp5 = fm_adrs[snd_num];
1105                 chan5_go = true;
1106
1107                 if (spos5 == end_pos5)
1108                         chan5_go = false;                                                       // No sound loaded, so don't do it!
1109         }
1110         else if (type == USERSOUND)
1111         {
1112                 spos6 = 0;
1113                 end_pos6 = snd_lens[snd_num];                                   // User sound
1114                 sndp6 = snd_array[snd_num];                                             // Load pointer
1115                 chan6_go = true;
1116         }
1117 }
1118
1119
1120 //
1121 // Sound card IRQ handler
1122 //
1123 void SoundFunc(void * userdata, Uint8 * buff, int num)
1124 {
1125         // 0-22 different sounds...
1126         uint16_t cnt = 0, sample;
1127         uint8_t start_samp1, end_samp1, start_samp2, end_samp2;
1128         uint8_t samp1 = 128, samp2 = 128, samp3 = 128,
1129                 samp4 = 128, samp5 = 128, samp6 = 128;                  // Zero samples...
1130
1131         // Kill sound...
1132         memset(buff, 128, num);
1133
1134         if (chan1_go || chan2_go || chan3_go || chan4_go || chan5_go || chan6_go)
1135         {
1136                 while (cnt != num)
1137                 {
1138                         if (chan1_go)
1139                         {
1140                                 if (sample1 < 1)
1141                                 {
1142                                         samp1 = voice_rom[spos1++];
1143
1144                                         // Kill channel 1 if done...
1145                                         if (samp1 == 0xFF)
1146                                         {
1147                                                 chan1_go = false;
1148                                                 samp1 = 128;
1149                                         }
1150                                         // RLE compression...
1151                                         else if (samp1 == 0x00)
1152                                         {
1153                                                 // # of repeats
1154                                                 sample1 += (float)voice_rom[spos1++] * sampleBase;
1155                                                 // Get last good sample
1156                                                 samp1   = prevSamp1;
1157                                         }
1158                                         else
1159                                                 // Keep fractional part intact
1160                                                 sample1 += sampleBase;
1161                                 }
1162
1163                                 prevSamp1 = samp1;              // Save last sample value
1164                                 sample1 -= 1.0;                 // Decrement repeat counter
1165                         }
1166
1167 // Stretching 5KHz samples to 22KHz:
1168 //   numRepeats = 4;
1169 //            6KHz -> 22KHz:  22/6 repeats...
1170                         if (chan2_go)
1171                         {
1172                                 if (sample2 < 1)
1173                                 {
1174                                         samp2 = voice_rom[spos2++];
1175
1176                                         if (samp2 == 0xFF)
1177                                         {
1178                                                 chan2_go = false;
1179                                                 samp2 = 128;                                    // Kill channel 2 if done...
1180                                         }
1181                                         else if (samp2 == 0x00)                         // RLE compression...
1182                                         {
1183                                                 sample2 += (float)voice_rom[spos2++] * sampleBase;      // # of repeats
1184                                                 samp2   = prevSamp2;
1185                                         }
1186                                         else
1187                                                 sample2 += sampleBase;
1188                                 }
1189
1190 // Delta-X values were making the samples sound like crap...
1191 //                              start_samp2 += delta_x2;
1192                                 prevSamp2 = samp2;
1193                                 sample2 -= 1.0;
1194                         }
1195
1196                         if (chan3_go)
1197                         {
1198                                 samp3 = sndp3[spos3++];
1199
1200                                 if (spos3 == end_pos3)
1201                                 {
1202                                         chan3_go = false;
1203                                         samp3 = 128; // Kill channel 3 if done...
1204                                 }
1205                         }
1206
1207                         if (chan4_go)
1208                         {
1209                                 samp4 = sndp4[spos4++];
1210
1211                                 if (spos4 == end_pos4)
1212                                 {
1213                                         chan4_go = false;
1214                                         samp4 = 128; // Kill channel 4 if done...
1215                                 }
1216                         }
1217
1218                         if (chan5_go)
1219                         {
1220                                 samp5 = sndp5[spos5++];
1221
1222                                 if (spos5 == end_pos5)
1223                                 {
1224                                         chan5_go = false;
1225                                         samp5 = 128; // Kill channel 5 if done...
1226                                 }
1227                         }
1228
1229                         if (chan6_go)
1230                         {
1231                                 samp6 = sndp6[spos6++];
1232
1233                                 if (spos6 == end_pos6)
1234                                 {
1235                                         chan6_go = false;
1236                                         samp6 = 128;            // Kill channel 6...
1237                                 }
1238                         }
1239
1240                         // Mix 'em...
1241                         sample = samp1 + samp2 + samp3 + samp4 + samp5 + samp6 - 640;
1242
1243                         // If it overflowed, clip it
1244                         if (sample & 0xFF00)
1245                                 sample = (sample & 0x8000 ? 0x00 : 0xFF);
1246
1247                         buff[cnt++] = sample;
1248                 }
1249         }
1250 }
1251