4 // Graphical User Interface support
23 using namespace std; // For STL stuff
25 // Private function prototypes
27 class Window; // Forward declaration...
29 void DrawTransparentBitmap(int16 * screen, uint32 x, uint32 y, uint16 * bitmap);
30 void DrawStringTrans(int16 * screen, uint32 x, uint32 y, uint16 color, uint8 opacity, const char * text, ...);
31 void DrawStringOpaque(int16 * screen, uint32 x, uint32 y, uint16 color1, uint16 color2, const char * text, ...);
32 Window * LoadROM(void);
33 Window * ResetJaguar(void);
34 Window * RunEmu(void);
37 Window * MiscOptions(void);
39 int gzfilelength(gzFile gd);
43 extern uint8 * jaguar_mainRam;
44 extern uint8 * jaguar_bootRom;
45 extern uint8 * jaguar_mainRom;
47 // Local global variables
54 0x03E0,0x0000,0x0000,0x0000,0x0000,0x0000, // +
55 0x0300,0x03E0,0x0000,0x0000,0x0000,0x0000, // @+
56 0x0300,0x03E0,0x03E0,0x0000,0x0000,0x0000, // @++
57 0x0300,0x0300,0x03E0,0x03E0,0x0000,0x0000, // @@++
58 0x0300,0x0300,0x03E0,0x03E0,0x03E0,0x0000, // @@+++
59 0x0300,0x0300,0x0300,0x03E0,0x03E0,0x03E0, // @@@+++
60 0x0300,0x0300,0x0300,0x0000,0x0000,0x0000, // @@@
61 0x0300,0x0000,0x0000,0x0000,0x0000,0x0000 // @
63 0xFFFF,0x0000,0x0000,0x0000,0x0000,0x0000, // +
64 0xE318,0xFFFF,0x0000,0x0000,0x0000,0x0000, // @+
65 0xE318,0xFFFF,0xFFFF,0x0000,0x0000,0x0000, // @++
66 0xE318,0xE318,0xFFFF,0xFFFF,0x0000,0x0000, // @@++
67 0xE318,0xE318,0xFFFF,0xFFFF,0xFFFF,0x0000, // @@+++
68 0xE318,0xE318,0xE318,0xFFFF,0xFFFF,0xFFFF, // @@@+++
69 0xE318,0xE318,0xE318,0x0000,0x0000,0x0000, // @@@
70 0xE318,0x0000,0x0000,0x0000,0x0000,0x0000 // @
73 // 1 111 00 11 100 1 1100 -> F39C
74 // 1 100 00 10 000 1 0000 -> C210
75 // 1 110 00 11 000 1 1000 -> E318
76 // 0 000 00 11 111 0 0000 -> 03E0
77 // 0 000 00 11 000 0 0000 -> 0300
82 0x0000,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x0000, // +++++
83 0x4B5E,0xFFFF,0x0000,0x0000,0x0000,0xFFFF,0x0217, // +@ @.
84 0x4B5E,0x0000,0xFFFF,0x0000,0xFFFF,0x0000,0x0217, // + @ @ .
85 0x4B5E,0x0000,0x0000,0xFFFF,0x0000,0x0000,0x0217, // + @ .
86 0x4B5E,0x0000,0xFFFF,0x0000,0xFFFF,0x0000,0x0217, // + @ @ .
87 0x4B5E,0xFFFF,0x0000,0x0000,0x0000,0xFFFF,0x0217, // +@ @.
88 0x0000,0x0217,0x0217,0x0217,0x0217,0x0217,0x0000 // .....
91 uint16 upArrowBox[] = {
94 0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E, // ++++++++
95 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
96 0x4B5E,0x0000,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x0000,0x0217, // + @@@@ .
97 0x4B5E,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x0217, // +@@@@@@.
98 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
99 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
100 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
101 0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217 // ........
104 uint16 downArrowBox[] = {
107 0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E, // ++++++++
108 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
109 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
110 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
111 0x4B5E,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x0217, // +@@@@@@.
112 0x4B5E,0x0000,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x0000,0x0217, // + @@@@ .
113 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
114 0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217 // ........
117 uint16 pushButtonUp[] = {
120 0x0000,0x0000,0x0000,0x000A,0x000A,0x0000,0x0000,0x0000, // ...##...
121 0x0000,0x000A,0x000A,0x000A,0x000A,0x000A,0x000A,0x0000, // .######.
122 0x0000,0x000A,0x000A,0x000A,0x000A,0x000A,0x000A,0x0000, // .######.
123 0x000A,0x000A,0x000A,0x000A,0x000A,0x000A,0x000A,0x000A, // ########
124 0x000A,0x000A,0x000A,0x000A,0x000A,0x000A,0x000A,0x000A, // ########
125 0x0000,0x000A,0x000A,0x000A,0x000A,0x000A,0x000A,0x0000, // .######.
126 0x0000,0x000A,0x000A,0x000A,0x000A,0x000A,0x000A,0x0000, // .######.
127 0x0000,0x0000,0x0000,0x000A,0x000A,0x0000,0x0000,0x0000 // ...##...
130 uint16 pushButtonDown[] = {
133 0x0000,0x0000,0x0000,0x000A,0x000A,0x0000,0x0000,0x0000, // ...@@...
134 0x0000,0x000A,0x000A,0x0C7F,0x0C7F,0x000A,0x000A,0x0000, // .@@##@@.
135 0x0000,0x000A,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x000A,0x0000, // .@####@.
136 0x000A,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x000A, // @######@
137 0x000A,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x000A, // @######@
138 0x0000,0x000A,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x000A,0x0000, // .@####@.
139 0x0000,0x000A,0x000A,0x0C7F,0x0C7F,0x000A,0x000A,0x0000, // .@@##@@.
140 0x0000,0x0000,0x0000,0x000A,0x000A,0x0000,0x0000,0x0000 // ...@@...
143 uint16 slideSwitchUp[] = {
146 0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E, // ++++++++
147 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
148 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
149 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
150 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
151 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
152 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
153 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
154 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
155 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
156 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
157 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
158 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
159 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
160 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
161 0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217 // ........
164 uint16 slideSwitchDown[] = {
167 0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E, // ++++++++
168 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
169 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
170 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
171 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
172 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
173 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
174 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
175 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
176 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
177 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
178 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
179 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
180 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
181 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
182 0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217 // ........
188 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
189 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
190 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
191 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
192 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
193 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
194 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
195 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 // ........
198 char separator[] = "--------------------------------------------------------";
200 uint16 background[1280 * 240];
206 enum { WINDOW_CLOSE, MENU_ITEM_CHOSEN };
211 Element(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0)
212 { extents.x = x, extents.y = y, extents.w = w, extents.h = h; }
213 virtual void HandleKey(SDLKey key) = 0;
214 virtual void HandleMouseMove(uint32 x, uint32 y) = 0;
215 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) = 0;
216 virtual void Draw(uint32, uint32) = 0;
217 virtual void Notify(Element *) = 0;
218 //Needed? virtual ~Element() = 0;
219 //We're not allocating anything in the base class, so the answer would be NO.
220 bool Inside(uint32 x, uint32 y);
222 static void SetScreenAndPitch(int16 * s, uint32 p) { screenBuffer = s, pitch = p; }
227 // Class variables...
228 static int16 * screenBuffer;
232 int16 * Element::screenBuffer = NULL;
233 uint32 Element::pitch = 0;
235 bool Element::Inside(uint32 x, uint32 y)
237 return (x >= (uint32)extents.x && x < (uint32)(extents.x + extents.w)
238 && y >= (uint32)extents.y && y < (uint32)(extents.y + extents.h) ? true : false);
242 class Button: public Element
245 Button(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
246 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
247 bgColor(0x03E0), pic(NULL), elementToTell(NULL) {}
248 Button(uint32 x, uint32 y, uint32 w, uint32 h, uint16 * p): Element(x, y, w, h),
249 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
250 bgColor(0x03E0), pic(p), elementToTell(NULL) {}
251 Button(uint32 x, uint32 y, uint16 * p): Element(x, y, 0, 0),
252 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
253 bgColor(0x03E0), pic(p), elementToTell(NULL)
254 { if (pic) extents.w = pic[0], extents.h = pic[1]; }
255 Button(uint32 x, uint32 y, uint32 w, uint32 h, string s): Element(x, y, w, h),
256 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
257 bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL) {}
258 Button(uint32 x, uint32 y, string s): Element(x, y, 0, 8),
259 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
260 bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL)
261 { extents.w = s.length() * 8; }
262 virtual void HandleKey(SDLKey key) {}
263 virtual void HandleMouseMove(uint32 x, uint32 y);
264 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
265 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
266 virtual void Notify(Element *) {}
267 bool ButtonClicked(void) { return activated; }
268 void SetNotificationElement(Element * e) { elementToTell = e; }
271 bool activated, clicked, inside;
272 uint16 fgColor, bgColor;
275 Element * elementToTell;
278 void Button::HandleMouseMove(uint32 x, uint32 y)
280 inside = Inside(x, y);
283 void Button::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
290 if (clicked && !mouseDown)
292 clicked = false, activated = true;
294 // Send a message that we're activated (if there's someone to tell, that is)
296 elementToTell->Notify(this);
300 clicked = activated = false;
303 void Button::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
305 uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
307 for(uint32 y=0; y<extents.h; y++)
309 for(uint32 x=0; x<extents.w; x++)
311 // Doesn't clip in y axis! !!! FIX !!!
312 if (extents.x + x < pitch)
313 screenBuffer[addr + x + (y * pitch)]
314 = (clicked && inside ? fgColor : (inside ? 0x43F0 : bgColor));
319 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, pic);
321 if (text.length() > 0)
322 DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY, false, "%s", text.c_str());
326 class PushButton: public Element
329 // Save state externally?
332 // PushButton(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
333 // activated(false), clicked(false), inside(false), fgColor(0xFFFF),
334 // bgColor(0x03E0), pic(NULL), elementToTell(NULL) {}
335 PushButton(uint32 x, uint32 y, bool * st, string s): Element(x, y, 8, 8), state(st),
336 inside(false), text(s) { if (st == NULL) state = &internalState; }
337 /* Button(uint32 x, uint32 y, uint32 w, uint32 h, uint16 * p): Element(x, y, w, h),
338 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
339 bgColor(0x03E0), pic(p), elementToTell(NULL) {}
340 Button(uint32 x, uint32 y, uint16 * p): Element(x, y, 0, 0),
341 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
342 bgColor(0x03E0), pic(p), elementToTell(NULL)
343 { if (pic) extents.w = pic[0], extents.h = pic[1]; }
344 Button(uint32 x, uint32 y, uint32 w, uint32 h, string s): Element(x, y, w, h),
345 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
346 bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL) {}
347 PushButton(uint32 x, uint32 y, string s): Element(x, y, 0, 8),
348 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
349 bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL)
350 { extents.w = s.length() * 8; }*/
351 virtual void HandleKey(SDLKey key) {}
352 virtual void HandleMouseMove(uint32 x, uint32 y);
353 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
354 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
355 virtual void Notify(Element *) {}
356 // bool ButtonClicked(void) { return activated; }
357 // void SetNotificationElement(Element * e) { elementToTell = e; }
362 // bool activated, clicked, inside;
363 // uint16 fgColor, bgColor;
366 // Element * elementToTell;
370 void PushButton::HandleMouseMove(uint32 x, uint32 y)
372 inside = Inside(x, y);
375 void PushButton::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
377 if (inside && mouseDown)
382 if (clicked && !mouseDown)
384 clicked = false, activated = true;
386 // Send a message that we're activated (if there's someone to tell, that is)
388 elementToTell->Notify(this);
393 // clicked = activated = false;
396 void PushButton::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
398 /* uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
400 for(uint32 y=0; y<extents.h; y++)
402 for(uint32 x=0; x<extents.w; x++)
404 // Doesn't clip in y axis! !!! FIX !!!
405 if (extents.x + x < pitch)
406 screenBuffer[addr + x + (y * pitch)]
407 = (clicked && inside ? fgColor : (inside ? 0x43F0 : bgColor));
411 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, (*state ? pushButtonDown : pushButtonUp));
412 if (text.length() > 0)
413 DrawString(screenBuffer, extents.x + offsetX + 12, extents.y + offsetY, false, "%s", text.c_str());
417 class SlideSwitch: public Element
420 // Save state externally?
423 SlideSwitch(uint32 x, uint32 y, bool * st, string s1, string s2): Element(x, y, 8, 16), state(st),
424 inside(false), text1(s1), text2(s2) {}
425 virtual void HandleKey(SDLKey key) {}
426 virtual void HandleMouseMove(uint32 x, uint32 y);
427 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
428 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
429 virtual void Notify(Element *) {}
430 // bool ButtonClicked(void) { return activated; }
431 // void SetNotificationElement(Element * e) { elementToTell = e; }
436 // bool activated, clicked, inside;
437 // uint16 fgColor, bgColor;
440 // Element * elementToTell;
443 void SlideSwitch::HandleMouseMove(uint32 x, uint32 y)
445 inside = Inside(x, y);
448 void SlideSwitch::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
450 if (inside && mouseDown)
455 if (clicked && !mouseDown)
457 clicked = false, activated = true;
459 // Send a message that we're activated (if there's someone to tell, that is)
461 elementToTell->Notify(this);
466 // clicked = activated = false;
469 void SlideSwitch::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
471 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, (*state ? slideSwitchDown : slideSwitchUp));
472 if (text1.length() > 0)
473 DrawString(screenBuffer, extents.x + offsetX + 12, extents.y + offsetY, false, "%s", text1.c_str());
474 if (text2.length() > 0)
475 DrawString(screenBuffer, extents.x + offsetX + 12, extents.y + offsetY + 8, false, "%s", text2.c_str());
479 class Window: public Element
482 /* Window(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
483 fgColor(0x4FF0), bgColor(0xFE10)
484 { close = new Button(w - 8, 1, closeBox); list.push_back(close); }*/
485 Window(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0,
486 void (* f)(Element *) = NULL): Element(x, y, w, h),
487 /*clicked(false), inside(false),*/ fgColor(0x4FF0), bgColor(0x1E10),
489 { close = new Button(w - 8, 1, closeBox); list.push_back(close);
490 close->SetNotificationElement(this); }
492 virtual void HandleKey(SDLKey key);
493 virtual void HandleMouseMove(uint32 x, uint32 y);
494 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
495 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
496 virtual void Notify(Element * e);
497 void AddElement(Element * e);
498 // bool WindowActive(void) { return true; }//return !close->ButtonClicked(); }
501 // bool clicked, inside;
502 uint16 fgColor, bgColor;
503 void (* handler)(Element *);
505 //We have to use a list of Element *pointers* because we can't make a list that will hold
506 //all the different object types in the same list...
507 vector<Element *> list;
512 for(uint32 i=0; i<list.size(); i++)
517 void Window::HandleKey(SDLKey key)
519 if (key == SDLK_ESCAPE)
522 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
523 SDL_PushEvent(&event);
526 // Handle the items this window contains...
527 for(uint32 i=0; i<list.size(); i++)
528 // Make coords relative to upper right corner of this window...
529 list[i]->HandleKey(key);
532 void Window::HandleMouseMove(uint32 x, uint32 y)
534 // Handle the items this window contains...
535 for(uint32 i=0; i<list.size(); i++)
536 // Make coords relative to upper right corner of this window...
537 list[i]->HandleMouseMove(x - extents.x, y - extents.y);
540 void Window::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
542 // Handle the items this window contains...
543 for(uint32 i=0; i<list.size(); i++)
544 // Make coords relative to upper right corner of this window...
545 list[i]->HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
548 void Window::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
550 uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
552 for(uint32 y=0; y<extents.h; y++)
554 for(uint32 x=0; x<extents.w; x++)
556 // Doesn't clip in y axis! !!! FIX !!!
557 if (extents.x + x < pitch)
558 screenBuffer[addr + x + (y * pitch)] = bgColor;
562 // Handle the items this window contains...
563 for(uint32 i=0; i<list.size(); i++)
564 list[i]->Draw(extents.x, extents.y);
567 void Window::AddElement(Element * e)
572 void Window::Notify(Element * e)
577 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
578 SDL_PushEvent(&event);
583 class Text: public Element
586 Text(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
587 fgColor(0x4FF0), bgColor(0xFE10) {}
588 Text(uint32 x, uint32 y, string s): Element(x, y, 0, 0),
589 fgColor(0x4FF0), bgColor(0xFE10), text(s) {}
590 virtual void HandleKey(SDLKey key) {}
591 virtual void HandleMouseMove(uint32 x, uint32 y) {}
592 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) {}
593 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
594 virtual void Notify(Element *) {}
597 uint16 fgColor, bgColor;
601 void Text::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
603 if (text.length() > 0)
604 DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY, false, "%s", text.c_str());
608 class ListBox: public Element
609 //class ListBox: public Window
612 // ListBox(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
613 ListBox(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0);//: Window(x, y, w, h),
614 // windowPtr(0), cursor(0), limit(0), charWidth((w / 8) - 1), charHeight(h / 8),
615 // elementToTell(NULL), upArrow(w - 8, 0, upArrowBox),
616 // downArrow(w - 8, h - 8, downArrowBox), upArrow2(w - 8, h - 16, upArrowBox) {}
617 virtual void HandleKey(SDLKey key);
618 virtual void HandleMouseMove(uint32 x, uint32 y);
619 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
620 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
621 virtual void Notify(Element * e);
622 void SetNotificationElement(Element * e) { elementToTell = e; }
623 void AddItem(string s);
624 string GetSelectedItem(void);
628 uint32 windowPtr, cursor, limit;
629 uint32 charWidth, charHeight; // Box width/height in characters
630 Element * elementToTell;
631 Button upArrow, downArrow, upArrow2;
635 uint32 yRelativePoint;
638 ListBox::ListBox(uint32 x, uint32 y, uint32 w, uint32 h): Element(x, y, w, h),
639 thumbClicked(false), windowPtr(0), cursor(0), limit(0), charWidth((w / 8) - 1),
640 charHeight(h / 8), elementToTell(NULL), upArrow(w - 8, 0, upArrowBox),
641 downArrow(w - 8, h - 8, downArrowBox), upArrow2(w - 8, h - 16, upArrowBox)
643 upArrow.SetNotificationElement(this);
644 downArrow.SetNotificationElement(this);
645 upArrow2.SetNotificationElement(this);
646 extents.w -= 8; // Make room for scrollbar...
649 void ListBox::HandleKey(SDLKey key)
651 if (key == SDLK_DOWN)
653 if (cursor != limit - 1) // Cursor is within its window
655 else // Otherwise, scroll the window...
657 if (cursor + windowPtr != item.size() - 1)
661 else if (key == SDLK_UP)
671 else if (key == SDLK_PAGEDOWN)
673 if (cursor != limit - 1)
678 if (windowPtr > item.size() - limit)
679 windowPtr = item.size() - limit;
682 else if (key == SDLK_PAGEUP)
688 if (windowPtr < limit)
694 //How to handle these???
695 /* if (key == SDLK_RETURN)
697 if (key == SDLK_ESCAPE)
699 WriteLog("GUI: Aborting VJ by user request.\n");
700 return false; // Bail out!
702 else if (key >= SDLK_a && key <= SDLK_z)
704 // Advance cursor to filename with first letter pressed...
705 uint8 which = (key - SDLK_a) + 65; // Convert key to A-Z char
707 for(uint32 i=0; i<item.size(); i++)
709 if ((item[i][0] & 0xDF) == which)
711 cursor = i - windowPtr;
712 if (i > windowPtr + limit - 1)
713 windowPtr = i - limit + 1,
724 void ListBox::HandleMouseMove(uint32 x, uint32 y)
726 upArrow.HandleMouseMove(x - extents.x, y - extents.y);
727 downArrow.HandleMouseMove(x - extents.x, y - extents.y);
728 upArrow2.HandleMouseMove(x - extents.x, y - extents.y);
732 uint32 sbHeight = extents.h - 24,
733 thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight);//,
734 // thumbStart = (uint32)(((float)windowPtr / (float)item.size()) * (float)sbHeight);
736 //yRelativePoint is the spot on the thumb where we clicked...
737 // int32 thumbDelta = y - yRelativePoint;
738 int32 newThumbStart = y - yRelativePoint;
740 if (newThumbStart < 0)
743 if (newThumbStart > sbHeight - thumb)
744 newThumbStart = sbHeight - thumb;
746 windowPtr = (uint32)(((float)newThumbStart / (float)sbHeight) * (float)item.size());
747 //Check for cursor bounds as well... Or do we need to???
751 void ListBox::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
753 if (Inside(x, y) && mouseDown)
755 // Why do we have to do this??? (- extents.y?)
756 // I guess it's because only the Window class has offsetting implemented...
757 cursor = (y - extents.y) / 8;
760 // Check for a hit on the scrollbar...
761 if (x > (extents.x + extents.w) && x <= (extents.x + extents.w + 8)
762 && y > (extents.y + 8) && y <= (extents.y + extents.h - 16))
766 // This shiaut should be calculated in AddItem(), not here... (or in Draw() for that matter)
767 uint32 sbHeight = extents.h - 24,
768 thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight),
769 thumbStart = (uint32)(((float)windowPtr / (float)item.size()) * (float)sbHeight);
771 // Did we hit the thumb?
772 if (y >= (extents.y + 8 + thumbStart) && y < (extents.y + 8 + thumbStart + thumb))
773 thumbClicked = true, yRelativePoint = y - thumbStart;
776 thumbClicked = false;
779 upArrow.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
780 downArrow.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
781 upArrow2.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
784 void ListBox::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
786 for(uint32 i=0; i<limit; i++)
788 // Strip off the extension
789 // (extension stripping should be an option, not default!)
790 string s(item[windowPtr + i], 0, item[windowPtr + i].length() - 4);
791 DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY + i*8,
792 (cursor == i ? true : false), "%-*.*s", charWidth, charWidth, s.c_str());
795 upArrow.Draw(extents.x + offsetX, extents.y + offsetY);
796 downArrow.Draw(extents.x + offsetX, extents.y + offsetY);
797 upArrow2.Draw(extents.x + offsetX, extents.y + offsetY);
799 uint32 sbHeight = extents.h - 24,
800 thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight),
801 thumbStart = (uint32)(((float)windowPtr / (float)item.size()) * (float)sbHeight);
803 for(uint32 y=extents.y+offsetY+8; y<extents.y+offsetY+extents.h-16; y++)
805 // for(uint32 x=extents.x+offsetX+extents.w-8; x<extents.x+offsetX+extents.w; x++)
806 for(uint32 x=extents.x+offsetX+extents.w; x<extents.x+offsetX+extents.w+8; x++)
808 if (y >= thumbStart + (extents.y+offsetY+8) && y < thumbStart + thumb + (extents.y+offsetY+8))
809 screenBuffer[x + (y * pitch)] = (thumbClicked ? 0x458E : 0xFFFF);
811 screenBuffer[x + (y * pitch)] = 0x0200;
816 void ListBox::Notify(Element * e)
818 if (e == &upArrow || e == &upArrow2)
824 if (cursor < limit - 1)
828 else if (e == &downArrow)
830 if (windowPtr < item.size() - limit)
840 void ListBox::AddItem(string s)
843 limit = (item.size() > charHeight ? charHeight : item.size());
844 //WriteLog("ListBox: Adding item [%s], limit = %u...\n", s.c_str(), limit);
846 //Do this *every* time?
847 //What other choice is there? :-p
848 sort(item.begin(), item.end());
851 string ListBox::GetSelectedItem(void)
853 return item[windowPtr + cursor];
857 class FileList: public Window
860 FileList(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0);
861 virtual ~FileList() {}
862 virtual void HandleKey(SDLKey key);
863 virtual void HandleMouseMove(uint32 x, uint32 y) { Window::HandleMouseMove(x, y); }
864 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) { Window::HandleMouseButton(x, y, mouseDown); }
865 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0) { Window::Draw(offsetX, offsetY); }
866 virtual void Notify(Element * e);
873 //Need 4 buttons, one scrollbar...
874 FileList::FileList(uint32 x, uint32 y, uint32 w, uint32 h): Window(x, y, w, h)
876 files = new ListBox(8, 8, w - 16, h - 32);
878 load = new Button(8, h - 16, " Load ");
880 load->SetNotificationElement(this);
882 // DIR * dp = opendir(path);
883 DIR * dp = opendir(vjs.ROMPath);
886 while ((de = readdir(dp)) != NULL)
888 char * ext = strrchr(de->d_name, '.');
891 if (stricmp(ext, ".zip") == 0 || stricmp(ext, ".jag") == 0)
892 files->AddItem(string(de->d_name));
898 void FileList::HandleKey(SDLKey key)
900 if (key == SDLK_RETURN)
903 Window::HandleKey(key);
906 void FileList::Notify(Element * e)
910 char filename[MAX_PATH];
911 strcpy(filename, vjs.ROMPath);
913 if (strlen(filename) > 0)
914 if (filename[strlen(filename) - 1] != '/')
915 strcat(filename, "/");
917 strcat(filename, files->GetSelectedItem().c_str());
919 // uint32 romSize = JaguarLoadROM(jaguar_mainRom, filename);
920 JaguarLoadCart(jaguar_mainRom, filename);
923 //We need better error checking here... !!! FIX !!!
924 // WriteLog("VJ: Could not load ROM from file \"%s\"...", files->GetSelectedItem().c_str());
927 // jaguar_mainRom_crc32 = crc32_calcCheckSum(jaguar_mainRom, romSize);
928 // WriteLog("CRC: %08X\n", (unsigned int)jaguar_mainRom_crc32);
932 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
933 SDL_PushEvent(&event);
935 event.type = SDL_USEREVENT, event.user.code = MENU_ITEM_CHOSEN;
936 event.user.data1 = (void *)ResetJaguar;
937 SDL_PushEvent(&event);
948 Window * (* action)(void);
951 NameAction(string n, Window * (* a)(void) = NULL, SDLKey k = SDLK_UNKNOWN): name(n),
952 action(a), hotKey(k) {}
959 MenuItems(): charLength(0) {}
960 bool Inside(uint32 x, uint32 y)
961 { return (x >= (uint32)extents.x && x < (uint32)(extents.x + extents.w)
962 && y >= (uint32)extents.y && y < (uint32)(extents.y + extents.h) ? true : false); }
965 vector<NameAction> item;
970 class Menu: public Element
973 Menu(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 8,
974 uint16 fgc = 0x1CFF, uint16 bgc = 0x000F, uint16 fgch = 0x421F,
975 uint16 bgch = 0x1CFF): Element(x, y, w, h), activated(false), clicked(false),
976 inside(0), insidePopup(0), fgColor(fgc), bgColor(bgc), fgColorHL(fgch),
977 bgColorHL(bgch), menuChosen(-1), menuItemChosen(-1) {}
978 virtual void HandleKey(SDLKey key);
979 virtual void HandleMouseMove(uint32 x, uint32 y);
980 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
981 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
982 virtual void Notify(Element *) {}
983 void Add(MenuItems mi);
986 bool activated, clicked;
987 uint32 inside, insidePopup;
988 uint16 fgColor, bgColor, fgColorHL, bgColorHL;
989 int menuChosen, menuItemChosen;
992 vector<MenuItems> itemList;
995 void Menu::HandleKey(SDLKey key)
997 for(uint32 i=0; i<itemList.size(); i++)
999 for(uint32 j=0; j<itemList[i].item.size(); j++)
1001 if (itemList[i].item[j].hotKey == key)
1004 event.type = SDL_USEREVENT;
1005 event.user.code = MENU_ITEM_CHOSEN;
1006 event.user.data1 = (void *)itemList[i].item[j].action;
1007 SDL_PushEvent(&event);
1009 clicked = false, menuChosen = menuItemChosen = -1;
1016 void Menu::HandleMouseMove(uint32 x, uint32 y)
1018 inside = insidePopup = 0;
1022 // Find out *where* we are inside the menu bar
1023 uint32 xpos = extents.x;
1025 for(uint32 i=0; i<itemList.size(); i++)
1027 uint32 width = (itemList[i].title.length() + 2) * 8;
1029 if (x >= xpos && x < xpos + width)
1040 if (!Inside(x, y) && !clicked)
1045 if (itemList[menuChosen].Inside(x, y) && clicked)
1047 insidePopup = ((y - itemList[menuChosen].extents.y) / 8) + 1;
1048 menuItemChosen = insidePopup - 1;
1052 void Menu::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
1061 menuChosen = -1; // clicked is already false...!
1064 else // clicked == true
1066 if (insidePopup && !mouseDown) // I.e., mouse-button-up
1069 if (itemList[menuChosen].item[menuItemChosen].action != NULL)
1071 // itemList[menuChosen].item[menuItemChosen].action();
1073 event.type = SDL_USEREVENT;
1074 event.user.code = MENU_ITEM_CHOSEN;
1075 event.user.data1 = (void *)itemList[menuChosen].item[menuItemChosen].action;
1076 SDL_PushEvent(&event);
1078 clicked = false, menuChosen = menuItemChosen = -1;
1081 while (SDL_PollEvent(&event)); // Flush the event queue...
1082 event.type = SDL_MOUSEMOTION;
1084 SDL_GetMouseState(&mx, &my);
1085 event.motion.x = mx, event.motion.y = my;
1086 SDL_PushEvent(&event); // & update mouse position...!
1090 if (!inside && !insidePopup && mouseDown)
1091 clicked = false, menuChosen = menuItemChosen = -1;
1095 void Menu::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
1097 uint32 xpos = extents.x + offsetX;
1099 for(uint32 i=0; i<itemList.size(); i++)
1101 uint16 color1 = fgColor, color2 = bgColor;
1102 if (inside == (i + 1) || (menuChosen != -1 && (uint32)menuChosen == i))
1103 color1 = fgColorHL, color2 = bgColorHL;
1105 DrawStringOpaque(screenBuffer, xpos, extents.y + offsetY, color1, color2,
1106 " %s ", itemList[i].title.c_str());
1107 xpos += (itemList[i].title.length() + 2) * 8;
1110 // Draw sub menu (but only if active)
1113 uint32 ypos = extents.y + 9;
1115 for(uint32 i=0; i<itemList[menuChosen].item.size(); i++)
1117 uint16 color1 = fgColor, color2 = bgColor;
1119 if (insidePopup == i + 1)
1120 color1 = fgColorHL, color2 = bgColorHL, menuItemChosen = i;
1122 if (itemList[menuChosen].item[i].name.length() > 0)
1123 DrawStringOpaque(screenBuffer, itemList[menuChosen].extents.x, ypos,
1124 color1, color2, " %-*.*s ", itemList[menuChosen].charLength,
1125 itemList[menuChosen].charLength, itemList[menuChosen].item[i].name.c_str());
1127 DrawStringOpaque(screenBuffer, itemList[menuChosen].extents.x, ypos,
1128 fgColor, bgColor, "%.*s", itemList[menuChosen].charLength + 2, separator);
1135 void Menu::Add(MenuItems mi)
1137 for(uint32 i=0; i<mi.item.size(); i++)
1138 if (mi.item[i].name.length() > mi.charLength)
1139 mi.charLength = mi.item[i].name.length();
1141 // Set extents here as well...
1142 mi.extents.x = extents.x + extents.w, mi.extents.y = extents.y + 9;
1143 mi.extents.w = (mi.charLength + 2) * 8, mi.extents.h = mi.item.size() * 8;
1145 itemList.push_back(mi);
1146 extents.w += (mi.title.length() + 2) * 8;
1150 //Do we even *need* this?
1151 class RootWindow: public Window
1154 RootWindow(Menu * m, Window * w = NULL): menu(m), window(w) {}
1155 //Do we even need to care about this crap?
1156 // { extents.x = extents.y = 0, extents.w = 320, extents.h = 240; }
1157 virtual void HandleKey(SDLKey key) {}
1158 virtual void HandleMouseMove(uint32 x, uint32 y) {}
1159 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) {}
1160 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0) {}
1161 virtual void Notify(Element *) {}
1166 int16 * rootImage[1280 * 240 * 2];
1172 // GUI stuff--it's not crunchy, it's GUI! ;-)
1177 SDL_ShowCursor(SDL_DISABLE);
1178 SDL_GetMouseState(&mouseX, &mouseY);
1186 // Draw text at the given x/y coordinates. Can invert text as well.
1188 void DrawString(int16 * screen, uint32 x, uint32 y, bool invert, const char * text, ...)
1193 va_start(arg, text);
1194 vsprintf(string, text, arg);
1197 uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1198 uint32 length = strlen(string), address = x + (y * pitch);
1200 for(uint32 i=0; i<length; i++)
1202 uint32 fontAddr = (uint32)string[i] * 64;
1204 for(uint32 yy=0; yy<8; yy++)
1206 for(uint32 xx=0; xx<8; xx++)
1208 if ((font1[fontAddr] && !invert) || (!font1[fontAddr] && invert))
1209 *(screen + address + xx + (yy * pitch)) = 0xFE00;
1219 // Draw text at the given x/y coordinates, using FG/BG colors.
1221 void DrawStringOpaque(int16 * screen, uint32 x, uint32 y, uint16 color1, uint16 color2, const char * text, ...)
1226 va_start(arg, text);
1227 vsprintf(string, text, arg);
1230 uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1231 uint32 length = strlen(string), address = x + (y * pitch);
1233 for(uint32 i=0; i<length; i++)
1235 uint32 fontAddr = (uint32)string[i] * 64;
1237 for(uint32 yy=0; yy<8; yy++)
1239 for(uint32 xx=0; xx<8; xx++)
1241 *(screen + address + xx + (yy * pitch)) = (font1[fontAddr] ? color1 : color2);
1251 // Draw text at the given x/y coordinates with transparency (0 is fully opaque, 32 is fully transparent).
1253 void DrawStringTrans(int16 * screen, uint32 x, uint32 y, uint16 color, uint8 trans, const char * text, ...)
1258 va_start(arg, text);
1259 vsprintf(string, text, arg);
1262 uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1263 uint32 length = strlen(string), address = x + (y * pitch);
1265 for(uint32 i=0; i<length; i++)
1267 uint32 fontAddr = (uint32)string[i] * 64;
1269 for(uint32 yy=0; yy<8; yy++)
1271 for(uint32 xx=0; xx<8; xx++)
1273 if (font1[fontAddr])
1275 uint16 existingColor = *(screen + address + xx + (yy * pitch));
1277 uint8 eRed = (existingColor >> 10) & 0x1F,
1278 eGreen = (existingColor >> 5) & 0x1F,
1279 eBlue = existingColor & 0x1F,
1280 //This could be done ahead of time, instead of on each pixel...
1281 nRed = (color >> 10) & 0x1F,
1282 nGreen = (color >> 5) & 0x1F,
1283 nBlue = color & 0x1F;
1285 //This could be sped up by using a table of 5 + 5 + 5 bits (32 levels transparency -> 32768 entries)
1286 //Here we've modified it to have 33 levels of transparency (could have any # we want!)
1287 //because dividing by 32 is faster than dividing by 31...!
1288 uint8 invTrans = 32 - trans;
1289 uint16 bRed = (eRed * trans + nRed * invTrans) / 32;
1290 uint16 bGreen = (eGreen * trans + nGreen * invTrans) / 32;
1291 uint16 bBlue = (eBlue * trans + nBlue * invTrans) / 32;
1293 uint16 blendedColor = (bRed << 10) | (bGreen << 5) | bBlue;
1295 *(screen + address + xx + (yy * pitch)) = blendedColor;
1311 extern int16 * backbuffer;
1314 Window * mainWindow = NULL;
1316 // Set up the GUI classes...
1317 Element::SetScreenAndPitch(backbuffer, GetSDLScreenPitch() / 2);
1322 mi.item.push_back(NameAction("Load...", LoadROM, SDLK_l));
1323 mi.item.push_back(NameAction("Reset", ResetJaguar));
1324 mi.item.push_back(NameAction("Run", RunEmu, SDLK_ESCAPE));
1325 mi.item.push_back(NameAction(""));
1326 mi.item.push_back(NameAction("Quit", Quit, SDLK_q));
1328 mi.title = "Settings";
1330 mi.item.push_back(NameAction("Video..."));
1331 mi.item.push_back(NameAction("Audio..."));
1332 mi.item.push_back(NameAction("Misc...", MiscOptions, SDLK_m));
1336 mi.item.push_back(NameAction("About...", About));
1339 bool showMouse = true;
1341 //This is crappy!!! !!! FIX !!!
1344 // Set up our background save...
1345 memset(background, 0x11, tom_getVideoModeWidth() * 240 * 2);
1349 while (SDL_PollEvent(&event))
1351 if (event.type == SDL_USEREVENT)
1353 if (event.user.code == WINDOW_CLOSE)
1358 else if (event.user.code == MENU_ITEM_CHOSEN)
1360 // Confused? Let me enlighten... What we're doing here is casting
1361 // data1 as a pointer to a function which returns a Window pointer and
1362 // which takes no parameters (the "(Window *(*)(void))" part), then
1363 // derefencing it (the "*" in front of that) in order to call the
1364 // function that it points to. Clear as mud? Yeah, I hate function
1365 // pointers too, but what else are you gonna do?
1366 mainWindow = (*(Window *(*)(void))event.user.data1)();
1368 while (SDL_PollEvent(&event)); // Flush the event queue...
1369 event.type = SDL_MOUSEMOTION;
1371 SDL_GetMouseState(&mx, &my);
1372 event.motion.x = mx, event.motion.y = my;
1373 SDL_PushEvent(&event); // & update mouse position...!
1375 mouseX = mx, mouseY = my; // This prevents "mouse flash"...
1377 mouseX /= 2, mouseY /= 2;
1380 else if (event.type == SDL_ACTIVEEVENT)
1382 if (event.active.state == SDL_APPMOUSEFOCUS)
1383 showMouse = (event.active.gain ? true : false);
1385 else if (event.type == SDL_KEYDOWN)
1388 mainWindow->HandleKey(event.key.keysym.sym);
1390 mainMenu.HandleKey(event.key.keysym.sym);
1392 else if (event.type == SDL_MOUSEMOTION)
1394 mouseX = event.motion.x, mouseY = event.motion.y;
1397 mouseX /= 2, mouseY /= 2;
1400 mainWindow->HandleMouseMove(mouseX, mouseY);
1402 mainMenu.HandleMouseMove(mouseX, mouseY);
1404 else if (event.type == SDL_MOUSEBUTTONDOWN)
1406 uint32 mx = event.button.x, my = event.button.y;
1412 mainWindow->HandleMouseButton(mx, my, true);
1414 mainMenu.HandleMouseButton(mx, my, true);
1416 else if (event.type == SDL_MOUSEBUTTONUP)
1418 uint32 mx = event.button.x, my = event.button.y;
1424 mainWindow->HandleMouseButton(mx, my, false);
1426 mainMenu.HandleMouseButton(mx, my, false);
1430 // The way we do things here is kinda stupid (redrawing the screen every frame), but
1431 // it's simple. Perhaps there may be a reason down the road to be more selective with
1432 // our clearing, but for now, this will suffice.
1433 // memset(backbuffer, 0x11, tom_getVideoModeWidth() * 240 * 2);
1434 memcpy(backbuffer, background, tom_getVideoModeWidth() * 240 * 2);
1441 DrawTransparentBitmap(backbuffer, mouseX, mouseY, mousePic);
1451 // GUI "action" functions
1453 Window * LoadROM(void)
1455 FileList * fileList = new FileList(8, 16, 304, 216);
1457 return (Window *)fileList;
1460 Window * ResetJaguar(void)
1466 bool debounceRunKey = true;
1467 Window * RunEmu(void)
1469 //This is crappy... !!! FIX !!!
1470 extern int16 * backbuffer;
1471 extern bool finished, showGUI;
1473 uint32 nFrame = 0, nFrameskip = 0;
1474 uint32 totalFrames = 0;
1476 bool showMessage = true;
1477 uint32 showMsgFrames = 120;
1478 uint8 transparency = 0;
1479 // Pass a message to the "joystick" code to debounce the ESC key...
1480 debounceRunKey = true;
1482 uint32 cartType = 2;
1483 if (jaguarRomSize == 0x200000)
1485 else if (jaguarRomSize == 0x400000)
1488 char * cartTypeName[3] = { "2M Cartridge", "4M Cartridge", "Homebrew" };
1492 // Set up new backbuffer with new pixels and data
1493 JaguarExecute(backbuffer, true);
1495 //WriteLog("Frame #%u...\n", totalFrames);
1496 //extern bool doDSPDis;
1497 //if (totalFrames == 373)
1500 //This sucks... !!! FIX !!!
1505 // Some QnD GUI stuff here...
1508 extern uint32 gpu_pc, dsp_pc;
1509 DrawString(backbuffer, 8, 8, false, "GPU PC: %08X", gpu_pc);
1510 DrawString(backbuffer, 8, 16, false, "DSP PC: %08X", dsp_pc);
1515 DrawStringTrans(backbuffer, 8, 24*8, 0xFF0F, transparency, "Running...");
1516 DrawStringTrans(backbuffer, 8, 26*8, 0x3FE3, transparency, "%s, run address: %06X", cartTypeName[cartType], jaguarRunAddress);
1517 DrawStringTrans(backbuffer, 8, 27*8, 0x3FE3, transparency, "CRC: %08X", jaguar_mainRom_crc32);
1519 if (showMsgFrames == 0)
1523 if (transparency == 33)
1525 showMessage = false;
1526 /*extern bool doGPUDis;
1527 doGPUDis = true;//*/
1536 if (nFrame == nFrameskip)
1545 // Reset the pitch, since it may have been changed in-game...
1546 Element::SetScreenAndPitch(backbuffer, GetSDLScreenPitch() / 2);
1548 // Save the background for the GUI...
1549 // memcpy(background, backbuffer, tom_getVideoModeWidth() * 240 * 2);
1550 // In this case, we squash the color to monochrome, then force it to blue + green...
1551 for(uint32 i=0; i<tom_getVideoModeWidth() * 240; i++)
1553 uint16 word = backbuffer[i];
1554 uint8 r = (word >> 10) & 0x1F, g = (word >> 5) & 0x1F, b = word & 0x1F;
1555 word = ((r + g + b) / 3) & 0x001F;
1556 word = (word << 5) | word;
1557 background[i] = word;
1565 //This is crap. We need some REAL exit code, instead of this psuedo crap... !!! FIX !!!
1566 WriteLog("GUI: Quitting due to user request.\n");
1572 VideoDone(); // Free SDL components last...!
1577 return NULL; // We never get here...
1580 Window * About(void)
1582 Window * window = new Window(8, 16, 304, 160);
1583 window->AddElement(new Text(8, 8, "Virtual Jaguar 1.0.7"));
1584 window->AddElement(new Text(8, 24, "Coders:"));
1585 window->AddElement(new Text(16, 32, "Niels Wagenaar (nwagenaar)"));
1586 window->AddElement(new Text(16, 40, "Carwin Jones (Caz)"));
1587 window->AddElement(new Text(16, 48, "James L. Hammons (shamus)"));
1588 window->AddElement(new Text(16, 56, "Adam Green"));
1593 Window * MiscOptions(void)
1595 Window * window = new Window(8, 16, 304, 160);
1596 window->AddElement(new PushButton(8, 8, &vjs.useJaguarBIOS, "BIOS"));
1597 window->AddElement(new SlideSwitch(8, 20, &vjs.hardwareTypeNTSC, "PAL", "NTSC"));
1598 window->AddElement(new PushButton(8, 40, &vjs.DSPEnabled, "DSP"));
1599 window->AddElement(new SlideSwitch(16, 52, &vjs.usePipelinedDSP, "Original", "Pipelined"));
1600 window->AddElement(new SlideSwitch(8, 72, (bool *)&vjs.glFilter, "Sharp", "Blurry"));
1610 // * Window/fullscreen
1618 // Uses zero as transparent color
1620 void DrawTransparentBitmap(int16 * screen, uint32 x, uint32 y, uint16 * bitmap)
1622 uint16 width = bitmap[0], height = bitmap[1];
1625 uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1626 uint32 address = x + (y * pitch);
1628 for(int yy=0; yy<height; yy++)
1630 for(int xx=0; xx<width; xx++)
1632 if (*bitmap && x + xx < pitch) // NOTE: Still doesn't clip the Y val...
1633 *(screen + address + xx + (yy * pitch)) = *bitmap;
1640 // Very very crude GUI file selector
1642 /*bool UserSelectFile(char * path, char * filename)
1647 extern int16 * backbuffer;
1648 vector<string> fileList;
1650 // Read in the candidate files from the directory pointed to by "path"
1652 DIR * dp = opendir(path);
1655 while ((de = readdir(dp)) != NULL)
1657 char * ext = strrchr(de->d_name, '.');
1660 if (stricmp(ext, ".zip") == 0 || stricmp(ext, ".jag") == 0)
1661 fileList.push_back(string(de->d_name));
1666 if (fileList.size() == 0) // Any files found?
1667 return false; // Nope. Bail!
1669 // Main GUI selection loop
1671 uint32 cursor = 0, startFile = 0;
1673 if (fileList.size() > 1) // Only go GUI if more than one possibility!
1675 sort(fileList.begin(), fileList.end());
1678 uint32 limit = (fileList.size() > 30 ? 30 : fileList.size());
1681 // Ensure that the GUI is drawn before any user input...
1682 event.type = SDL_USEREVENT;
1683 SDL_PushEvent(&event);
1687 while (SDL_PollEvent(&event))
1689 if (event.type == SDL_KEYDOWN)
1691 SDLKey key = event.key.keysym.sym;
1693 if (key == SDLK_DOWN)
1695 if (cursor != limit - 1) // Cursor is within its window
1697 else // Otherwise, scroll the window...
1699 if (cursor + startFile != fileList.size() - 1)
1713 if (key == SDLK_PAGEDOWN)
1715 if (cursor != limit - 1)
1720 if (startFile > fileList.size() - limit)
1721 startFile = fileList.size() - limit;
1724 if (key == SDLK_PAGEUP)
1730 if (startFile < limit)
1736 if (key == SDLK_RETURN)
1738 if (key == SDLK_ESCAPE)
1740 WriteLog("GUI: Aborting VJ by user request.\n");
1741 return false; // Bail out!
1743 if (key >= SDLK_a && key <= SDLK_z)
1745 // Advance cursor to filename with first letter pressed...
1746 uint8 which = (key - SDLK_a) + 65; // Convert key to A-Z char
1748 for(uint32 i=0; i<fileList.size(); i++)
1750 if ((fileList[i][0] & 0xDF) == which)
1752 cursor = i - startFile;
1753 if (i > startFile + limit - 1)
1754 startFile = i - limit + 1,
1764 else if (event.type == SDL_MOUSEMOTION)
1766 mouseX = event.motion.x, mouseY = event.motion.y;
1768 mouseX /= 2, mouseY /= 2;
1770 else if (event.type == SDL_MOUSEBUTTONDOWN)
1772 uint32 mx = event.button.x, my = event.button.y;
1779 // memset(backbuffer, 0x11, tom_getVideoModeWidth() * tom_getVideoModeHeight() * 2);
1780 memset(backbuffer, 0x11, tom_getVideoModeWidth() * 240 * 2);
1782 for(uint32 i=0; i<limit; i++)
1784 // Clip our strings to guarantee that they fit on the screen...
1785 // (and strip off the extension too)
1786 string s(fileList[startFile + i], 0, fileList[startFile + i].length() - 4);
1787 if (s.length() > 38)
1789 DrawString(backbuffer, 0, i*8, (cursor == i ? true : false), " %s ", s.c_str());
1792 DrawTransparentBitmap(backbuffer, mouseX, mouseY, mousePic);
1799 strcpy(filename, path);
1801 if (strlen(path) > 0)
1802 if (path[strlen(path) - 1] != '/')
1803 strcat(filename, "/");
1805 strcat(filename, fileList[startFile + cursor].c_str());
1811 // Generic ROM loading
1813 uint32 JaguarLoadROM(uint8 * rom, char * path)
1817 char * ext = strrchr(path, '.');
1820 WriteLog("VJ: Loading \"%s\"...", path);
1822 if (stricmp(ext, ".zip") == 0)
1824 // Handle ZIP file loading here...
1825 WriteLog("(ZIPped)...");
1827 if (load_zipped_file(0, 0, path, NULL, &rom, &romSize) == -1)
1829 WriteLog("Failed!\n");
1835 /* FILE * fp = fopen(path, "rb");
1839 WriteLog("Failed!\n");
1843 fseek(fp, 0, SEEK_END);
1844 romSize = ftell(fp);
1845 fseek(fp, 0, SEEK_SET);
1846 fread(rom, 1, romSize, fp);
1849 gzFile fp = gzopen(path, "rb");
1853 WriteLog("Failed!\n");
1857 romSize = gzfilelength(fp);
1858 gzseek(fp, 0, SEEK_SET);
1859 gzread(fp, rom, romSize);
1863 WriteLog("OK (%i bytes)\n", romSize);
1870 // Jaguar cartridge ROM loading
1872 void JaguarLoadCart(uint8 * mem, char * path)
1874 jaguarRomSize = JaguarLoadROM(mem, path);
1876 // if (romSize == 0)
1878 /* char newPath[2048];
1879 WriteLog("VJ: Trying GUI...\n");
1881 //This is not *nix friendly for some reason...
1882 // if (!UserSelectFile(path, newPath))
1883 if (!UserSelectFile((strlen(path) == 0 ? (char *)"." : path), newPath))
1885 WriteLog("VJ: Could not find valid ROM in directory \"%s\"...\nAborting!\n", path);
1890 romSize = JaguarLoadROM(mem, newPath);
1892 if (jaguarRomSize == 0)
1894 // WriteLog("VJ: Could not load ROM from file \"%s\"...\nAborting!\n", newPath);
1895 WriteLog("VJ: Could not load ROM from file \"%s\"...\nAborting!\n", path);
1901 jaguar_mainRom_crc32 = crc32_calcCheckSum(jaguar_mainRom, jaguarRomSize);
1902 WriteLog("CRC: %08X\n", (unsigned int)jaguar_mainRom_crc32);
1905 jaguarRunAddress = 0x802000;
1906 //NOTE: The bytes 'JAGR' should also be at position $1C...
1907 // Also, there's *always* a $601A header at position $00...
1908 if (jaguar_mainRom[0] == 0x60 && jaguar_mainRom[1] == 0x1A)
1910 uint32 loadAddress = GET32(jaguar_mainRom, 0x22), runAddress = GET32(jaguar_mainRom, 0x2A);
1911 //This is not always right! Especially when converted via bin2jag1!!!
1912 //We should have access to the length of the furshlumiger file that was loaded anyway!
1914 // uint32 progLength = GET32(jaguar_mainRom, 0x02);
1917 // WriteLog("Jaguar: Setting up PD ROM... Run address: %08X, length: %08X\n", runAddress, progLength);
1918 // memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, progLength);
1919 WriteLog("Jaguar: Setting up PD ROM... Run address: %08X, length: %08X\n", runAddress, jaguarRomSize - 0x2E);
1920 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, jaguarRomSize - 0x2E);
1921 // SET32(jaguar_mainRam, 4, runAddress);
1922 jaguarRunAddress = runAddress;
1927 // Get the length of a (possibly) gzipped file
1929 int gzfilelength(gzFile gd)
1931 int size = 0, length = 0;
1932 unsigned char buffer[0x10000];
1938 // Read in chunks until EOF
1939 size = gzread(gd, buffer, 0x10000);