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