4 // Graphical User Interface support
13 #include <ctype.h> // For toupper()
24 using namespace std; // For STL stuff
26 // Private function prototypes
28 class Window; // Forward declaration...
30 void DrawTransparentBitmap(int16 * screen, uint32 x, uint32 y, uint16 * bitmap, uint8 * alpha = NULL);
31 void DrawStringTrans(int16 * screen, uint32 x, uint32 y, uint16 color, uint8 opacity, const char * text, ...);
32 void DrawStringOpaque(int16 * screen, uint32 x, uint32 y, uint16 color1, uint16 color2, const char * text, ...);
33 Window * LoadROM(void);
34 Window * ResetJaguar(void);
35 Window * RunEmu(void);
38 Window * MiscOptions(void);
40 int gzfilelength(gzFile gd);
44 extern uint8 * jaguar_mainRam;
45 extern uint8 * jaguar_bootRom;
46 extern uint8 * jaguar_mainRom;
48 // Local global variables
55 0x03E0,0x0000,0x0000,0x0000,0x0000,0x0000, // +
56 0x0300,0x03E0,0x0000,0x0000,0x0000,0x0000, // @+
57 0x0300,0x03E0,0x03E0,0x0000,0x0000,0x0000, // @++
58 0x0300,0x0300,0x03E0,0x03E0,0x0000,0x0000, // @@++
59 0x0300,0x0300,0x03E0,0x03E0,0x03E0,0x0000, // @@+++
60 0x0300,0x0300,0x0300,0x03E0,0x03E0,0x03E0, // @@@+++
61 0x0300,0x0300,0x0300,0x0000,0x0000,0x0000, // @@@
62 0x0300,0x0000,0x0000,0x0000,0x0000,0x0000 // @
64 0xFFFF,0x0000,0x0000,0x0000,0x0000,0x0000, // +
65 0xE318,0xFFFF,0x0000,0x0000,0x0000,0x0000, // @+
66 0xE318,0xFFFF,0xFFFF,0x0000,0x0000,0x0000, // @++
67 0xE318,0xE318,0xFFFF,0xFFFF,0x0000,0x0000, // @@++
68 0xE318,0xE318,0xFFFF,0xFFFF,0xFFFF,0x0000, // @@+++
69 0xE318,0xE318,0xE318,0xFFFF,0xFFFF,0xFFFF, // @@@+++
70 0xE318,0xE318,0xE318,0x0000,0x0000,0x0000, // @@@
71 0xE318,0x0000,0x0000,0x0000,0x0000,0x0000 // @
74 // 1 111 00 11 100 1 1100 -> F39C
75 // 1 100 00 10 000 1 0000 -> C210
76 // 1 110 00 11 000 1 1000 -> E318
77 // 0 000 00 11 111 0 0000 -> 03E0
78 // 0 000 00 11 000 0 0000 -> 0300
83 0x0000,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x0000, // +++++
84 0x4B5E,0xFFFF,0x0000,0x0000,0x0000,0xFFFF,0x0217, // +@ @.
85 0x4B5E,0x0000,0xFFFF,0x0000,0xFFFF,0x0000,0x0217, // + @ @ .
86 0x4B5E,0x0000,0x0000,0xFFFF,0x0000,0x0000,0x0217, // + @ .
87 0x4B5E,0x0000,0xFFFF,0x0000,0xFFFF,0x0000,0x0217, // + @ @ .
88 0x4B5E,0xFFFF,0x0000,0x0000,0x0000,0xFFFF,0x0217, // +@ @.
89 0x0000,0x0217,0x0217,0x0217,0x0217,0x0217,0x0000 // .....
92 uint16 upArrowBox[] = {
95 0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E, // ++++++++
96 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
97 0x4B5E,0x0000,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x0000,0x0217, // + @@@@ .
98 0x4B5E,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x0217, // +@@@@@@.
99 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
100 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
101 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
102 0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217 // ........
105 uint16 downArrowBox[] = {
108 0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E, // ++++++++
109 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
110 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
111 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
112 0x4B5E,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x0217, // +@@@@@@.
113 0x4B5E,0x0000,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x0000,0x0217, // + @@@@ .
114 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
115 0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217 // ........
118 uint16 pushButtonUp[] = {
121 0x0000, 0x0C63, 0x394A, 0x494A, 0x4108, 0x2CC6, 0x0421, 0x0000,
122 0x0C63, 0x518C, 0x48E7, 0x48C6, 0x48A5, 0x48A5, 0x3CE7, 0x0421,
123 0x3D4A, 0x48E7, 0x48C6, 0x48C6, 0x44A5, 0x48A5, 0x48A5, 0x2CC6,
124 0x494A, 0x48C6, 0x48C6, 0x44A5, 0x44A5, 0x44A5, 0x48A5, 0x40E7,
125 0x4529, 0x48A5, 0x44A5, 0x44A5, 0x44A5, 0x44A5, 0x4CA5, 0x40E7,
126 0x2CC6, 0x48A5, 0x48A5, 0x44A5, 0x44A5, 0x48A5, 0x4CA5, 0x2CC6,
127 0x0421, 0x3CE7, 0x48A5, 0x48A5, 0x4CA5, 0x4CA5, 0x44E7, 0x0421,
128 0x0000, 0x0421, 0x28C6, 0x40E7, 0x40E7, 0x2CC6, 0x0421, 0x0000
132 0xFF, 0xE4, 0xA0, 0x99, 0xA4, 0xBE, 0xF0, 0xFF,
133 0xE3, 0x85, 0x00, 0x00, 0x00, 0x00, 0xAF, 0xF0,
134 0x9F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0,
135 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAD,
136 0xA3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAC,
137 0xBD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF,
138 0xF1, 0xAD, 0x00, 0x00, 0x00, 0x00, 0xAC, 0xF1,
139 0xFF, 0xF2, 0xC0, 0xAD, 0xAD, 0xC0, 0xF2, 0xFF
142 uint16 pushButtonDown[] = {
145 0x0000, 0x0C63, 0x4A31, 0x5631, 0x4DCE, 0x2D4A, 0x0421, 0x0000,
146 0x0C63, 0x6AF7, 0x714A, 0x7908, 0x7908, 0x6908, 0x418C, 0x0421,
147 0x4A31, 0x714A, 0x7508, 0x6CE7, 0x6CE7, 0x74E7, 0x68E7, 0x2929,
148 0x5A31, 0x7908, 0x6CE7, 0x6CE7, 0x6CE7, 0x6CE7, 0x78E7, 0x3D6B,
149 0x4DCE, 0x7908, 0x6CE7, 0x6CE7, 0x6CE7, 0x6CE7, 0x78E7, 0x416B,
150 0x2D4A, 0x6D08, 0x74E7, 0x6CE7, 0x6CE7, 0x74E7, 0x6CE7, 0x2929,
151 0x0842, 0x418C, 0x6CE7, 0x78E7, 0x78E7, 0x6CE7, 0x416B, 0x0842,
152 0x0000, 0x0842, 0x2929, 0x416B, 0x416B, 0x2929, 0x0842, 0x0000
156 0xFF, 0xE4, 0x72, 0x68, 0x7E, 0xA7, 0xF0, 0xFF,
157 0xE4, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x93, 0xF0,
158 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB2,
159 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A,
160 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A,
161 0xA6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB1,
162 0xEF, 0x91, 0x00, 0x00, 0x00, 0x00, 0x96, 0xEF,
163 0xFF, 0xEF, 0xAE, 0x98, 0x97, 0xAF, 0xEF, 0xFF
166 uint16 slideSwitchUp[] = {
169 0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E, // ++++++++
170 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
171 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
172 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
173 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
174 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
175 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
176 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
177 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
178 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
179 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
180 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
181 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
182 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
183 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
184 0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217 // ........
187 uint16 slideSwitchDown[] = {
190 0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E, // ++++++++
191 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
192 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
193 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
194 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
195 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
196 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
197 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
198 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
199 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
200 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
201 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
202 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
203 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
204 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
205 0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217 // ........
211 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
212 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
213 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
214 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
215 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
216 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
217 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
218 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 // ........
221 char separator[] = "--------------------------------------------------------";
223 uint16 background[1280 * 240];
226 // Case insensitive string compare function
227 // Taken straight out of Thinking In C++ by Bruce Eckel. Thanks Bruce!
230 int stringCmpi(const string &s1, const string &s2)
232 // Select the first element of each string:
233 string::const_iterator p1 = s1.begin(), p2 = s2.begin();
235 while (p1 != s1.end() && p2 != s2.end()) // Don
\92t run past the end
237 if (toupper(*p1) != toupper(*p2)) // Compare upper-cased chars
238 return (toupper(*p1) < toupper(*p2) ? -1 : 1);// Report which was lexically greater
244 // If they match up to the detected eos, say which was longer. Return 0 if the same.
245 return s2.size() - s1.size();
252 enum { WINDOW_CLOSE, MENU_ITEM_CHOSEN };
257 Element(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0)
258 { extents.x = x, extents.y = y, extents.w = w, extents.h = h; }
259 virtual void HandleKey(SDLKey key) = 0;
260 virtual void HandleMouseMove(uint32 x, uint32 y) = 0;
261 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) = 0;
262 virtual void Draw(uint32, uint32) = 0;
263 virtual void Notify(Element *) = 0;
264 //Needed? virtual ~Element() = 0;
265 //We're not allocating anything in the base class, so the answer would be NO.
266 bool Inside(uint32 x, uint32 y);
268 static void SetScreenAndPitch(int16 * s, uint32 p) { screenBuffer = s, pitch = p; }
273 // Class variables...
274 static int16 * screenBuffer;
278 int16 * Element::screenBuffer = NULL;
279 uint32 Element::pitch = 0;
281 bool Element::Inside(uint32 x, uint32 y)
283 return (x >= (uint32)extents.x && x < (uint32)(extents.x + extents.w)
284 && y >= (uint32)extents.y && y < (uint32)(extents.y + extents.h) ? true : false);
288 class Button: public Element
291 Button(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
292 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
293 bgColor(0x03E0), pic(NULL), elementToTell(NULL) {}
294 Button(uint32 x, uint32 y, uint32 w, uint32 h, uint16 * p): Element(x, y, w, h),
295 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
296 bgColor(0x03E0), pic(p), elementToTell(NULL) {}
297 Button(uint32 x, uint32 y, uint16 * p): Element(x, y, 0, 0),
298 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
299 bgColor(0x03E0), pic(p), elementToTell(NULL)
300 { if (pic) extents.w = pic[0], extents.h = pic[1]; }
301 Button(uint32 x, uint32 y, uint32 w, uint32 h, string s): Element(x, y, w, h),
302 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
303 bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL) {}
304 Button(uint32 x, uint32 y, string s): Element(x, y, 0, 8),
305 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
306 bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL)
307 { extents.w = s.length() * 8; }
308 virtual void HandleKey(SDLKey key) {}
309 virtual void HandleMouseMove(uint32 x, uint32 y);
310 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
311 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
312 virtual void Notify(Element *) {}
313 bool ButtonClicked(void) { return activated; }
314 void SetNotificationElement(Element * e) { elementToTell = e; }
317 bool activated, clicked, inside;
318 uint16 fgColor, bgColor;
321 Element * elementToTell;
324 void Button::HandleMouseMove(uint32 x, uint32 y)
326 inside = Inside(x, y);
329 void Button::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
336 if (clicked && !mouseDown)
338 clicked = false, activated = true;
340 // Send a message that we're activated (if there's someone to tell, that is)
342 elementToTell->Notify(this);
346 clicked = activated = false;
349 void Button::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
351 uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
353 for(uint32 y=0; y<extents.h; y++)
355 for(uint32 x=0; x<extents.w; x++)
357 // Doesn't clip in y axis! !!! FIX !!!
358 if (extents.x + x < pitch)
359 screenBuffer[addr + x + (y * pitch)]
360 = (clicked && inside ? fgColor : (inside ? 0x43F0 : bgColor));
365 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, pic);
367 if (text.length() > 0)
368 DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY, false, "%s", text.c_str());
372 class PushButton: public Element
375 // Save state externally?
378 // PushButton(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
379 // activated(false), clicked(false), inside(false), fgColor(0xFFFF),
380 // bgColor(0x03E0), pic(NULL), elementToTell(NULL) {}
381 PushButton(uint32 x, uint32 y, bool * st, string s): Element(x, y, 8, 8), state(st),
382 inside(false), text(s) { if (st == NULL) state = &internalState; }
383 /* Button(uint32 x, uint32 y, uint32 w, uint32 h, uint16 * p): Element(x, y, w, h),
384 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
385 bgColor(0x03E0), pic(p), elementToTell(NULL) {}
386 Button(uint32 x, uint32 y, uint16 * p): Element(x, y, 0, 0),
387 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
388 bgColor(0x03E0), pic(p), elementToTell(NULL)
389 { if (pic) extents.w = pic[0], extents.h = pic[1]; }
390 Button(uint32 x, uint32 y, uint32 w, uint32 h, string s): Element(x, y, w, h),
391 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
392 bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL) {}
393 PushButton(uint32 x, uint32 y, string s): Element(x, y, 0, 8),
394 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
395 bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL)
396 { extents.w = s.length() * 8; }*/
397 virtual void HandleKey(SDLKey key) {}
398 virtual void HandleMouseMove(uint32 x, uint32 y);
399 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
400 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
401 virtual void Notify(Element *) {}
402 // bool ButtonClicked(void) { return activated; }
403 // void SetNotificationElement(Element * e) { elementToTell = e; }
408 // bool activated, clicked, inside;
409 // uint16 fgColor, bgColor;
412 // Element * elementToTell;
416 void PushButton::HandleMouseMove(uint32 x, uint32 y)
418 inside = Inside(x, y);
421 void PushButton::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
423 if (inside && mouseDown)
428 if (clicked && !mouseDown)
430 clicked = false, activated = true;
432 // Send a message that we're activated (if there's someone to tell, that is)
434 elementToTell->Notify(this);
439 // clicked = activated = false;
442 void PushButton::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
444 /* uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
446 for(uint32 y=0; y<extents.h; y++)
448 for(uint32 x=0; x<extents.w; x++)
450 // Doesn't clip in y axis! !!! FIX !!!
451 if (extents.x + x < pitch)
452 screenBuffer[addr + x + (y * pitch)]
453 = (clicked && inside ? fgColor : (inside ? 0x43F0 : bgColor));
457 // DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, (*state ? pushButtonDown : pushButtonUp));
458 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, (*state ? pushButtonDown : pushButtonUp), (*state ? pbdAlpha : pbuAlpha));
459 if (text.length() > 0)
460 DrawString(screenBuffer, extents.x + offsetX + 12, extents.y + offsetY, false, "%s", text.c_str());
464 class SlideSwitch: public Element
467 // Save state externally?
470 SlideSwitch(uint32 x, uint32 y, bool * st, string s1, string s2): Element(x, y, 8, 16), state(st),
471 inside(false), text1(s1), text2(s2) {}
472 virtual void HandleKey(SDLKey key) {}
473 virtual void HandleMouseMove(uint32 x, uint32 y);
474 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
475 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
476 virtual void Notify(Element *) {}
477 // bool ButtonClicked(void) { return activated; }
478 // void SetNotificationElement(Element * e) { elementToTell = e; }
483 // bool activated, clicked, inside;
484 // uint16 fgColor, bgColor;
487 // Element * elementToTell;
490 void SlideSwitch::HandleMouseMove(uint32 x, uint32 y)
492 inside = Inside(x, y);
495 void SlideSwitch::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
497 if (inside && mouseDown)
502 if (clicked && !mouseDown)
504 clicked = false, activated = true;
506 // Send a message that we're activated (if there's someone to tell, that is)
508 elementToTell->Notify(this);
513 // clicked = activated = false;
516 void SlideSwitch::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
518 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, (*state ? slideSwitchDown : slideSwitchUp));
519 if (text1.length() > 0)
520 DrawString(screenBuffer, extents.x + offsetX + 12, extents.y + offsetY, false, "%s", text1.c_str());
521 if (text2.length() > 0)
522 DrawString(screenBuffer, extents.x + offsetX + 12, extents.y + offsetY + 8, false, "%s", text2.c_str());
526 class Window: public Element
529 /* Window(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
530 fgColor(0x4FF0), bgColor(0xFE10)
531 { close = new Button(w - 8, 1, closeBox); list.push_back(close); }*/
532 Window(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0,
533 void (* f)(Element *) = NULL): Element(x, y, w, h),
534 /*clicked(false), inside(false),*/ fgColor(0x4FF0), bgColor(0x1E10),
536 { close = new Button(w - 8, 1, closeBox); list.push_back(close);
537 close->SetNotificationElement(this); }
539 virtual void HandleKey(SDLKey key);
540 virtual void HandleMouseMove(uint32 x, uint32 y);
541 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
542 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
543 virtual void Notify(Element * e);
544 void AddElement(Element * e);
545 // bool WindowActive(void) { return true; }//return !close->ButtonClicked(); }
548 // bool clicked, inside;
549 uint16 fgColor, bgColor;
550 void (* handler)(Element *);
552 //We have to use a list of Element *pointers* because we can't make a list that will hold
553 //all the different object types in the same list...
554 vector<Element *> list;
559 for(uint32 i=0; i<list.size(); i++)
564 void Window::HandleKey(SDLKey key)
566 if (key == SDLK_ESCAPE)
569 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
570 SDL_PushEvent(&event);
573 // Handle the items this window contains...
574 for(uint32 i=0; i<list.size(); i++)
575 // Make coords relative to upper right corner of this window...
576 list[i]->HandleKey(key);
579 void Window::HandleMouseMove(uint32 x, uint32 y)
581 // Handle the items this window contains...
582 for(uint32 i=0; i<list.size(); i++)
583 // Make coords relative to upper right corner of this window...
584 list[i]->HandleMouseMove(x - extents.x, y - extents.y);
587 void Window::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
589 // Handle the items this window contains...
590 for(uint32 i=0; i<list.size(); i++)
591 // Make coords relative to upper right corner of this window...
592 list[i]->HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
595 void Window::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
597 uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
599 for(uint32 y=0; y<extents.h; y++)
601 for(uint32 x=0; x<extents.w; x++)
603 // Doesn't clip in y axis! !!! FIX !!!
604 if (extents.x + x < pitch)
605 screenBuffer[addr + x + (y * pitch)] = bgColor;
609 // Handle the items this window contains...
610 for(uint32 i=0; i<list.size(); i++)
611 list[i]->Draw(extents.x, extents.y);
614 void Window::AddElement(Element * e)
619 void Window::Notify(Element * e)
624 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
625 SDL_PushEvent(&event);
630 class Text: public Element
633 Text(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
634 fgColor(0x4FF0), bgColor(0xFE10) {}
635 Text(uint32 x, uint32 y, string s): Element(x, y, 0, 0),
636 fgColor(0x4FF0), bgColor(0xFE10), text(s) {}
637 virtual void HandleKey(SDLKey key) {}
638 virtual void HandleMouseMove(uint32 x, uint32 y) {}
639 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) {}
640 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
641 virtual void Notify(Element *) {}
644 uint16 fgColor, bgColor;
648 void Text::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
650 if (text.length() > 0)
651 DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY, false, "%s", text.c_str());
655 class ListBox: public Element
656 //class ListBox: public Window
659 // ListBox(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
660 ListBox(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0);//: Window(x, y, w, h),
661 // windowPtr(0), cursor(0), limit(0), charWidth((w / 8) - 1), charHeight(h / 8),
662 // elementToTell(NULL), upArrow(w - 8, 0, upArrowBox),
663 // downArrow(w - 8, h - 8, downArrowBox), upArrow2(w - 8, h - 16, upArrowBox) {}
664 virtual void HandleKey(SDLKey key);
665 virtual void HandleMouseMove(uint32 x, uint32 y);
666 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
667 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
668 virtual void Notify(Element * e);
669 void SetNotificationElement(Element * e) { elementToTell = e; }
670 void AddItem(string s);
671 string GetSelectedItem(void);
675 uint32 windowPtr, cursor, limit;
676 uint32 charWidth, charHeight; // Box width/height in characters
677 Element * elementToTell;
678 Button upArrow, downArrow, upArrow2;
682 uint32 yRelativePoint;
685 ListBox::ListBox(uint32 x, uint32 y, uint32 w, uint32 h): Element(x, y, w, h),
686 thumbClicked(false), windowPtr(0), cursor(0), limit(0), charWidth((w / 8) - 1),
687 charHeight(h / 8), elementToTell(NULL), upArrow(w - 8, 0, upArrowBox),
688 downArrow(w - 8, h - 8, downArrowBox), upArrow2(w - 8, h - 16, upArrowBox)
690 upArrow.SetNotificationElement(this);
691 downArrow.SetNotificationElement(this);
692 upArrow2.SetNotificationElement(this);
693 extents.w -= 8; // Make room for scrollbar...
696 void ListBox::HandleKey(SDLKey key)
698 if (key == SDLK_DOWN)
700 if (cursor != limit - 1) // Cursor is within its window
702 else // Otherwise, scroll the window...
704 if (cursor + windowPtr != item.size() - 1)
708 else if (key == SDLK_UP)
718 else if (key == SDLK_PAGEDOWN)
720 if (cursor != limit - 1)
725 if (windowPtr > item.size() - limit)
726 windowPtr = item.size() - limit;
729 else if (key == SDLK_PAGEUP)
735 if (windowPtr < limit)
741 else if (key >= SDLK_a && key <= SDLK_z)
743 // Advance cursor to filename with first letter pressed...
744 uint8 which = (key - SDLK_a) + 65; // Convert key to A-Z char
746 for(uint32 i=0; i<item.size(); i++)
748 if ((item[i][0] & 0xDF) == which)
750 cursor = i - windowPtr;
751 if (i > windowPtr + limit - 1)
752 windowPtr = i - limit + 1, cursor = limit - 1;
754 windowPtr = i, cursor = 0;
761 void ListBox::HandleMouseMove(uint32 x, uint32 y)
763 upArrow.HandleMouseMove(x - extents.x, y - extents.y);
764 downArrow.HandleMouseMove(x - extents.x, y - extents.y);
765 upArrow2.HandleMouseMove(x - extents.x, y - extents.y);
769 uint32 sbHeight = extents.h - 24,
770 thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight);
772 //yRelativePoint is the spot on the thumb where we clicked...
773 int32 newThumbStart = y - yRelativePoint;
775 if (newThumbStart < 0)
778 if (newThumbStart > sbHeight - thumb)
779 newThumbStart = sbHeight - thumb;
781 windowPtr = (uint32)(((float)newThumbStart / (float)sbHeight) * (float)item.size());
782 //Check for cursor bounds as well... Or do we need to???
783 //Actually, we don't...!
787 void ListBox::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
789 if (Inside(x, y) && mouseDown)
791 // Why do we have to do this??? (- extents.y?)
792 // I guess it's because only the Window class has offsetting implemented...
793 cursor = (y - extents.y) / 8;
796 // Check for a hit on the scrollbar...
797 if (x > (extents.x + extents.w) && x <= (extents.x + extents.w + 8)
798 && y > (extents.y + 8) && y <= (extents.y + extents.h - 16))
802 // This shiaut should be calculated in AddItem(), not here... (or in Draw() for that matter)
803 uint32 sbHeight = extents.h - 24,
804 thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight),
805 thumbStart = (uint32)(((float)windowPtr / (float)item.size()) * (float)sbHeight);
807 // Did we hit the thumb?
808 if (y >= (extents.y + 8 + thumbStart) && y < (extents.y + 8 + thumbStart + thumb))
809 thumbClicked = true, yRelativePoint = y - thumbStart;
812 thumbClicked = false;
815 upArrow.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
816 downArrow.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
817 upArrow2.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
820 void ListBox::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
822 for(uint32 i=0; i<limit; i++)
824 // Strip off the extension
825 // (extension stripping should be an option, not default!)
826 string s(item[windowPtr + i], 0, item[windowPtr + i].length() - 4);
827 DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY + i*8,
828 (cursor == i ? true : false), "%-*.*s", charWidth, charWidth, s.c_str());
831 upArrow.Draw(extents.x + offsetX, extents.y + offsetY);
832 downArrow.Draw(extents.x + offsetX, extents.y + offsetY);
833 upArrow2.Draw(extents.x + offsetX, extents.y + offsetY);
835 uint32 sbHeight = extents.h - 24,
836 thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight),
837 thumbStart = (uint32)(((float)windowPtr / (float)item.size()) * (float)sbHeight);
839 for(uint32 y=extents.y+offsetY+8; y<extents.y+offsetY+extents.h-16; y++)
841 // for(uint32 x=extents.x+offsetX+extents.w-8; x<extents.x+offsetX+extents.w; x++)
842 for(uint32 x=extents.x+offsetX+extents.w; x<extents.x+offsetX+extents.w+8; x++)
844 if (y >= thumbStart + (extents.y+offsetY+8) && y < thumbStart + thumb + (extents.y+offsetY+8))
845 screenBuffer[x + (y * pitch)] = (thumbClicked ? 0x458E : 0xFFFF);
847 screenBuffer[x + (y * pitch)] = 0x0200;
852 void ListBox::Notify(Element * e)
854 if (e == &upArrow || e == &upArrow2)
860 if (cursor < limit - 1)
864 else if (e == &downArrow)
866 if (windowPtr < item.size() - limit)
876 void ListBox::AddItem(string s)
878 // Do a simple insertion sort
879 bool inserted = false;
881 for(vector<string>::iterator i=item.begin(); i<item.end(); i++)
883 if (stringCmpi(s, *i) == -1)
894 limit = (item.size() > charHeight ? charHeight : item.size());
897 string ListBox::GetSelectedItem(void)
899 return item[windowPtr + cursor];
903 class FileList: public Window
906 FileList(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0);
907 virtual ~FileList() {}
908 virtual void HandleKey(SDLKey key);
909 virtual void HandleMouseMove(uint32 x, uint32 y) { Window::HandleMouseMove(x, y); }
910 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) { Window::HandleMouseButton(x, y, mouseDown); }
911 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0) { Window::Draw(offsetX, offsetY); }
912 virtual void Notify(Element * e);
919 //Need 4 buttons, one scrollbar...
920 FileList::FileList(uint32 x, uint32 y, uint32 w, uint32 h): Window(x, y, w, h)
922 files = new ListBox(8, 8, w - 16, h - 32);
924 load = new Button(8, h - 16, " Load ");
926 load->SetNotificationElement(this);
928 DIR * dp = opendir(vjs.ROMPath);
931 while ((de = readdir(dp)) != NULL)
933 char * ext = strrchr(de->d_name, '.');
936 if (stricmp(ext, ".zip") == 0 || stricmp(ext, ".jag") == 0)
937 files->AddItem(string(de->d_name));
943 void FileList::HandleKey(SDLKey key)
945 if (key == SDLK_RETURN)
948 Window::HandleKey(key);
951 void FileList::Notify(Element * e)
955 char filename[MAX_PATH];
956 strcpy(filename, vjs.ROMPath);
958 if (strlen(filename) > 0)
959 if (filename[strlen(filename) - 1] != '/')
960 strcat(filename, "/");
962 strcat(filename, files->GetSelectedItem().c_str());
964 // uint32 romSize = JaguarLoadROM(jaguar_mainRom, filename);
965 JaguarLoadCart(jaguar_mainRom, filename);
968 //We need better error checking here... !!! FIX !!!
969 // WriteLog("VJ: Could not load ROM from file \"%s\"...", files->GetSelectedItem().c_str());
972 // jaguar_mainRom_crc32 = crc32_calcCheckSum(jaguar_mainRom, romSize);
973 // WriteLog("CRC: %08X\n", (unsigned int)jaguar_mainRom_crc32);
977 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
978 SDL_PushEvent(&event);
980 event.type = SDL_USEREVENT, event.user.code = MENU_ITEM_CHOSEN;
981 event.user.data1 = (void *)ResetJaguar;
982 SDL_PushEvent(&event);
993 Window * (* action)(void);
996 NameAction(string n, Window * (* a)(void) = NULL, SDLKey k = SDLK_UNKNOWN): name(n),
997 action(a), hotKey(k) {}
1004 MenuItems(): charLength(0) {}
1005 bool Inside(uint32 x, uint32 y)
1006 { return (x >= (uint32)extents.x && x < (uint32)(extents.x + extents.w)
1007 && y >= (uint32)extents.y && y < (uint32)(extents.y + extents.h) ? true : false); }
1010 vector<NameAction> item;
1015 class Menu: public Element
1018 Menu(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 8,
1019 uint16 fgc = 0x1CFF, uint16 bgc = 0x000F, uint16 fgch = 0x421F,
1020 uint16 bgch = 0x1CFF): Element(x, y, w, h), activated(false), clicked(false),
1021 inside(0), insidePopup(0), fgColor(fgc), bgColor(bgc), fgColorHL(fgch),
1022 bgColorHL(bgch), menuChosen(-1), menuItemChosen(-1) {}
1023 virtual void HandleKey(SDLKey key);
1024 virtual void HandleMouseMove(uint32 x, uint32 y);
1025 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
1026 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
1027 virtual void Notify(Element *) {}
1028 void Add(MenuItems mi);
1031 bool activated, clicked;
1032 uint32 inside, insidePopup;
1033 uint16 fgColor, bgColor, fgColorHL, bgColorHL;
1034 int menuChosen, menuItemChosen;
1037 vector<MenuItems> itemList;
1040 void Menu::HandleKey(SDLKey key)
1042 for(uint32 i=0; i<itemList.size(); i++)
1044 for(uint32 j=0; j<itemList[i].item.size(); j++)
1046 if (itemList[i].item[j].hotKey == key)
1049 event.type = SDL_USEREVENT;
1050 event.user.code = MENU_ITEM_CHOSEN;
1051 event.user.data1 = (void *)itemList[i].item[j].action;
1052 SDL_PushEvent(&event);
1054 clicked = false, menuChosen = menuItemChosen = -1;
1061 void Menu::HandleMouseMove(uint32 x, uint32 y)
1063 inside = insidePopup = 0;
1067 // Find out *where* we are inside the menu bar
1068 uint32 xpos = extents.x;
1070 for(uint32 i=0; i<itemList.size(); i++)
1072 uint32 width = (itemList[i].title.length() + 2) * 8;
1074 if (x >= xpos && x < xpos + width)
1085 if (!Inside(x, y) && !clicked)
1090 if (itemList[menuChosen].Inside(x, y) && clicked)
1092 insidePopup = ((y - itemList[menuChosen].extents.y) / 8) + 1;
1093 menuItemChosen = insidePopup - 1;
1097 void Menu::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
1106 menuChosen = -1; // clicked is already false...!
1109 else // clicked == true
1111 if (insidePopup && !mouseDown) // I.e., mouse-button-up
1114 if (itemList[menuChosen].item[menuItemChosen].action != NULL)
1116 // itemList[menuChosen].item[menuItemChosen].action();
1118 event.type = SDL_USEREVENT;
1119 event.user.code = MENU_ITEM_CHOSEN;
1120 event.user.data1 = (void *)itemList[menuChosen].item[menuItemChosen].action;
1121 SDL_PushEvent(&event);
1123 clicked = false, menuChosen = menuItemChosen = -1;
1126 while (SDL_PollEvent(&event)); // Flush the event queue...
1127 event.type = SDL_MOUSEMOTION;
1129 SDL_GetMouseState(&mx, &my);
1130 event.motion.x = mx, event.motion.y = my;
1131 SDL_PushEvent(&event); // & update mouse position...!
1135 if (!inside && !insidePopup && mouseDown)
1136 clicked = false, menuChosen = menuItemChosen = -1;
1140 void Menu::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
1142 uint32 xpos = extents.x + offsetX;
1144 for(uint32 i=0; i<itemList.size(); i++)
1146 uint16 color1 = fgColor, color2 = bgColor;
1147 if (inside == (i + 1) || (menuChosen != -1 && (uint32)menuChosen == i))
1148 color1 = fgColorHL, color2 = bgColorHL;
1150 DrawStringOpaque(screenBuffer, xpos, extents.y + offsetY, color1, color2,
1151 " %s ", itemList[i].title.c_str());
1152 xpos += (itemList[i].title.length() + 2) * 8;
1155 // Draw sub menu (but only if active)
1158 uint32 ypos = extents.y + 9;
1160 for(uint32 i=0; i<itemList[menuChosen].item.size(); i++)
1162 uint16 color1 = fgColor, color2 = bgColor;
1164 if (insidePopup == i + 1)
1165 color1 = fgColorHL, color2 = bgColorHL, menuItemChosen = i;
1167 if (itemList[menuChosen].item[i].name.length() > 0)
1168 DrawStringOpaque(screenBuffer, itemList[menuChosen].extents.x, ypos,
1169 color1, color2, " %-*.*s ", itemList[menuChosen].charLength,
1170 itemList[menuChosen].charLength, itemList[menuChosen].item[i].name.c_str());
1172 DrawStringOpaque(screenBuffer, itemList[menuChosen].extents.x, ypos,
1173 fgColor, bgColor, "%.*s", itemList[menuChosen].charLength + 2, separator);
1180 void Menu::Add(MenuItems mi)
1182 for(uint32 i=0; i<mi.item.size(); i++)
1183 if (mi.item[i].name.length() > mi.charLength)
1184 mi.charLength = mi.item[i].name.length();
1186 // Set extents here as well...
1187 mi.extents.x = extents.x + extents.w, mi.extents.y = extents.y + 9;
1188 mi.extents.w = (mi.charLength + 2) * 8, mi.extents.h = mi.item.size() * 8;
1190 itemList.push_back(mi);
1191 extents.w += (mi.title.length() + 2) * 8;
1195 //Do we even *need* this?
1196 class RootWindow: public Window
1199 RootWindow(Menu * m, Window * w = NULL): menu(m), window(w) {}
1200 //Do we even need to care about this crap?
1201 // { extents.x = extents.y = 0, extents.w = 320, extents.h = 240; }
1202 virtual void HandleKey(SDLKey key) {}
1203 virtual void HandleMouseMove(uint32 x, uint32 y) {}
1204 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) {}
1205 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0) {}
1206 virtual void Notify(Element *) {}
1211 int16 * rootImage[1280 * 240 * 2];
1217 // GUI stuff--it's not crunchy, it's GUI! ;-)
1222 SDL_ShowCursor(SDL_DISABLE);
1223 SDL_GetMouseState(&mouseX, &mouseY);
1231 // Draw text at the given x/y coordinates. Can invert text as well.
1233 void DrawString(int16 * screen, uint32 x, uint32 y, bool invert, const char * text, ...)
1238 va_start(arg, text);
1239 vsprintf(string, text, arg);
1242 uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1243 uint32 length = strlen(string), address = x + (y * pitch);
1245 for(uint32 i=0; i<length; i++)
1247 uint32 fontAddr = (uint32)string[i] * 64;
1249 for(uint32 yy=0; yy<8; yy++)
1251 for(uint32 xx=0; xx<8; xx++)
1253 if ((font1[fontAddr] && !invert) || (!font1[fontAddr] && invert))
1254 *(screen + address + xx + (yy * pitch)) = 0xFE00;
1264 // Draw text at the given x/y coordinates, using FG/BG colors.
1266 void DrawStringOpaque(int16 * screen, uint32 x, uint32 y, uint16 color1, uint16 color2, const char * text, ...)
1271 va_start(arg, text);
1272 vsprintf(string, text, arg);
1275 uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1276 uint32 length = strlen(string), address = x + (y * pitch);
1278 for(uint32 i=0; i<length; i++)
1280 uint32 fontAddr = (uint32)string[i] * 64;
1282 for(uint32 yy=0; yy<8; yy++)
1284 for(uint32 xx=0; xx<8; xx++)
1286 *(screen + address + xx + (yy * pitch)) = (font1[fontAddr] ? color1 : color2);
1296 // Draw text at the given x/y coordinates with transparency (0 is fully opaque, 32 is fully transparent).
1298 void DrawStringTrans(int16 * screen, uint32 x, uint32 y, uint16 color, uint8 trans, const char * text, ...)
1303 va_start(arg, text);
1304 vsprintf(string, text, arg);
1307 uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1308 uint32 length = strlen(string), address = x + (y * pitch);
1310 for(uint32 i=0; i<length; i++)
1312 uint32 fontAddr = (uint32)string[i] * 64;
1314 for(uint32 yy=0; yy<8; yy++)
1316 for(uint32 xx=0; xx<8; xx++)
1318 if (font1[fontAddr])
1320 uint16 existingColor = *(screen + address + xx + (yy * pitch));
1322 uint8 eRed = (existingColor >> 10) & 0x1F,
1323 eGreen = (existingColor >> 5) & 0x1F,
1324 eBlue = existingColor & 0x1F,
1325 //This could be done ahead of time, instead of on each pixel...
1326 nRed = (color >> 10) & 0x1F,
1327 nGreen = (color >> 5) & 0x1F,
1328 nBlue = color & 0x1F;
1330 //This could be sped up by using a table of 5 + 5 + 5 bits (32 levels transparency -> 32768 entries)
1331 //Here we've modified it to have 33 levels of transparency (could have any # we want!)
1332 //because dividing by 32 is faster than dividing by 31...!
1333 uint8 invTrans = 32 - trans;
1334 uint16 bRed = (eRed * trans + nRed * invTrans) / 32;
1335 uint16 bGreen = (eGreen * trans + nGreen * invTrans) / 32;
1336 uint16 bBlue = (eBlue * trans + nBlue * invTrans) / 32;
1338 uint16 blendedColor = (bRed << 10) | (bGreen << 5) | bBlue;
1340 *(screen + address + xx + (yy * pitch)) = blendedColor;
1356 extern int16 * backbuffer;
1359 Window * mainWindow = NULL;
1361 // Set up the GUI classes...
1362 Element::SetScreenAndPitch(backbuffer, GetSDLScreenPitch() / 2);
1367 mi.item.push_back(NameAction("Load...", LoadROM, SDLK_l));
1368 mi.item.push_back(NameAction("Reset", ResetJaguar));
1369 mi.item.push_back(NameAction("Run", RunEmu, SDLK_ESCAPE));
1370 mi.item.push_back(NameAction(""));
1371 mi.item.push_back(NameAction("Quit", Quit, SDLK_q));
1373 mi.title = "Settings";
1375 mi.item.push_back(NameAction("Video..."));
1376 mi.item.push_back(NameAction("Audio..."));
1377 mi.item.push_back(NameAction("Misc...", MiscOptions, SDLK_m));
1381 mi.item.push_back(NameAction("About...", About));
1384 bool showMouse = true;
1386 //This is crappy!!! !!! FIX !!!
1389 // Set up our background save...
1390 memset(background, 0x11, tom_getVideoModeWidth() * 240 * 2);
1394 while (SDL_PollEvent(&event))
1396 if (event.type == SDL_USEREVENT)
1398 if (event.user.code == WINDOW_CLOSE)
1403 else if (event.user.code == MENU_ITEM_CHOSEN)
1405 // Confused? Let me enlighten... What we're doing here is casting
1406 // data1 as a pointer to a function which returns a Window pointer and
1407 // which takes no parameters (the "(Window *(*)(void))" part), then
1408 // derefencing it (the "*" in front of that) in order to call the
1409 // function that it points to. Clear as mud? Yeah, I hate function
1410 // pointers too, but what else are you gonna do?
1411 mainWindow = (*(Window *(*)(void))event.user.data1)();
1413 while (SDL_PollEvent(&event)); // Flush the event queue...
1414 event.type = SDL_MOUSEMOTION;
1416 SDL_GetMouseState(&mx, &my);
1417 event.motion.x = mx, event.motion.y = my;
1418 SDL_PushEvent(&event); // & update mouse position...!
1420 mouseX = mx, mouseY = my; // This prevents "mouse flash"...
1422 mouseX /= 2, mouseY /= 2;
1425 else if (event.type == SDL_ACTIVEEVENT)
1427 if (event.active.state == SDL_APPMOUSEFOCUS)
1428 showMouse = (event.active.gain ? true : false);
1430 else if (event.type == SDL_KEYDOWN)
1433 mainWindow->HandleKey(event.key.keysym.sym);
1435 mainMenu.HandleKey(event.key.keysym.sym);
1437 else if (event.type == SDL_MOUSEMOTION)
1439 mouseX = event.motion.x, mouseY = event.motion.y;
1442 mouseX /= 2, mouseY /= 2;
1445 mainWindow->HandleMouseMove(mouseX, mouseY);
1447 mainMenu.HandleMouseMove(mouseX, mouseY);
1449 else if (event.type == SDL_MOUSEBUTTONDOWN)
1451 uint32 mx = event.button.x, my = event.button.y;
1457 mainWindow->HandleMouseButton(mx, my, true);
1459 mainMenu.HandleMouseButton(mx, my, true);
1461 else if (event.type == SDL_MOUSEBUTTONUP)
1463 uint32 mx = event.button.x, my = event.button.y;
1469 mainWindow->HandleMouseButton(mx, my, false);
1471 mainMenu.HandleMouseButton(mx, my, false);
1475 // The way we do things here is kinda stupid (redrawing the screen every frame), but
1476 // it's simple. Perhaps there may be a reason down the road to be more selective with
1477 // our clearing, but for now, this will suffice.
1478 // memset(backbuffer, 0x11, tom_getVideoModeWidth() * 240 * 2);
1479 memcpy(backbuffer, background, tom_getVideoModeWidth() * 240 * 2);
1486 DrawTransparentBitmap(backbuffer, mouseX, mouseY, mousePic);
1496 // GUI "action" functions
1498 Window * LoadROM(void)
1500 FileList * fileList = new FileList(8, 16, 304, 216);
1502 return (Window *)fileList;
1505 Window * ResetJaguar(void)
1511 bool debounceRunKey = true;
1512 Window * RunEmu(void)
1514 //This is crappy... !!! FIX !!!
1515 extern int16 * backbuffer;
1516 extern bool finished, showGUI;
1518 uint32 nFrame = 0, nFrameskip = 0;
1519 uint32 totalFrames = 0;
1521 bool showMessage = true;
1522 uint32 showMsgFrames = 120;
1523 uint8 transparency = 0;
1524 // Pass a message to the "joystick" code to debounce the ESC key...
1525 debounceRunKey = true;
1527 uint32 cartType = 2;
1528 if (jaguarRomSize == 0x200000)
1530 else if (jaguarRomSize == 0x400000)
1533 char * cartTypeName[3] = { "2M Cartridge", "4M Cartridge", "Homebrew" };
1537 // Set up new backbuffer with new pixels and data
1538 JaguarExecute(backbuffer, true);
1540 //WriteLog("Frame #%u...\n", totalFrames);
1541 //extern bool doDSPDis;
1542 //if (totalFrames == 373)
1545 //This sucks... !!! FIX !!!
1550 // Some QnD GUI stuff here...
1553 extern uint32 gpu_pc, dsp_pc;
1554 DrawString(backbuffer, 8, 8, false, "GPU PC: %08X", gpu_pc);
1555 DrawString(backbuffer, 8, 16, false, "DSP PC: %08X", dsp_pc);
1560 DrawStringTrans(backbuffer, 8, 24*8, 0xFF0F, transparency, "Running...");
1561 DrawStringTrans(backbuffer, 8, 26*8, 0x3FE3, transparency, "%s, run address: %06X", cartTypeName[cartType], jaguarRunAddress);
1562 DrawStringTrans(backbuffer, 8, 27*8, 0x3FE3, transparency, "CRC: %08X", jaguar_mainRom_crc32);
1564 if (showMsgFrames == 0)
1568 if (transparency == 33)
1570 showMessage = false;
1571 /*extern bool doGPUDis;
1572 doGPUDis = true;//*/
1581 if (nFrame == nFrameskip)
1590 // Reset the pitch, since it may have been changed in-game...
1591 Element::SetScreenAndPitch(backbuffer, GetSDLScreenPitch() / 2);
1593 // Save the background for the GUI...
1594 // memcpy(background, backbuffer, tom_getVideoModeWidth() * 240 * 2);
1595 // In this case, we squash the color to monochrome, then force it to blue + green...
1596 for(uint32 i=0; i<tom_getVideoModeWidth() * 240; i++)
1598 uint16 word = backbuffer[i];
1599 uint8 r = (word >> 10) & 0x1F, g = (word >> 5) & 0x1F, b = word & 0x1F;
1600 word = ((r + g + b) / 3) & 0x001F;
1601 word = (word << 5) | word;
1602 background[i] = word;
1610 //This is crap. We need some REAL exit code, instead of this psuedo crap... !!! FIX !!!
1611 WriteLog("GUI: Quitting due to user request.\n");
1617 VideoDone(); // Free SDL components last...!
1622 return NULL; // We never get here...
1625 Window * About(void)
1627 Window * window = new Window(8, 16, 304, 160);
1628 window->AddElement(new Text(8, 8, "Virtual Jaguar 1.0.7"));
1629 window->AddElement(new Text(8, 24, "Coders:"));
1630 window->AddElement(new Text(16, 32, "Niels Wagenaar (nwagenaar)"));
1631 window->AddElement(new Text(16, 40, "Carwin Jones (Caz)"));
1632 window->AddElement(new Text(16, 48, "James L. Hammons (shamus)"));
1633 window->AddElement(new Text(16, 56, "Adam Green"));
1638 Window * MiscOptions(void)
1640 Window * window = new Window(8, 16, 304, 160);
1641 window->AddElement(new PushButton(8, 8, &vjs.useJaguarBIOS, "BIOS"));
1642 window->AddElement(new SlideSwitch(8, 20, &vjs.hardwareTypeNTSC, "PAL", "NTSC"));
1643 window->AddElement(new PushButton(8, 40, &vjs.DSPEnabled, "DSP"));
1644 window->AddElement(new SlideSwitch(16, 52, &vjs.usePipelinedDSP, "Original", "Pipelined"));
1645 window->AddElement(new SlideSwitch(8, 72, (bool *)&vjs.glFilter, "Sharp", "Blurry"));
1655 // * Window/fullscreen
1663 // Uses zero as transparent color
1664 // Can also use an optional alpha channel
1666 void DrawTransparentBitmap(int16 * screen, uint32 x, uint32 y, uint16 * bitmap, uint8 * alpha/*=NULL*/)
1668 uint16 width = bitmap[0], height = bitmap[1];
1671 uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1672 uint32 address = x + (y * pitch);
1674 for(int yy=0; yy<height; yy++)
1676 for(int xx=0; xx<width; xx++)
1680 if (*bitmap && x + xx < pitch) // NOTE: Still doesn't clip the Y val...
1681 *(screen + address + xx + (yy * pitch)) = *bitmap;
1685 uint8 trans = *alpha;
1686 uint16 color = *bitmap;
1687 uint16 existingColor = *(screen + address + xx + (yy * pitch));
1689 uint8 eRed = (existingColor >> 10) & 0x1F,
1690 eGreen = (existingColor >> 5) & 0x1F,
1691 eBlue = existingColor & 0x1F,
1693 nRed = (color >> 10) & 0x1F,
1694 nGreen = (color >> 5) & 0x1F,
1695 nBlue = color & 0x1F;
1697 uint8 invTrans = 255 - trans;
1698 uint16 bRed = (eRed * trans + nRed * invTrans) / 255;
1699 uint16 bGreen = (eGreen * trans + nGreen * invTrans) / 255;
1700 uint16 bBlue = (eBlue * trans + nBlue * invTrans) / 255;
1702 uint16 blendedColor = (bRed << 10) | (bGreen << 5) | bBlue;
1704 *(screen + address + xx + (yy * pitch)) = blendedColor;
1715 // Very very crude GUI file selector
1717 /*bool UserSelectFile(char * path, char * filename)
1722 extern int16 * backbuffer;
1723 vector<string> fileList;
1725 // Read in the candidate files from the directory pointed to by "path"
1727 DIR * dp = opendir(path);
1730 while ((de = readdir(dp)) != NULL)
1732 char * ext = strrchr(de->d_name, '.');
1735 if (stricmp(ext, ".zip") == 0 || stricmp(ext, ".jag") == 0)
1736 fileList.push_back(string(de->d_name));
1741 if (fileList.size() == 0) // Any files found?
1742 return false; // Nope. Bail!
1744 // Main GUI selection loop
1746 uint32 cursor = 0, startFile = 0;
1748 if (fileList.size() > 1) // Only go GUI if more than one possibility!
1750 sort(fileList.begin(), fileList.end());
1753 uint32 limit = (fileList.size() > 30 ? 30 : fileList.size());
1756 // Ensure that the GUI is drawn before any user input...
1757 event.type = SDL_USEREVENT;
1758 SDL_PushEvent(&event);
1762 while (SDL_PollEvent(&event))
1764 if (event.type == SDL_KEYDOWN)
1766 SDLKey key = event.key.keysym.sym;
1768 if (key == SDLK_DOWN)
1770 if (cursor != limit - 1) // Cursor is within its window
1772 else // Otherwise, scroll the window...
1774 if (cursor + startFile != fileList.size() - 1)
1788 if (key == SDLK_PAGEDOWN)
1790 if (cursor != limit - 1)
1795 if (startFile > fileList.size() - limit)
1796 startFile = fileList.size() - limit;
1799 if (key == SDLK_PAGEUP)
1805 if (startFile < limit)
1811 if (key == SDLK_RETURN)
1813 if (key == SDLK_ESCAPE)
1815 WriteLog("GUI: Aborting VJ by user request.\n");
1816 return false; // Bail out!
1818 if (key >= SDLK_a && key <= SDLK_z)
1820 // Advance cursor to filename with first letter pressed...
1821 uint8 which = (key - SDLK_a) + 65; // Convert key to A-Z char
1823 for(uint32 i=0; i<fileList.size(); i++)
1825 if ((fileList[i][0] & 0xDF) == which)
1827 cursor = i - startFile;
1828 if (i > startFile + limit - 1)
1829 startFile = i - limit + 1,
1839 else if (event.type == SDL_MOUSEMOTION)
1841 mouseX = event.motion.x, mouseY = event.motion.y;
1843 mouseX /= 2, mouseY /= 2;
1845 else if (event.type == SDL_MOUSEBUTTONDOWN)
1847 uint32 mx = event.button.x, my = event.button.y;
1854 // memset(backbuffer, 0x11, tom_getVideoModeWidth() * tom_getVideoModeHeight() * 2);
1855 memset(backbuffer, 0x11, tom_getVideoModeWidth() * 240 * 2);
1857 for(uint32 i=0; i<limit; i++)
1859 // Clip our strings to guarantee that they fit on the screen...
1860 // (and strip off the extension too)
1861 string s(fileList[startFile + i], 0, fileList[startFile + i].length() - 4);
1862 if (s.length() > 38)
1864 DrawString(backbuffer, 0, i*8, (cursor == i ? true : false), " %s ", s.c_str());
1867 DrawTransparentBitmap(backbuffer, mouseX, mouseY, mousePic);
1874 strcpy(filename, path);
1876 if (strlen(path) > 0)
1877 if (path[strlen(path) - 1] != '/')
1878 strcat(filename, "/");
1880 strcat(filename, fileList[startFile + cursor].c_str());
1886 // Generic ROM loading
1888 uint32 JaguarLoadROM(uint8 * rom, char * path)
1892 char * ext = strrchr(path, '.');
1895 WriteLog("VJ: Loading \"%s\"...", path);
1897 if (stricmp(ext, ".zip") == 0)
1899 // Handle ZIP file loading here...
1900 WriteLog("(ZIPped)...");
1902 if (load_zipped_file(0, 0, path, NULL, &rom, &romSize) == -1)
1904 WriteLog("Failed!\n");
1910 /* FILE * fp = fopen(path, "rb");
1914 WriteLog("Failed!\n");
1918 fseek(fp, 0, SEEK_END);
1919 romSize = ftell(fp);
1920 fseek(fp, 0, SEEK_SET);
1921 fread(rom, 1, romSize, fp);
1924 gzFile fp = gzopen(path, "rb");
1928 WriteLog("Failed!\n");
1932 romSize = gzfilelength(fp);
1933 gzseek(fp, 0, SEEK_SET);
1934 gzread(fp, rom, romSize);
1938 WriteLog("OK (%i bytes)\n", romSize);
1945 // Jaguar cartridge ROM loading
1947 void JaguarLoadCart(uint8 * mem, char * path)
1949 jaguarRomSize = JaguarLoadROM(mem, path);
1951 // if (romSize == 0)
1953 /* char newPath[2048];
1954 WriteLog("VJ: Trying GUI...\n");
1956 //This is not *nix friendly for some reason...
1957 // if (!UserSelectFile(path, newPath))
1958 if (!UserSelectFile((strlen(path) == 0 ? (char *)"." : path), newPath))
1960 WriteLog("VJ: Could not find valid ROM in directory \"%s\"...\nAborting!\n", path);
1965 romSize = JaguarLoadROM(mem, newPath);
1967 if (jaguarRomSize == 0)
1969 // WriteLog("VJ: Could not load ROM from file \"%s\"...\nAborting!\n", newPath);
1970 WriteLog("VJ: Could not load ROM from file \"%s\"...\nAborting!\n", path);
1976 jaguar_mainRom_crc32 = crc32_calcCheckSum(jaguar_mainRom, jaguarRomSize);
1977 WriteLog("CRC: %08X\n", (unsigned int)jaguar_mainRom_crc32);
1980 jaguarRunAddress = 0x802000;
1981 //NOTE: The bytes 'JAGR' should also be at position $1C...
1982 // Also, there's *always* a $601A header at position $00...
1983 if (jaguar_mainRom[0] == 0x60 && jaguar_mainRom[1] == 0x1A)
1985 uint32 loadAddress = GET32(jaguar_mainRom, 0x22), runAddress = GET32(jaguar_mainRom, 0x2A);
1986 //This is not always right! Especially when converted via bin2jag1!!!
1987 //We should have access to the length of the furshlumiger file that was loaded anyway!
1989 // uint32 progLength = GET32(jaguar_mainRom, 0x02);
1992 // WriteLog("Jaguar: Setting up PD ROM... Run address: %08X, length: %08X\n", runAddress, progLength);
1993 // memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, progLength);
1994 WriteLog("Jaguar: Setting up homebrew... Run address: %08X, length: %08X\n", runAddress, jaguarRomSize - 0x2E);
1995 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, jaguarRomSize - 0x2E);
1996 // SET32(jaguar_mainRam, 4, runAddress);
1997 jaguarRunAddress = runAddress;
2002 ABS Format sleuthing (LBUGDEMO.ABS):
2004 000000 60 1B 00 00 05 0C 00 04 62 C0 00 00 04 28 00 00
2005 000010 12 A6 00 00 00 00 00 80 20 00 FF FF 00 80 25 0C
2008 DRI-format file detected...
2009 Text segment size = 0x0000050c bytes
2010 Data segment size = 0x000462c0 bytes
2011 BSS Segment size = 0x00000428 bytes
2012 Symbol Table size = 0x000012a6 bytes
2013 Absolute Address for text segment = 0x00802000
2014 Absolute Address for data segment = 0x0080250c
2015 Absolute Address for BSS segment = 0x00004000
2018 000000 01 50 00 03 00 00 00 00 00 03 83 10 00 00 05 3b
2019 000010 00 1c 00 03 00 00 01 07 00 00 1d d0 00 03 64 98
2020 000020 00 06 8b 80 00 80 20 00 00 80 20 00 00 80 3d d0
2022 000030 2e 74 78 74 00 00 00 00 00 80 20 00 00 80 20 00 .txt (+36 bytes)
2023 000040 00 00 1d d0 00 00 00 a8 00 00 00 00 00 00 00 00
2024 000050 00 00 00 00 00 00 00 20
2025 000058 2e 64 74 61 00 00 00 00 00 80 3d d0 00 80 3d d0 .dta (+36 bytes)
2026 000068 00 03 64 98 00 00 1e 78 00 00 00 00 00 00 00 00
2027 000078 00 00 00 00 00 00 00 40
2028 000080 2e 62 73 73 00 00 00 00 00 00 50 00 00 00 50 00 .bss (+36 bytes)
2029 000090 00 06 8b 80 00 03 83 10 00 00 00 00 00 00 00 00
2030 0000a0 00 00 00 00 00 00 00 80
2032 Header size is $A8 bytes...
2034 BSD/COFF format file detected...
2035 3 sections specified
2036 Symbol Table offset = 230160 ($00038310)
2037 Symbol Table contains 1339 symbol entries ($0000053B)
2038 The additional header size is 28 bytes ($001C)
2039 Magic Number for RUN_HDR = 0x00000107
2040 Text Segment Size = 7632 ($00001DD0)
2041 Data Segment Size = 222360 ($00036498)
2042 BSS Segment Size = 428928 ($00068B80)
2043 Starting Address for executable = 0x00802000
2044 Start of Text Segment = 0x00802000
2045 Start of Data Segment = 0x00803dd0
2050 // Get the length of a (possibly) gzipped file
2052 int gzfilelength(gzFile gd)
2054 int size = 0, length = 0;
2055 unsigned char buffer[0x10000];
2061 // Read in chunks until EOF
2062 size = gzread(gd, buffer, 0x10000);