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