]> Shamusworld >> Repos - apple2/blob - src/gui/guimisc.cpp
Created new MMU based code for R/W handling. Should be much faster now.
[apple2] / src / gui / guimisc.cpp
1 //
2 // GUIMISC.CPP
3 //
4 // Graphical User Interface support functions
5 // by James Hammons
6 //
7 // JLH = James Hammons <jlhamm@acm.org>
8 //
9 // WHO  WHEN        WHAT
10 // ---  ----------  ------------------------------------------------------------
11 // JLH  02/02/2006  Created this file
12 // JLH  03/13/2006  Abstracted out font to allow external fonts
13 //
14
15 #include "guimisc.h"
16 #include "font14pt.h"
17 //Can't do this...!
18 //#include "charset.h"  // For Apple II font (small)
19 #include <string>
20 #include <vector>
21
22
23 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
24 #define MASK_R 0xFF000000
25 #define MASK_G 0x00FF0000
26 #define MASK_B 0x0000FF00
27 #define MASK_A 0x000000FF
28 #else
29 #define MASK_R 0x000000FF
30 #define MASK_G 0x0000FF00
31 #define MASK_B 0x00FF0000
32 #define MASK_A 0xFF000000
33 #endif
34
35 // Local variables
36 // This will enable us to set up any font without having it embedded here...
37
38 static Font font((uint8_t *)font2, FONT_WIDTH, FONT_HEIGHT);
39 static std::vector<Font> oldFontList;
40
41
42 void SetNewFont(Font newFont)
43 {
44         oldFontList.push_back(font);
45         font.data = newFont.data, font.width = newFont.width, font.height = newFont.height;
46 }
47
48 void RestoreOldFont(void)
49 {
50         if (oldFontList.size() == 0)
51                 return;
52
53         font = oldFontList.back();
54         oldFontList.pop_back();
55 }
56
57 uint32_t GetFontWidth(void)
58 {
59         return font.width;
60 }
61
62 uint32_t GetFontHeight(void)
63 {
64         return font.height;
65 }
66
67 //
68 // Draw text at the given x/y coordinates with transparency (255 is fully opaque, 0 is fully transparent).
69 //
70 void DrawStringTrans(SDL_Surface * screen, uint32_t x, uint32_t y, uint32_t color, const char * text, ...)
71 {
72         char string[4096];
73         va_list arg;
74
75         va_start(arg, text);
76         vsprintf(string, text, arg);
77         va_end(arg);
78
79         uint8_t * esColor = (uint8_t *)&color;                  // Do things endian safe...!
80         uint8_t trans = esColor[3];
81         uint32_t length = strlen(string);
82
83         // Make a "stamp" surface (with built in alpha!) for constructing our font chars...
84         SDL_Surface * chr = SDL_CreateRGBSurface(SDL_SWSURFACE, font.width, font.height, 32,
85                 MASK_R, MASK_G, MASK_B, MASK_A);
86         SDL_Rect rect;
87         rect.x = x, rect.y = y;
88
89 //bleh
90 uint8_t r1, g1, b1, a1;
91 SDL_GetRGBA(color, screen->format, &r1, &g1, &b1, &a1);
92 color = SDL_MapRGBA(chr->format, r1, g1, b1, a1);
93 //helb
94
95         for(uint32_t i=0; i<length; i++)
96         {
97                 uint8_t c = string[i];
98                 uint32_t fontAddr = (uint32_t)(c < 32 ? 0 : c - 32) * font.width * font.height;
99
100                 for(uint32_t yy=0; yy<font.height; yy++)
101                 {
102                         for(uint32_t xx=0; xx<font.width; xx++)
103                         {
104                                 esColor[3] = (font.data[fontAddr++] * trans) / 255;
105                                 ((uint32_t *)chr->pixels)[xx + (yy * (chr->pitch / 4))] = color;
106                         }
107                 }
108
109                 SDL_BlitSurface(chr, NULL, screen, &rect);
110                 rect.x += font.width;
111         }
112
113         SDL_FreeSurface(chr);
114 }
115
116 //
117 // Draw text at given x/y coords using foreground/background color combination
118 //
119 void DrawStringOpaque(SDL_Surface * screen, uint32_t x, uint32_t y, uint32_t fg, uint32_t bg, const char * text, ...)
120 {
121         char string[4096];
122         va_list arg;
123
124         va_start(arg, text);
125         vsprintf(string, text, arg);
126         va_end(arg);
127
128         uint8_t * esColor = (uint8_t *)&fg;                             // Do things endian safe...!
129         uint32_t length = strlen(string);
130
131         SDL_Rect destRect;
132
133         destRect.x = x, destRect.y = y;
134         destRect.w = length * font.width, destRect.h = font.height;
135
136         SDL_FillRect(screen, &destRect, bg);
137
138         // Make a "stamp" surface (with built in alpha!) for constructing our font chars...
139         SDL_Surface * chr = SDL_CreateRGBSurface(SDL_SWSURFACE, font.width, font.height, 32,
140                 MASK_R, MASK_G, MASK_B, MASK_A);
141         SDL_Rect rect;
142         rect.x = x, rect.y = y;
143
144 //bleh (we have to map colors from the HW surface to the SW surface)
145 uint8_t r1, g1, b1, a1;
146 SDL_GetRGBA(fg, screen->format, &r1, &g1, &b1, &a1);
147 fg = SDL_MapRGBA(chr->format, r1, g1, b1, a1);
148 SDL_GetRGBA(bg, screen->format, &r1, &g1, &b1, &a1);
149 bg = SDL_MapRGBA(chr->format, r1, g1, b1, a1);
150 //helb
151
152         for(uint32_t i=0; i<length; i++)
153         {
154                 uint8_t c = string[i];
155                 uint32_t fontAddr = (uint32_t)(c < 32 ? 0 : c - 32) * font.width * font.height;
156
157                 for(uint32_t yy=0; yy<font.height; yy++)
158                 {
159                         for(uint32_t xx=0; xx<font.width; xx++)
160                         {
161                                 esColor[3] = font.data[fontAddr++];
162                                 ((uint32_t *)chr->pixels)[xx + (yy * (chr->pitch / 4))] = fg;
163                         }
164                 }
165
166                 SDL_BlitSurface(chr, NULL, screen, &rect);
167                 rect.x += font.width;
168         }
169
170         SDL_FreeSurface(chr);
171 }
172
173 bool RectanglesIntersect(SDL_Rect r1, SDL_Rect r2)
174 {
175         // The strategy here is to see if any of the sides of the smaller rect
176         // fall within the larger.
177
178 /*
179     +-----------------+ r1
180     |                 |
181     |   +------+ r2   |
182     |   |      |      |
183     |   |      |      |
184     |   +------+      |
185     |                 |
186     +-----------------+
187
188 */
189
190 //This approach fails if r2 is inside of r1. !!! FIX !!! [DONE]
191         if (RectangleFirstInsideSecond(r2, r1))
192                 return true;
193
194         if ((r1.x > r2.x && r1.x < (r2.x + r2.w))
195                 || ((r1.x + r1.w) > r2.x && (r1.x + r1.w) < (r2.x + r2.w))
196                 || (r1.y > r2.y && r1.y < (r2.y + r2.h))
197                 || ((r1.y + r1.h) > r2.y && (r1.y + r1.h) < (r2.y + r2.h)))
198                 return true;
199
200         return false;
201 }
202
203 bool RectangleFirstInsideSecond(SDL_Rect r1, SDL_Rect r2)
204 {
205         if ((r1.x > r2.x             && (r1.x + r1.w) > r2.x)
206                 && (r1.x < (r2.x + r2.w) && (r1.x + r1.w) < (r2.x + r2.w))
207                 && (r1.y > r2.y          && (r1.y + r1.h) > r2.y)
208                 && (r1.y < (r2.y + r2.h) && (r1.y + r1.h) < (r2.y + r2.h)))
209                 return true;
210
211         return false;
212 }
213
214
215 //
216 // Various GUI bitmaps
217 //
218
219 // These representations *should* be endian safe.
220
221 uint8_t closeBox[] = {
222         15 / 256, 15 % 256,             // width (HI byte, LO byte)
223         15 / 256, 15 % 256,             // height (HI byte, LO byte)
224
225         0x00, 0x00, 0x00, 0x00, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0x00, 0x00, 0x00, 0x00,
226         0xED, 0x38, 0x38, 0xFF, 0xE7, 0x58, 0x58, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xE7, 0x58, 0x58, 0xFF, 0xED, 0x38, 0x38, 0xFF,
227         0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
228         0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
229         0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
230         0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
231         0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
232         0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
233         0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
234         0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
235         0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
236         0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
237         0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
238         0xED, 0x38, 0x38, 0xFF, 0xE7, 0x58, 0x58, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xE7, 0x58, 0x58, 0xFF, 0xED, 0x38, 0x38, 0xFF,
239         0x00, 0x00, 0x00, 0x00, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0x00, 0x00, 0x00, 0x00
240 };
241
242 uint8_t closeBoxHover[] = {
243         15 / 256, 15 % 256,             // width (HI byte, LO byte)
244         15 / 256, 15 % 256,             // height (HI byte, LO byte)
245
246         0x00, 0x00, 0x00, 0x00, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0x00, 0x00, 0x00, 0x00,
247         0xED, 0x38, 0x38, 0xFF, 0xE7, 0x58, 0x58, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xE7, 0x58, 0x58, 0xFF, 0xED, 0x38, 0x38, 0xFF,
248         0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
249         0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFF, 0xAF, 0x40, 0xFF, 0xFF, 0xAF, 0x40, 0xFF, 0xFF, 0xAF, 0x40, 0xFF, 0xFF, 0xAF, 0x40, 0xFF, 0xFF, 0xAF, 0x40, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
250         0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFF, 0xB7, 0x52, 0xFF, 0xFF, 0xB7, 0x52, 0xFF, 0xFF, 0xB7, 0x52, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
251         0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFF, 0xAF, 0x40, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFF, 0xBE, 0x63, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFF, 0xAF, 0x40, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
252         0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFF, 0xAF, 0x40, 0xFF, 0xFF, 0xB7, 0x52, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFF, 0xB7, 0x52, 0xFF, 0xFF, 0xAF, 0x40, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
253         0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFF, 0xAF, 0x40, 0xFF, 0xFF, 0xB7, 0x52, 0xFF, 0xFF, 0xBE, 0x63, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFF, 0xBE, 0x63, 0xFF, 0xFF, 0xB7, 0x52, 0xFF, 0xFF, 0xAF, 0x40, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
254         0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFF, 0xAF, 0x40, 0xFF, 0xFF, 0xB7, 0x52, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFF, 0xB7, 0x52, 0xFF, 0xFF, 0xAF, 0x40, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
255         0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFF, 0xAF, 0x40, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFF, 0xBE, 0x63, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFF, 0xAF, 0x40, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
256         0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFF, 0xB7, 0x52, 0xFF, 0xFF, 0xB7, 0x52, 0xFF, 0xFF, 0xB7, 0x52, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
257         0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFF, 0xAF, 0x40, 0xFF, 0xFF, 0xAF, 0x40, 0xFF, 0xFF, 0xAF, 0x40, 0xFF, 0xFF, 0xAF, 0x40, 0xFF, 0xFF, 0xAF, 0x40, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
258         0xED, 0x38, 0x38, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFF, 0xA2, 0x20, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
259         0xED, 0x38, 0x38, 0xFF, 0xE7, 0x58, 0x58, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xFB, 0x6B, 0x6B, 0xFF, 0xE7, 0x58, 0x58, 0xFF, 0xED, 0x38, 0x38, 0xFF,
260         0x00, 0x00, 0x00, 0x00, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0x00, 0x00, 0x00, 0x00
261 };
262
263 uint8_t closeBoxDown[] = {
264         15 / 256, 15 % 256,             // width (HI byte, LO byte)
265         15 / 256, 15 % 256,             // height (HI byte, LO byte)
266
267         0x00, 0x00, 0x00, 0x00, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0x00, 0x00, 0x00, 0x00,
268         0xED, 0x38, 0x38, 0xFF, 0xE2, 0x1D, 0x1D, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xE2, 0x1D, 0x1D, 0xFF, 0xED, 0x38, 0x38, 0xFF,
269         0xED, 0x38, 0x38, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
270         0xED, 0x38, 0x38, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xE2, 0x86, 0x07, 0xFF, 0xE2, 0x86, 0x07, 0xFF, 0xE2, 0x86, 0x07, 0xFF, 0xE2, 0x86, 0x07, 0xFF, 0xE2, 0x86, 0x07, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
271         0xED, 0x38, 0x38, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xCC, 0x77, 0x00, 0xFF, 0xCC, 0x77, 0x00, 0xFF, 0xCC, 0x77, 0x00, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
272         0xED, 0x38, 0x38, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xE2, 0x86, 0x07, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xBD, 0x6E, 0x00, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xE2, 0x86, 0x07, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
273         0xED, 0x38, 0x38, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xE2, 0x86, 0x07, 0xFF, 0xCC, 0x77, 0x00, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xCC, 0x77, 0x00, 0xFF, 0xE2, 0x86, 0x07, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
274         0xED, 0x38, 0x38, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xE2, 0x86, 0x07, 0xFF, 0xCC, 0x77, 0x00, 0xFF, 0xBD, 0x6E, 0x00, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xBD, 0x6E, 0x00, 0xFF, 0xCC, 0x77, 0x00, 0xFF, 0xE2, 0x86, 0x07, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
275         0xED, 0x38, 0x38, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xE2, 0x86, 0x07, 0xFF, 0xCC, 0x77, 0x00, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xCC, 0x77, 0x00, 0xFF, 0xE2, 0x86, 0x07, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
276         0xED, 0x38, 0x38, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xE2, 0x86, 0x07, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xBD, 0x6E, 0x00, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xE2, 0x86, 0x07, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
277         0xED, 0x38, 0x38, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xCC, 0x77, 0x00, 0xFF, 0xCC, 0x77, 0x00, 0xFF, 0xCC, 0x77, 0x00, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
278         0xED, 0x38, 0x38, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xE2, 0x86, 0x07, 0xFF, 0xE2, 0x86, 0x07, 0xFF, 0xE2, 0x86, 0x07, 0xFF, 0xE2, 0x86, 0x07, 0xFF, 0xE2, 0x86, 0x07, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
279         0xED, 0x38, 0x38, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xF7, 0x9D, 0x1F, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xED, 0x38, 0x38, 0xFF,
280         0xED, 0x38, 0x38, 0xFF, 0xE2, 0x1D, 0x1D, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xC0, 0x2B, 0x2B, 0xFF, 0xE2, 0x1D, 0x1D, 0xFF, 0xED, 0x38, 0x38, 0xFF,
281         0x00, 0x00, 0x00, 0x00, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0xED, 0x38, 0x38, 0xFF, 0x00, 0x00, 0x00, 0x00
282 };
283
284 #include "fd-img-128x128.c"
285
286
287 #if 0
288 #include <stdarg.h>
289 #include <sys/types.h>                                                          // For MacOS <dirent.h> dependency
290 #include <dirent.h>
291 #include <SDL.h>
292 #include <string>
293 #include <vector>
294 #include <algorithm>
295 #include <ctype.h>                                                                      // For toupper()
296 #include "settings.h"
297 #include "tom.h"
298 #include "video.h"
299 #include "clock.h"
300 #include "font1.h"
301 #include "font14pt.h"                                                           // Also 15, 16, 17, 18
302 #include "guielements.h"
303 #include "crc32.h"
304 #include "zlib.h"
305 #include "unzip.h"
306 #include "sdlemu_opengl.h"
307 #include "gui.h"
308
309 using namespace std;                                                            // For STL stuff
310
311 // Private function prototypes
312
313 class Window;                                                                           // Forward declaration...
314
315 //void DrawTransparentBitmap(uint32_t * screen, uint32_t x, uint32_t y, uint32_t * bitmap, uint8_t * alpha = NULL);
316 void DrawTransparentBitmapDeprecated(uint32_t * screen, uint32_t x, uint32_t y, uint32_t * bitmap);
317 void DrawTransparentBitmap(uint32_t * screen, uint32_t x, uint32_t y, const void * bitmap);
318 void DrawBitmap(uint32_t * screen, uint32_t x, uint32_t y, const void * bitmap);
319 //Should call this FillScreenRectangle with a number representing the RGBA value to fill. !!! FIX !!!
320 //void ClearScreenRectangle(uint32_t * screen, uint32_t x, uint32_t y, uint32_t w, uint32_t h);
321 void FillScreenRectangle(uint32_t * screen, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t color);
322 void DrawStringTrans(uint32_t * screen, uint32_t x, uint32_t y, uint32_t color, uint8_t opacity, const char * text, ...);
323 void DrawStringOpaque(uint32_t * screen, uint32_t x, uint32_t y, uint32_t color1, uint32_t color2, const char * text, ...);
324 void DrawString(uint32_t * screen, uint32_t x, uint32_t y, bool invert, const char * text, ...);
325 void DrawString2(uint32_t * screen, uint32_t x, uint32_t y, uint32_t color, uint8_t transparency, const char * text, ...);
326 Window * LoadROM(void);
327 Window * ResetJaguar(void);
328 Window * ResetJaguarCD(void);
329 Window * RunEmu(void);
330 Window * Quit(void);
331 Window * About(void);
332 Window * MiscOptions(void);
333
334 int gzfilelength(gzFile gd);
335
336 // External variables
337
338 extern uint8_t * jaguar_mainRam;
339 extern uint8_t * jaguar_mainRom;
340 extern uint8_t * jaguar_bootRom;
341 extern uint8_t * jaguar_CDBootROM;
342 extern bool BIOSLoaded;
343 extern bool CDBIOSLoaded;
344
345 // Local global variables
346
347 bool exitGUI = false;                                                           // GUI (emulator) done variable
348 int mouseX = 0, mouseY = 0;
349 uint32_t background[1280 * 256];                                                // GUI background buffer
350
351 char separator[] = "--------------------------------------------------------";
352
353 //
354 // Case insensitive string compare function
355 // Taken straight out of Thinking In C++ by Bruce Eckel. Thanks Bruce!
356 //
357
358 int stringCmpi(const string &s1, const string &s2)
359 {
360         // Select the first element of each string:
361         string::const_iterator p1 = s1.begin(), p2 = s2.begin();
362
363         while (p1 != s1.end() && p2 != s2.end())                // Don�t run past the end
364         {
365                 if (toupper(*p1) != toupper(*p2))                       // Compare upper-cased chars
366                         return (toupper(*p1) < toupper(*p2) ? -1 : 1);// Report which was lexically greater
367
368                 p1++;
369                 p2++;
370         }
371
372         // If they match up to the detected eos, say which was longer. Return 0 if the same.
373         return s2.size() - s1.size();
374 }
375
376 //
377 // Local GUI classes
378 //
379
380 enum { WINDOW_CLOSE, MENU_ITEM_CHOSEN };
381
382 class Element
383 {
384         public:
385                 Element(uint32_t x = 0, uint32_t y = 0, uint32_t w = 0, uint32_t h = 0)
386                         { extents.x = x, extents.y = y, extents.w = w, extents.h = h; }
387                 virtual void HandleKey(SDL_Scancode key) = 0;           // These are "pure" virtual functions...
388                 virtual void HandleMouseMove(uint32_t x, uint32_t y) = 0;
389                 virtual void HandleMouseButton(uint32_t x, uint32_t y, bool mouseDown) = 0;
390                 virtual void Draw(uint32_t, uint32_t) = 0;
391                 virtual void Notify(Element *) = 0;
392 //Needed?               virtual ~Element() = 0;
393 //We're not allocating anything in the base class, so the answer would be NO.
394                 bool Inside(uint32_t x, uint32_t y);
395                 // Class method
396 //              static void SetScreenAndPitch(int16_t * s, uint32_t p) { screenBuffer = s, pitch = p; }
397                 static void SetScreenAndPitch(uint32_t * s, uint32_t p) { screenBuffer = s, pitch = p; }
398
399         protected:
400                 SDL_Rect extents;
401                 uint32_t state;
402                 // Class variables...
403 //              static int16_t * screenBuffer;
404                 static uint32_t * screenBuffer;
405                 static uint32_t pitch;
406 };
407
408 // Initialize class variables (Element)
409 //int16_t * Element::screenBuffer = NULL;
410 uint32_t * Element::screenBuffer = NULL;
411 uint32_t Element::pitch = 0;
412
413 bool Element::Inside(uint32_t x, uint32_t y)
414 {
415         return (x >= (uint32_t)extents.x && x < (uint32_t)(extents.x + extents.w)
416                 && y >= (uint32_t)extents.y && y < (uint32_t)(extents.y + extents.h) ? true : false);
417 }
418
419
420 //
421 // Button class
422 //
423
424 class Button: public Element
425 {
426         public:
427                 Button(uint32_t x = 0, uint32_t y = 0, uint32_t w = 0, uint32_t h = 0): Element(x, y, w, h),
428                         activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
429                         bgColor(0xFF00FF00), pic(NULL), elementToTell(NULL) {}
430                 Button(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t * p): Element(x, y, w, h),
431                         activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
432                         bgColor(0xFF00FF00), pic(p), elementToTell(NULL) {}
433 //              Button(uint32_t x, uint32_t y, uint32_t * p): Element(x, y, 0, 0),
434                 Button(uint32_t x, uint32_t y, uint32_t * p, uint32_t * pH = NULL, uint32_t * pD = NULL): Element(x, y, 0, 0),
435                         activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
436                         bgColor(0xFF00FF00), pic(p), picHover(pH), picDown(pD), elementToTell(NULL)
437                         { if (pic) extents.w = pic[0], extents.h = pic[1]; }
438                 Button(uint32_t x, uint32_t y, uint32_t w, uint32_t h, string s): Element(x, y, w, h),
439                         activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
440                         bgColor(0xFF00FF00), pic(NULL), text(s), elementToTell(NULL) {}
441                 Button(uint32_t x, uint32_t y, string s): Element(x, y, 0, FONT_HEIGHT),
442                         activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
443                         bgColor(0xFF00FF00), pic(NULL), text(s), elementToTell(NULL)
444                         { extents.w = s.length() * FONT_WIDTH; }
445                 virtual void HandleKey(SDL_Scancode key) {}
446                 virtual void HandleMouseMove(uint32_t x, uint32_t y);
447                 virtual void HandleMouseButton(uint32_t x, uint32_t y, bool mouseDown);
448                 virtual void Draw(uint32_t offsetX = 0, uint32_t offsetY = 0);
449                 virtual void Notify(Element *) {}
450                 bool ButtonClicked(void) { return activated; }
451                 void SetNotificationElement(Element * e) { elementToTell = e; }
452
453         protected:
454                 bool activated, clicked, inside;
455                 uint32_t fgColor, bgColor;
456                 uint32_t * pic, * picHover, * picDown;
457                 string text;
458                 Element * elementToTell;
459 };
460
461 void Button::HandleMouseMove(uint32_t x, uint32_t y)
462 {
463         inside = Inside(x, y);
464 }
465
466 void Button::HandleMouseButton(uint32_t x, uint32_t y, bool mouseDown)
467 {
468         if (inside)
469         {
470                 if (mouseDown)
471                         clicked = true;
472
473                 if (clicked && !mouseDown)
474                 {
475                         clicked = false, activated = true;
476
477                         // Send a message that we're activated (if there's someone to tell, that is)
478                         if (elementToTell)
479                                 elementToTell->Notify(this);
480                 }
481         }
482         else
483                 clicked = activated = false;
484 }
485
486 void Button::Draw(uint32_t offsetX/*= 0*/, uint32_t offsetY/*= 0*/)
487 {
488         uint32_t addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
489
490         if (text.length() > 0)                                                  // Simple text button
491 //      if (pic == NULL)
492         {
493                 for(uint32_t y=0; y<extents.h; y++)
494                 {
495                         for(uint32_t x=0; x<extents.w; x++)
496                         {
497                                 // Doesn't clip in y axis! !!! FIX !!!
498                                 if (extents.x + x < pitch)
499                                         screenBuffer[addr + x + (y * pitch)]
500 //                                      = (clicked && inside ? fgColor : (inside ? 0x43F0 : bgColor));
501 //43F0 -> 010000 11111 10000 -> 0100 0001 1111 1111 1000 0100 -> 41 FF 84
502                                                 = (clicked && inside ? fgColor : (inside ? 0xFF84FF41 : bgColor));
503                         }
504                 }
505
506                 DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY, false, "%s", text.c_str());
507         }
508         else                                                                                    // Graphical button
509         {
510                 uint32_t * picToShow = pic;
511
512                 if (picHover != NULL && inside && !clicked)
513                         picToShow = picHover;
514
515                 if (picDown != NULL && inside && clicked)
516                         picToShow = picDown;
517
518                 DrawTransparentBitmapDeprecated(screenBuffer, extents.x + offsetX, extents.y + offsetY, picToShow);
519         }
520 }
521
522
523 //
524 // PushButton class
525 //
526
527 class PushButton: public Element
528 {
529 // How to handle?
530 // Save state externally?
531 //We pass in a state variable if we want to track it externally, otherwise we use our own
532 //internal state var. Still need to do some kind of callback for pushbuttons that do things
533 //like change from fullscreen to windowed... !!! FIX !!!
534
535         public:
536 //              PushButton(uint32_t x = 0, uint32_t y = 0, uint32_t w = 0, uint32_t h = 0): Element(x, y, w, h),
537 //                      activated(false), clicked(false), inside(false), fgColor(0xFFFF),
538 //                      bgColor(0x03E0), pic(NULL), elementToTell(NULL) {}
539 //              PushButton(uint32_t x, uint32_t y, bool * st, string s): Element(x, y, 8, 8), state(st),
540 //                      inside(false), text(s) { if (st == NULL) state = &internalState; }
541                 PushButton(uint32_t x, uint32_t y, bool * st, string s): Element(x, y, 16, 16), state(st),
542                         inside(false), text(s) { if (st == NULL) state = &internalState; }
543 /*              Button(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t * p): Element(x, y, w, h),
544                         activated(false), clicked(false), inside(false), fgColor(0xFFFF),
545                         bgColor(0x03E0), pic(p), elementToTell(NULL) {}
546                 Button(uint32_t x, uint32_t y, uint32_t * p): Element(x, y, 0, 0),
547                         activated(false), clicked(false), inside(false), fgColor(0xFFFF),
548                         bgColor(0x03E0), pic(p), elementToTell(NULL)
549                         { if (pic) extents.w = pic[0], extents.h = pic[1]; }
550                 Button(uint32_t x, uint32_t y, uint32_t w, uint32_t h, string s): Element(x, y, w, h),
551                         activated(false), clicked(false), inside(false), fgColor(0xFFFF),
552                         bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL) {}
553                 PushButton(uint32_t x, uint32_t y, string s): Element(x, y, 0, 8),
554                         activated(false), clicked(false), inside(false), fgColor(0xFFFF),
555                         bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL)
556                         { extents.w = s.length() * 8; }*/
557                 virtual void HandleKey(SDL_Scancode key) {}
558                 virtual void HandleMouseMove(uint32_t x, uint32_t y);
559                 virtual void HandleMouseButton(uint32_t x, uint32_t y, bool mouseDown);
560                 virtual void Draw(uint32_t offsetX = 0, uint32_t offsetY = 0);
561                 virtual void Notify(Element *) {}
562 //              bool ButtonClicked(void) { return activated; }
563 //              void SetNotificationElement(Element * e) { elementToTell = e; }
564
565         protected:
566                 bool * state;
567                 bool inside;
568 //              bool activated, clicked, inside;
569 //              uint16_t fgColor, bgColor;
570 //              uint32_t * pic;
571                 string text;
572 //              Element * elementToTell;
573                 bool internalState;
574 };
575
576 void PushButton::HandleMouseMove(uint32_t x, uint32_t y)
577 {
578         inside = Inside(x, y);
579 }
580
581 void PushButton::HandleMouseButton(uint32_t x, uint32_t y, bool mouseDown)
582 {
583         if (inside && mouseDown)
584         {
585 /*              if (mouseDown)
586                         clicked = true;
587
588                 if (clicked && !mouseDown)
589                 {
590                         clicked = false, activated = true;
591
592                         // Send a message that we're activated (if there's someone to tell, that is)
593                         if (elementToTell)
594                                 elementToTell->Notify(this);
595                 }*/
596                 *state = !(*state);
597         }
598 //      else
599 //              clicked = activated = false;
600 }
601
602 void PushButton::Draw(uint32_t offsetX/*= 0*/, uint32_t offsetY/*= 0*/)
603 {
604 /*      uint32_t addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
605
606         for(uint32_t y=0; y<extents.h; y++)
607         {
608                 for(uint32_t x=0; x<extents.w; x++)
609                 {
610                         // Doesn't clip in y axis! !!! FIX !!!
611                         if (extents.x + x < pitch)
612                                 screenBuffer[addr + x + (y * pitch)]
613                                         = (clicked && inside ? fgColor : (inside ? 0x43F0 : bgColor));
614                 }
615         }*/
616
617         if (*state)
618                 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, &pbDown);
619         else
620                 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, &pbUp);
621
622         if (text.length() > 0)
623                 DrawString(screenBuffer, extents.x + offsetX + 24, extents.y + offsetY, false, "%s", text.c_str());
624 }
625
626
627 //
628 // SlideSwitch class
629 //
630
631 class SlideSwitch: public Element
632 {
633 // How to handle?
634 // Save state externally?
635 //Seems to be handled the same as PushButton, but without sanity checks. !!! FIX !!!
636
637         public:
638                 SlideSwitch(uint32_t x, uint32_t y, bool * st, string s1, string s2): Element(x, y, 16, 32), state(st),
639                         inside(false), text1(s1), text2(s2) {}
640                 virtual void HandleKey(SDL_Scancode key) {}
641                 virtual void HandleMouseMove(uint32_t x, uint32_t y);
642                 virtual void HandleMouseButton(uint32_t x, uint32_t y, bool mouseDown);
643                 virtual void Draw(uint32_t offsetX = 0, uint32_t offsetY = 0);
644                 virtual void Notify(Element *) {}
645 //              bool ButtonClicked(void) { return activated; }
646 //              void SetNotificationElement(Element * e) { elementToTell = e; }
647
648         protected:
649                 bool * state;
650                 bool inside;
651 //              bool activated, clicked, inside;
652 //              uint16_t fgColor, bgColor;
653 //              uint32_t * pic;
654                 string text1, text2;
655 //              Element * elementToTell;
656 };
657
658 void SlideSwitch::HandleMouseMove(uint32_t x, uint32_t y)
659 {
660         inside = Inside(x, y);
661 }
662
663 void SlideSwitch::HandleMouseButton(uint32_t x, uint32_t y, bool mouseDown)
664 {
665         if (inside && mouseDown)
666         {
667 /*              if (mouseDown)
668                         clicked = true;
669
670                 if (clicked && !mouseDown)
671                 {
672                         clicked = false, activated = true;
673
674                         // Send a message that we're activated (if there's someone to tell, that is)
675                         if (elementToTell)
676                                 elementToTell->Notify(this);
677                 }*/
678                 *state = !(*state);
679         }
680 //      else
681 //              clicked = activated = false;
682 }
683
684 void SlideSwitch::Draw(uint32_t offsetX/*= 0*/, uint32_t offsetY/*= 0*/)
685 {
686         DrawTransparentBitmapDeprecated(screenBuffer, extents.x + offsetX, extents.y + offsetY, (*state ? slideSwitchDown : slideSwitchUp));
687
688         if (text1.length() > 0)
689                 DrawString(screenBuffer, extents.x + offsetX + 24, extents.y + offsetY, false, "%s", text1.c_str());
690
691         if (text2.length() > 0)
692                 DrawString(screenBuffer, extents.x + offsetX + 24, extents.y + offsetY + 16, false, "%s", text2.c_str());
693 }
694
695
696 //
697 // Window class
698 //
699
700 class Window: public Element
701 {
702         public:
703 /*              Window(uint32_t x = 0, uint32_t y = 0, uint32_t w = 0, uint32_t h = 0): Element(x, y, w, h),
704                         fgColor(0x4FF0), bgColor(0xFE10)
705                         { close = new Button(w - 8, 1, closeBox); list.push_back(close); }*/
706                 Window(uint32_t x = 0, uint32_t y = 0, uint32_t w = 0, uint32_t h = 0,
707                         void (* f)(Element *) = NULL): Element(x, y, w, h),
708 //                      /*clicked(false), inside(false),*/ fgColor(0x4FF0), bgColor(0x1E10),
709 //4FF0 -> 010011 11111 10000 -> 0100 1101 1111 1111 1000 0100 -> 4D FF 84
710 //1E10 -> 000111 10000 10000 -> 0001 1111 1000 0100 1000 0100 -> 1F 84 84
711                         /*clicked(false), inside(false),*/ fgColor(0xFF84FF4D), bgColor(0xFF84841F),
712                         handler(f)
713                         { close = new Button(w - (CLOSEBOX_WIDTH + 1), 1, closeBox, closeBoxHover, closeBoxDown);
714                           list.push_back(close);
715                           close->SetNotificationElement(this); }
716                 virtual ~Window();
717                 virtual void HandleKey(SDL_Scancode key);
718                 virtual void HandleMouseMove(uint32_t x, uint32_t y);
719                 virtual void HandleMouseButton(uint32_t x, uint32_t y, bool mouseDown);
720                 virtual void Draw(uint32_t offsetX = 0, uint32_t offsetY = 0);
721                 virtual void Notify(Element * e);
722                 void AddElement(Element * e);
723 //              bool WindowActive(void) { return true; }//return !close->ButtonClicked(); }
724
725         protected:
726 //              bool clicked, inside;
727                 uint32_t fgColor, bgColor;
728                 void (* handler)(Element *);
729                 Button * close;
730 //We have to use a list of Element *pointers* because we can't make a list that will hold
731 //all the different object types in the same list...
732                 vector<Element *> list;
733 };
734
735 Window::~Window()
736 {
737         for(uint32_t i=0; i<list.size(); i++)
738                 if (list[i])
739                         delete list[i];
740 }
741
742 void Window::HandleKey(SDL_Scancode key)
743 {
744         if (key == SDLK_ESCAPE)
745         {
746                 SDL_Event event;
747                 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
748                 SDL_PushEvent(&event);
749         }
750
751         // Handle the items this window contains...
752         for(uint32_t i=0; i<list.size(); i++)
753                 // Make coords relative to upper right corner of this window...
754                 list[i]->HandleKey(key);
755 }
756
757 void Window::HandleMouseMove(uint32_t x, uint32_t y)
758 {
759         // Handle the items this window contains...
760         for(uint32_t i=0; i<list.size(); i++)
761                 // Make coords relative to upper right corner of this window...
762                 list[i]->HandleMouseMove(x - extents.x, y - extents.y);
763 }
764
765 void Window::HandleMouseButton(uint32_t x, uint32_t y, bool mouseDown)
766 {
767         // Handle the items this window contains...
768         for(uint32_t i=0; i<list.size(); i++)
769                 // Make coords relative to upper right corner of this window...
770                 list[i]->HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
771 }
772
773 void Window::Draw(uint32_t offsetX/*= 0*/, uint32_t offsetY/*= 0*/)
774 {
775         uint32_t addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
776
777         for(uint32_t y=0; y<extents.h; y++)
778         {
779                 for(uint32_t x=0; x<extents.w; x++)
780                 {
781                         // Doesn't clip in y axis! !!! FIX !!!
782                         if (extents.x + x < pitch)
783                                 screenBuffer[addr + x + (y * pitch)] = bgColor;
784                 }
785         }
786
787         // Handle the items this window contains...
788         for(uint32_t i=0; i<list.size(); i++)
789                 list[i]->Draw(extents.x, extents.y);
790 }
791
792 void Window::AddElement(Element * e)
793 {
794         list.push_back(e);
795 }
796
797 void Window::Notify(Element * e)
798 {
799         if (e == close)
800         {
801                 SDL_Event event;
802                 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
803                 SDL_PushEvent(&event);
804         }
805 }
806
807
808 //
809 // Static text class
810 //
811
812 class Text: public Element
813 {
814         public:
815 //              Text(uint32_t x = 0, uint32_t y = 0, uint32_t w = 0, uint32_t h = 0): Element(x, y, w, h),
816 //                      fgColor(0x4FF0), bgColor(0xFE10) {}
817 //              Text(uint32_t x, uint32_t y, string s, uint16_t fg = 0x4FF0, uint16_t bg = 0xFE10): Element(x, y, 0, 0),
818 //                      fgColor(fg), bgColor(bg), text(s) {}
819 //4FF0 -> 010011 11111 10000 -> 0100 1101 1111 1111 1000 0100 -> 4D FF 84
820 //FE10 -> 111111 10000 10000 -> 1111 1111 1000 0100 1000 0100 -> FF 84 84
821                 Text(uint32_t x = 0, uint32_t y = 0, uint32_t w = 0, uint32_t h = 0): Element(x, y, w, h),
822                         fgColor(0xFF8484FF), bgColor(0xFF84FF4D) {}
823                 Text(uint32_t x, uint32_t y, string s, uint32_t fg = 0xFF8484FF, uint32_t bg = 0xFF84FF4D):
824                         Element(x, y, 0, 0), fgColor(fg), bgColor(bg), text(s) {}
825                 virtual void HandleKey(SDL_Scancode key) {}
826                 virtual void HandleMouseMove(uint32_t x, uint32_t y) {}
827                 virtual void HandleMouseButton(uint32_t x, uint32_t y, bool mouseDown) {}
828                 virtual void Draw(uint32_t offsetX = 0, uint32_t offsetY = 0);
829                 virtual void Notify(Element *) {}
830
831         protected:
832                 uint32_t fgColor, bgColor;
833                 string text;
834 };
835
836 void Text::Draw(uint32_t offsetX/*= 0*/, uint32_t offsetY/*= 0*/)
837 {
838         if (text.length() > 0)
839 //              DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY, false, "%s", text.c_str());
840                 DrawStringOpaque(screenBuffer, extents.x + offsetX, extents.y + offsetY, fgColor, bgColor, "%s", text.c_str());
841 }
842
843
844 //
845 // Static image class
846 //
847
848 class Image: public Element
849 {
850         public:
851                 Image(uint32_t x, uint32_t y, const void * img): Element(x, y, 0, 0), image(img) {}
852                 virtual void HandleKey(SDL_Scancode key) {}
853                 virtual void HandleMouseMove(uint32_t x, uint32_t y) {}
854                 virtual void HandleMouseButton(uint32_t x, uint32_t y, bool mouseDown) {}
855                 virtual void Draw(uint32_t offsetX = 0, uint32_t offsetY = 0);
856                 virtual void Notify(Element *) {}
857
858         protected:
859                 uint32_t fgColor, bgColor;
860                 const void * image;
861 };
862
863 void Image::Draw(uint32_t offsetX/*= 0*/, uint32_t offsetY/*= 0*/)
864 {
865         if (image != NULL)
866                 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, image);
867 }
868
869
870 //
871 // TextEdit class
872 //
873
874 class TextEdit: public Element
875 {
876         public:
877                 TextEdit(uint32_t x = 0, uint32_t y = 0, uint32_t w = 0, uint32_t h = 0): Element(x, y, w, h),
878                         fgColor(0xFF8484FF), bgColor(0xFF84FF4D), text(""), caretPos(0),
879                         maxScreenSize(10) {}
880                 TextEdit(uint32_t x, uint32_t y, string s, uint32_t mss = 10, uint32_t fg = 0xFF8484FF,
881                         uint32_t bg = 0xFF84FF4D): Element(x, y, 0, 0), fgColor(fg), bgColor(bg), text(s),
882                         caretPos(0), maxScreenSize(mss) {}
883                 virtual void HandleKey(SDL_Scancode key);
884                 virtual void HandleMouseMove(uint32_t x, uint32_t y) {}
885                 virtual void HandleMouseButton(uint32_t x, uint32_t y, bool mouseDown) {}
886                 virtual void Draw(uint32_t offsetX = 0, uint32_t offsetY = 0);
887                 virtual void Notify(Element *) {}
888
889         protected:
890                 uint32_t fgColor, bgColor;
891                 string text;
892                 uint32_t caretPos;
893                 uint32_t maxScreenSize;
894 };
895
896 //Set different filters depending on type passed in on construction, e.g., filename, amount, etc...?
897 void TextEdit::HandleKey(SDL_Scancode key)
898 {
899         if ((key >= SDLK_a && key <= SDLK_z) || (key >= SDLK_0 && key <= SDLK_9) || key == SDLK_PERIOD
900                 || key == SDLK_SLASH)
901         {
902                 //Need to handle shift key as well...
903                 text[caretPos++] = key;
904                 Draw();
905         }
906         else if (key == SDLK_BACKSPACE)
907         {
908
909         }
910         else if (key == SDLK_DELETE)
911         {
912         }
913 //left, right arrow
914 }
915
916 void TextEdit::Draw(uint32_t offsetX/*= 0*/, uint32_t offsetY/*= 0*/)
917 {
918         if (text.length() > 0)
919         {
920                 FillScreenRectangle(screenBuffer, extents.x + offsetX, extents.y + offsetY, FONT_WIDTH * maxScreenSize, FONT_HEIGHT, bgColor);
921 //              DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY, false, "%s", text.c_str());
922                 DrawStringOpaque(screenBuffer, extents.x + offsetX, extents.y + offsetY, fgColor, bgColor, "%s", text.c_str());
923         }
924
925         // Draw the caret (underscore? or vertical line?)
926 }
927
928
929 //
930 // ListBox class
931 //
932
933 class ListBox: public Element
934 //class ListBox: public Window
935 {
936         public:
937 //              ListBox(uint32_t x = 0, uint32_t y = 0, uint32_t w = 0, uint32_t h = 0): Element(x, y, w, h),
938                 ListBox(uint32_t x = 0, uint32_t y = 0, uint32_t w = 0, uint32_t h = 0);//: Window(x, y, w, h),
939 //              windowPtr(0), cursor(0), limit(0), charWidth((w / 8) - 1), charHeight(h / 8),
940 //              elementToTell(NULL), upArrow(w - 8, 0, upArrowBox),
941 //              downArrow(w - 8, h - 8, downArrowBox), upArrow2(w - 8, h - 16, upArrowBox) {}
942                 virtual void HandleKey(SDL_Scancode key);
943                 virtual void HandleMouseMove(uint32_t x, uint32_t y);
944                 virtual void HandleMouseButton(uint32_t x, uint32_t y, bool mouseDown);
945                 virtual void Draw(uint32_t offsetX = 0, uint32_t offsetY = 0);
946                 virtual void Notify(Element * e);
947                 void SetNotificationElement(Element * e) { elementToTell = e; }
948                 void AddItem(string s);
949                 string GetSelectedItem(void);
950
951         protected:
952                 bool thumbClicked;
953                 uint32_t windowPtr, cursor, limit;
954                 uint32_t charWidth, charHeight;                         // Box width/height in characters
955                 Element * elementToTell;
956                 Button upArrow, downArrow, upArrow2;
957                 vector<string> item;
958
959         private:
960                 uint32_t yRelativePoint;
961 };
962
963 ListBox::ListBox(uint32_t x, uint32_t y, uint32_t w, uint32_t h): Element(x, y, w, h),
964         thumbClicked(false), windowPtr(0), cursor(0), limit(0), charWidth((w / FONT_WIDTH) - 1),
965         charHeight(h / FONT_HEIGHT), elementToTell(NULL), upArrow(w - 8, 0, upArrowBox),
966         downArrow(w - 8, h - 8, downArrowBox), upArrow2(w - 8, h - 16, upArrowBox)
967 {
968         upArrow.SetNotificationElement(this);
969         downArrow.SetNotificationElement(this);
970         upArrow2.SetNotificationElement(this);
971         extents.w -= 8;                                                                 // Make room for scrollbar...
972 }
973
974 void ListBox::HandleKey(SDL_Scancode key)
975 {
976         if (key == SDLK_DOWN)
977         {
978                 if (cursor != limit - 1)        // Cursor is within its window
979                         cursor++;
980                 else                                            // Otherwise, scroll the window...
981                 {
982                         if (cursor + windowPtr != item.size() - 1)
983                                 windowPtr++;
984                 }
985         }
986         else if (key == SDLK_UP)
987         {
988                 if (cursor != 0)
989                         cursor--;
990                 else
991                 {
992                         if (windowPtr != 0)
993                                 windowPtr--;
994                 }
995         }
996         else if (key == SDLK_PAGEDOWN)
997         {
998                 if (cursor != limit - 1)
999                         cursor = limit - 1;
1000                 else
1001                 {
1002                         windowPtr += limit;
1003                         if (windowPtr > item.size() - limit)
1004                                 windowPtr = item.size() - limit;
1005                 }
1006         }
1007         else if (key == SDLK_PAGEUP)
1008         {
1009                 if (cursor != 0)
1010                         cursor = 0;
1011                 else
1012                 {
1013                         if (windowPtr < limit)
1014                                 windowPtr = 0;
1015                         else
1016                                 windowPtr -= limit;
1017                 }
1018         }
1019         else if (key >= SDLK_a && key <= SDLK_z)
1020         {
1021                 // Advance cursor to filename with first letter pressed...
1022                 uint8_t which = (key - SDLK_a) + 65;    // Convert key to A-Z char
1023
1024                 for(uint32_t i=0; i<item.size(); i++)
1025                 {
1026                         if ((item[i][0] & 0xDF) == which)
1027                         {
1028                                 cursor = i - windowPtr;
1029                                 if (i > windowPtr + limit - 1)
1030                                         windowPtr = i - limit + 1, cursor = limit - 1;
1031                                 if (i < windowPtr)
1032                                         windowPtr = i, cursor = 0;
1033                                 break;
1034                         }
1035                 }
1036         }
1037 }
1038
1039 void ListBox::HandleMouseMove(uint32_t x, uint32_t y)
1040 {
1041         upArrow.HandleMouseMove(x - extents.x, y - extents.y);
1042         downArrow.HandleMouseMove(x - extents.x, y - extents.y);
1043         upArrow2.HandleMouseMove(x - extents.x, y - extents.y);
1044
1045         if (thumbClicked)
1046         {
1047                 uint32_t sbHeight = extents.h - 24,
1048                         thumb = (uint32_t)(((float)limit / (float)item.size()) * (float)sbHeight);
1049
1050 //yRelativePoint is the spot on the thumb where we clicked...
1051                 int32_t newThumbStart = y - yRelativePoint;
1052
1053                 if (newThumbStart < 0)
1054                         newThumbStart = 0;
1055
1056                 if ((uint32_t)newThumbStart > sbHeight - thumb)
1057                         newThumbStart = sbHeight - thumb;
1058
1059                 windowPtr = (uint32_t)(((float)newThumbStart / (float)sbHeight) * (float)item.size());
1060 //Check for cursor bounds as well... Or do we need to???
1061 //Actually, we don't...!
1062         }
1063 }
1064
1065 void ListBox::HandleMouseButton(uint32_t x, uint32_t y, bool mouseDown)
1066 {
1067         if (Inside(x, y) && mouseDown)
1068         {
1069                 // Why do we have to do this??? (- extents.y?)
1070                 // I guess it's because only the Window class has offsetting implemented... !!! FIX !!!
1071 //              cursor = (y - extents.y) / 8;
1072                 cursor = (y - extents.y) / FONT_HEIGHT;
1073         }
1074
1075         // Check for a hit on the scrollbar...
1076         if (x > (uint32_t)(extents.x + extents.w) && x <= (uint32_t)(extents.x + extents.w + 8)
1077                 && y > (uint32_t)(extents.y + 8) && y <= (uint32_t)(extents.y + extents.h - 16))
1078         {
1079                 if (mouseDown)
1080                 {
1081 // This shiaut should be calculated in AddItem(), not here... (or in Draw() for that matter)
1082                         uint32_t sbHeight = extents.h - 24,
1083                                 thumb = (uint32_t)(((float)limit / (float)item.size()) * (float)sbHeight),
1084                                 thumbStart = (uint32_t)(((float)windowPtr / (float)item.size()) * (float)sbHeight);
1085
1086                         // Did we hit the thumb?
1087                         if (y >= (extents.y + 8 + thumbStart) && y < (extents.y + 8 + thumbStart + thumb))
1088                                 thumbClicked = true, yRelativePoint = y - thumbStart;
1089                 }
1090 //Seems that this is useless--never reached except in rare cases and that the code outside is
1091 //more effective...
1092 //              else
1093 //                      thumbClicked = false;
1094         }
1095
1096         if (!mouseDown)
1097                 thumbClicked = false;
1098
1099         upArrow.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
1100         downArrow.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
1101         upArrow2.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
1102 }
1103
1104 void ListBox::Draw(uint32_t offsetX/*= 0*/, uint32_t offsetY/*= 0*/)
1105 {
1106         for(uint32_t i=0; i<limit; i++)
1107         {
1108                 // Strip off the extension
1109                 // (extension stripping should be an option, not default!)
1110                 string s(item[windowPtr + i], 0, item[windowPtr + i].length() - 4);
1111 //              DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY + i*8,
1112                 DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY + i*FONT_HEIGHT,
1113                         (cursor == i ? true : false), "%-*.*s", charWidth, charWidth, s.c_str());
1114         }
1115
1116         upArrow.Draw(extents.x + offsetX, extents.y + offsetY);
1117         downArrow.Draw(extents.x + offsetX, extents.y + offsetY);
1118         upArrow2.Draw(extents.x + offsetX, extents.y + offsetY);
1119
1120         uint32_t sbHeight = extents.h - 24,
1121                 thumb = (uint32_t)(((float)limit / (float)item.size()) * (float)sbHeight),
1122                 thumbStart = (uint32_t)(((float)windowPtr / (float)item.size()) * (float)sbHeight);
1123
1124         for(uint32_t y=extents.y+offsetY+8; y<extents.y+offsetY+extents.h-16; y++)
1125         {
1126 //              for(uint32_t x=extents.x+offsetX+extents.w-8; x<extents.x+offsetX+extents.w; x++)
1127                 for(uint32_t x=extents.x+offsetX+extents.w; x<extents.x+offsetX+extents.w+8; x++)
1128                 {
1129                         if (y >= thumbStart + (extents.y+offsetY+8) && y < thumbStart + thumb + (extents.y+offsetY+8))
1130 //                              screenBuffer[x + (y * pitch)] = (thumbClicked ? 0x458E : 0xFFFF);
1131 //458E -> 01 0001  0 1100  0 1110 -> 0100 0101  0110 0011  0111 0011 -> 45 63 73
1132                                 screenBuffer[x + (y * pitch)] = (thumbClicked ? 0xFF736345 : 0xFFFFFFFF);
1133                         else
1134 //                              screenBuffer[x + (y * pitch)] = 0x0200;
1135 //0200 -> 000000 10000 00000 -> 00 1000 0100 00
1136                                 screenBuffer[x + (y * pitch)] = 0xFF008400;
1137                 }
1138         }
1139 }
1140
1141 void ListBox::Notify(Element * e)
1142 {
1143         if (e == &upArrow || e == &upArrow2)
1144         {
1145                 if (windowPtr != 0)
1146                 {
1147                         windowPtr--;
1148
1149                         if (cursor < limit - 1)
1150                                 cursor++;
1151                 }
1152         }
1153         else if (e == &downArrow)
1154         {
1155                 if (windowPtr < item.size() - limit)
1156                 {
1157                         windowPtr++;
1158
1159                         if (cursor != 0)
1160                                 cursor--;
1161                 }
1162         }
1163 }
1164
1165 void ListBox::AddItem(string s)
1166 {
1167         // Do a simple insertion sort
1168         bool inserted = false;
1169
1170         for(vector<string>::iterator i=item.begin(); i<item.end(); i++)
1171         {
1172                 if (stringCmpi(s, *i) == -1)
1173                 {
1174                         item.insert(i, s);
1175                         inserted = true;
1176                         break;
1177                 }
1178         }
1179
1180         if (!inserted)
1181                 item.push_back(s);
1182
1183         limit = (item.size() > charHeight ? charHeight : item.size());
1184 }
1185
1186 string ListBox::GetSelectedItem(void)
1187 {
1188         return item[windowPtr + cursor];
1189 }
1190
1191
1192 //
1193 // FileList class
1194 //
1195
1196 class FileList: public Window
1197 {
1198         public:
1199                 FileList(uint32_t x = 0, uint32_t y = 0, uint32_t w = 0, uint32_t h = 0);
1200                 virtual ~FileList() {}
1201                 virtual void HandleKey(SDL_Scancode key);
1202                 virtual void HandleMouseMove(uint32_t x, uint32_t y) { Window::HandleMouseMove(x, y); }
1203                 virtual void HandleMouseButton(uint32_t x, uint32_t y, bool mouseDown) { Window::HandleMouseButton(x, y, mouseDown); }
1204                 virtual void Draw(uint32_t offsetX = 0, uint32_t offsetY = 0) { Window::Draw(offsetX, offsetY); }
1205                 virtual void Notify(Element * e);
1206
1207         protected:
1208                 ListBox * files;
1209                 Button * load;
1210 };
1211
1212 //Need 4 buttons, one scrollbar...
1213 FileList::FileList(uint32_t x, uint32_t y, uint32_t w, uint32_t h): Window(x, y, w, h)
1214 {
1215         files = new ListBox(8, 8, w - 16, h - 32);
1216         AddElement(files);
1217         load = new Button(8, h - 16, " Load ");
1218         AddElement(load);
1219         load->SetNotificationElement(this);
1220
1221 //!!! FIX !!! Directory might not exist--this shouldn't cause VJ to crash!
1222         DIR * dp = opendir(vjs.ROMPath);
1223         dirent * de;
1224
1225         if (dp != NULL)
1226         {
1227                 while ((de = readdir(dp)) != NULL)
1228                 {
1229                         char * ext = strrchr(de->d_name, '.');
1230
1231                         if (ext != NULL)
1232                                 if (strcasecmp(ext, ".zip") == 0 || strcasecmp(ext, ".j64") == 0
1233                                         || strcasecmp(ext, ".abs") == 0 || strcasecmp(ext, ".jag") == 0
1234                                         || strcasecmp(ext, ".rom") == 0)
1235                                         files->AddItem(string(de->d_name));
1236                 }
1237
1238                 closedir(dp);
1239         }
1240         else
1241         {
1242 //Give a diagnostic message here so that the (l)user can figure out what went wrong. !!! FIX !!!
1243         }
1244 }
1245
1246 void FileList::HandleKey(SDL_Scancode key)
1247 {
1248         if (key == SDLK_RETURN)
1249                 Notify(load);
1250         else
1251                 Window::HandleKey(key);
1252 }
1253
1254 void FileList::Notify(Element * e)
1255 {
1256         if (e == load)
1257         {
1258                 char filename[MAX_PATH];
1259                 strcpy(filename, vjs.ROMPath);
1260
1261                 if (strlen(filename) > 0)
1262                         if (filename[strlen(filename) - 1] != '/')
1263                                 strcat(filename, "/");
1264
1265                 strcat(filename, files->GetSelectedItem().c_str());
1266
1267 //              uint32_t romSize = JaguarLoadROM(jaguar_mainRom, filename);
1268 //              JaguarLoadCart(jaguar_mainRom, filename);
1269                 if (JaguarLoadFile(filename))
1270                 {
1271                         SDL_Event event;
1272                         event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
1273                         SDL_PushEvent(&event);
1274
1275                         event.type = SDL_USEREVENT, event.user.code = MENU_ITEM_CHOSEN;
1276                         event.user.data1 = (void *)ResetJaguar;
1277                 SDL_PushEvent(&event);
1278                 }
1279                 else
1280                 {
1281                         SDL_Event event;
1282                         event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
1283                         SDL_PushEvent(&event);
1284
1285                         // Handle the error, but don't run...
1286                         // Tell the user that we couldn't run their file for some reason... !!! FIX !!!
1287 //how to kludge: Make a function like ResetJaguar which creates the dialog window
1288                 }
1289         }
1290         else
1291                 Window::Notify(e);
1292 }
1293
1294
1295 //
1296 // Menu class & supporting structs/classes
1297 //
1298
1299 struct NameAction
1300 {
1301         string name;
1302         Window * (* action)(void);
1303         SDL_Scancode hotKey;
1304
1305         NameAction(string n, Window * (* a)(void) = NULL, SDL_Scancode k = SDLK_UNKNOWN): name(n),
1306                 action(a), hotKey(k) {}
1307 };
1308
1309 class MenuItems
1310 {
1311         public:
1312                 MenuItems(): charLength(0) {}
1313                 bool Inside(uint32_t x, uint32_t y)
1314                 { return (x >= (uint32_t)extents.x && x < (uint32_t)(extents.x + extents.w)
1315                 && y >= (uint32_t)extents.y && y < (uint32_t)(extents.y + extents.h) ? true : false); }
1316
1317                 string title;
1318                 vector<NameAction> item;
1319                 uint32_t charLength;
1320                 SDL_Rect extents;
1321 };
1322
1323 class Menu: public Element
1324 {
1325         public:
1326 // 1CFF -> 0 001 11 00  111 1 1111
1327 // 421F -> 0 100 00 10  000 1 1111
1328                 Menu(uint32_t x = 0, uint32_t y = 0, uint32_t w = 0, uint32_t h = FONT_HEIGHT,
1329 /*                      uint16_t fgc = 0x1CFF, uint16_t bgc = 0x000F, uint16_t fgch = 0x421F,
1330                         uint16_t bgch = 0x1CFF): Element(x, y, w, h), activated(false), clicked(false),*/
1331 /*                      uint32_t fgc = 0xFF3F3F00, uint32_t bgc = 0x7F000000, uint32_t fgch = 0xFF878700,
1332                         uint32_t bgch = 0xFF3F3F00): Element(x, y, w, h), activated(false), clicked(false),*/
1333 /*                      uint32_t fgc = 0xFFFF3F3F, uint32_t bgc = 0xFF7F0000, uint32_t fgch = 0xFFFF8787,
1334                         uint32_t bgch = 0xFFFF3F3F): Element(x, y, w, h), activated(false), clicked(false),*/
1335                         uint32_t fgc = 0xFF7F0000, uint32_t bgc = 0xFFFF3F3F, uint32_t fgch = 0xFFFF3F3F,
1336                         uint32_t bgch = 0xFFFF8787): Element(x, y, w, h), activated(false), clicked(false),
1337                         inside(0), insidePopup(0), fgColor(fgc), bgColor(bgc), fgColorHL(fgch),
1338                         bgColorHL(bgch), menuChosen(-1), menuItemChosen(-1) {}
1339                 virtual void HandleKey(SDL_Scancode key);
1340                 virtual void HandleMouseMove(uint32_t x, uint32_t y);
1341                 virtual void HandleMouseButton(uint32_t x, uint32_t y, bool mouseDown);
1342                 virtual void Draw(uint32_t offsetX = 0, uint32_t offsetY = 0);
1343                 virtual void Notify(Element *) {}
1344                 void Add(MenuItems mi);
1345
1346         protected:
1347                 bool activated, clicked;
1348                 uint32_t inside, insidePopup;
1349 //              uint16_t fgColor, bgColor, fgColorHL, bgColorHL;
1350                 uint32_t fgColor, bgColor, fgColorHL, bgColorHL;
1351                 int menuChosen, menuItemChosen;
1352
1353         private:
1354                 vector<MenuItems> itemList;
1355 };
1356
1357 void Menu::HandleKey(SDL_Scancode key)
1358 {
1359         for(uint32_t i=0; i<itemList.size(); i++)
1360         {
1361                 for(uint32_t j=0; j<itemList[i].item.size(); j++)
1362                 {
1363                         if (itemList[i].item[j].hotKey == key)
1364                         {
1365                                 SDL_Event event;
1366                                 event.type = SDL_USEREVENT;
1367                                 event.user.code = MENU_ITEM_CHOSEN;
1368                                 event.user.data1 = (void *)itemList[i].item[j].action;
1369                         SDL_PushEvent(&event);
1370
1371                                 clicked = false, menuChosen = menuItemChosen = -1;
1372                                 break;
1373                         }
1374                 }
1375         }
1376 }
1377
1378 void Menu::HandleMouseMove(uint32_t x, uint32_t y)
1379 {
1380         inside = insidePopup = 0;
1381
1382         if (Inside(x, y))
1383         {
1384                 // Find out *where* we are inside the menu bar
1385                 uint32_t xpos = extents.x;
1386
1387                 for(uint32_t i=0; i<itemList.size(); i++)
1388                 {
1389                         uint32_t width = (itemList[i].title.length() + 2) * FONT_WIDTH;
1390
1391                         if (x >= xpos && x < xpos + width)
1392                         {
1393                                 inside = i + 1;
1394                                 menuChosen = i;
1395                                 break;
1396                         }
1397
1398                         xpos += width;
1399                 }
1400         }
1401
1402         if (!Inside(x, y) && !clicked)
1403         {
1404                 menuChosen = -1;
1405         }
1406
1407         if (itemList[menuChosen].Inside(x, y) && clicked)
1408         {
1409                 insidePopup = ((y - itemList[menuChosen].extents.y) / FONT_HEIGHT) + 1;
1410                 menuItemChosen = insidePopup - 1;
1411         }
1412 }
1413
1414 void Menu::HandleMouseButton(uint32_t x, uint32_t y, bool mouseDown)
1415 {
1416         if (!clicked)
1417         {
1418                 if (mouseDown)
1419                 {
1420                         if (inside)
1421                                 clicked = true;
1422                         else
1423                                 menuChosen = -1;                                        // clicked is already false...!
1424                 }
1425         }
1426         else                                                                                    // clicked == true
1427         {
1428                 if (insidePopup && !mouseDown)                          // I.e., mouse-button-up
1429                 {
1430                         activated = true;
1431                         if (itemList[menuChosen].item[menuItemChosen].action != NULL)
1432                         {
1433 //                              itemList[menuChosen].item[menuItemChosen].action();
1434                                 SDL_Event event;
1435                                 event.type = SDL_USEREVENT;
1436                                 event.user.code = MENU_ITEM_CHOSEN;
1437                                 event.user.data1 = (void *)itemList[menuChosen].item[menuItemChosen].action;
1438                             SDL_PushEvent(&event);
1439
1440                                 clicked = false, menuChosen = menuItemChosen = -1;
1441
1442 /*                              SDL_Event event;
1443                                 while (SDL_PollEvent(&event));          // Flush the event queue...
1444                                 event.type = SDL_MOUSEMOTION;
1445                                 int mx, my;
1446                                 SDL_GetMouseState(&mx, &my);
1447                                 event.motion.x = mx, event.motion.y = my;
1448                             SDL_PushEvent(&event);                              // & update mouse position...!
1449 */                      }
1450                 }
1451
1452                 if (!inside && !insidePopup && mouseDown)
1453                         clicked = false, menuChosen = menuItemChosen = -1;
1454         }
1455 }
1456
1457 void Menu::Draw(uint32_t offsetX/*= 0*/, uint32_t offsetY/*= 0*/)
1458 {
1459         uint32_t xpos = extents.x + offsetX;
1460
1461         for(uint32_t i=0; i<itemList.size(); i++)
1462         {
1463 //              uint16_t color1 = fgColor, color2 = bgColor;
1464                 uint32_t color1 = fgColor, color2 = bgColor;
1465                 if (inside == (i + 1) || (menuChosen != -1 && (uint32_t)menuChosen == i))
1466                         color1 = fgColorHL, color2 = bgColorHL;
1467
1468                 DrawStringOpaque(screenBuffer, xpos, extents.y + offsetY, color1, color2,
1469                         " %s ", itemList[i].title.c_str());
1470                 xpos += (itemList[i].title.length() + 2) * FONT_WIDTH;
1471         }
1472
1473         // Draw sub menu (but only if active)
1474         if (clicked)
1475         {
1476                 uint32_t ypos = extents.y + FONT_HEIGHT + 1;
1477
1478                 for(uint32_t i=0; i<itemList[menuChosen].item.size(); i++)
1479                 {
1480 //                      uint16_t color1 = fgColor, color2 = bgColor;
1481                         uint32_t color1 = fgColor, color2 = bgColor;
1482
1483                         if (insidePopup == i + 1)
1484                                 color1 = fgColorHL, color2 = bgColorHL, menuItemChosen = i;
1485
1486                         if (itemList[menuChosen].item[i].name.length() > 0)
1487                                 DrawStringOpaque(screenBuffer, itemList[menuChosen].extents.x, ypos,
1488                                         color1, color2, " %-*.*s ", itemList[menuChosen].charLength,
1489                                         itemList[menuChosen].charLength, itemList[menuChosen].item[i].name.c_str());
1490                         else
1491                                 DrawStringOpaque(screenBuffer, itemList[menuChosen].extents.x, ypos,
1492                                         fgColor, bgColor, "%.*s", itemList[menuChosen].charLength + 2, separator);
1493
1494                         ypos += FONT_HEIGHT;
1495                 }
1496         }
1497 }
1498
1499 void Menu::Add(MenuItems mi)
1500 {
1501         for(uint32_t i=0; i<mi.item.size(); i++)
1502                 if (mi.item[i].name.length() > mi.charLength)
1503                         mi.charLength = mi.item[i].name.length();
1504
1505         // Set extents here as well...
1506         mi.extents.x = extents.x + extents.w, mi.extents.y = extents.y + FONT_HEIGHT + 1;
1507         mi.extents.w = (mi.charLength + 2) * FONT_WIDTH, mi.extents.h = mi.item.size() * FONT_HEIGHT;
1508
1509         itemList.push_back(mi);
1510         extents.w += (mi.title.length() + 2) * FONT_WIDTH;
1511 }
1512
1513
1514 //Do we even *need* this?
1515 //Doesn't seem like it...
1516 /*class RootWindow: public Window
1517 {
1518         public:
1519                 RootWindow(Menu * m, Window * w = NULL): menu(m), window(w) {}
1520 //Do we even need to care about this crap?
1521 //                      { extents.x = extents.y = 0, extents.w = 320, extents.h = 240; }
1522                 virtual void HandleKey(SDL_Scancode key) {}
1523                 virtual void HandleMouseMove(uint32_t x, uint32_t y) {}
1524                 virtual void HandleMouseButton(uint32_t x, uint32_t y, bool mouseDown) {}
1525                 virtual void Draw(uint32_t offsetX = 0, uint32_t offsetY = 0) {}
1526                 virtual void Notify(Element *) {}
1527
1528         private:
1529                 Menu * menu;
1530                 Window * window;
1531                 int16_t * rootImage[1280 * 240 * 2];
1532 };//*/
1533
1534
1535 //
1536 // Draw text at the given x/y coordinates. Can invert text as well.
1537 //
1538 void DrawString(uint32_t * screen, uint32_t x, uint32_t y, bool invert, const char * text, ...)
1539 {
1540         char string[4096];
1541         va_list arg;
1542
1543         va_start(arg, text);
1544         vsprintf(string, text, arg);
1545         va_end(arg);
1546
1547         uint32_t pitch = sdlemuGetOverlayWidthInPixels();//GetSDLScreenWidthInPixels();
1548         uint32_t length = strlen(string), address = x + (y * pitch);
1549
1550         uint32_t color1 = 0x0080FF;
1551         uint8_t nBlue = (color1 >> 16) & 0xFF, nGreen = (color1 >> 8) & 0xFF, nRed = color1 & 0xFF;
1552         uint8_t xorMask = (invert ? 0xFF : 0x00);
1553
1554         for(uint32_t i=0; i<length; i++)
1555         {
1556                 uint8_t c = string[i];
1557                 uint32_t fontAddr = (uint32_t)(c < 32 ? 0 : c - 32) * FONT_WIDTH * FONT_HEIGHT;
1558
1559                 for(uint32_t yy=0; yy<FONT_HEIGHT; yy++)
1560                 {
1561                         for(uint32_t xx=0; xx<FONT_WIDTH; xx++)
1562                         {
1563                                 uint32_t existingColor = *(screen + address + xx + (yy * pitch));
1564
1565                                 uint8_t eBlue = (existingColor >> 16) & 0xFF,
1566                                         eGreen = (existingColor >> 8) & 0xFF,
1567                                         eRed = existingColor & 0xFF;
1568
1569                                 uint8_t trans = font2[fontAddr] ^ xorMask;
1570                                 uint8_t invTrans = trans ^ 0xFF;
1571
1572                                 uint32_t bRed = (eRed * invTrans + nRed * trans) / 255,
1573                                         bGreen = (eGreen * invTrans + nGreen * trans) / 255,
1574                                         bBlue = (eBlue * invTrans + nBlue * trans) / 255;
1575
1576                                 *(screen + address + xx + (yy * pitch)) = 0xFF000000 | (bBlue << 16) | (bGreen << 8) | bRed;
1577                                 fontAddr++;
1578                         }
1579                 }
1580
1581                 address += FONT_WIDTH;
1582         }
1583 }
1584
1585 //
1586 // Draw text at the given x/y coordinates, using FG/BG colors.
1587 //
1588 void DrawStringOpaque(uint32_t * screen, uint32_t x, uint32_t y, uint32_t color1, uint32_t color2, const char * text, ...)
1589 {
1590         char string[4096];
1591         va_list arg;
1592
1593         va_start(arg, text);
1594         vsprintf(string, text, arg);
1595         va_end(arg);
1596
1597         uint32_t pitch = sdlemuGetOverlayWidthInPixels();
1598         uint32_t length = strlen(string), address = x + (y * pitch);
1599
1600         uint8_t eBlue = (color2 >> 16) & 0xFF, eGreen = (color2 >> 8) & 0xFF, eRed = color2 & 0xFF,
1601                 nBlue = (color1 >> 16) & 0xFF, nGreen = (color1 >> 8) & 0xFF, nRed = color1 & 0xFF;
1602
1603         for(uint32_t i=0; i<length; i++)
1604         {
1605                 uint8_t c = string[i];
1606                 c = (c < 32 ? 0 : c - 32);
1607                 uint32_t fontAddr = (uint32_t)c * FONT_WIDTH * FONT_HEIGHT;
1608
1609                 for(uint32_t yy=0; yy<FONT_HEIGHT; yy++)
1610                 {
1611                         for(uint32_t xx=0; xx<FONT_WIDTH; xx++)
1612                         {
1613                                 uint8_t trans = font2[fontAddr++];
1614                                 uint8_t invTrans = trans ^ 0xFF;
1615
1616                                 uint32_t bRed   = (eRed   * invTrans + nRed   * trans) / 255;
1617                                 uint32_t bGreen = (eGreen * invTrans + nGreen * trans) / 255;
1618                                 uint32_t bBlue  = (eBlue  * invTrans + nBlue  * trans) / 255;
1619
1620                                 *(screen + address + xx + (yy * pitch)) = 0xFF000000 | (bBlue << 16) | (bGreen << 8) | bRed;
1621                         }
1622                 }
1623
1624                 address += FONT_WIDTH;
1625         }
1626 }
1627
1628 //
1629 // Draw text at the given x/y coordinates with transparency (0 is fully opaque, 32 is fully transparent).
1630 //
1631 void DrawStringTrans(uint32_t * screen, uint32_t x, uint32_t y, uint32_t color, uint8_t trans, const char * text, ...)
1632 {
1633         char string[4096];
1634         va_list arg;
1635
1636         va_start(arg, text);
1637         vsprintf(string, text, arg);
1638         va_end(arg);
1639
1640         uint32_t pitch = sdlemuGetOverlayWidthInPixels();//GetSDLScreenWidthInPixels();
1641         uint32_t length = strlen(string), address = x + (y * pitch);
1642
1643         for(uint32_t i=0; i<length; i++)
1644         {
1645                 uint32_t fontAddr = (uint32_t)string[i] * 64;
1646
1647                 for(uint32_t yy=0; yy<8; yy++)
1648                 {
1649                         for(uint32_t xx=0; xx<8; xx++)
1650                         {
1651                                 if (font1[fontAddr])
1652                                 {
1653                                         uint32_t existingColor = *(screen + address + xx + (yy * pitch));
1654
1655                                         uint8_t eBlue = (existingColor >> 16) & 0xFF,
1656                                                 eGreen = (existingColor >> 8) & 0xFF,
1657                                                 eRed = existingColor & 0xFF,
1658 //This could be done ahead of time, instead of on each pixel...
1659                                                 nBlue = (color >> 16) & 0xFF,
1660                                                 nGreen = (color >> 8) & 0xFF,
1661                                                 nRed = color & 0xFF;
1662
1663 //This could be sped up by using a table of 5 + 5 + 5 bits (32 levels transparency -> 32768 entries)
1664 //Here we've modified it to have 33 levels of transparency (could have any # we want!)
1665 //because dividing by 32 is faster than dividing by 31...!
1666                                         uint8_t invTrans = 32 - trans;
1667
1668                                         uint32_t bRed = (eRed * trans + nRed * invTrans) / 32;
1669                                         uint32_t bGreen = (eGreen * trans + nGreen * invTrans) / 32;
1670                                         uint32_t bBlue = (eBlue * trans + nBlue * invTrans) / 32;
1671
1672                                         *(screen + address + xx + (yy * pitch)) = 0xFF000000 | (bBlue << 16) | (bGreen << 8) | bRed;
1673                                 }
1674
1675                                 fontAddr++;
1676                         }
1677                 }
1678
1679                 address += 8;
1680         }
1681 }
1682
1683 //
1684 // Draw text at the given x/y coordinates, using FG color and overlay alpha blending.
1685 //
1686 void DrawString2(uint32_t * screen, uint32_t x, uint32_t y, uint32_t color, uint8_t transparency, const char * text, ...)
1687 {
1688         char string[4096];
1689         va_list arg;
1690
1691         va_start(arg, text);
1692         vsprintf(string, text, arg);
1693         va_end(arg);
1694
1695         uint32_t pitch = sdlemuGetOverlayWidthInPixels();
1696         uint32_t length = strlen(string), address = x + (y * pitch);
1697
1698         color &= 0x00FFFFFF;                                            // Just in case alpha was passed in...
1699
1700         for(uint32_t i=0; i<length; i++)
1701         {
1702                 uint8_t c = string[i];
1703                 c = (c < 32 ? 0 : c - 32);
1704                 uint32_t fontAddr = (uint32_t)c * FONT_WIDTH * FONT_HEIGHT;
1705
1706                 for(uint32_t yy=0; yy<FONT_HEIGHT; yy++)
1707                 {
1708                         for(uint32_t xx=0; xx<FONT_WIDTH; xx++)
1709                         {
1710                                 uint8_t fontTrans = font2[fontAddr++];
1711                                 uint32_t newTrans = (fontTrans * transparency / 255) << 24;
1712                                 uint32_t pixel = newTrans | color;
1713
1714                                 *(screen + address + xx + (yy * pitch)) = pixel;
1715                         }
1716                 }
1717
1718                 address += FONT_WIDTH;
1719         }
1720 }
1721
1722 //
1723 // Draw "picture"
1724 // Uses zero as transparent color
1725 // Can also use an optional alpha channel
1726 // Alpha channel is now mandatory! ;-)
1727 //
1728 //void DrawTransparentBitmap(int16_t * screen, uint32_t x, uint32_t y, uint16_t * bitmap, uint8_t * alpha/*=NULL*/)
1729 /*void DrawTransparentBitmap(uint32_t * screen, uint32_t x, uint32_t y, uint32_t * bitmap, uint8_t * alpha)
1730 {
1731         uint32_t width = bitmap[0], height = bitmap[1];
1732         bitmap += 2;
1733
1734 //      uint32_t pitch = GetSDLScreenPitch() / 2;                       // Returns pitch in bytes but we need words...
1735         uint32_t pitch = sdlemuGetOverlayWidthInPixels();//GetSDLScreenWidthInPixels();
1736         uint32_t address = x + (y * pitch);
1737
1738         for(uint32_t yy=0; yy<height; yy++)
1739         {
1740                 for(uint32_t xx=0; xx<width; xx++)
1741                 {
1742                         if (alpha == NULL)
1743                         {
1744                                 if (*bitmap && x + xx < pitch)                  // NOTE: Still doesn't clip the Y val...
1745                                         *(screen + address + xx + (yy * pitch)) = *bitmap;
1746                         }
1747                         else
1748                         {
1749                                 uint8_t trans = *alpha;
1750                                 uint32_t color = *bitmap;
1751                                 uint32_t existingColor = *(screen + address + xx + (yy * pitch));
1752
1753                                 uint8_t eRed = existingColor & 0xFF,
1754                                         eGreen = (existingColor >> 8) & 0xFF,
1755                                         eBlue = (existingColor >> 16) & 0xFF,
1756
1757                                         nRed = color & 0xFF,
1758                                         nGreen = (color >> 8) & 0xFF,
1759                                         nBlue = (color >> 16) & 0xFF;
1760
1761                                 uint8_t invTrans = 255 - trans;
1762                                 uint32_t bRed = (eRed * trans + nRed * invTrans) / 255;
1763                                 uint32_t bGreen = (eGreen * trans + nGreen * invTrans) / 255;
1764                                 uint32_t bBlue = (eBlue * trans + nBlue * invTrans) / 255;
1765
1766                                 uint32_t blendedColor = 0xFF000000 | bRed | (bGreen << 8) | (bBlue << 16);
1767
1768                                 *(screen + address + xx + (yy * pitch)) = blendedColor;
1769
1770                                 alpha++;
1771                         }
1772
1773                         bitmap++;
1774                 }
1775         }
1776 }*/
1777 void DrawTransparentBitmapDeprecated(uint32_t * screen, uint32_t x, uint32_t y, uint32_t * bitmap)
1778 {
1779         uint32_t width = bitmap[0], height = bitmap[1];
1780         bitmap += 2;
1781
1782         uint32_t pitch = sdlemuGetOverlayWidthInPixels();//GetSDLScreenWidthInPixels();
1783         uint32_t address = x + (y * pitch);
1784
1785         for(uint32_t yy=0; yy<height; yy++)
1786         {
1787                 for(uint32_t xx=0; xx<width; xx++)
1788                 {
1789                         uint32_t color = *bitmap;
1790                         uint32_t blendedColor = color;
1791                         uint32_t existingColor = *(screen + address + xx + (yy * pitch));
1792
1793                         if (existingColor >> 24 != 0x00)                // Pixel needs blending
1794                         {
1795                                 uint8_t trans = color >> 24;
1796                                 uint8_t invTrans = trans ^ 0xFF;//255 - trans;
1797
1798                                 uint8_t eRed = existingColor & 0xFF,
1799                                         eGreen = (existingColor >> 8) & 0xFF,
1800                                         eBlue = (existingColor >> 16) & 0xFF,
1801
1802                                         nRed = color & 0xFF,
1803                                         nGreen = (color >> 8) & 0xFF,
1804                                         nBlue = (color >> 16) & 0xFF;
1805
1806                                 uint32_t bRed = (eRed * invTrans + nRed * trans) / 255;
1807                                 uint32_t bGreen = (eGreen * invTrans + nGreen * trans) / 255;
1808                                 uint32_t bBlue = (eBlue * invTrans + nBlue * trans) / 255;
1809
1810                                 blendedColor = 0xFF000000 | bRed | (bGreen << 8) | (bBlue << 16);
1811                         }
1812
1813                         *(screen + address + xx + (yy * pitch)) = blendedColor;
1814                         bitmap++;
1815                 }
1816         }
1817 }
1818
1819 void DrawTransparentBitmap(uint32_t * screen, uint32_t x, uint32_t y, const void * bitmap)
1820 {
1821         uint32_t pitch = sdlemuGetOverlayWidthInPixels();
1822         uint32_t address = x + (y * pitch);
1823         uint32_t count = 0;
1824
1825         for(uint32_t yy=0; yy<((Bitmap *)bitmap)->height; yy++)
1826         {
1827                 for(uint32_t xx=0; xx<((Bitmap *)bitmap)->width; xx++)
1828                 {
1829                         uint32_t color = ((uint32_t *)((Bitmap *)bitmap)->pixelData)[count];
1830                         uint32_t blendedColor = color;
1831                         uint32_t existingColor = *(screen + address + xx + (yy * pitch));
1832
1833                         if (existingColor >> 24 != 0x00)        // Pixel needs blending
1834                         {
1835                                 uint8_t trans = color >> 24;
1836                                 uint8_t invTrans = trans ^ 0xFF;
1837
1838                                 uint8_t eRed = existingColor & 0xFF,
1839                                         eGreen = (existingColor >> 8) & 0xFF,
1840                                         eBlue = (existingColor >> 16) & 0xFF,
1841
1842                                         nRed = color & 0xFF,
1843                                         nGreen = (color >> 8) & 0xFF,
1844                                         nBlue = (color >> 16) & 0xFF;
1845
1846                                 uint32_t bRed = (eRed * invTrans + nRed * trans) / 255;
1847                                 uint32_t bGreen = (eGreen * invTrans + nGreen * trans) / 255;
1848                                 uint32_t bBlue = (eBlue * invTrans + nBlue * trans) / 255;
1849
1850 // Instead of $FF, should use the alpha from the destination pixel as the final alpha value...
1851                                 blendedColor = 0xFF000000 | bRed | (bGreen << 8) | (bBlue << 16);
1852                         }
1853
1854                         *(screen + address + xx + (yy * pitch)) = blendedColor;
1855                         count++;
1856                 }
1857         }
1858 }
1859
1860 //
1861 // Draw a bitmap without using blending
1862 //
1863 void DrawBitmap(uint32_t * screen, uint32_t x, uint32_t y, const void * bitmap)
1864 {
1865         uint32_t pitch = sdlemuGetOverlayWidthInPixels();
1866         uint32_t address = x + (y * pitch);
1867         uint32_t count = 0;
1868
1869         for(uint32_t yy=0; yy<((Bitmap *)bitmap)->height; yy++)
1870         {
1871                 for(uint32_t xx=0; xx<((Bitmap *)bitmap)->width; xx++)
1872                 {
1873                         *(screen + address + xx + (yy * pitch)) = ((uint32_t *)((Bitmap *)bitmap)->pixelData)[count];
1874                         count++;
1875                 }
1876         }
1877 }
1878
1879 //
1880 // Fill a portion of the screen with the passed in color
1881 //
1882 void FillScreenRectangle(uint32_t * screen, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t color)
1883 //void ClearScreenRectangle(uint32_t * screen, uint32_t x, uint32_t y, uint32_t w, uint32_t h)
1884 {
1885         uint32_t pitch = sdlemuGetOverlayWidthInPixels();
1886         uint32_t address = x + (y * pitch);
1887
1888         for(uint32_t yy=0; yy<h; yy++)
1889                 for(uint32_t xx=0; xx<w; xx++)
1890                         *(screen + address + xx + (yy * pitch)) = color;
1891 }
1892
1893
1894 //
1895 // GUI stuff--it's not crunchy, it's GUI! ;-)
1896 //
1897
1898 void InitGUI(void)
1899 {
1900         SDL_ShowCursor(SDL_DISABLE);
1901         SDL_GetMouseState(&mouseX, &mouseY);
1902 }
1903
1904 void GUIDone(void)
1905 {
1906 }
1907
1908 //
1909 // GUI main loop
1910 //
1911 //bool GUIMain(void)
1912 bool GUIMain(char * filename)
1913 {
1914 WriteLog("GUI: Inside GUIMain...\n");
1915
1916         uint32_t pointerBGSave[6 * 8 + 2];
1917         pointerBGSave[0] = 6;
1918         pointerBGSave[1] = 8;
1919
1920 // Need to set things up so that it loads and runs a file if given on the command line. !!! FIX !!! [DONE]
1921         extern uint32_t * backbuffer;
1922 //      bool done = false;
1923         SDL_Event event;
1924         Window * mainWindow = NULL;
1925
1926         // Set up the GUI classes...
1927 //      Element::SetScreenAndPitch(backbuffer, GetSDLScreenWidthInPixels());
1928         Element::SetScreenAndPitch((uint32_t *)sdlemuGetOverlayPixels(), sdlemuGetOverlayWidthInPixels());
1929         sdlemuEnableOverlay();
1930
1931         Menu mainMenu;
1932         MenuItems mi;
1933         mi.title = "Jaguar";
1934         mi.item.push_back(NameAction("Load...", LoadROM, SDLK_l));
1935         mi.item.push_back(NameAction("Reset", ResetJaguar, SDLK_r));
1936         if (CDBIOSLoaded)
1937                 mi.item.push_back(NameAction("Reset CD", ResetJaguarCD, SDLK_c));
1938         mi.item.push_back(NameAction("Run", RunEmu, SDLK_ESCAPE));
1939         mi.item.push_back(NameAction(""));
1940         mi.item.push_back(NameAction("Quit", Quit, SDLK_q));
1941         mainMenu.Add(mi);
1942         mi.title = "Settings";
1943         mi.item.clear();
1944         mi.item.push_back(NameAction("Video..."));
1945         mi.item.push_back(NameAction("Audio..."));
1946         mi.item.push_back(NameAction("Misc...", MiscOptions, SDLK_m));
1947         mainMenu.Add(mi);
1948         mi.title = "Info";
1949         mi.item.clear();
1950         mi.item.push_back(NameAction("About...", About));
1951         mainMenu.Add(mi);
1952
1953         bool showMouse = true;
1954
1955         // Grab the BG where the mouse will be painted (prime the backstore)
1956
1957 /*
1958 DISNOWOK
1959 Bitmap ptr = { 6, 8, 4,
1960 ""//"000011112222333344445555"
1961 //"000011112222333344445555"
1962 //"000011112222333344445555"
1963 //"000011112222333344445555"
1964 //"000011112222333344445555"
1965 //"000011112222333344445555"
1966 //"000011112222333344445555"
1967 //"000011112222333344445555"
1968 };//*/
1969         uint32_t * overlayPixels = (uint32_t *)sdlemuGetOverlayPixels();
1970         uint32_t count = 2;
1971
1972         for(uint32_t y=0; y<pointerBGSave[1]; y++)
1973                 for(uint32_t x=0; x<pointerBGSave[0]; x++)
1974                         pointerBGSave[count++] = overlayPixels[((mouseY + y) * sdlemuGetOverlayWidthInPixels()) + (mouseX + x)];
1975
1976         uint32_t oldMouseX = mouseX, oldMouseY = mouseY;
1977
1978 //This is crappy!!! !!! FIX !!!
1979 //Is this even needed any more? Hmm. Maybe. Dunno.
1980 WriteLog("GUI: Resetting Jaguar...\n");
1981         jaguar_reset();
1982
1983 WriteLog("GUI: Clearing BG save...\n");
1984         // Set up our background save...
1985 //      memset(background, 0x11, tom_getVideoModeWidth() * 240 * 2);
1986 //1111 -> 000100 01000 10001 -> 0001 0000 0100 0010 1000 1100 -> 10 42 8C
1987         for(uint32_t i=0; i<tom_getVideoModeWidth()*240; i++)
1988 //              background[i] = 0xFF8C4210;
1989                 backbuffer[i] = 0xFF8C4210;
1990
1991 /*      uint32_t * overlayPix = (uint32_t *)sdlemuGetOverlayPixels();
1992         for(uint32_t i=0; i<sdlemuGetOverlayWidthInPixels()*480; i++)
1993                 overlayPix[i] = 0x00000000;*/
1994
1995         // Handle loading file passed in on the command line...! [DONE]
1996
1997         if (filename)
1998         {
1999                 if (JaguarLoadFile(filename))
2000                 {
2001 //                      event.type = SDL_USEREVENT, event.user.code = MENU_ITEM_CHOSEN;
2002 //                      event.user.data1 = (void *)ResetJaguar;
2003 //              SDL_PushEvent(&event);
2004                         // Make it so that if passed in on the command line, we quit right
2005                         // away when pressing ESC
2006 WriteLog("GUI: Bypassing GUI since ROM passed in on command line...\n");
2007                         ResetJaguar();
2008                         return true;
2009                 }
2010                 else
2011                 {
2012                         // Create error dialog...
2013                         char errText[1024];
2014                         sprintf(errText, "The file %40s could not be loaded.", filename);
2015
2016                         mainWindow = new Window(8, 16, 304, 160);
2017                         mainWindow->AddElement(new Text(8, 8, "Error!"));
2018                         mainWindow->AddElement(new Text(8, 24, errText));
2019                 }
2020         }
2021
2022 WriteLog("GUI: Entering main loop...\n");
2023         while (!exitGUI)
2024         {
2025                 if (SDL_PollEvent(&event))
2026                 {
2027                         if (event.type == SDL_USEREVENT)
2028                         {
2029                                 if (event.user.code == WINDOW_CLOSE)
2030                                 {
2031                                         delete mainWindow;
2032                                         mainWindow = NULL;
2033                                 }
2034                                 else if (event.user.code == MENU_ITEM_CHOSEN)
2035                                 {
2036                                         // Confused? Let me enlighten... What we're doing here is casting
2037                                         // data1 as a pointer to a function which returns a Window pointer and
2038                                         // which takes no parameters (the "(Window *(*)(void))" part), then
2039                                         // derefencing it (the "*" in front of that) in order to call the
2040                                         // function that it points to. Clear as mud? Yeah, I hate function
2041                                         // pointers too, but what else are you gonna do?
2042                                         mainWindow = (*(Window *(*)(void))event.user.data1)();
2043
2044                                         while (SDL_PollEvent(&event));  // Flush the event queue...
2045                                         event.type = SDL_MOUSEMOTION;
2046                                         int mx, my;
2047                                         SDL_GetMouseState(&mx, &my);
2048                                         event.motion.x = mx, event.motion.y = my;
2049                                     SDL_PushEvent(&event);                      // & update mouse position...!
2050
2051                                         oldMouseX = mouseX, oldMouseY = mouseY;
2052                                         mouseX = mx, mouseY = my;               // This prevents "mouse flash"...
2053                                 }
2054                         }
2055                         else if (event.type == SDL_ACTIVEEVENT)
2056                         {
2057                                 if (event.active.state == SDL_APPMOUSEFOCUS)
2058                                         showMouse = (event.active.gain ? true : false);
2059                         }
2060                         else if (event.type == SDL_KEYDOWN)
2061                         {
2062                                 if (mainWindow)
2063                                         mainWindow->HandleKey(event.key.keysym.sym);
2064                                 else
2065                                         mainMenu.HandleKey(event.key.keysym.sym);
2066                         }
2067                         else if (event.type == SDL_MOUSEMOTION)
2068                         {
2069                                 oldMouseX = mouseX, oldMouseY = mouseY;
2070                                 mouseX = event.motion.x, mouseY = event.motion.y;
2071
2072                                 if (mainWindow)
2073                                         mainWindow->HandleMouseMove(mouseX, mouseY);
2074                                 else
2075                                         mainMenu.HandleMouseMove(mouseX, mouseY);
2076                         }
2077                         else if (event.type == SDL_MOUSEBUTTONDOWN)
2078                         {
2079                                 uint32_t mx = event.button.x, my = event.button.y;
2080
2081                                 if (mainWindow)
2082                                         mainWindow->HandleMouseButton(mx, my, true);
2083                                 else
2084                                         mainMenu.HandleMouseButton(mx, my, true);
2085                         }
2086                         else if (event.type == SDL_MOUSEBUTTONUP)
2087                         {
2088                                 uint32_t mx = event.button.x, my = event.button.y;
2089
2090                                 if (mainWindow)
2091                                         mainWindow->HandleMouseButton(mx, my, false);
2092                                 else
2093                                         mainMenu.HandleMouseButton(mx, my, false);
2094                         }
2095
2096 //PROBLEM: In order to use the dirty rectangle approach here, we need some way of
2097 //         handling it in mainMenu.Draw() and mainWindow->Draw(). !!! FIX !!!
2098 //POSSIBLE SOLUTION:
2099 // When mouse is moving and not on menu or window, can do straight dirty rect.
2100 // When mouse is on menu, need to update screen. Same for buttons on windows...
2101 // What the menu & windows should do is only redraw on a state change. IOW, they
2102 // should call their own/child window's Draw() function instead of doing it top
2103 // level.
2104 //#define NEW_BACKSTORE_METHOD
2105
2106                         // Draw the GUI...
2107 // The way we do things here is kinda stupid (redrawing the screen every frame), but
2108 // it's simple. Perhaps there may be a reason down the road to be more selective with
2109 // our clearing, but for now, this will suffice.
2110 //                      memset(backbuffer, 0x11, tom_getVideoModeWidth() * 240 * 2);
2111 //                      memcpy(backbuffer, background, tom_getVideoModeWidth() * 256 * 2);
2112 //                      memcpy(backbuffer, background, tom_getVideoModeWidth() * 256 * 4);
2113 #ifndef NEW_BACKSTORE_METHOD
2114                         memset(sdlemuGetOverlayPixels(), 0, sdlemuGetOverlayWidthInPixels() * 480 * 4);
2115
2116                         mainMenu.Draw();
2117 //Could do multiple windows here by using a vector + priority info...
2118 //Though the way ZSNES does it seems to be by a bool (i.e., they're always active, just not shown)
2119                         if (mainWindow)
2120                                 mainWindow->Draw();
2121 #endif
2122
2123 /*uint32_t pBGS[6 * 8 + 3] = { 6, 8, 4,
2124         0, 0, 0, 0, 0, 0,
2125         0, 0, 0, 0, 0, 0,
2126         0, 0, 0, 0, 0, 0,
2127         0, 0, 0, 0, 0, 0,
2128         0, 0, 0, 0, 0, 0,
2129         0, 0, 0, 0, 0, 0,
2130         0, 0, 0, 0, 0, 0,
2131         0, 0, 0, 0, 0, 0
2132 };*/
2133 //This isn't working... Why????
2134 //It's because DrawTransparentBitmap does alpha blending if it detects zero in the alpha channel.
2135 //So why do it that way? Hm.
2136                         overlayPixels = (uint32_t *)sdlemuGetOverlayPixels();
2137
2138 #ifdef NEW_BACKSTORE_METHOD
2139 //                      DrawTransparentBitmapDeprecated(overlayPixels, oldMouseX, oldMouseY, pointerBGSave);
2140 //                      DrawTransparentBitmap(overlayPixels, oldMouseX, oldMouseY, pBGS);
2141                         for(uint32_t y=0; y<pointerBGSave[1]; y++)
2142                                 for(uint32_t x=0; x<pointerBGSave[0]; x++)
2143                                         overlayPixels[((oldMouseY + y) * sdlemuGetOverlayWidthInPixels()) + (oldMouseX + x)] = 0x00000000;
2144
2145                         count = 2;
2146
2147                         for(uint32_t y=0; y<pointerBGSave[1]; y++)
2148                                 for(uint32_t x=0; x<pointerBGSave[0]; x++)
2149                                         pointerBGSave[count++] = overlayPixels[((mouseY + y) * sdlemuGetOverlayWidthInPixels()) + (mouseX + x)];
2150 #endif
2151
2152                         if (showMouse)
2153 //                              DrawTransparentBitmapDeprecated(backbuffer, mouseX, mouseY, mousePic);
2154                                 DrawTransparentBitmapDeprecated(overlayPixels, mouseX, mouseY, mousePic);
2155
2156                         RenderBackbuffer();
2157                 }
2158         }
2159
2160         return true;
2161 }
2162
2163 //
2164 // GUI "action" functions
2165 //
2166
2167 Window * LoadROM(void)
2168 {
2169         FileList * fileList = new FileList(20, 20, 600, 440);
2170
2171         return (Window *)fileList;
2172 }
2173
2174 Window * ResetJaguar(void)
2175 {
2176         jaguar_reset();
2177
2178         return RunEmu();
2179 }
2180
2181 Window * ResetJaguarCD(void)
2182 {
2183         memcpy(jaguar_mainRom, jaguar_CDBootROM, 0x40000);
2184         jaguarRunAddress = 0x802000;
2185         jaguar_mainRom_crc32 = crc32_calcCheckSum(jaguar_mainRom, 0x40000);
2186         jaguar_reset();
2187 //This is a quick kludge to get the CDBIOS to boot properly...
2188 //Wild speculation: It could be that this memory location is wired into the CD unit
2189 //somehow, which lets it know whether or not a cart is present in the unit...
2190         jaguar_mainRom[0x0040B] = 0x03;
2191
2192         return RunEmu();
2193 }
2194
2195
2196 #if 0
2197
2198 bool debounceRunKey = true;
2199 Window * RunEmu(void)
2200 {
2201         extern uint32_t * backbuffer;
2202 //Temporary, to test the new timer based code...
2203 sdlemuDisableOverlay();
2204 JaguarExecuteNew();
2205 sdlemuEnableOverlay();
2206         // Save the background for the GUI...
2207         // In this case, we squash the color to monochrome, then force it to blue + green...
2208         for(uint32_t i=0; i<tom_getVideoModeWidth() * 256; i++)
2209         {
2210                 uint32_t pixel = backbuffer[i];
2211                 uint8_t b = (pixel >> 16) & 0xFF, g = (pixel >> 8) & 0xFF, r = pixel & 0xFF;
2212                 pixel = ((r + g + b) / 3) & 0x00FF;
2213                 backbuffer[i] = 0xFF000000 | (pixel << 16) | (pixel << 8);
2214         }
2215 return NULL;//*/
2216
2217 //This is crappy... !!! FIX !!!
2218         extern bool finished, showGUI;
2219
2220 //      uint32_t nFrame = 0, nFrameskip = 0;
2221         uint32_t totalFrames = 0;
2222         finished = false;
2223         bool showMessage = true;
2224         uint32_t showMsgFrames = 120;
2225         uint8_t transparency = 0;
2226         // Pass a message to the "joystick" code to debounce the ESC key...
2227         debounceRunKey = true;
2228
2229         uint32_t cartType = 4;
2230         if (jaguarRomSize == 0x200000)
2231                 cartType = 0;
2232         else if (jaguarRomSize == 0x400000)
2233                 cartType = 1;
2234         else if (jaguar_mainRom_crc32 == 0x687068D5)
2235                 cartType = 2;
2236         else if (jaguar_mainRom_crc32 == 0x55A0669C)
2237                 cartType = 3;
2238
2239         char * cartTypeName[5] = { "2M Cartridge", "4M Cartridge", "CD BIOS", "CD Dev BIOS", "Homebrew" };
2240         uint32_t elapsedTicks = SDL_GetTicks(), frameCount = 0, framesPerSecond = 0;
2241
2242         while (true)
2243         {
2244                 // Set up new backbuffer with new pixels and data
2245                 JaguarExecute(backbuffer, true);
2246 //              JaguarExecuteNew();
2247                 totalFrames++;
2248 //WriteLog("Frame #%u...\n", totalFrames);
2249 //extern bool doDSPDis;
2250 //if (totalFrames == 373)
2251 //      doDSPDis = true;
2252
2253 //This sucks... !!! FIX !!!
2254                 joystick_exec();
2255 //This is done here so that the crud below doesn't get on our GUI background...
2256                 if (finished)
2257                         break;
2258
2259                 // Some QnD GUI stuff here...
2260                 if (showGUI)
2261                 {
2262                         extern uint32_t gpu_pc, dsp_pc;
2263                         DrawString(backbuffer, 8, 8, false, "GPU PC: %08X", gpu_pc);
2264                         DrawString(backbuffer, 8, 16, false, "DSP PC: %08X", dsp_pc);
2265                         DrawString(backbuffer, 8, 32, false, "%u FPS", framesPerSecond);
2266                 }
2267
2268                 if (showMessage)
2269                 {
2270 // FF0F -> 1111 11 11  000 0 1111 -> 3F 18 0F
2271 // 3FE3 -> 0011 11 11  111 0 0011 -> 0F 3F 03
2272 /*                      DrawStringTrans((uint32_t *)backbuffer, 8, 24*8, 0xFF0F, transparency, "Running...");
2273                         DrawStringTrans((uint32_t *)backbuffer, 8, 26*8, 0x3FE3, transparency, "%s, run address: %06X", cartTypeName[cartType], jaguarRunAddress);
2274                         DrawStringTrans((uint32_t *)backbuffer, 8, 27*8, 0x3FE3, transparency, "CRC: %08X", jaguar_mainRom_crc32);//*/
2275 //first has wrong color. !!! FIX !!!
2276                         DrawStringTrans(backbuffer, 8, 24*8, 0xFF7F63FF, transparency, "Running...");
2277                         DrawStringTrans(backbuffer, 8, 26*8, 0xFF1FFF3F, transparency, "%s, run address: %06X", cartTypeName[cartType], jaguarRunAddress);
2278                         DrawStringTrans(backbuffer, 8, 27*8, 0xFF1FFF3F, transparency, "CRC: %08X", jaguar_mainRom_crc32);
2279
2280                         if (showMsgFrames == 0)
2281                         {
2282                                 transparency++;
2283
2284                                 if (transparency == 33)
2285 {
2286                                         showMessage = false;
2287 /*extern bool doGPUDis;
2288 doGPUDis = true;//*/
2289 }
2290
2291                         }
2292                         else
2293                                 showMsgFrames--;
2294                 }
2295
2296                 RenderBackbuffer();
2297                 frameCount++;
2298
2299                 if (SDL_GetTicks() - elapsedTicks > 250)
2300                         elapsedTicks += 250, framesPerSecond = frameCount * 4, frameCount = 0;
2301         }
2302
2303         // Reset the pitch, since it may have been changed in-game...
2304         Element::SetScreenAndPitch((uint32_t *)backbuffer, GetSDLScreenWidthInPixels());
2305
2306         // Save the background for the GUI...
2307 //      memcpy(background, backbuffer, tom_getVideoModeWidth() * 240 * 2);
2308         // In this case, we squash the color to monochrome, then force it to blue + green...
2309         for(uint32_t i=0; i<tom_getVideoModeWidth() * 256; i++)
2310         {
2311                 uint32_t pixel = backbuffer[i];
2312                 uint8_t b = (pixel >> 16) & 0xFF, g = (pixel >> 8) & 0xFF, r = pixel & 0xFF;
2313                 pixel = ((r + g + b) / 3) & 0x00FF;
2314                 background[i] = 0xFF000000 | (pixel << 16) | (pixel << 8);
2315         }
2316
2317         return NULL;
2318 }
2319
2320 #else
2321
2322 bool debounceRunKey = true;
2323 Window * RunEmu(void)
2324 {
2325         extern uint32_t * backbuffer;
2326         uint32_t * overlayPixels = (uint32_t *)sdlemuGetOverlayPixels();
2327         memset(overlayPixels, 0x00, 640 * 480 * 4);                     // Clear out overlay...
2328
2329 //This is crappy... !!! FIX !!!
2330         extern bool finished, showGUI;
2331
2332         sdlemuDisableOverlay();
2333
2334 //      uint32_t nFrame = 0, nFrameskip = 0;
2335         uint32_t totalFrames = 0;
2336         finished = false;
2337         bool showMessage = true;
2338         uint32_t showMsgFrames = 120;
2339         uint8_t transparency = 0xFF;
2340         // Pass a message to the "joystick" code to debounce the ESC key...
2341         debounceRunKey = true;
2342
2343         uint32_t cartType = 4;
2344         if (jaguarRomSize == 0x200000)
2345                 cartType = 0;
2346         else if (jaguarRomSize == 0x400000)
2347                 cartType = 1;
2348         else if (jaguar_mainRom_crc32 == 0x687068D5)
2349                 cartType = 2;
2350         else if (jaguar_mainRom_crc32 == 0x55A0669C)
2351                 cartType = 3;
2352
2353         char * cartTypeName[5] = { "2M Cartridge", "4M Cartridge", "CD BIOS", "CD Dev BIOS", "Homebrew" };
2354         uint32_t elapsedTicks = SDL_GetTicks(), frameCount = 0, framesPerSecond = 0;
2355
2356         while (!finished)
2357         {
2358                 // Set up new backbuffer with new pixels and data
2359                 JaguarExecuteNew();
2360                 totalFrames++;
2361 //WriteLog("Frame #%u...\n", totalFrames);
2362 //extern bool doDSPDis;
2363 //if (totalFrames == 373)
2364 //      doDSPDis = true;
2365
2366 //Problem: Need to do this *only* when the state changes from visible to not...
2367 //Also, need to clear out the GUI when not on (when showMessage is active...)
2368 if (showGUI || showMessage)
2369         sdlemuEnableOverlay();
2370 else
2371         sdlemuDisableOverlay();
2372
2373 //Add in a new function for clearing patches of screen (ClearOverlayRect)
2374
2375                 // Some QnD GUI stuff here...
2376                 if (showGUI)
2377                 {
2378                         FillScreenRectangle(overlayPixels, 8, 1*FONT_HEIGHT, 128, 4*FONT_HEIGHT, 0x00000000);
2379                         extern uint32_t gpu_pc, dsp_pc;
2380                         DrawString(overlayPixels, 8, 1*FONT_HEIGHT, false, "GPU PC: %08X", gpu_pc);
2381                         DrawString(overlayPixels, 8, 2*FONT_HEIGHT, false, "DSP PC: %08X", dsp_pc);
2382                         DrawString(overlayPixels, 8, 4*FONT_HEIGHT, false, "%u FPS", framesPerSecond);
2383                 }
2384
2385                 if (showMessage)
2386                 {
2387                         DrawString2(overlayPixels, 8, 24*FONT_HEIGHT, 0x007F63FF, transparency, "Running...");
2388                         DrawString2(overlayPixels, 8, 26*FONT_HEIGHT, 0x001FFF3F, transparency, "%s, run address: %06X", cartTypeName[cartType], jaguarRunAddress);
2389                         DrawString2(overlayPixels, 8, 27*FONT_HEIGHT, 0x001FFF3F, transparency, "CRC: %08X", jaguar_mainRom_crc32);
2390
2391                         if (showMsgFrames == 0)
2392                         {
2393                                 transparency--;
2394
2395                                 if (transparency == 0)
2396 {
2397                                         showMessage = false;
2398 /*extern bool doGPUDis;
2399 doGPUDis = true;//*/
2400 }
2401
2402                         }
2403                         else
2404                                 showMsgFrames--;
2405                 }
2406
2407                 frameCount++;
2408
2409                 if (SDL_GetTicks() - elapsedTicks > 250)
2410                         elapsedTicks += 250, framesPerSecond = frameCount * 4, frameCount = 0;
2411         }
2412
2413         // Save the background for the GUI...
2414         // In this case, we squash the color to monochrome, then force it to blue + green...
2415         for(uint32_t i=0; i<tom_getVideoModeWidth() * 256; i++)
2416         {
2417                 uint32_t pixel = backbuffer[i];
2418                 uint8_t b = (pixel >> 16) & 0xFF, g = (pixel >> 8) & 0xFF, r = pixel & 0xFF;
2419                 pixel = ((r + g + b) / 3) & 0x00FF;
2420                 backbuffer[i] = 0xFF000000 | (pixel << 16) | (pixel << 8);
2421         }
2422
2423         sdlemuEnableOverlay();
2424
2425         return NULL;
2426 }
2427
2428 #endif
2429
2430
2431 Window * Quit(void)
2432 {
2433         WriteLog("GUI: Quitting due to user request.\n");
2434         exitGUI = true;
2435
2436         return NULL;
2437 }
2438
2439 Window * About(void)
2440 {
2441         char buf[512];
2442 //      sprintf(buf, "Virtual Jaguar CVS %s", __DATE__);
2443         sprintf(buf, "CVS %s", __DATE__);
2444 //fprintf(fp, "VirtualJaguar v1.0.8 (Last full build was on %s %s)\n", __DATE__, __TIME__);
2445 //VirtualJaguar v1.0.8 (Last full build was on Dec 30 2004 20:01:31)
2446 //Hardwired, bleh... !!! FIX !!!
2447 uint32_t width = 55 * FONT_WIDTH, height = 18 * FONT_HEIGHT;
2448 uint32_t xpos = (640 - width) / 2, ypos = (480 - height) / 2;
2449 //      Window * window = new Window(8, 16, 50 * FONT_WIDTH, 21 * FONT_HEIGHT);
2450         Window * window = new Window(xpos, ypos, width, height);
2451 //      window->AddElement(new Text(8, 8, "Virtual Jaguar 1.0.8"));
2452 //      window->AddElement(new Text(8, 8, "Virtual Jaguar CVS 20050110", 0xFF3030FF, 0xFF000000));
2453 //      window->AddElement(new Text(208, 8+0*FONT_HEIGHT, buf, 0xFF3030FF, 0xFF000000));
2454         window->AddElement(new Text(248, 8+4*FONT_HEIGHT+5, buf, 0xFF3030FF, 0xFF000000));
2455         window->AddElement(new Text(8, 8+0*FONT_HEIGHT, "Coders:"));
2456         window->AddElement(new Text(16, 8+1*FONT_HEIGHT, "James L. Hammons (shamus)"));
2457         window->AddElement(new Text(16, 8+2*FONT_HEIGHT, "Niels Wagenaar (nwagenaar)"));
2458         window->AddElement(new Text(16, 8+3*FONT_HEIGHT, "Carwin Jones (Caz)"));
2459         window->AddElement(new Text(16, 8+4*FONT_HEIGHT, "Adam Green"));
2460         window->AddElement(new Text(8, 8+6*FONT_HEIGHT, "Testers:"));
2461         window->AddElement(new Text(16, 8+7*FONT_HEIGHT, "Guruma"));
2462         window->AddElement(new Text(8, 8+9*FONT_HEIGHT, "Thanks go out to:"));
2463         window->AddElement(new Text(16, 8+10*FONT_HEIGHT, "Aaron Giles for the original CoJag"));
2464         window->AddElement(new Text(16, 8+11*FONT_HEIGHT, "David Raingeard for the original VJ"));
2465         window->AddElement(new Text(16, 8+12*FONT_HEIGHT, "Karl Stenerud for his Musashi 68K emu"));
2466         window->AddElement(new Text(16, 8+13*FONT_HEIGHT, "Sam Lantinga for his amazing SDL libs"));
2467         window->AddElement(new Text(16, 8+14*FONT_HEIGHT, "Ryan C. Gordon for VJ's web presence"));
2468         window->AddElement(new Text(16, 8+15*FONT_HEIGHT, "Curt Vendel for various Jaguar goodies"));
2469         window->AddElement(new Text(16, 8+16*FONT_HEIGHT, "The guys over at Atari Age ;-)"));
2470 //      window->AddElement(new Image(8, 8, &vj_title_small));
2471         window->AddElement(new Image(width - (vj_title_small.width + 8), 8, &vj_title_small));
2472
2473         return window;
2474 }
2475
2476 Window * MiscOptions(void)
2477 {
2478         Window * window = new Window(8, 16, 304, 192);
2479         window->AddElement(new PushButton(8, 8, &vjs.useJaguarBIOS, "BIOS"));
2480         window->AddElement(new SlideSwitch(8, 32, &vjs.hardwareTypeNTSC, "PAL", "NTSC"));
2481         window->AddElement(new PushButton(8, 64, &vjs.DSPEnabled, "DSP"));
2482         window->AddElement(new SlideSwitch(24, 88, &vjs.usePipelinedDSP, "Original", "Pipelined"));
2483         window->AddElement(new SlideSwitch(8, 120, (bool *)&vjs.glFilter, "Sharp", "Blurry"));
2484         window->AddElement(new SlideSwitch(8, 152, (bool *)&vjs.renderType, "Normal render", "TV style"));
2485
2486         window->AddElement(new TextEdit(88, 8, vjs.ROMPath, 20, 0xFF8484FF, 0xFF000000));
2487
2488 /*TextEdit(uint32_t x, uint32_t y, string s, uint32_t mss = 10, uint32_t fg = 0xFF8484FF,
2489         uint32_t bg = 0xFF84FF4D): Element(x, y, 0, 0), fgColor(fg), bgColor(bg), text(s),
2490         caretPos(0), maxScreenSize(mss) {}*/
2491 // Missing:
2492 // * BIOS path
2493 // * ROM path
2494 // * EEPROM path
2495 // * joystick
2496 // * joystick port
2497 // * OpenGL?
2498 // * GL Filter type
2499 // * Window/fullscreen
2500 // * Key definitions
2501
2502         return window;
2503 }
2504
2505
2506 //
2507 // Generic ROM loading
2508 //
2509 uint32_t JaguarLoadROM(uint8_t * rom, char * path)
2510 {
2511 // We really should have some kind of sanity checking for the ROM size here to prevent
2512 // a buffer overflow... !!! FIX !!!
2513         uint32_t romSize = 0;
2514
2515 WriteLog("JaguarLoadROM: Attempting to load file '%s'...", path);
2516         char * ext = strrchr(path, '.');
2517 if (ext == NULL)
2518         WriteLog("FAILED!\n");
2519 else
2520         WriteLog("Succeeded in finding extension (%s)!\n", ext);
2521
2522         if (ext != NULL)
2523         {
2524                 WriteLog("VJ: Loading \"%s\"...", path);
2525
2526                 if (strcasecmp(ext, ".zip") == 0)
2527                 {
2528                         // Handle ZIP file loading here...
2529                         WriteLog("(ZIPped)...");
2530
2531                         if (load_zipped_file(0, 0, path, NULL, &rom, &romSize) == -1)
2532                         {
2533                                 WriteLog("Failed!\n");
2534                                 return 0;
2535                         }
2536                 }
2537                 else
2538                 {
2539 /*                      FILE * fp = fopen(path, "rb");
2540
2541                         if (fp == NULL)
2542                         {
2543                                 WriteLog("Failed!\n");
2544                                 return 0;
2545                         }
2546
2547                         fseek(fp, 0, SEEK_END);
2548                         romSize = ftell(fp);
2549                         fseek(fp, 0, SEEK_SET);
2550                         fread(rom, 1, romSize, fp);
2551                         fclose(fp);*/
2552
2553                         // Handle gzipped files transparently [Adam Green]...
2554
2555                         gzFile fp = gzopen(path, "rb");
2556
2557                         if (fp == NULL)
2558                         {
2559                                 WriteLog("Failed!\n");
2560                                 return 0;
2561                         }
2562
2563                         romSize = gzfilelength(fp);
2564                         gzseek(fp, 0, SEEK_SET);
2565                         gzread(fp, rom, romSize);
2566                         gzclose(fp);
2567                 }
2568
2569                 WriteLog("OK (%i bytes)\n", romSize);
2570         }
2571
2572         return romSize;
2573 }
2574
2575 //
2576 // Jaguar file loading
2577 //
2578 bool JaguarLoadFile(char * path)
2579 {
2580 //      jaguarRomSize = JaguarLoadROM(mem, path);
2581         jaguarRomSize = JaguarLoadROM(jaguar_mainRom, path);
2582
2583 /*//This is not *nix friendly for some reason...
2584 //              if (!UserSelectFile(path, newPath))
2585         if (!UserSelectFile((strlen(path) == 0 ? (char *)"." : path), newPath))
2586         {
2587                 WriteLog("VJ: Could not find valid ROM in directory \"%s\"...\nAborting!\n", path);
2588                 log_done();
2589                 exit(0);
2590         }*/
2591
2592         if (jaguarRomSize == 0)
2593         {
2594 //                      WriteLog("VJ: Could not load ROM from file \"%s\"...\nAborting!\n", newPath);
2595                 WriteLog("GUI: Could not load ROM from file \"%s\"...\nAborting load!\n", path);
2596 // Need to do something else here, like throw up an error dialog instead of aborting. !!! FIX !!!
2597 //              log_done();
2598 //              exit(0);
2599                 return false;                                                           // This is a start...
2600         }
2601
2602         jaguar_mainRom_crc32 = crc32_calcCheckSum(jaguar_mainRom, jaguarRomSize);
2603         WriteLog("CRC: %08X\n", (unsigned int)jaguar_mainRom_crc32);
2604         eeprom_init();
2605
2606         jaguarRunAddress = 0x802000;
2607
2608         char * ext = strrchr(path, '.');                                // Get the file's extension for non-cartridge checking
2609
2610 //NOTE: Should fix JaguarLoadROM() to replace .zip with what's *in* the zip (.abs, .j64, etc.)
2611         if (strcasecmp(ext, ".rom") == 0)
2612         {
2613                 // File extension ".ROM": Alpine image that loads/runs at $802000
2614                 WriteLog("GUI: Setting up homebrew (ROM)... Run address: 00802000, length: %08X\n", jaguarRomSize);
2615
2616                 for(int i=jaguarRomSize-1; i>=0; i--)
2617                         jaguar_mainRom[0x2000 + i] = jaguar_mainRom[i];
2618
2619                 memset(jaguar_mainRom, 0xFF, 0x2000);
2620 /*              memcpy(jaguar_mainRam, jaguar_mainRom, jaguarRomSize);
2621                 memset(jaguar_mainRom, 0xFF, 0x600000);
2622                 memcpy(jaguar_mainRom + 0x2000, jaguar_mainRam, jaguarRomSize);
2623                 memset(jaguar_mainRam, 0x00, 0x400000);*/
2624
2625 /*
2626 Stubulator ROM vectors...
2627 handler 001 at $00E00008
2628 handler 002 at $00E008DE
2629 handler 003 at $00E008E2
2630 handler 004 at $00E008E6
2631 handler 005 at $00E008EA
2632 handler 006 at $00E008EE
2633 handler 007 at $00E008F2
2634 handler 008 at $00E0054A
2635 handler 009 at $00E008FA
2636 handler 010 at $00000000
2637 handler 011 at $00000000
2638 handler 012 at $00E008FE
2639 handler 013 at $00E00902
2640 handler 014 at $00E00906
2641 handler 015 at $00E0090A
2642 handler 016 at $00E0090E
2643 handler 017 at $00E00912
2644 handler 018 at $00E00916
2645 handler 019 at $00E0091A
2646 handler 020 at $00E0091E
2647 handler 021 at $00E00922
2648 handler 022 at $00E00926
2649 handler 023 at $00E0092A
2650 handler 024 at $00E0092E
2651 handler 025 at $00E0107A
2652 handler 026 at $00E0107A
2653 handler 027 at $00E0107A
2654 handler 028 at $00E008DA
2655 handler 029 at $00E0107A
2656 handler 030 at $00E0107A
2657 handler 031 at $00E0107A
2658 handler 032 at $00000000
2659
2660 Let's try setting up the illegal instruction vector for a stubulated jaguar...
2661 */
2662 /*              SET32(jaguar_mainRam, 0x08, 0x00E008DE);
2663                 SET32(jaguar_mainRam, 0x0C, 0x00E008E2);
2664                 SET32(jaguar_mainRam, 0x10, 0x00E008E6);        // <-- Should be here (it is)...
2665                 SET32(jaguar_mainRam, 0x14, 0x00E008EA);//*/
2666
2667                 // Try setting the vector to say, $1000 and putting an instruction there that loops forever:
2668                 // This kludge works! Yeah!
2669                 SET32(jaguar_mainRam, 0x10, 0x00001000);
2670                 SET16(jaguar_mainRam, 0x1000, 0x60FE);          // Here: bra Here
2671         }
2672         else if (strcasecmp(ext, ".abs") == 0)
2673         {
2674                 // File extension ".ABS": Atari linker output file with header (w/o is useless to us here)
2675
2676 /*
2677 ABS Format sleuthing (LBUGDEMO.ABS):
2678
2679 000000  60 1B 00 00 05 0C 00 04 62 C0 00 00 04 28 00 00
2680 000010  12 A6 00 00 00 00 00 80 20 00 FF FF 00 80 25 0C
2681 000020  00 00 40 00
2682
2683 DRI-format file detected...
2684 Text segment size = 0x0000050c bytes
2685 Data segment size = 0x000462c0 bytes
2686 BSS Segment size = 0x00000428 bytes
2687 Symbol Table size = 0x000012a6 bytes
2688 Absolute Address for text segment = 0x00802000
2689 Absolute Address for data segment = 0x0080250c
2690 Absolute Address for BSS segment = 0x00004000
2691
2692 (CRZDEMO.ABS):
2693 000000  01 50 00 03 00 00 00 00 00 03 83 10 00 00 05 3b
2694 000010  00 1c 00 03 00 00 01 07 00 00 1d d0 00 03 64 98
2695 000020  00 06 8b 80 00 80 20 00 00 80 20 00 00 80 3d d0
2696
2697 000030  2e 74 78 74 00 00 00 00 00 80 20 00 00 80 20 00 .txt (+36 bytes)
2698 000040  00 00 1d d0 00 00 00 a8 00 00 00 00 00 00 00 00
2699 000050  00 00 00 00 00 00 00 20
2700 000058  2e 64 74 61 00 00 00 00 00 80 3d d0 00 80 3d d0 .dta (+36 bytes)
2701 000068  00 03 64 98 00 00 1e 78 00 00 00 00 00 00 00 00
2702 000078  00 00 00 00 00 00 00 40
2703 000080  2e 62 73 73 00 00 00 00 00 00 50 00 00 00 50 00 .bss (+36 bytes)
2704 000090  00 06 8b 80 00 03 83 10 00 00 00 00 00 00 00 00
2705 0000a0  00 00 00 00 00 00 00 80
2706
2707 Header size is $A8 bytes...
2708
2709 BSD/COFF format file detected...
2710 3 sections specified
2711 Symbol Table offset = 230160                            ($00038310)
2712 Symbol Table contains 1339 symbol entries       ($0000053B)
2713 The additional header size is 28 bytes          ($001C)
2714 Magic Number for RUN_HDR = 0x00000107
2715 Text Segment Size = 7632                                        ($00001DD0)
2716 Data Segment Size = 222360                                      ($00036498)
2717 BSS Segment Size = 428928                                       ($00068B80)
2718 Starting Address for executable = 0x00802000
2719 Start of Text Segment = 0x00802000
2720 Start of Data Segment = 0x00803dd0
2721 */
2722                 if (jaguar_mainRom[0] == 0x60 && jaguar_mainRom[1] == 0x1B)
2723                 {
2724                         uint32_t loadAddress = GET32(jaguar_mainRom, 0x16), //runAddress = GET32(jaguar_mainRom, 0x2A),
2725                                 codeSize = GET32(jaguar_mainRom, 0x02) + GET32(jaguar_mainRom, 0x06);
2726                         WriteLog("GUI: Setting up homebrew (ABS-1)... Run address: %08X, length: %08X\n", loadAddress, codeSize);
2727
2728                         if (loadAddress < 0x800000)
2729                                 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x24, codeSize);
2730                         else
2731                         {
2732                                 for(int i=codeSize-1; i>=0; i--)
2733                                         jaguar_mainRom[(loadAddress - 0x800000) + i] = jaguar_mainRom[i + 0x24];
2734 /*                              memcpy(jaguar_mainRam, jaguar_mainRom + 0x24, codeSize);
2735                                 memset(jaguar_mainRom, 0xFF, 0x600000);
2736                                 memcpy(jaguar_mainRom + (loadAddress - 0x800000), jaguar_mainRam, codeSize);
2737                                 memset(jaguar_mainRam, 0x00, 0x400000);*/
2738                         }
2739
2740                         jaguarRunAddress = loadAddress;
2741                 }
2742                 else if (jaguar_mainRom[0] == 0x01 && jaguar_mainRom[1] == 0x50)
2743                 {
2744                         uint32_t loadAddress = GET32(jaguar_mainRom, 0x28), runAddress = GET32(jaguar_mainRom, 0x24),
2745                                 codeSize = GET32(jaguar_mainRom, 0x18) + GET32(jaguar_mainRom, 0x1C);
2746                         WriteLog("GUI: Setting up homebrew (ABS-2)... Run address: %08X, length: %08X\n", runAddress, codeSize);
2747
2748                         if (loadAddress < 0x800000)
2749                                 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0xA8, codeSize);
2750                         else
2751                         {
2752                                 for(int i=codeSize-1; i>=0; i--)
2753                                         jaguar_mainRom[(loadAddress - 0x800000) + i] = jaguar_mainRom[i + 0xA8];
2754 /*                              memcpy(jaguar_mainRam, jaguar_mainRom + 0xA8, codeSize);
2755                                 memset(jaguar_mainRom, 0xFF, 0x600000);
2756                                 memcpy(jaguar_mainRom + (loadAddress - 0x800000), jaguar_mainRam, codeSize);
2757                                 memset(jaguar_mainRam, 0x00, 0x400000);*/
2758                         }
2759
2760                         jaguarRunAddress = runAddress;
2761                 }
2762                 else
2763                 {
2764                         WriteLog("GUI: Couldn't find correct ABS format: %02X %02X\n", jaguar_mainRom[0], jaguar_mainRom[1]);
2765                         return false;
2766                 }
2767         }
2768         else if (strcasecmp(ext, ".jag") == 0)
2769         {
2770                 // File extension ".JAG": Atari server file with header
2771 //NOTE: The bytes 'JAGR' should also be at position $1C...
2772 //      Also, there's *always* a $601A header at position $00...
2773                 if (jaguar_mainRom[0] == 0x60 && jaguar_mainRom[1] == 0x1A)
2774                 {
2775                         uint32_t loadAddress = GET32(jaguar_mainRom, 0x22), runAddress = GET32(jaguar_mainRom, 0x2A);
2776 //This is not always right! Especially when converted via bin2jag1!!!
2777 //We should have access to the length of the furshlumiger file that was loaded anyway!
2778 //Now, we do! ;-)
2779 //                      uint32_t progLength = GET32(jaguar_mainRom, 0x02);
2780 //jaguarRomSize
2781 //jaguarRunAddress
2782 //                      WriteLog("Jaguar: Setting up PD ROM... Run address: %08X, length: %08X\n", runAddress, progLength);
2783 //                      memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, progLength);
2784                         WriteLog("GUI: Setting up homebrew (JAG)... Run address: %08X, length: %08X\n", runAddress, jaguarRomSize - 0x2E);
2785                         memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, jaguarRomSize - 0x2E);
2786 //              SET32(jaguar_mainRam, 4, runAddress);
2787                         jaguarRunAddress = runAddress;
2788                 }
2789                 else
2790                         return false;
2791         }
2792         // .J64 (Jaguar cartridge ROM image) is implied by the FileList object...
2793
2794         return true;
2795 }
2796
2797 //
2798 // Get the length of a (possibly) gzipped file
2799 //
2800 int gzfilelength(gzFile gd)
2801 {
2802    int size = 0, length = 0;
2803    unsigned char buffer[0x10000];
2804
2805    gzrewind(gd);
2806
2807    do
2808    {
2809       // Read in chunks until EOF
2810       size = gzread(gd, buffer, 0x10000);
2811
2812       if (size <= 0)
2813         break;
2814
2815       length += size;
2816    }
2817    while (!gzeof(gd));
2818
2819    gzrewind(gd);
2820    return length;
2821 }
2822 #endif