]> Shamusworld >> Repos - virtualjaguar/blob - src/gui.cpp
32BPP rendering/new exit behaviour for cmd line execution
[virtualjaguar] / src / gui.cpp
1 //
2 // GUI.CPP
3 //
4 // Graphical User Interface support
5 // by James L. Hammons
6 //
7
8 #include <stdarg.h>
9 #include <sys/types.h>                                                          // For MacOS <dirent.h> dependency
10 #include <dirent.h>
11 #include <SDL.h>
12 #include <string>
13 #include <vector>
14 #include <algorithm>
15 #include <ctype.h>                                                                      // For toupper()
16 #include "settings.h"
17 #include "tom.h"
18 #include "video.h"
19 #include "font1.h"
20 #include "crc32.h"
21 #include "zlib.h"
22 #include "unzip.h"
23 #include "gui.h"
24
25 using namespace std;                                                            // For STL stuff
26
27 // Private function prototypes
28
29 class Window;                                                                           // Forward declaration...
30
31 //void DrawTransparentBitmap(int16 * screen, uint32 x, uint32 y, uint16 * bitmap, uint8 * alpha = NULL);
32 //void DrawStringTrans(int16 * screen, uint32 x, uint32 y, uint16 color, uint8 opacity, const char * text, ...);
33 //void DrawStringOpaque(int16 * screen, uint32 x, uint32 y, uint16 color1, uint16 color2, const char * text, ...);
34 //void DrawString(int16 * screen, uint32 x, uint32 y, bool invert, const char * text, ...);
35 void DrawTransparentBitmap(uint32 * screen, uint32 x, uint32 y, uint32 * bitmap, uint8 * alpha = NULL);
36 void DrawStringTrans(uint32 * screen, uint32 x, uint32 y, uint32 color, uint8 opacity, const char * text, ...);
37 void DrawStringOpaque(uint32 * screen, uint32 x, uint32 y, uint32 color1, uint32 color2, const char * text, ...);
38 void DrawString(uint32 * screen, uint32 x, uint32 y, bool invert, const char * text, ...);
39 Window * LoadROM(void);
40 Window * ResetJaguar(void);
41 Window * ResetJaguarCD(void);
42 Window * RunEmu(void);
43 Window * Quit(void);
44 Window * About(void);
45 Window * MiscOptions(void);
46
47 int gzfilelength(gzFile gd);
48
49 // External variables
50
51 extern uint8 * jaguar_mainRam;
52 extern uint8 * jaguar_mainRom;
53 extern uint8 * jaguar_bootRom;
54 extern uint8 * jaguar_CDBootROM;
55 extern bool BIOSLoaded;
56 extern bool CDBIOSLoaded;
57
58 // Local global variables
59
60 bool exitGUI = false;                                                           // GUI (emulator) done variable
61 int mouseX, mouseY;
62 //uint16 background[1280 * 256];                                                // GUI background buffer
63 uint32 background[1280 * 256];                                          // GUI background buffer
64
65 //NOTE: 32-bit pixels are in the format of ABGR...
66 uint32 mousePic[] = {
67         6, 8,
68
69         0xFF00FF00,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,              // +
70         0xFF00C600,0xFF00FF00,0x00000000,0x00000000,0x00000000,0x00000000,              // @+
71         0xFF00C600,0xFF00FF00,0xFF00FF00,0x00000000,0x00000000,0x00000000,              // @++
72         0xFF00C600,0xFF00C600,0xFF00FF00,0xFF00FF00,0x00000000,0x00000000,              // @@++
73         0xFF00C600,0xFF00C600,0xFF00FF00,0xFF00FF00,0xFF00FF00,0x00000000,              // @@+++
74         0xFF00C600,0xFF00C600,0xFF00C600,0xFF00FF00,0xFF00FF00,0xFF00FF00,              // @@@+++
75         0xFF00C600,0xFF00C600,0xFF00C600,0x00000000,0x00000000,0x00000000,              // @@@
76         0xFF00C600,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000               // @
77 /*
78         0x03E0,0x0000,0x0000,0x0000,0x0000,0x0000,              // +
79         0x0300,0x03E0,0x0000,0x0000,0x0000,0x0000,              // @+
80         0x0300,0x03E0,0x03E0,0x0000,0x0000,0x0000,              // @++
81         0x0300,0x0300,0x03E0,0x03E0,0x0000,0x0000,              // @@++
82         0x0300,0x0300,0x03E0,0x03E0,0x03E0,0x0000,              // @@+++
83         0x0300,0x0300,0x0300,0x03E0,0x03E0,0x03E0,              // @@@+++
84         0x0300,0x0300,0x0300,0x0000,0x0000,0x0000,              // @@@
85         0x0300,0x0000,0x0000,0x0000,0x0000,0x0000               // @
86 */
87 /*
88         0xFFFF,0x0000,0x0000,0x0000,0x0000,0x0000,              // +
89         0xE318,0xFFFF,0x0000,0x0000,0x0000,0x0000,              // @+
90         0xE318,0xFFFF,0xFFFF,0x0000,0x0000,0x0000,              // @++
91         0xE318,0xE318,0xFFFF,0xFFFF,0x0000,0x0000,              // @@++
92         0xE318,0xE318,0xFFFF,0xFFFF,0xFFFF,0x0000,              // @@+++
93         0xE318,0xE318,0xE318,0xFFFF,0xFFFF,0xFFFF,              // @@@+++
94         0xE318,0xE318,0xE318,0x0000,0x0000,0x0000,              // @@@
95         0xE318,0x0000,0x0000,0x0000,0x0000,0x0000               // @
96 */
97 };
98 // 1 111 00 11 100 1 1100 -> F39C
99 // 1 100 00 10 000 1 0000 -> C210
100 // 1 110 00 11 000 1 1000 -> E318
101 // 0 000 00 11 111 0 0000 -> 03E0
102 // 0 000 00 11 000 0 0000 -> 0300 -> FF00C600
103
104 uint32 closeBox[] = {
105         7, 7,
106
107 //4B5E -> 010010 11010 11110 -> 0100 1001 1101 0110 1111 0111 -> 49 D6 F7
108 //0217 -> 000000 10000 10111 -> 0000 0000 1000 0100 1011 1101 -> 00 84 BD
109         0x00000000,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0x00000000,           //  +++++
110         0xFFF7D649,0xFFFFFFFF,0x00000000,0x00000000,0x00000000,0xFFFFFFFF,0xFFBD8400,           // +@   @.
111         0xFFF7D649,0x00000000,0xFFFFFFFF,0x00000000,0xFFFFFFFF,0x00000000,0xFFBD8400,           // + @ @ .
112         0xFFF7D649,0x00000000,0x00000000,0xFFFFFFFF,0x00000000,0x00000000,0xFFBD8400,           // +  @  .
113         0xFFF7D649,0x00000000,0xFFFFFFFF,0x00000000,0xFFFFFFFF,0x00000000,0xFFBD8400,           // + @ @ .
114         0xFFF7D649,0xFFFFFFFF,0x00000000,0x00000000,0x00000000,0xFFFFFFFF,0xFFBD8400,           // +@   @.
115         0x00000000,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0x00000000            //  .....
116 /*
117         0x0000,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x0000,               //  +++++
118         0x4B5E,0xFFFF,0x0000,0x0000,0x0000,0xFFFF,0x0217,               // +@   @.
119         0x4B5E,0x0000,0xFFFF,0x0000,0xFFFF,0x0000,0x0217,               // + @ @ .
120         0x4B5E,0x0000,0x0000,0xFFFF,0x0000,0x0000,0x0217,               // +  @  .
121         0x4B5E,0x0000,0xFFFF,0x0000,0xFFFF,0x0000,0x0217,               // + @ @ .
122         0x4B5E,0xFFFF,0x0000,0x0000,0x0000,0xFFFF,0x0217,               // +@   @.
123         0x0000,0x0217,0x0217,0x0217,0x0217,0x0217,0x0000                //  .....
124 */
125 };
126
127 uint32 upArrowBox[] = {
128         8, 8,
129
130         0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,                // ++++++++
131         0xFFF7D649,0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0x00000000,0xFFBD8400,                // +  @@  .
132         0xFFF7D649,0x00000000,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0xFFBD8400,                // + @@@@ .
133         0xFFF7D649,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFBD8400,                // +@@@@@@.
134         0xFFF7D649,0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0x00000000,0xFFBD8400,                // +  @@  .
135         0xFFF7D649,0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0x00000000,0xFFBD8400,                // +  @@  .
136         0xFFF7D649,0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0x00000000,0xFFBD8400,                // +  @@  .
137         0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400                 // ........
138 };
139
140 uint32 downArrowBox[] = {
141         8, 8,
142
143         0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,                // ++++++++
144         0xFFF7D649,0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0x00000000,0xFFBD8400,                // +  @@  .
145         0xFFF7D649,0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0x00000000,0xFFBD8400,                // +  @@  .
146         0xFFF7D649,0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0x00000000,0xFFBD8400,                // +  @@  .
147         0xFFF7D649,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFBD8400,                // +@@@@@@.
148         0xFFF7D649,0x00000000,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0xFFBD8400,                // + @@@@ .
149         0xFFF7D649,0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0x00000000,0xFFBD8400,                // +  @@  .
150         0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400                 // ........
151 };
152
153 uint32 pushButtonUp[] = {
154         8, 8,
155
156         0x00000000, 0xFF1B1B1B, 0xFF545477, 0xFF525292, 0xFF474787, 0xFF363659, 0xFF0F0F0F, 0x00000000,
157         0xFF1B1B1C, 0xFF6666A7, 0xFF393995, 0xFF343492, 0xFF2F2F90, 0xFF2C2C90, 0xFF3B3B7E, 0xFF0F0F0F,
158         0xFF555578, 0xFF3A3A95, 0xFF353594, 0xFF303091, 0xFF2D2D8F, 0xFF2B2B90, 0xFF2A2A92, 0xFF333358,
159         0xFF545493, 0xFF343492, 0xFF303092, 0xFF2D2D8B, 0xFF2B2B8A, 0xFF2A2A8D, 0xFF292994, 0xFF3D3D83,
160         0xFF484889, 0xFF2F2F90, 0xFF2D2D8F, 0xFF2B2B8A, 0xFF2A2A89, 0xFF29298E, 0xFF292998, 0xFF3D3D84,
161         0xFF37375A, 0xFF2C2C90, 0xFF2B2B90, 0xFF2A2A8D, 0xFF29298E, 0xFF292995, 0xFF29299D, 0xFF34345B,
162         0xFF0E0E0E, 0xFF3E3E7F, 0xFF2A2A92, 0xFF292994, 0xFF292998, 0xFF29299D, 0xFF3C3C88, 0xFF0E0E0E,
163         0x00000000, 0xFF0D0D0D, 0xFF343456, 0xFF3D3D80, 0xFF3D3D82, 0xFF333358, 0xFF0D0D0D, 0x00000000
164 };
165
166 uint8 pbuAlpha[] = {
167         0xFF, 0xE4, 0xA0, 0x99, 0xA4, 0xBE, 0xF0, 0xFF, 
168         0xE3, 0x85, 0x00, 0x00, 0x00, 0x00, 0xAF, 0xF0, 
169         0x9F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 
170         0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAD, 
171         0xA3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAC, 
172         0xBD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 
173         0xF1, 0xAD, 0x00, 0x00, 0x00, 0x00, 0xAC, 0xF1, 
174         0xFF, 0xF2, 0xC0, 0xAD, 0xAD, 0xC0, 0xF2, 0xFF
175 };
176
177 uint32 pushButtonDown[] = {
178         8, 8,
179
180         0x00000000, 0xFF1B1B1B, 0xFF8B8B90, 0xFF8C8CAF, 0xFF767699, 0xFF56565B, 0xFF0F0F0F, 0x00000000,
181         0xFF1B1B1B, 0xFFB8B8D6, 0xFF5555E4, 0xFF4444F2, 0xFF4040F1, 0xFF4141D5, 0xFF626282, 0xFF0F0F0F,
182         0xFF8C8C91, 0xFF5555E4, 0xFF4444EF, 0xFF3E3EDC, 0xFF3B3BDB, 0xFF3D3DEC, 0xFF3E3ED4, 0xFF4B4B51,
183         0xFF8D8DB1, 0xFF4444F2, 0xFF3E3EDC, 0xFF3E3EDD, 0xFF3C3CDC, 0xFF3939D9, 0xFF3C3CF3, 0xFF59597E,
184         0xFF77779B, 0xFF4141F1, 0xFF3B3BDB, 0xFF3C3CDC, 0xFF3B3BDC, 0xFF3838D9, 0xFF3C3CF5, 0xFF595980,
185         0xFF57575D, 0xFF4242D8, 0xFF3D3DEC, 0xFF3939D9, 0xFF3838D9, 0xFF3C3CEF, 0xFF3D3DDC, 0xFF4C4C52,
186         0xFF101010, 0xFF636385, 0xFF3E3ED8, 0xFF3D3DF4, 0xFF3D3DF6, 0xFF3D3DDD, 0xFF5D5D83, 0xFF101010,
187         0x00000000, 0xFF101010, 0xFF4E4E55, 0xFF5B5B83, 0xFF5B5B84, 0xFF4D4D54, 0xFF101010, 0x00000000
188 };
189
190 uint8 pbdAlpha[] = {
191         0xFF, 0xE4, 0x72, 0x68, 0x7E, 0xA7, 0xF0, 0xFF, 
192         0xE4, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x93, 0xF0, 
193         0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB2, 
194         0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A, 
195         0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A, 
196         0xA6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB1, 
197         0xEF, 0x91, 0x00, 0x00, 0x00, 0x00, 0x96, 0xEF, 
198         0xFF, 0xEF, 0xAE, 0x98, 0x97, 0xAF, 0xEF, 0xFF
199 };
200
201 uint32 slideSwitchUp[] = {
202         8, 16,
203
204 //0C7F -> 000011 00011 11111 -> 0000 1100 0001 1000 1111 1111 -> 0C 18 FF
205         0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,                // ++++++++
206         0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400,                // +      .
207         0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400,                // +      .
208         0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400,                // +      .
209         0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400,                // +      .
210         0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400,                // +      .
211         0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400,                // +      .
212         0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400,                // +      .
213         0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400,                // +.......
214         0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400,                // +.......
215         0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400,                // +.......
216         0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400,                // +.......
217         0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400,                // +.......
218         0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400,                // +.......
219         0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400,                // +.......
220         0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400                 // ........
221 };
222
223 uint32 slideSwitchDown[] = {
224         8, 16,
225
226         0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,                // ++++++++
227         0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400,                // +.......
228         0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400,                // +.......
229         0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400,                // +.......
230         0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400,                // +.......
231         0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400,                // +.......
232         0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400,                // +.......
233         0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400,                // +.......
234         0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400,                // +      .
235         0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400,                // +      .
236         0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400,                // +      .
237         0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400,                // +      .
238         0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400,                // +      .
239         0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400,                // +      .
240         0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400,                // +      .
241         0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400                 // ........
242 };
243
244 /*uint32 [] = {
245         8, 8,
246
247         0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,                // ........
248         0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,                // ........
249         0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,                // ........
250         0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,                // ........
251         0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,                // ........
252         0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,                // ........
253         0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,                // ........
254         0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000                 // ........
255 };*/
256
257 char separator[] = "--------------------------------------------------------";
258
259 //
260 // Case insensitive string compare function
261 // Taken straight out of Thinking In C++ by Bruce Eckel. Thanks Bruce!
262 //
263
264 int stringCmpi(const string &s1, const string &s2)
265 {
266         // Select the first element of each string:
267         string::const_iterator p1 = s1.begin(), p2 = s2.begin();
268
269         while (p1 != s1.end() && p2 != s2.end())                // Don\92t run past the end
270         {
271                 if (toupper(*p1) != toupper(*p2))                       // Compare upper-cased chars
272                         return (toupper(*p1) < toupper(*p2) ? -1 : 1);// Report which was lexically greater
273
274                 p1++;
275                 p2++;
276         }
277
278         // If they match up to the detected eos, say which was longer. Return 0 if the same.
279         return s2.size() - s1.size();
280 }
281
282 //
283 // Local GUI classes
284 //
285
286 enum { WINDOW_CLOSE, MENU_ITEM_CHOSEN };
287
288 class Element
289 {
290         public:
291                 Element(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0)
292                         { extents.x = x, extents.y = y, extents.w = w, extents.h = h; }
293                 virtual void HandleKey(SDLKey key) = 0;         // These are "pure" virtual functions...
294                 virtual void HandleMouseMove(uint32 x, uint32 y) = 0;
295                 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) = 0;
296                 virtual void Draw(uint32, uint32) = 0;
297                 virtual void Notify(Element *) = 0;
298 //Needed?               virtual ~Element() = 0;
299 //We're not allocating anything in the base class, so the answer would be NO.
300                 bool Inside(uint32 x, uint32 y);
301                 // Class method
302 //              static void SetScreenAndPitch(int16 * s, uint32 p) { screenBuffer = s, pitch = p; }
303                 static void SetScreenAndPitch(uint32 * s, uint32 p) { screenBuffer = s, pitch = p; }
304
305         protected:
306                 SDL_Rect extents;
307                 uint32 state;
308                 // Class variables...
309 //              static int16 * screenBuffer;
310                 static uint32 * screenBuffer;
311                 static uint32 pitch;
312 };
313
314 // Initialize class variables (Element)
315 //int16 * Element::screenBuffer = NULL;
316 uint32 * Element::screenBuffer = NULL;
317 uint32 Element::pitch = 0;
318
319 bool Element::Inside(uint32 x, uint32 y)
320 {
321         return (x >= (uint32)extents.x && x < (uint32)(extents.x + extents.w)
322                 && y >= (uint32)extents.y && y < (uint32)(extents.y + extents.h) ? true : false);
323 }
324
325
326 class Button: public Element
327 {
328         public:
329                 Button(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
330                         activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
331                         bgColor(0xFF00FF00), pic(NULL), elementToTell(NULL) {}
332                 Button(uint32 x, uint32 y, uint32 w, uint32 h, uint32 * p): Element(x, y, w, h),
333                         activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
334                         bgColor(0xFF00FF00), pic(p), elementToTell(NULL) {}
335                 Button(uint32 x, uint32 y, uint32 * p): Element(x, y, 0, 0),
336                         activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
337                         bgColor(0xFF00FF00), pic(p), elementToTell(NULL)
338                         { if (pic) extents.w = pic[0], extents.h = pic[1]; }
339                 Button(uint32 x, uint32 y, uint32 w, uint32 h, string s): Element(x, y, w, h),
340                         activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
341                         bgColor(0xFF00FF00), pic(NULL), text(s), elementToTell(NULL) {}
342                 Button(uint32 x, uint32 y, string s): Element(x, y, 0, 8),
343                         activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
344                         bgColor(0xFF00FF00), pic(NULL), text(s), elementToTell(NULL)
345                         { extents.w = s.length() * 8; }
346                 virtual void HandleKey(SDLKey key) {}
347                 virtual void HandleMouseMove(uint32 x, uint32 y);
348                 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
349                 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
350                 virtual void Notify(Element *) {}
351                 bool ButtonClicked(void) { return activated; }
352                 void SetNotificationElement(Element * e) { elementToTell = e; }
353
354         protected:
355                 bool activated, clicked, inside;
356                 uint32 fgColor, bgColor;
357                 uint32 * pic;
358                 string text;
359                 Element * elementToTell;
360 };
361
362 void Button::HandleMouseMove(uint32 x, uint32 y)
363 {
364         inside = Inside(x, y);
365 }
366
367 void Button::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
368 {
369         if (inside)
370         {
371                 if (mouseDown)
372                         clicked = true;
373
374                 if (clicked && !mouseDown)
375                 {
376                         clicked = false, activated = true;
377
378                         // Send a message that we're activated (if there's someone to tell, that is)
379                         if (elementToTell)
380                                 elementToTell->Notify(this);
381                 }
382         }
383         else
384                 clicked = activated = false;
385 }
386
387 void Button::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
388 {
389         uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
390
391         for(uint32 y=0; y<extents.h; y++)
392         {
393                 for(uint32 x=0; x<extents.w; x++)
394                 {
395                         // Doesn't clip in y axis! !!! FIX !!!
396                         if (extents.x + x < pitch)
397                                 screenBuffer[addr + x + (y * pitch)] 
398 //                                      = (clicked && inside ? fgColor : (inside ? 0x43F0 : bgColor));
399 //43F0 -> 010000 11111 10000 -> 0100 0001 1111 1111 1000 0100 -> 41 FF 84
400                                         = (clicked && inside ? fgColor : (inside ? 0xFF84FF41 : bgColor));
401                 }
402         }
403
404         if (pic != NULL)
405                 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, pic);
406
407         if (text.length() > 0)
408                 DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY, false, "%s", text.c_str());
409 }
410
411
412 class PushButton: public Element
413 {
414 // How to handle?
415 // Save state externally?
416 //We pass in a state variable if we want to track it externally, otherwise we use our own
417 //internal state var. Still need to do some kind of callback for pushbuttons that do things
418 //like change from fullscreen to windowed... !!! FIX !!!
419
420         public:
421 //              PushButton(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
422 //                      activated(false), clicked(false), inside(false), fgColor(0xFFFF),
423 //                      bgColor(0x03E0), pic(NULL), elementToTell(NULL) {}
424                 PushButton(uint32 x, uint32 y, bool * st, string s): Element(x, y, 8, 8), state(st),
425                         inside(false), text(s) { if (st == NULL) state = &internalState; }
426 /*              Button(uint32 x, uint32 y, uint32 w, uint32 h, uint32 * p): Element(x, y, w, h),
427                         activated(false), clicked(false), inside(false), fgColor(0xFFFF),
428                         bgColor(0x03E0), pic(p), elementToTell(NULL) {}
429                 Button(uint32 x, uint32 y, uint32 * p): Element(x, y, 0, 0),
430                         activated(false), clicked(false), inside(false), fgColor(0xFFFF),
431                         bgColor(0x03E0), pic(p), elementToTell(NULL)
432                         { if (pic) extents.w = pic[0], extents.h = pic[1]; }
433                 Button(uint32 x, uint32 y, uint32 w, uint32 h, string s): Element(x, y, w, h),
434                         activated(false), clicked(false), inside(false), fgColor(0xFFFF),
435                         bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL) {}
436                 PushButton(uint32 x, uint32 y, string s): Element(x, y, 0, 8),
437                         activated(false), clicked(false), inside(false), fgColor(0xFFFF),
438                         bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL)
439                         { extents.w = s.length() * 8; }*/
440                 virtual void HandleKey(SDLKey key) {}
441                 virtual void HandleMouseMove(uint32 x, uint32 y);
442                 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
443                 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
444                 virtual void Notify(Element *) {}
445 //              bool ButtonClicked(void) { return activated; }
446 //              void SetNotificationElement(Element * e) { elementToTell = e; }
447
448         protected:
449                 bool * state;
450                 bool inside;
451 //              bool activated, clicked, inside;
452 //              uint16 fgColor, bgColor;
453 //              uint32 * pic;
454                 string text;
455 //              Element * elementToTell;
456                 bool internalState;
457 };
458
459 void PushButton::HandleMouseMove(uint32 x, uint32 y)
460 {
461         inside = Inside(x, y);
462 }
463
464 void PushButton::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
465 {
466         if (inside && mouseDown)
467         {
468 /*              if (mouseDown)
469                         clicked = true;
470
471                 if (clicked && !mouseDown)
472                 {
473                         clicked = false, activated = true;
474
475                         // Send a message that we're activated (if there's someone to tell, that is)
476                         if (elementToTell)
477                                 elementToTell->Notify(this);
478                 }*/
479                 *state = !(*state);
480         }
481 //      else
482 //              clicked = activated = false;
483 }
484
485 void PushButton::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
486 {
487 /*      uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
488
489         for(uint32 y=0; y<extents.h; y++)
490         {
491                 for(uint32 x=0; x<extents.w; x++)
492                 {
493                         // Doesn't clip in y axis! !!! FIX !!!
494                         if (extents.x + x < pitch)
495                                 screenBuffer[addr + x + (y * pitch)] 
496                                         = (clicked && inside ? fgColor : (inside ? 0x43F0 : bgColor));
497                 }
498         }*/
499
500 //      DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, (*state ? pushButtonDown : pushButtonUp));
501         DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, (*state ? pushButtonDown : pushButtonUp), (*state ? pbdAlpha : pbuAlpha));
502         if (text.length() > 0)
503                 DrawString(screenBuffer, extents.x + offsetX + 12, extents.y + offsetY, false, "%s", text.c_str());
504 }
505
506
507 class SlideSwitch: public Element
508 {
509 // How to handle?
510 // Save state externally?
511 //Seems to be handled the same as PushButton, but without sanity checks. !!! FIX !!!
512
513         public:
514                 SlideSwitch(uint32 x, uint32 y, bool * st, string s1, string s2): Element(x, y, 8, 16), state(st),
515                         inside(false), text1(s1), text2(s2) {}
516                 virtual void HandleKey(SDLKey key) {}
517                 virtual void HandleMouseMove(uint32 x, uint32 y);
518                 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
519                 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
520                 virtual void Notify(Element *) {}
521 //              bool ButtonClicked(void) { return activated; }
522 //              void SetNotificationElement(Element * e) { elementToTell = e; }
523
524         protected:
525                 bool * state;
526                 bool inside;
527 //              bool activated, clicked, inside;
528 //              uint16 fgColor, bgColor;
529 //              uint32 * pic;
530                 string text1, text2;
531 //              Element * elementToTell;
532 };
533
534 void SlideSwitch::HandleMouseMove(uint32 x, uint32 y)
535 {
536         inside = Inside(x, y);
537 }
538
539 void SlideSwitch::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
540 {
541         if (inside && mouseDown)
542         {
543 /*              if (mouseDown)
544                         clicked = true;
545
546                 if (clicked && !mouseDown)
547                 {
548                         clicked = false, activated = true;
549
550                         // Send a message that we're activated (if there's someone to tell, that is)
551                         if (elementToTell)
552                                 elementToTell->Notify(this);
553                 }*/
554                 *state = !(*state);
555         }
556 //      else
557 //              clicked = activated = false;
558 }
559
560 void SlideSwitch::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
561 {
562         DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, (*state ? slideSwitchDown : slideSwitchUp));
563         if (text1.length() > 0)
564                 DrawString(screenBuffer, extents.x + offsetX + 12, extents.y + offsetY, false, "%s", text1.c_str());
565         if (text2.length() > 0)
566                 DrawString(screenBuffer, extents.x + offsetX + 12, extents.y + offsetY + 8, false, "%s", text2.c_str());
567 }
568
569
570 class Window: public Element
571 {
572         public:
573 /*              Window(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
574                         fgColor(0x4FF0), bgColor(0xFE10)
575                         { close = new Button(w - 8, 1, closeBox); list.push_back(close); }*/
576                 Window(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0,
577                         void (* f)(Element *) = NULL): Element(x, y, w, h),
578 //                      /*clicked(false), inside(false),*/ fgColor(0x4FF0), bgColor(0x1E10),
579 //4FF0 -> 010011 11111 10000 -> 0100 1101 1111 1111 1000 0100 -> 4D FF 84
580 //1E10 -> 000111 10000 10000 -> 0001 1111 1000 0100 1000 0100 -> 1F 84 84
581                         /*clicked(false), inside(false),*/ fgColor(0xFF84FF4D), bgColor(0xFF84841F),
582                         handler(f)
583                         { close = new Button(w - 8, 1, closeBox); list.push_back(close);
584                           close->SetNotificationElement(this); }
585                 virtual ~Window();
586                 virtual void HandleKey(SDLKey key);
587                 virtual void HandleMouseMove(uint32 x, uint32 y);
588                 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
589                 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
590                 virtual void Notify(Element * e);
591                 void AddElement(Element * e);
592 //              bool WindowActive(void) { return true; }//return !close->ButtonClicked(); }
593
594         protected:
595 //              bool clicked, inside;
596                 uint32 fgColor, bgColor;
597                 void (* handler)(Element *);
598                 Button * close;
599 //We have to use a list of Element *pointers* because we can't make a list that will hold
600 //all the different object types in the same list...
601                 vector<Element *> list;
602 };
603
604 Window::~Window()
605 {
606         for(uint32 i=0; i<list.size(); i++)
607                 if (list[i])
608                         delete list[i];
609 }
610
611 void Window::HandleKey(SDLKey key)
612 {
613         if (key == SDLK_ESCAPE)
614         {
615                 SDL_Event event;
616                 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
617                 SDL_PushEvent(&event);
618         }
619
620         // Handle the items this window contains...
621         for(uint32 i=0; i<list.size(); i++)
622                 // Make coords relative to upper right corner of this window...
623                 list[i]->HandleKey(key);
624 }
625
626 void Window::HandleMouseMove(uint32 x, uint32 y)
627 {
628         // Handle the items this window contains...
629         for(uint32 i=0; i<list.size(); i++)
630                 // Make coords relative to upper right corner of this window...
631                 list[i]->HandleMouseMove(x - extents.x, y - extents.y);
632 }
633
634 void Window::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
635 {
636         // Handle the items this window contains...
637         for(uint32 i=0; i<list.size(); i++)
638                 // Make coords relative to upper right corner of this window...
639                 list[i]->HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
640 }
641
642 void Window::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
643 {
644         uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
645
646         for(uint32 y=0; y<extents.h; y++)
647         {
648                 for(uint32 x=0; x<extents.w; x++)
649                 {
650                         // Doesn't clip in y axis! !!! FIX !!!
651                         if (extents.x + x < pitch)
652                                 screenBuffer[addr + x + (y * pitch)] = bgColor;
653                 }
654         }
655
656         // Handle the items this window contains...
657         for(uint32 i=0; i<list.size(); i++)
658                 list[i]->Draw(extents.x, extents.y);
659 }
660
661 void Window::AddElement(Element * e)
662 {
663         list.push_back(e);
664 }
665
666 void Window::Notify(Element * e)
667 {
668         if (e == close)
669         {
670                 SDL_Event event;
671                 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
672                 SDL_PushEvent(&event);
673         }
674 }
675
676
677 class Text: public Element
678 {
679         public:
680 //              Text(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
681 //                      fgColor(0x4FF0), bgColor(0xFE10) {}
682 //              Text(uint32 x, uint32 y, string s, uint16 fg = 0x4FF0, uint16 bg = 0xFE10): Element(x, y, 0, 0),
683 //                      fgColor(fg), bgColor(bg), text(s) {}
684 //4FF0 -> 010011 11111 10000 -> 0100 1101 1111 1111 1000 0100 -> 4D FF 84
685 //FE10 -> 111111 10000 10000 -> 1111 1111 1000 0100 1000 0100 -> FF 84 84
686                 Text(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
687                         fgColor(0xFF84FF4D), bgColor(0xFF8484FF) {}
688                 Text(uint32 x, uint32 y, string s, uint32 fg = 0xFF84FF4D, uint32 bg = 0xFF8484FF): Element(x, y, 0, 0),
689                         fgColor(fg), bgColor(bg), text(s) {}
690                 virtual void HandleKey(SDLKey key) {}
691                 virtual void HandleMouseMove(uint32 x, uint32 y) {}
692                 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) {}
693                 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
694                 virtual void Notify(Element *) {}
695
696         protected:
697                 uint32 fgColor, bgColor;
698                 string text;
699 };
700
701 void Text::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
702 {
703         if (text.length() > 0)
704 //              DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY, false, "%s", text.c_str());
705                 DrawStringOpaque(screenBuffer, extents.x + offsetX, extents.y + offsetY, fgColor, bgColor, "%s", text.c_str());
706 }
707
708
709 class ListBox: public Element
710 //class ListBox: public Window
711 {
712         public:
713 //              ListBox(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
714                 ListBox(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0);//: Window(x, y, w, h),
715 //              windowPtr(0), cursor(0), limit(0), charWidth((w / 8) - 1), charHeight(h / 8),
716 //              elementToTell(NULL), upArrow(w - 8, 0, upArrowBox),
717 //              downArrow(w - 8, h - 8, downArrowBox), upArrow2(w - 8, h - 16, upArrowBox) {}
718                 virtual void HandleKey(SDLKey key);
719                 virtual void HandleMouseMove(uint32 x, uint32 y);
720                 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
721                 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
722                 virtual void Notify(Element * e);
723                 void SetNotificationElement(Element * e) { elementToTell = e; }
724                 void AddItem(string s);
725                 string GetSelectedItem(void);
726
727         protected:
728                 bool thumbClicked;
729                 uint32 windowPtr, cursor, limit;
730                 uint32 charWidth, charHeight;                           // Box width/height in characters
731                 Element * elementToTell;
732                 Button upArrow, downArrow, upArrow2;
733                 vector<string> item;
734
735         private:
736                 uint32 yRelativePoint;
737 };
738
739 ListBox::ListBox(uint32 x, uint32 y, uint32 w, uint32 h): Element(x, y, w, h),
740         thumbClicked(false), windowPtr(0), cursor(0), limit(0), charWidth((w / 8) - 1),
741         charHeight(h / 8), elementToTell(NULL), upArrow(w - 8, 0, upArrowBox),
742         downArrow(w - 8, h - 8, downArrowBox), upArrow2(w - 8, h - 16, upArrowBox)
743 {
744         upArrow.SetNotificationElement(this);
745         downArrow.SetNotificationElement(this);
746         upArrow2.SetNotificationElement(this);
747         extents.w -= 8;                                                                 // Make room for scrollbar...
748 }
749
750 void ListBox::HandleKey(SDLKey key)
751 {
752         if (key == SDLK_DOWN)
753         {
754                 if (cursor != limit - 1)        // Cursor is within its window
755                         cursor++;
756                 else                                            // Otherwise, scroll the window...
757                 {
758                         if (cursor + windowPtr != item.size() - 1)
759                                 windowPtr++;
760                 }
761         }
762         else if (key == SDLK_UP)
763         {
764                 if (cursor != 0)
765                         cursor--;
766                 else
767                 {
768                         if (windowPtr != 0)
769                                 windowPtr--;
770                 }
771         }
772         else if (key == SDLK_PAGEDOWN)
773         {
774                 if (cursor != limit - 1)
775                         cursor = limit - 1;
776                 else
777                 {
778                         windowPtr += limit;
779                         if (windowPtr > item.size() - limit)
780                                 windowPtr = item.size() - limit;
781                 }
782         }
783         else if (key == SDLK_PAGEUP)
784         {
785                 if (cursor != 0)
786                         cursor = 0;
787                 else
788                 {
789                         if (windowPtr < limit)
790                                 windowPtr = 0;
791                         else
792                                 windowPtr -= limit;
793                 }
794         }
795         else if (key >= SDLK_a && key <= SDLK_z)
796         {
797                 // Advance cursor to filename with first letter pressed...
798                 uint8 which = (key - SDLK_a) + 65;      // Convert key to A-Z char
799
800                 for(uint32 i=0; i<item.size(); i++)
801                 {
802                         if ((item[i][0] & 0xDF) == which)
803                         {
804                                 cursor = i - windowPtr;
805                                 if (i > windowPtr + limit - 1)
806                                         windowPtr = i - limit + 1, cursor = limit - 1;
807                                 if (i < windowPtr)
808                                         windowPtr = i, cursor = 0;
809                                 break;
810                         }
811                 }
812         }
813 }
814
815 void ListBox::HandleMouseMove(uint32 x, uint32 y)
816 {
817         upArrow.HandleMouseMove(x - extents.x, y - extents.y);
818         downArrow.HandleMouseMove(x - extents.x, y - extents.y);
819         upArrow2.HandleMouseMove(x - extents.x, y - extents.y);
820
821         if (thumbClicked)
822         {
823                 uint32 sbHeight = extents.h - 24,
824                         thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight);
825
826 //yRelativePoint is the spot on the thumb where we clicked...
827                 int32 newThumbStart = y - yRelativePoint;
828
829                 if (newThumbStart < 0)
830                         newThumbStart = 0;
831
832                 if ((uint32)newThumbStart > sbHeight - thumb)
833                         newThumbStart = sbHeight - thumb;
834
835                 windowPtr = (uint32)(((float)newThumbStart / (float)sbHeight) * (float)item.size());
836 //Check for cursor bounds as well... Or do we need to???
837 //Actually, we don't...!
838         }
839 }
840
841 void ListBox::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
842 {
843         if (Inside(x, y) && mouseDown)
844         {
845                 // Why do we have to do this??? (- extents.y?)
846                 // I guess it's because only the Window class has offsetting implemented... !!! FIX !!!
847                 cursor = (y - extents.y) / 8;
848         }
849
850         // Check for a hit on the scrollbar...
851         if (x > (uint32)(extents.x + extents.w) && x <= (uint32)(extents.x + extents.w + 8)
852                 && y > (uint32)(extents.y + 8) && y <= (uint32)(extents.y + extents.h - 16))
853         {
854                 if (mouseDown)
855                 {
856 // This shiaut should be calculated in AddItem(), not here... (or in Draw() for that matter)
857                         uint32 sbHeight = extents.h - 24,
858                                 thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight),
859                                 thumbStart = (uint32)(((float)windowPtr / (float)item.size()) * (float)sbHeight);
860
861                         // Did we hit the thumb?
862                         if (y >= (extents.y + 8 + thumbStart) && y < (extents.y + 8 + thumbStart + thumb))
863                                 thumbClicked = true, yRelativePoint = y - thumbStart;
864                 }
865 //Seems that this is useless--never reached except in rare cases and that the code outside is
866 //more effective...
867 //              else
868 //                      thumbClicked = false;
869         }
870
871         if (!mouseDown)
872                 thumbClicked = false;
873
874         upArrow.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
875         downArrow.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
876         upArrow2.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
877 }
878
879 void ListBox::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
880 {
881         for(uint32 i=0; i<limit; i++)
882         {
883                 // Strip off the extension
884                 // (extension stripping should be an option, not default!)
885                 string s(item[windowPtr + i], 0, item[windowPtr + i].length() - 4);
886                 DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY + i*8,
887                         (cursor == i ? true : false), "%-*.*s", charWidth, charWidth, s.c_str());
888         }
889
890         upArrow.Draw(extents.x + offsetX, extents.y + offsetY);
891         downArrow.Draw(extents.x + offsetX, extents.y + offsetY);
892         upArrow2.Draw(extents.x + offsetX, extents.y + offsetY);
893
894         uint32 sbHeight = extents.h - 24,
895                 thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight),
896                 thumbStart = (uint32)(((float)windowPtr / (float)item.size()) * (float)sbHeight);
897
898         for(uint32 y=extents.y+offsetY+8; y<extents.y+offsetY+extents.h-16; y++)
899         {
900 //              for(uint32 x=extents.x+offsetX+extents.w-8; x<extents.x+offsetX+extents.w; x++)
901                 for(uint32 x=extents.x+offsetX+extents.w; x<extents.x+offsetX+extents.w+8; x++)
902                 {
903                         if (y >= thumbStart + (extents.y+offsetY+8) && y < thumbStart + thumb + (extents.y+offsetY+8))
904 //                              screenBuffer[x + (y * pitch)] = (thumbClicked ? 0x458E : 0xFFFF);
905 //458E -> 01 0001  0 1100  0 1110 -> 0100 0101  0110 0011  0111 0011 -> 45 63 73
906                                 screenBuffer[x + (y * pitch)] = (thumbClicked ? 0xFF736345 : 0xFFFFFFFF);
907                         else
908 //                              screenBuffer[x + (y * pitch)] = 0x0200;
909 //0200 -> 000000 10000 00000 -> 00 1000 0100 00
910                                 screenBuffer[x + (y * pitch)] = 0xFF008400;
911                 }
912         }
913 }
914
915 void ListBox::Notify(Element * e)
916 {
917         if (e == &upArrow || e == &upArrow2)
918         {
919                 if (windowPtr != 0)
920                 {
921                         windowPtr--;
922
923                         if (cursor < limit - 1)
924                                 cursor++;
925                 }
926         }
927         else if (e == &downArrow)
928         {
929                 if (windowPtr < item.size() - limit)
930                 {
931                         windowPtr++;
932
933                         if (cursor != 0)
934                                 cursor--;
935                 }
936         }
937 }
938
939 void ListBox::AddItem(string s)
940 {
941         // Do a simple insertion sort
942         bool inserted = false;
943
944         for(vector<string>::iterator i=item.begin(); i<item.end(); i++)
945         {
946                 if (stringCmpi(s, *i) == -1)
947                 {
948                         item.insert(i, s);
949                         inserted = true;
950                         break;
951                 }
952         }
953
954         if (!inserted)
955                 item.push_back(s);
956
957         limit = (item.size() > charHeight ? charHeight : item.size());
958 }
959
960 string ListBox::GetSelectedItem(void)
961 {
962         return item[windowPtr + cursor];
963 }
964
965
966 class FileList: public Window
967 {
968         public:
969                 FileList(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0);
970                 virtual ~FileList() {}
971                 virtual void HandleKey(SDLKey key);
972                 virtual void HandleMouseMove(uint32 x, uint32 y) { Window::HandleMouseMove(x, y); }
973                 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) { Window::HandleMouseButton(x, y, mouseDown); }
974                 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0) { Window::Draw(offsetX, offsetY); }
975                 virtual void Notify(Element * e);
976
977         protected:
978                 ListBox * files;
979                 Button * load;
980 };
981
982 //Need 4 buttons, one scrollbar...
983 FileList::FileList(uint32 x, uint32 y, uint32 w, uint32 h): Window(x, y, w, h)
984 {
985         files = new ListBox(8, 8, w - 16, h - 32);
986         AddElement(files);
987         load = new Button(8, h - 16, " Load ");
988         AddElement(load);
989         load->SetNotificationElement(this);
990
991 //!!! FIX !!! Directory might not exist--this shouldn't cause VJ to crash!
992         DIR * dp = opendir(vjs.ROMPath);
993         dirent * de;
994
995         while ((de = readdir(dp)) != NULL)
996         {
997                 char * ext = strrchr(de->d_name, '.');
998
999                 if (ext != NULL)
1000                         if (strcasecmp(ext, ".zip") == 0 || strcasecmp(ext, ".j64") == 0
1001                                 || strcasecmp(ext, ".abs") == 0 || strcasecmp(ext, ".jag") == 0
1002                                 || strcasecmp(ext, ".rom") == 0)
1003                                 files->AddItem(string(de->d_name));
1004         }
1005
1006         closedir(dp);
1007 }
1008
1009 void FileList::HandleKey(SDLKey key)
1010 {
1011         if (key == SDLK_RETURN)
1012                 Notify(load);
1013         else
1014                 Window::HandleKey(key);
1015 }
1016
1017 void FileList::Notify(Element * e)
1018 {
1019         if (e == load)
1020         {
1021                 char filename[MAX_PATH];
1022                 strcpy(filename, vjs.ROMPath);
1023
1024                 if (strlen(filename) > 0)
1025                         if (filename[strlen(filename) - 1] != '/')
1026                                 strcat(filename, "/");
1027
1028                 strcat(filename, files->GetSelectedItem().c_str());
1029
1030 //              uint32 romSize = JaguarLoadROM(jaguar_mainRom, filename);
1031 //              JaguarLoadCart(jaguar_mainRom, filename);
1032                 if (JaguarLoadFile(filename))
1033                 {
1034                         SDL_Event event;
1035                         event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
1036                         SDL_PushEvent(&event);
1037
1038                         event.type = SDL_USEREVENT, event.user.code = MENU_ITEM_CHOSEN;
1039                         event.user.data1 = (void *)ResetJaguar;
1040                 SDL_PushEvent(&event);
1041                 }
1042                 else
1043                 {
1044                         SDL_Event event;
1045                         event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
1046                         SDL_PushEvent(&event);
1047
1048                         // Handle the error, but don't run...
1049                         // Tell the user that we couldn't run their file for some reason... !!! FIX !!!
1050 //how to kludge: Make a function like ResetJaguar which creates the dialog window
1051                 }
1052         }
1053         else
1054                 Window::Notify(e);
1055 }
1056
1057
1058 struct NameAction
1059 {
1060         string name;
1061         Window * (* action)(void);
1062         SDLKey hotKey;
1063
1064         NameAction(string n, Window * (* a)(void) = NULL, SDLKey k = SDLK_UNKNOWN): name(n),
1065                 action(a), hotKey(k) {}
1066 };
1067
1068
1069 class MenuItems
1070 {
1071         public:
1072                 MenuItems(): charLength(0) {}
1073                 bool Inside(uint32 x, uint32 y)
1074                 { return (x >= (uint32)extents.x && x < (uint32)(extents.x + extents.w)
1075                 && y >= (uint32)extents.y && y < (uint32)(extents.y + extents.h) ? true : false); }
1076
1077                 string title;
1078                 vector<NameAction> item;
1079                 uint32 charLength;
1080                 SDL_Rect extents;
1081 };
1082
1083 class Menu: public Element
1084 {
1085         public:
1086 // 1CFF -> 0 001 11 00  111 1 1111 
1087 // 421F -> 0 100 00 10  000 1 1111
1088                 Menu(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 8,
1089 /*                      uint16 fgc = 0x1CFF, uint16 bgc = 0x000F, uint16 fgch = 0x421F,
1090                         uint16 bgch = 0x1CFF): Element(x, y, w, h), activated(false), clicked(false),*/
1091 /*                      uint32 fgc = 0xFF3F3F00, uint32 bgc = 0x7F000000, uint32 fgch = 0xFF878700,
1092                         uint32 bgch = 0xFF3F3F00): Element(x, y, w, h), activated(false), clicked(false),*/
1093                         uint32 fgc = 0xFFFF3F3F, uint32 bgc = 0xFF7F0000, uint32 fgch = 0xFFFF8787,
1094                         uint32 bgch = 0xFFFF3F3F): Element(x, y, w, h), activated(false), clicked(false),
1095                         inside(0), insidePopup(0), fgColor(fgc), bgColor(bgc), fgColorHL(fgch),
1096                         bgColorHL(bgch), menuChosen(-1), menuItemChosen(-1) {}
1097                 virtual void HandleKey(SDLKey key);
1098                 virtual void HandleMouseMove(uint32 x, uint32 y);
1099                 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
1100                 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
1101                 virtual void Notify(Element *) {}
1102                 void Add(MenuItems mi);
1103
1104         protected:
1105                 bool activated, clicked;
1106                 uint32 inside, insidePopup;
1107 //              uint16 fgColor, bgColor, fgColorHL, bgColorHL;
1108                 uint32 fgColor, bgColor, fgColorHL, bgColorHL;
1109                 int menuChosen, menuItemChosen;
1110
1111         private:
1112                 vector<MenuItems> itemList;
1113 };
1114
1115 void Menu::HandleKey(SDLKey key)
1116 {
1117         for(uint32 i=0; i<itemList.size(); i++)
1118         {
1119                 for(uint32 j=0; j<itemList[i].item.size(); j++)
1120                 {
1121                         if (itemList[i].item[j].hotKey == key)
1122                         {
1123                                 SDL_Event event;
1124                                 event.type = SDL_USEREVENT;
1125                                 event.user.code = MENU_ITEM_CHOSEN;
1126                                 event.user.data1 = (void *)itemList[i].item[j].action;
1127                         SDL_PushEvent(&event);
1128
1129                                 clicked = false, menuChosen = menuItemChosen = -1;
1130                                 break;
1131                         }
1132                 }
1133         }
1134 }
1135
1136 void Menu::HandleMouseMove(uint32 x, uint32 y)
1137 {
1138         inside = insidePopup = 0;
1139
1140         if (Inside(x, y))
1141         {
1142                 // Find out *where* we are inside the menu bar
1143                 uint32 xpos = extents.x;
1144
1145                 for(uint32 i=0; i<itemList.size(); i++)
1146                 {
1147                         uint32 width = (itemList[i].title.length() + 2) * 8;
1148
1149                         if (x >= xpos && x < xpos + width)
1150                         {
1151                                 inside = i + 1;
1152                                 menuChosen = i;
1153                                 break;
1154                         }
1155
1156                         xpos += width;
1157                 }
1158         }
1159
1160         if (!Inside(x, y) && !clicked)
1161         {
1162                 menuChosen = -1;
1163         }
1164
1165         if (itemList[menuChosen].Inside(x, y) && clicked)
1166         {
1167                 insidePopup = ((y - itemList[menuChosen].extents.y) / 8) + 1;
1168                 menuItemChosen = insidePopup - 1;
1169         }
1170 }
1171
1172 void Menu::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
1173 {
1174         if (!clicked)
1175         {
1176                 if (mouseDown)
1177                 {
1178                         if (inside)
1179                                 clicked = true;
1180                         else
1181                                 menuChosen = -1;                                        // clicked is already false...!
1182                 }
1183         }
1184         else                                                                                    // clicked == true
1185         {
1186                 if (insidePopup && !mouseDown)                          // I.e., mouse-button-up
1187                 {
1188                         activated = true;
1189                         if (itemList[menuChosen].item[menuItemChosen].action != NULL)
1190                         {
1191 //                              itemList[menuChosen].item[menuItemChosen].action();
1192                                 SDL_Event event;
1193                                 event.type = SDL_USEREVENT;
1194                                 event.user.code = MENU_ITEM_CHOSEN;
1195                                 event.user.data1 = (void *)itemList[menuChosen].item[menuItemChosen].action;
1196                             SDL_PushEvent(&event);
1197
1198                                 clicked = false, menuChosen = menuItemChosen = -1;
1199
1200 /*                              SDL_Event event;
1201                                 while (SDL_PollEvent(&event));          // Flush the event queue...
1202                                 event.type = SDL_MOUSEMOTION;
1203                                 int mx, my;
1204                                 SDL_GetMouseState(&mx, &my);
1205                                 event.motion.x = mx, event.motion.y = my;
1206                             SDL_PushEvent(&event);                              // & update mouse position...!
1207 */                      }
1208                 }
1209
1210                 if (!inside && !insidePopup && mouseDown)
1211                         clicked = false, menuChosen = menuItemChosen = -1;
1212         }
1213 }
1214
1215 void Menu::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
1216 {
1217         uint32 xpos = extents.x + offsetX;
1218
1219         for(uint32 i=0; i<itemList.size(); i++)
1220         {
1221 //              uint16 color1 = fgColor, color2 = bgColor;
1222                 uint32 color1 = fgColor, color2 = bgColor;
1223                 if (inside == (i + 1) || (menuChosen != -1 && (uint32)menuChosen == i))
1224                         color1 = fgColorHL, color2 = bgColorHL;
1225
1226                 DrawStringOpaque(screenBuffer, xpos, extents.y + offsetY, color1, color2,
1227                         " %s ", itemList[i].title.c_str());
1228                 xpos += (itemList[i].title.length() + 2) * 8;
1229         }
1230
1231         // Draw sub menu (but only if active)
1232         if (clicked)
1233         {
1234                 uint32 ypos = extents.y + 9;
1235
1236                 for(uint32 i=0; i<itemList[menuChosen].item.size(); i++)
1237                 {
1238 //                      uint16 color1 = fgColor, color2 = bgColor;
1239                         uint32 color1 = fgColor, color2 = bgColor;
1240
1241                         if (insidePopup == i + 1)
1242                                 color1 = fgColorHL, color2 = bgColorHL, menuItemChosen = i;
1243
1244                         if (itemList[menuChosen].item[i].name.length() > 0)
1245                                 DrawStringOpaque(screenBuffer, itemList[menuChosen].extents.x, ypos,
1246                                         color1, color2, " %-*.*s ", itemList[menuChosen].charLength,
1247                                         itemList[menuChosen].charLength, itemList[menuChosen].item[i].name.c_str());
1248                         else
1249                                 DrawStringOpaque(screenBuffer, itemList[menuChosen].extents.x, ypos,
1250                                         fgColor, bgColor, "%.*s", itemList[menuChosen].charLength + 2, separator);
1251
1252                         ypos += 8;
1253                 }
1254         }
1255 }
1256
1257 void Menu::Add(MenuItems mi)
1258 {
1259         for(uint32 i=0; i<mi.item.size(); i++)
1260                 if (mi.item[i].name.length() > mi.charLength)
1261                         mi.charLength = mi.item[i].name.length();
1262
1263         // Set extents here as well...
1264         mi.extents.x = extents.x + extents.w, mi.extents.y = extents.y + 9;
1265         mi.extents.w = (mi.charLength + 2) * 8, mi.extents.h = mi.item.size() * 8;
1266
1267         itemList.push_back(mi);
1268         extents.w += (mi.title.length() + 2) * 8;
1269 }
1270
1271
1272 //Do we even *need* this?
1273 //Doesn't seem like it...
1274 /*class RootWindow: public Window
1275 {
1276         public:
1277                 RootWindow(Menu * m, Window * w = NULL): menu(m), window(w) {}
1278 //Do we even need to care about this crap?
1279 //                      { extents.x = extents.y = 0, extents.w = 320, extents.h = 240; }
1280                 virtual void HandleKey(SDLKey key) {}
1281                 virtual void HandleMouseMove(uint32 x, uint32 y) {}
1282                 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) {}
1283                 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0) {}
1284                 virtual void Notify(Element *) {}
1285
1286         private:
1287                 Menu * menu;
1288                 Window * window;
1289                 int16 * rootImage[1280 * 240 * 2];
1290 };//*/
1291
1292
1293 //
1294 // Draw text at the given x/y coordinates. Can invert text as well.
1295 //
1296 //void DrawString(int16 * screen, uint32 x, uint32 y, bool invert, const char * text, ...)
1297 void DrawString(uint32 * screen, uint32 x, uint32 y, bool invert, const char * text, ...)
1298 {
1299         char string[4096];
1300         va_list arg;
1301
1302         va_start(arg, text);
1303         vsprintf(string, text, arg);
1304         va_end(arg);
1305
1306 //      uint32 pitch = GetSDLScreenPitch() / 2;                 // Returns pitch in bytes but we need words...
1307         uint32 pitch = GetSDLScreenWidthInPixels();
1308         uint32 length = strlen(string), address = x + (y * pitch);
1309
1310         for(uint32 i=0; i<length; i++)
1311         {
1312                 uint32 fontAddr = (uint32)string[i] * 64;
1313
1314                 for(uint32 yy=0; yy<8; yy++)
1315                 {
1316                         for(uint32 xx=0; xx<8; xx++)
1317                         {
1318                                 if ((font1[fontAddr] && !invert) || (!font1[fontAddr] && invert))
1319 //                                      *(screen + address + xx + (yy * pitch)) = 0xFE00;
1320                                         *(screen + address + xx + (yy * pitch)) = 0xFF0080FF;
1321                                 fontAddr++;
1322                         }
1323                 }
1324
1325                 address += 8;
1326         }
1327 }
1328
1329 //
1330 // Draw text at the given x/y coordinates, using FG/BG colors.
1331 //
1332 //void DrawStringOpaque(int16 * screen, uint32 x, uint32 y, uint16 color1, uint16 color2, const char * text, ...)
1333 void DrawStringOpaque(uint32 * screen, uint32 x, uint32 y, uint32 color1, uint32 color2, const char * text, ...)
1334 {
1335         char string[4096];
1336         va_list arg;
1337
1338         va_start(arg, text);
1339         vsprintf(string, text, arg);
1340         va_end(arg);
1341
1342 //      uint32 pitch = GetSDLScreenPitch() / 2;                 // Returns pitch in bytes but we need words...
1343         uint32 pitch = GetSDLScreenWidthInPixels();
1344         uint32 length = strlen(string), address = x + (y * pitch);
1345
1346         for(uint32 i=0; i<length; i++)
1347         {
1348                 uint32 fontAddr = (uint32)string[i] * 64;
1349
1350                 for(uint32 yy=0; yy<8; yy++)
1351                 {
1352                         for(uint32 xx=0; xx<8; xx++)
1353                         {
1354                                 *(screen + address + xx + (yy * pitch)) = (font1[fontAddr] ? color1 : color2);
1355                                 fontAddr++;
1356                         }
1357                 }
1358
1359                 address += 8;
1360         }
1361 }
1362
1363 //
1364 // Draw text at the given x/y coordinates with transparency (0 is fully opaque, 32 is fully transparent).
1365 //
1366 //void DrawStringTrans(int16 * screen, uint32 x, uint32 y, uint16 color, uint8 trans, const char * text, ...)
1367 void DrawStringTrans(uint32 * screen, uint32 x, uint32 y, uint32 color, uint8 trans, const char * text, ...)
1368 {
1369         char string[4096];
1370         va_list arg;
1371
1372         va_start(arg, text);
1373         vsprintf(string, text, arg);
1374         va_end(arg);
1375
1376 //      uint32 pitch = GetSDLScreenPitch() / 2;                 // Returns pitch in bytes but we need words...
1377         uint32 pitch = GetSDLScreenWidthInPixels();
1378         uint32 length = strlen(string), address = x + (y * pitch);
1379
1380         for(uint32 i=0; i<length; i++)
1381         {
1382                 uint32 fontAddr = (uint32)string[i] * 64;
1383
1384                 for(uint32 yy=0; yy<8; yy++)
1385                 {
1386                         for(uint32 xx=0; xx<8; xx++)
1387                         {
1388                                 if (font1[fontAddr])
1389                                 {
1390 //                                      uint16 existingColor = *(screen + address + xx + (yy * pitch));
1391                                         uint32 existingColor = *(screen + address + xx + (yy * pitch));
1392
1393 /*                                      uint8 eRed = (existingColor >> 10) & 0x1F,
1394                                                 eGreen = (existingColor >> 5) & 0x1F,
1395                                                 eBlue = existingColor & 0x1F,
1396 //This could be done ahead of time, instead of on each pixel...
1397                                                 nRed = (color >> 10) & 0x1F,
1398                                                 nGreen = (color >> 5) & 0x1F,
1399                                                 nBlue = color & 0x1F;//*/
1400                                         uint8 eBlue = (existingColor >> 16) & 0xFF,
1401                                                 eGreen = (existingColor >> 8) & 0xFF,
1402                                                 eRed = existingColor & 0xFF,
1403 //This could be done ahead of time, instead of on each pixel...
1404                                                 nBlue = (color >> 16) & 0xFF,
1405                                                 nGreen = (color >> 8) & 0xFF,
1406                                                 nRed = color & 0xFF;
1407
1408 //This could be sped up by using a table of 5 + 5 + 5 bits (32 levels transparency -> 32768 entries)
1409 //Here we've modified it to have 33 levels of transparency (could have any # we want!)
1410 //because dividing by 32 is faster than dividing by 31...!
1411                                         uint8 invTrans = 32 - trans;
1412 /*                                      uint16 bRed = (eRed * trans + nRed * invTrans) / 32;
1413                                         uint16 bGreen = (eGreen * trans + nGreen * invTrans) / 32;
1414                                         uint16 bBlue = (eBlue * trans + nBlue * invTrans) / 32;
1415
1416                                         uint16 blendedColor = (bRed << 10) | (bGreen << 5) | bBlue;//*/
1417
1418                                         uint32 bRed = (eRed * trans + nRed * invTrans) / 32;
1419                                         uint32 bGreen = (eGreen * trans + nGreen * invTrans) / 32;
1420                                         uint32 bBlue = (eBlue * trans + nBlue * invTrans) / 32;
1421
1422                                         *(screen + address + xx + (yy * pitch)) = 0xFF000000 | (bBlue << 16) | (bGreen << 8) | bRed;
1423                                 }
1424
1425                                 fontAddr++;
1426                         }
1427                 }
1428
1429                 address += 8;
1430         }
1431 }
1432
1433 //
1434 // Draw "picture"
1435 // Uses zero as transparent color
1436 // Can also use an optional alpha channel
1437 //
1438 //void DrawTransparentBitmap(int16 * screen, uint32 x, uint32 y, uint16 * bitmap, uint8 * alpha/*=NULL*/)
1439 void DrawTransparentBitmap(uint32 * screen, uint32 x, uint32 y, uint32 * bitmap, uint8 * alpha/*=NULL*/)
1440 {
1441         uint32 width = bitmap[0], height = bitmap[1];
1442         bitmap += 2;
1443
1444 //      uint32 pitch = GetSDLScreenPitch() / 2;                 // Returns pitch in bytes but we need words...
1445         uint32 pitch = GetSDLScreenWidthInPixels();
1446         uint32 address = x + (y * pitch);
1447
1448         for(uint32 yy=0; yy<height; yy++)
1449         {
1450                 for(uint32 xx=0; xx<width; xx++)
1451                 {
1452                         if (alpha == NULL)
1453                         {
1454                                 if (*bitmap && x + xx < pitch)                  // NOTE: Still doesn't clip the Y val...
1455                                         *(screen + address + xx + (yy * pitch)) = *bitmap;
1456                         }
1457                         else
1458                         {
1459                                 uint8 trans = *alpha;
1460                                 uint32 color = *bitmap;
1461                                 uint32 existingColor = *(screen + address + xx + (yy * pitch));
1462
1463                                 uint8 eRed = existingColor & 0xFF,
1464                                         eGreen = (existingColor >> 8) & 0xFF,
1465                                         eBlue = (existingColor >> 16) & 0xFF,
1466
1467                                         nRed = color & 0xFF,
1468                                         nGreen = (color >> 8) & 0xFF,
1469                                         nBlue = (color >> 16) & 0xFF;
1470
1471                                 uint8 invTrans = 255 - trans;
1472                                 uint32 bRed = (eRed * trans + nRed * invTrans) / 255;
1473                                 uint32 bGreen = (eGreen * trans + nGreen * invTrans) / 255;
1474                                 uint32 bBlue = (eBlue * trans + nBlue * invTrans) / 255;
1475
1476                                 uint32 blendedColor = 0xFF000000 | bRed | (bGreen << 8) | (bBlue << 16);
1477
1478                                 *(screen + address + xx + (yy * pitch)) = blendedColor;
1479
1480                                 alpha++;
1481                         }
1482
1483                         bitmap++;
1484                 }
1485         }
1486 }
1487
1488
1489 //
1490 // GUI stuff--it's not crunchy, it's GUI! ;-)
1491 //
1492
1493 void InitGUI(void)
1494 {
1495         SDL_ShowCursor(SDL_DISABLE);
1496         SDL_GetMouseState(&mouseX, &mouseY);
1497 }
1498
1499 void GUIDone(void)
1500 {
1501 }
1502
1503 //
1504 // GUI main loop
1505 //
1506 //bool GUIMain(void)
1507 bool GUIMain(char * filename)
1508 {
1509 WriteLog("GUI: Inside GUIMain...\n");
1510 // Need to set things up so that it loads and runs a file if given on the command line. !!! FIX !!!
1511         extern uint32 * backbuffer;
1512 //      bool done = false;
1513         SDL_Event event;
1514         Window * mainWindow = NULL;
1515
1516         // Set up the GUI classes...
1517 //      Element::SetScreenAndPitch(backbuffer, GetSDLScreenPitch() / 2);
1518         Element::SetScreenAndPitch(backbuffer, GetSDLScreenWidthInPixels());
1519
1520         Menu mainMenu;
1521         MenuItems mi;
1522         mi.title = "Jaguar";
1523         mi.item.push_back(NameAction("Load...", LoadROM, SDLK_l));
1524         mi.item.push_back(NameAction("Reset", ResetJaguar, SDLK_r));
1525         if (CDBIOSLoaded)
1526                 mi.item.push_back(NameAction("Reset CD", ResetJaguarCD, SDLK_c));
1527         mi.item.push_back(NameAction("Run", RunEmu, SDLK_ESCAPE));
1528         mi.item.push_back(NameAction(""));
1529         mi.item.push_back(NameAction("Quit", Quit, SDLK_q));
1530         mainMenu.Add(mi);
1531         mi.title = "Settings";
1532         mi.item.clear();
1533         mi.item.push_back(NameAction("Video..."));
1534         mi.item.push_back(NameAction("Audio..."));
1535         mi.item.push_back(NameAction("Misc...", MiscOptions, SDLK_m));
1536         mainMenu.Add(mi);
1537         mi.title = "Info";
1538         mi.item.clear();
1539         mi.item.push_back(NameAction("About...", About));
1540         mainMenu.Add(mi);
1541
1542         bool showMouse = true;
1543
1544 //This is crappy!!! !!! FIX !!!
1545 //Is this even needed any more? Hmm. Maybe. Dunno.
1546 WriteLog("GUI: Resetting Jaguar...\n");
1547         jaguar_reset();
1548
1549 WriteLog("GUI: Clearing BG save...\n");
1550         // Set up our background save...
1551 //      memset(background, 0x11, tom_getVideoModeWidth() * 240 * 2);
1552 //1111 -> 000100 01000 10001 -> 0001 0000 0100 0010 1000 1100 -> 10 42 8C
1553         for(uint32 i=0; i<tom_getVideoModeWidth()*240; i++)
1554                 background[i] = 0xFF8C4210;
1555
1556         // Handle loading file passed in on the command line...! [DONE]
1557
1558         if (filename)
1559         {
1560                 if (JaguarLoadFile(filename))
1561                 {
1562 //                      event.type = SDL_USEREVENT, event.user.code = MENU_ITEM_CHOSEN;
1563 //                      event.user.data1 = (void *)ResetJaguar;
1564 //              SDL_PushEvent(&event);
1565                         // Make it so that if passed in on the command line, we quit right
1566                         // away when pressing ESC
1567 WriteLog("GUI: Bypassing GUI since ROM passed in on command line...\n");
1568                         ResetJaguar();
1569                         return true;
1570                 }
1571                 else
1572                 {
1573                         // Create error dialog...
1574                         char errText[1024];
1575                         sprintf(errText, "The file %40s could not be loaded.", filename);
1576
1577                         mainWindow = new Window(8, 16, 304, 160);
1578                         mainWindow->AddElement(new Text(8, 8, "Error!"));
1579                         mainWindow->AddElement(new Text(8, 24, errText));
1580                 }
1581         }
1582
1583 WriteLog("GUI: Entering main loop...\n");
1584         while (!exitGUI)
1585         {
1586                 if (SDL_PollEvent(&event))
1587                 {
1588                         if (event.type == SDL_USEREVENT)
1589                         {
1590                                 if (event.user.code == WINDOW_CLOSE)
1591                                 {
1592                                         delete mainWindow;
1593                                         mainWindow = NULL;
1594                                 }
1595                                 else if (event.user.code == MENU_ITEM_CHOSEN)
1596                                 {
1597                                         // Confused? Let me enlighten... What we're doing here is casting
1598                                         // data1 as a pointer to a function which returns a Window pointer and
1599                                         // which takes no parameters (the "(Window *(*)(void))" part), then
1600                                         // derefencing it (the "*" in front of that) in order to call the
1601                                         // function that it points to. Clear as mud? Yeah, I hate function
1602                                         // pointers too, but what else are you gonna do?
1603                                         mainWindow = (*(Window *(*)(void))event.user.data1)();
1604
1605                                         while (SDL_PollEvent(&event));  // Flush the event queue...
1606                                         event.type = SDL_MOUSEMOTION;
1607                                         int mx, my;
1608                                         SDL_GetMouseState(&mx, &my);
1609                                         event.motion.x = mx, event.motion.y = my;
1610                                     SDL_PushEvent(&event);                      // & update mouse position...!
1611
1612                                         mouseX = mx, mouseY = my;               // This prevents "mouse flash"...
1613                                         if (vjs.useOpenGL)
1614                                                 mouseX /= 2, mouseY /= 2;
1615                                 }
1616                         }
1617                         else if (event.type == SDL_ACTIVEEVENT)
1618                         {
1619                                 if (event.active.state == SDL_APPMOUSEFOCUS)
1620                                         showMouse = (event.active.gain ? true : false);
1621                         }
1622                         else if (event.type == SDL_KEYDOWN)
1623                         {
1624                                 if (mainWindow)
1625                                         mainWindow->HandleKey(event.key.keysym.sym);
1626                                 else
1627                                         mainMenu.HandleKey(event.key.keysym.sym);
1628                         }
1629                         else if (event.type == SDL_MOUSEMOTION)
1630                         {
1631                                 mouseX = event.motion.x, mouseY = event.motion.y;
1632
1633                                 if (vjs.useOpenGL)
1634                                         mouseX /= 2, mouseY /= 2;
1635
1636                                 if (mainWindow)
1637                                         mainWindow->HandleMouseMove(mouseX, mouseY);
1638                                 else
1639                                         mainMenu.HandleMouseMove(mouseX, mouseY);
1640                         }
1641                         else if (event.type == SDL_MOUSEBUTTONDOWN)
1642                         {
1643                                 uint32 mx = event.button.x, my = event.button.y;
1644
1645                                 if (vjs.useOpenGL)
1646                                         mx /= 2, my /= 2;
1647
1648                                 if (mainWindow)
1649                                         mainWindow->HandleMouseButton(mx, my, true);
1650                                 else
1651                                         mainMenu.HandleMouseButton(mx, my, true);
1652                         }
1653                         else if (event.type == SDL_MOUSEBUTTONUP)
1654                         {
1655                                 uint32 mx = event.button.x, my = event.button.y;
1656
1657                                 if (vjs.useOpenGL)
1658                                         mx /= 2, my /= 2;
1659
1660                                 if (mainWindow)
1661                                         mainWindow->HandleMouseButton(mx, my, false);
1662                                 else
1663                                         mainMenu.HandleMouseButton(mx, my, false);
1664                         }
1665
1666                         // Draw the GUI...
1667 // The way we do things here is kinda stupid (redrawing the screen every frame), but
1668 // it's simple. Perhaps there may be a reason down the road to be more selective with
1669 // our clearing, but for now, this will suffice.
1670 //                      memset(backbuffer, 0x11, tom_getVideoModeWidth() * 240 * 2);
1671 //                      memcpy(backbuffer, background, tom_getVideoModeWidth() * 256 * 2);
1672                         memcpy(backbuffer, background, tom_getVideoModeWidth() * 256 * 4);
1673
1674                         mainMenu.Draw();
1675 //Could do multiple windows here by using a vector + priority info...
1676 //Though the way ZSNES does it seems to be by a bool (i.e., they're always active, just not shown)
1677                         if (mainWindow)
1678                                 mainWindow->Draw();
1679
1680                         if (showMouse)
1681 //                              DrawTransparentBitmap(backbuffer, mouseX, mouseY, mousePic);
1682                                 DrawTransparentBitmap(backbuffer, mouseX, mouseY, mousePic);
1683
1684                         RenderBackbuffer();
1685                 }
1686         }
1687
1688         return true;
1689 }
1690
1691 //
1692 // GUI "action" functions
1693 //
1694
1695 Window * LoadROM(void)
1696 {
1697         FileList * fileList = new FileList(8, 16, 304, 216);
1698
1699         return (Window *)fileList;
1700 }
1701
1702 Window * ResetJaguar(void)
1703 {
1704         jaguar_reset();
1705
1706         return RunEmu();
1707 }
1708
1709 Window * ResetJaguarCD(void)
1710 {
1711         memcpy(jaguar_mainRom, jaguar_CDBootROM, 0x40000);
1712         jaguarRunAddress = 0x802000;
1713         jaguar_mainRom_crc32 = crc32_calcCheckSum(jaguar_mainRom, 0x40000);
1714         jaguar_reset();
1715 //This is a quick kludge to get the CDBIOS to boot properly...
1716 //Wild speculation: It could be that this memory location is wired into the CD unit
1717 //somehow, which lets it know whether or not a cart is present in the unit...
1718         jaguar_mainRom[0x0040B] = 0x03;
1719
1720         return RunEmu();
1721 }
1722
1723 bool debounceRunKey = true;
1724 Window * RunEmu(void)
1725 {
1726 //This is crappy... !!! FIX !!!
1727         extern uint32 * backbuffer;
1728         extern bool finished, showGUI;
1729
1730         uint32 nFrame = 0, nFrameskip = 0;
1731         uint32 totalFrames = 0;
1732         finished = false;
1733         bool showMessage = true;
1734         uint32 showMsgFrames = 120;
1735         uint8 transparency = 0;
1736         // Pass a message to the "joystick" code to debounce the ESC key...
1737         debounceRunKey = true;
1738
1739         uint32 cartType = 4;
1740         if (jaguarRomSize == 0x200000)
1741                 cartType = 0;
1742         else if (jaguarRomSize == 0x400000)
1743                 cartType = 1;
1744         else if (jaguar_mainRom_crc32 == 0x687068D5)
1745                 cartType = 2;
1746         else if (jaguar_mainRom_crc32 == 0x55A0669C)
1747                 cartType = 3;
1748
1749         char * cartTypeName[5] = { "2M Cartridge", "4M Cartridge", "CD BIOS", "CD Dev BIOS", "Homebrew" };
1750
1751 //      while (!finished)
1752         while (true)
1753         {
1754                 // Set up new backbuffer with new pixels and data
1755                 JaguarExecute(backbuffer, true);
1756                 totalFrames++;
1757 //WriteLog("Frame #%u...\n", totalFrames);
1758 //extern bool doDSPDis;
1759 //if (totalFrames == 373)
1760 //      doDSPDis = true;
1761
1762 //This sucks... !!! FIX !!!
1763                 joystick_exec();
1764 //This is done here so that the crud below doesn't get on our GUI background...
1765                 if (finished)
1766                         break;
1767
1768                 // Some QnD GUI stuff here...
1769                 if (showGUI)
1770                 {
1771                         extern uint32 gpu_pc, dsp_pc;
1772                         DrawString((uint32 *)backbuffer, 8, 8, false, "GPU PC: %08X", gpu_pc);
1773                         DrawString((uint32 *)backbuffer, 8, 16, false, "DSP PC: %08X", dsp_pc);
1774                 }
1775
1776                 if (showMessage)
1777                 {
1778 // FF0F -> 1111 11 11  000 0 1111 -> 3F 18 0F
1779 // 3FE3 -> 0011 11 11  111 0 0011 -> 0F 3F 03
1780 /*                      DrawStringTrans((uint32 *)backbuffer, 8, 24*8, 0xFF0F, transparency, "Running...");
1781                         DrawStringTrans((uint32 *)backbuffer, 8, 26*8, 0x3FE3, transparency, "%s, run address: %06X", cartTypeName[cartType], jaguarRunAddress);
1782                         DrawStringTrans((uint32 *)backbuffer, 8, 27*8, 0x3FE3, transparency, "CRC: %08X", jaguar_mainRom_crc32);//*/
1783 //first has wrong color. !!! FIX !!!
1784                         DrawStringTrans((uint32 *)backbuffer, 8, 24*8, 0xFF7F63FF, transparency, "Running...");
1785                         DrawStringTrans((uint32 *)backbuffer, 8, 26*8, 0xFF1FFF3F, transparency, "%s, run address: %06X", cartTypeName[cartType], jaguarRunAddress);
1786                         DrawStringTrans((uint32 *)backbuffer, 8, 27*8, 0xFF1FFF3F, transparency, "CRC: %08X", jaguar_mainRom_crc32);
1787
1788                         if (showMsgFrames == 0)
1789                         {                       
1790                                 transparency++;
1791
1792                                 if (transparency == 33)
1793 {
1794                                         showMessage = false;
1795 /*extern bool doGPUDis;
1796 doGPUDis = true;//*/
1797 }
1798
1799                         }
1800                         else
1801                                 showMsgFrames--;
1802                 }
1803
1804                 // Simple frameskip
1805                 if (nFrame == nFrameskip)
1806                 {
1807                         RenderBackbuffer();
1808                         nFrame = 0;
1809                 }
1810                 else
1811                         nFrame++;
1812         }
1813
1814         // Reset the pitch, since it may have been changed in-game...
1815 //      Element::SetScreenAndPitch(backbuffer, GetSDLScreenPitch() / 2);
1816         Element::SetScreenAndPitch((uint32 *)backbuffer, GetSDLScreenWidthInPixels());
1817
1818         // Save the background for the GUI...
1819 //      memcpy(background, backbuffer, tom_getVideoModeWidth() * 240 * 2);
1820         // In this case, we squash the color to monochrome, then force it to blue + green...
1821         for(uint32 i=0; i<tom_getVideoModeWidth() * 256; i++)
1822         {
1823 //              uint32 word = backbuffer[i];
1824 //              uint8 r = (word >> 10) & 0x1F, g = (word >> 5) & 0x1F, b = word & 0x1F;
1825 //              word = ((r + g + b) / 3) & 0x001F;
1826 //              word = (word << 5) | word;
1827 //              background[i] = word;
1828
1829                 uint32 pixel = backbuffer[i];
1830                 uint8 b = (pixel >> 16) & 0xFF, g = (pixel >> 8) & 0xFF, r = pixel & 0xFF;
1831                 pixel = ((r + g + b) / 3) & 0x00FF;
1832                 background[i] = 0xFF000000 | (pixel << 16) | (pixel << 8);
1833         }
1834
1835         return NULL;
1836 }
1837
1838 Window * Quit(void)
1839 {
1840         WriteLog("GUI: Quitting due to user request.\n");
1841         exitGUI = true;
1842
1843         return NULL;
1844 }
1845
1846 Window * About(void)
1847 {
1848         Window * window = new Window(8, 16, 304, 160);
1849 //      window->AddElement(new Text(8, 8, "Virtual Jaguar 1.0.8"));
1850         window->AddElement(new Text(8, 8, "Virtual Jaguar CVS 20041224"));
1851         window->AddElement(new Text(8, 24, "Coders:"));
1852         window->AddElement(new Text(16, 32, "Niels Wagenaar (nwagenaar)"));
1853         window->AddElement(new Text(16, 40, "Carwin Jones (Caz)"));
1854         window->AddElement(new Text(16, 48, "James L. Hammons (shamus)"));
1855         window->AddElement(new Text(16, 56, "Adam Green"));
1856         window->AddElement(new Text(8, 72, "Testers:"));
1857         window->AddElement(new Text(16, 80, "Guruma"));
1858         window->AddElement(new Text(8, 96, "Thanks go out to:"));
1859         window->AddElement(new Text(16, 104, "Aaron Giles (original CoJag)"));
1860         window->AddElement(new Text(16, 112, "David Raingeard (original VJ)"));
1861         window->AddElement(new Text(16, 120, "Karl Stenerud (Musashi 68K emu)"));
1862         window->AddElement(new Text(16, 128, "Sam Lantinga (amazing SDL libs)"));
1863         window->AddElement(new Text(16, 136, "Ryan C. Gordon (VJ's web presence)"));
1864         window->AddElement(new Text(16, 144, "The guys over at Atari Age ;-)"));
1865
1866         return window;
1867 }
1868
1869 Window * MiscOptions(void)
1870 {
1871         Window * window = new Window(8, 16, 304, 160);
1872         window->AddElement(new PushButton(8, 8, &vjs.useJaguarBIOS, "BIOS"));
1873         window->AddElement(new SlideSwitch(8, 20, &vjs.hardwareTypeNTSC, "PAL", "NTSC"));
1874         window->AddElement(new PushButton(8, 40, &vjs.DSPEnabled, "DSP"));
1875         window->AddElement(new SlideSwitch(16, 52, &vjs.usePipelinedDSP, "Original", "Pipelined"));
1876         window->AddElement(new SlideSwitch(8, 72, (bool *)&vjs.glFilter, "Sharp", "Blurry"));
1877
1878 // Missing:
1879 // * BIOS path
1880 // * ROM path
1881 // * EEPROM path
1882 // * joystick
1883 // * joystick port
1884 // * OpenGL?
1885 // * GL Filter type
1886 // * Window/fullscreen
1887
1888         return window;
1889 }
1890
1891
1892 //
1893 // Generic ROM loading
1894 //
1895 uint32 JaguarLoadROM(uint8 * rom, char * path)
1896 {
1897 // We really should have some kind of sanity checking for the ROM size here to prevent
1898 // a buffer overflow... !!! FIX !!!
1899         uint32 romSize = 0;
1900
1901         char * ext = strrchr(path, '.');
1902         if (ext != NULL)
1903         {
1904                 WriteLog("VJ: Loading \"%s\"...", path);
1905
1906                 if (strcasecmp(ext, ".zip") == 0)
1907                 {
1908                         // Handle ZIP file loading here...
1909                         WriteLog("(ZIPped)...");
1910
1911                         if (load_zipped_file(0, 0, path, NULL, &rom, &romSize) == -1)
1912                         {
1913                                 WriteLog("Failed!\n");
1914                                 return 0;
1915                         }
1916                 }
1917                 else
1918                 {
1919 /*                      FILE * fp = fopen(path, "rb");
1920
1921                         if (fp == NULL)
1922                         {
1923                                 WriteLog("Failed!\n");
1924                                 return 0;
1925                         }
1926
1927                         fseek(fp, 0, SEEK_END);
1928                         romSize = ftell(fp);
1929                         fseek(fp, 0, SEEK_SET);
1930                         fread(rom, 1, romSize, fp);
1931                         fclose(fp);*/
1932
1933                         // Handle gzipped files transparently [Adam Green]...
1934
1935                         gzFile fp = gzopen(path, "rb");
1936
1937                         if (fp == NULL)
1938                         {
1939                                 WriteLog("Failed!\n");
1940                                 return 0;
1941                         }
1942
1943                         romSize = gzfilelength(fp);
1944                         gzseek(fp, 0, SEEK_SET);
1945                         gzread(fp, rom, romSize);
1946                         gzclose(fp);
1947                 }
1948
1949                 WriteLog("OK (%i bytes)\n", romSize);
1950         }
1951
1952         return romSize;
1953 }
1954
1955 //
1956 // Jaguar file loading
1957 //
1958 bool JaguarLoadFile(char * path)
1959 {
1960 //      jaguarRomSize = JaguarLoadROM(mem, path);
1961         jaguarRomSize = JaguarLoadROM(jaguar_mainRom, path);
1962
1963 /*//This is not *nix friendly for some reason...
1964 //              if (!UserSelectFile(path, newPath))
1965         if (!UserSelectFile((strlen(path) == 0 ? (char *)"." : path), newPath))
1966         {
1967                 WriteLog("VJ: Could not find valid ROM in directory \"%s\"...\nAborting!\n", path);
1968                 log_done();
1969                 exit(0);
1970         }*/
1971
1972         if (jaguarRomSize == 0)
1973         {
1974 //                      WriteLog("VJ: Could not load ROM from file \"%s\"...\nAborting!\n", newPath);
1975                 WriteLog("GUI: Could not load ROM from file \"%s\"...\nAborting load!\n", path);
1976 // Need to do something else here, like throw up an error dialog instead of aborting. !!! FIX !!!
1977 //              log_done();
1978 //              exit(0);
1979                 return false;                                                           // This is a start...
1980         }
1981
1982         jaguar_mainRom_crc32 = crc32_calcCheckSum(jaguar_mainRom, jaguarRomSize);
1983         WriteLog("CRC: %08X\n", (unsigned int)jaguar_mainRom_crc32);
1984         eeprom_init();
1985
1986         jaguarRunAddress = 0x802000;
1987
1988         char * ext = strrchr(path, '.');                                // Get the file's extension for non-cartridge checking
1989
1990 //NOTE: Should fix JaguarLoadROM() to replace .zip with what's *in* the zip (.abs, .j64, etc.)
1991         if (strcasecmp(ext, ".rom") == 0)
1992         {
1993                 // File extension ".ROM": Alpine image that loads/runs at $802000
1994                 WriteLog("GUI: Setting up homebrew (ROM)... Run address: 00802000, length: %08X\n", jaguarRomSize);
1995
1996                 for(int i=jaguarRomSize-1; i>=0; i--)
1997                         jaguar_mainRom[0x2000 + i] = jaguar_mainRom[i];
1998
1999                 memset(jaguar_mainRom, 0xFF, 0x2000);
2000 /*              memcpy(jaguar_mainRam, jaguar_mainRom, jaguarRomSize);
2001                 memset(jaguar_mainRom, 0xFF, 0x600000);
2002                 memcpy(jaguar_mainRom + 0x2000, jaguar_mainRam, jaguarRomSize);
2003                 memset(jaguar_mainRam, 0x00, 0x400000);*/
2004
2005 /*
2006 Stubulator ROM vectors...
2007 handler 001 at $00E00008
2008 handler 002 at $00E008DE
2009 handler 003 at $00E008E2
2010 handler 004 at $00E008E6
2011 handler 005 at $00E008EA
2012 handler 006 at $00E008EE
2013 handler 007 at $00E008F2
2014 handler 008 at $00E0054A
2015 handler 009 at $00E008FA
2016 handler 010 at $00000000
2017 handler 011 at $00000000
2018 handler 012 at $00E008FE
2019 handler 013 at $00E00902
2020 handler 014 at $00E00906
2021 handler 015 at $00E0090A
2022 handler 016 at $00E0090E
2023 handler 017 at $00E00912
2024 handler 018 at $00E00916
2025 handler 019 at $00E0091A
2026 handler 020 at $00E0091E
2027 handler 021 at $00E00922
2028 handler 022 at $00E00926
2029 handler 023 at $00E0092A
2030 handler 024 at $00E0092E
2031 handler 025 at $00E0107A
2032 handler 026 at $00E0107A
2033 handler 027 at $00E0107A
2034 handler 028 at $00E008DA
2035 handler 029 at $00E0107A
2036 handler 030 at $00E0107A
2037 handler 031 at $00E0107A
2038 handler 032 at $00000000
2039
2040 Let's try setting up the illegal instruction vector for a stubulated jaguar...
2041 */
2042 /*              SET32(jaguar_mainRam, 0x08, 0x00E008DE);
2043                 SET32(jaguar_mainRam, 0x0C, 0x00E008E2);
2044                 SET32(jaguar_mainRam, 0x10, 0x00E008E6);        // <-- Should be here (it is)...
2045                 SET32(jaguar_mainRam, 0x14, 0x00E008EA);//*/
2046
2047                 // Try setting the vector to say, $1000 and putting an instruction there that loops forever:
2048                 // This kludge works! Yeah!
2049                 SET32(jaguar_mainRam, 0x10, 0x00001000);
2050                 SET16(jaguar_mainRam, 0x1000, 0x60FE);          // Here: bra Here
2051         }
2052         else if (strcasecmp(ext, ".abs") == 0)
2053         {
2054                 // File extension ".ABS": Atari linker output file with header (w/o is useless to us here)
2055
2056 /*
2057 ABS Format sleuthing (LBUGDEMO.ABS):
2058
2059 000000  60 1B 00 00 05 0C 00 04 62 C0 00 00 04 28 00 00
2060 000010  12 A6 00 00 00 00 00 80 20 00 FF FF 00 80 25 0C
2061 000020  00 00 40 00
2062
2063 DRI-format file detected...
2064 Text segment size = 0x0000050c bytes
2065 Data segment size = 0x000462c0 bytes
2066 BSS Segment size = 0x00000428 bytes
2067 Symbol Table size = 0x000012a6 bytes
2068 Absolute Address for text segment = 0x00802000
2069 Absolute Address for data segment = 0x0080250c
2070 Absolute Address for BSS segment = 0x00004000
2071
2072 (CRZDEMO.ABS):
2073 000000  01 50 00 03 00 00 00 00 00 03 83 10 00 00 05 3b
2074 000010  00 1c 00 03 00 00 01 07 00 00 1d d0 00 03 64 98
2075 000020  00 06 8b 80 00 80 20 00 00 80 20 00 00 80 3d d0
2076
2077 000030  2e 74 78 74 00 00 00 00 00 80 20 00 00 80 20 00 .txt (+36 bytes)
2078 000040  00 00 1d d0 00 00 00 a8 00 00 00 00 00 00 00 00
2079 000050  00 00 00 00 00 00 00 20
2080 000058  2e 64 74 61 00 00 00 00 00 80 3d d0 00 80 3d d0 .dta (+36 bytes)
2081 000068  00 03 64 98 00 00 1e 78 00 00 00 00 00 00 00 00
2082 000078  00 00 00 00 00 00 00 40
2083 000080  2e 62 73 73 00 00 00 00 00 00 50 00 00 00 50 00 .bss (+36 bytes)
2084 000090  00 06 8b 80 00 03 83 10 00 00 00 00 00 00 00 00
2085 0000a0  00 00 00 00 00 00 00 80
2086
2087 Header size is $A8 bytes...
2088
2089 BSD/COFF format file detected...
2090 3 sections specified
2091 Symbol Table offset = 230160                            ($00038310)
2092 Symbol Table contains 1339 symbol entries       ($0000053B)
2093 The additional header size is 28 bytes          ($001C)
2094 Magic Number for RUN_HDR = 0x00000107
2095 Text Segment Size = 7632                                        ($00001DD0)
2096 Data Segment Size = 222360                                      ($00036498)
2097 BSS Segment Size = 428928                                       ($00068B80)
2098 Starting Address for executable = 0x00802000
2099 Start of Text Segment = 0x00802000
2100 Start of Data Segment = 0x00803dd0
2101 */
2102                 if (jaguar_mainRom[0] == 0x60 && jaguar_mainRom[1] == 0x1B)
2103                 {
2104                         uint32 loadAddress = GET32(jaguar_mainRom, 0x16), //runAddress = GET32(jaguar_mainRom, 0x2A),
2105                                 codeSize = GET32(jaguar_mainRom, 0x02) + GET32(jaguar_mainRom, 0x06);
2106                         WriteLog("GUI: Setting up homebrew (ABS-1)... Run address: %08X, length: %08X\n", loadAddress, codeSize);
2107
2108                         if (loadAddress < 0x800000)
2109                                 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x24, codeSize);
2110                         else
2111                         {
2112                                 for(int i=codeSize-1; i>=0; i--)
2113                                         jaguar_mainRom[(loadAddress - 0x800000) + i] = jaguar_mainRom[i + 0x24];
2114 /*                              memcpy(jaguar_mainRam, jaguar_mainRom + 0x24, codeSize);
2115                                 memset(jaguar_mainRom, 0xFF, 0x600000);
2116                                 memcpy(jaguar_mainRom + (loadAddress - 0x800000), jaguar_mainRam, codeSize);
2117                                 memset(jaguar_mainRam, 0x00, 0x400000);*/
2118                         }
2119
2120                         jaguarRunAddress = loadAddress;
2121                 }
2122                 else if (jaguar_mainRom[0] == 0x01 && jaguar_mainRom[1] == 0x50)
2123                 {
2124                         uint32 loadAddress = GET32(jaguar_mainRom, 0x28), runAddress = GET32(jaguar_mainRom, 0x24),
2125                                 codeSize = GET32(jaguar_mainRom, 0x18) + GET32(jaguar_mainRom, 0x1C);
2126                         WriteLog("GUI: Setting up homebrew (ABS-2)... Run address: %08X, length: %08X\n", runAddress, codeSize);
2127
2128                         if (loadAddress < 0x800000)
2129                                 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0xA8, codeSize);
2130                         else
2131                         {
2132                                 for(int i=codeSize-1; i>=0; i--)
2133                                         jaguar_mainRom[(loadAddress - 0x800000) + i] = jaguar_mainRom[i + 0xA8];
2134 /*                              memcpy(jaguar_mainRam, jaguar_mainRom + 0xA8, codeSize);
2135                                 memset(jaguar_mainRom, 0xFF, 0x600000);
2136                                 memcpy(jaguar_mainRom + (loadAddress - 0x800000), jaguar_mainRam, codeSize);
2137                                 memset(jaguar_mainRam, 0x00, 0x400000);*/
2138                         }
2139
2140                         jaguarRunAddress = runAddress;
2141                 }
2142                 else
2143                 {
2144                         WriteLog("GUI: Couldn't find correct ABS format: %02X %02X\n", jaguar_mainRom[0], jaguar_mainRom[1]);
2145                         return false;
2146                 }
2147         }
2148         else if (strcasecmp(ext, ".jag") == 0)
2149         {
2150                 // File extension ".JAG": Atari server file with header
2151 //NOTE: The bytes 'JAGR' should also be at position $1C...
2152 //      Also, there's *always* a $601A header at position $00...
2153                 if (jaguar_mainRom[0] == 0x60 && jaguar_mainRom[1] == 0x1A)
2154                 {
2155                         uint32 loadAddress = GET32(jaguar_mainRom, 0x22), runAddress = GET32(jaguar_mainRom, 0x2A);
2156 //This is not always right! Especially when converted via bin2jag1!!!
2157 //We should have access to the length of the furshlumiger file that was loaded anyway!
2158 //Now, we do! ;-)
2159 //                      uint32 progLength = GET32(jaguar_mainRom, 0x02);
2160 //jaguarRomSize
2161 //jaguarRunAddress
2162 //                      WriteLog("Jaguar: Setting up PD ROM... Run address: %08X, length: %08X\n", runAddress, progLength);
2163 //                      memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, progLength);
2164                         WriteLog("GUI: Setting up homebrew (JAG)... Run address: %08X, length: %08X\n", runAddress, jaguarRomSize - 0x2E);
2165                         memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, jaguarRomSize - 0x2E);
2166 //              SET32(jaguar_mainRam, 4, runAddress);
2167                         jaguarRunAddress = runAddress;
2168                 }
2169                 else
2170                         return false;
2171         }
2172         // .J64 (Jaguar cartridge ROM image) is implied by the FileList object...
2173
2174         return true;
2175 }
2176
2177 //
2178 // Get the length of a (possibly) gzipped file
2179 //
2180 int gzfilelength(gzFile gd)
2181 {
2182    int size = 0, length = 0;
2183    unsigned char buffer[0x10000];
2184
2185    gzrewind(gd);
2186
2187    do
2188    {
2189       // Read in chunks until EOF
2190       size = gzread(gd, buffer, 0x10000);
2191
2192       if (size <= 0)
2193         break;
2194
2195       length += size;
2196    }
2197    while (!gzeof(gd));
2198
2199    gzrewind(gd);
2200    return length;
2201 }