4 // Graphical User Interface support
9 #include <sys/types.h> // For MacOS <dirent.h> dependency
15 #include <ctype.h> // For toupper()
25 using namespace std; // For STL stuff
27 // Private function prototypes
29 class Window; // Forward declaration...
31 void DrawTransparentBitmap(int16 * screen, uint32 x, uint32 y, uint16 * bitmap, uint8 * alpha = NULL);
32 void DrawStringTrans(int16 * screen, uint32 x, uint32 y, uint16 color, uint8 opacity, const char * text, ...);
33 void DrawStringOpaque(int16 * screen, uint32 x, uint32 y, uint16 color1, uint16 color2, const char * text, ...);
34 void DrawString(int16 * screen, uint32 x, uint32 y, bool invert, const char * text, ...);
35 Window * LoadROM(void);
36 Window * ResetJaguar(void);
37 Window * ResetJaguarCD(void);
38 Window * RunEmu(void);
41 Window * MiscOptions(void);
43 int gzfilelength(gzFile gd);
47 extern uint8 * jaguar_mainRam;
48 extern uint8 * jaguar_mainRom;
49 extern uint8 * jaguar_bootRom;
50 extern uint8 * jaguar_CDBootROM;
51 extern bool BIOSLoaded;
52 extern bool CDBIOSLoaded;
54 // Local global variables
56 bool exitGUI = false; // GUI (emulator) done variable
58 uint16 background[1280 * 256]; // GUI background buffer
63 0x03E0,0x0000,0x0000,0x0000,0x0000,0x0000, // +
64 0x0300,0x03E0,0x0000,0x0000,0x0000,0x0000, // @+
65 0x0300,0x03E0,0x03E0,0x0000,0x0000,0x0000, // @++
66 0x0300,0x0300,0x03E0,0x03E0,0x0000,0x0000, // @@++
67 0x0300,0x0300,0x03E0,0x03E0,0x03E0,0x0000, // @@+++
68 0x0300,0x0300,0x0300,0x03E0,0x03E0,0x03E0, // @@@+++
69 0x0300,0x0300,0x0300,0x0000,0x0000,0x0000, // @@@
70 0x0300,0x0000,0x0000,0x0000,0x0000,0x0000 // @
72 0xFFFF,0x0000,0x0000,0x0000,0x0000,0x0000, // +
73 0xE318,0xFFFF,0x0000,0x0000,0x0000,0x0000, // @+
74 0xE318,0xFFFF,0xFFFF,0x0000,0x0000,0x0000, // @++
75 0xE318,0xE318,0xFFFF,0xFFFF,0x0000,0x0000, // @@++
76 0xE318,0xE318,0xFFFF,0xFFFF,0xFFFF,0x0000, // @@+++
77 0xE318,0xE318,0xE318,0xFFFF,0xFFFF,0xFFFF, // @@@+++
78 0xE318,0xE318,0xE318,0x0000,0x0000,0x0000, // @@@
79 0xE318,0x0000,0x0000,0x0000,0x0000,0x0000 // @
82 // 1 111 00 11 100 1 1100 -> F39C
83 // 1 100 00 10 000 1 0000 -> C210
84 // 1 110 00 11 000 1 1000 -> E318
85 // 0 000 00 11 111 0 0000 -> 03E0
86 // 0 000 00 11 000 0 0000 -> 0300
91 0x0000,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x0000, // +++++
92 0x4B5E,0xFFFF,0x0000,0x0000,0x0000,0xFFFF,0x0217, // +@ @.
93 0x4B5E,0x0000,0xFFFF,0x0000,0xFFFF,0x0000,0x0217, // + @ @ .
94 0x4B5E,0x0000,0x0000,0xFFFF,0x0000,0x0000,0x0217, // + @ .
95 0x4B5E,0x0000,0xFFFF,0x0000,0xFFFF,0x0000,0x0217, // + @ @ .
96 0x4B5E,0xFFFF,0x0000,0x0000,0x0000,0xFFFF,0x0217, // +@ @.
97 0x0000,0x0217,0x0217,0x0217,0x0217,0x0217,0x0000 // .....
100 uint16 upArrowBox[] = {
103 0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E, // ++++++++
104 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
105 0x4B5E,0x0000,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x0000,0x0217, // + @@@@ .
106 0x4B5E,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x0217, // +@@@@@@.
107 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
108 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
109 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
110 0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217 // ........
113 uint16 downArrowBox[] = {
116 0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E, // ++++++++
117 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
118 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
119 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
120 0x4B5E,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x0217, // +@@@@@@.
121 0x4B5E,0x0000,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x0000,0x0217, // + @@@@ .
122 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
123 0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217 // ........
126 uint16 pushButtonUp[] = {
129 0x0000, 0x0C63, 0x394A, 0x494A, 0x4108, 0x2CC6, 0x0421, 0x0000,
130 0x0C63, 0x518C, 0x48E7, 0x48C6, 0x48A5, 0x48A5, 0x3CE7, 0x0421,
131 0x3D4A, 0x48E7, 0x48C6, 0x48C6, 0x44A5, 0x48A5, 0x48A5, 0x2CC6,
132 0x494A, 0x48C6, 0x48C6, 0x44A5, 0x44A5, 0x44A5, 0x48A5, 0x40E7,
133 0x4529, 0x48A5, 0x44A5, 0x44A5, 0x44A5, 0x44A5, 0x4CA5, 0x40E7,
134 0x2CC6, 0x48A5, 0x48A5, 0x44A5, 0x44A5, 0x48A5, 0x4CA5, 0x2CC6,
135 0x0421, 0x3CE7, 0x48A5, 0x48A5, 0x4CA5, 0x4CA5, 0x44E7, 0x0421,
136 0x0000, 0x0421, 0x28C6, 0x40E7, 0x40E7, 0x2CC6, 0x0421, 0x0000
140 0xFF, 0xE4, 0xA0, 0x99, 0xA4, 0xBE, 0xF0, 0xFF,
141 0xE3, 0x85, 0x00, 0x00, 0x00, 0x00, 0xAF, 0xF0,
142 0x9F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0,
143 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAD,
144 0xA3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAC,
145 0xBD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF,
146 0xF1, 0xAD, 0x00, 0x00, 0x00, 0x00, 0xAC, 0xF1,
147 0xFF, 0xF2, 0xC0, 0xAD, 0xAD, 0xC0, 0xF2, 0xFF
150 uint16 pushButtonDown[] = {
153 0x0000, 0x0C63, 0x4A31, 0x5631, 0x4DCE, 0x2D4A, 0x0421, 0x0000,
154 0x0C63, 0x6AF7, 0x714A, 0x7908, 0x7908, 0x6908, 0x418C, 0x0421,
155 0x4A31, 0x714A, 0x7508, 0x6CE7, 0x6CE7, 0x74E7, 0x68E7, 0x2929,
156 0x5A31, 0x7908, 0x6CE7, 0x6CE7, 0x6CE7, 0x6CE7, 0x78E7, 0x3D6B,
157 0x4DCE, 0x7908, 0x6CE7, 0x6CE7, 0x6CE7, 0x6CE7, 0x78E7, 0x416B,
158 0x2D4A, 0x6D08, 0x74E7, 0x6CE7, 0x6CE7, 0x74E7, 0x6CE7, 0x2929,
159 0x0842, 0x418C, 0x6CE7, 0x78E7, 0x78E7, 0x6CE7, 0x416B, 0x0842,
160 0x0000, 0x0842, 0x2929, 0x416B, 0x416B, 0x2929, 0x0842, 0x0000
164 0xFF, 0xE4, 0x72, 0x68, 0x7E, 0xA7, 0xF0, 0xFF,
165 0xE4, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x93, 0xF0,
166 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB2,
167 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A,
168 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A,
169 0xA6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB1,
170 0xEF, 0x91, 0x00, 0x00, 0x00, 0x00, 0x96, 0xEF,
171 0xFF, 0xEF, 0xAE, 0x98, 0x97, 0xAF, 0xEF, 0xFF
174 uint16 slideSwitchUp[] = {
177 0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E, // ++++++++
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 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
183 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
184 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
185 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
186 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
187 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
188 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
189 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
190 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
191 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
192 0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217 // ........
195 uint16 slideSwitchDown[] = {
198 0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E, // ++++++++
199 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
200 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
201 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
202 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
203 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
204 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
205 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
206 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
207 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
208 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
209 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
210 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
211 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
212 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
213 0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217 // ........
219 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
220 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
221 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
222 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
223 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
224 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
225 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
226 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 // ........
229 char separator[] = "--------------------------------------------------------";
232 // Case insensitive string compare function
233 // Taken straight out of Thinking In C++ by Bruce Eckel. Thanks Bruce!
236 int stringCmpi(const string &s1, const string &s2)
238 // Select the first element of each string:
239 string::const_iterator p1 = s1.begin(), p2 = s2.begin();
241 while (p1 != s1.end() && p2 != s2.end()) // Don
\92t run past the end
243 if (toupper(*p1) != toupper(*p2)) // Compare upper-cased chars
244 return (toupper(*p1) < toupper(*p2) ? -1 : 1);// Report which was lexically greater
250 // If they match up to the detected eos, say which was longer. Return 0 if the same.
251 return s2.size() - s1.size();
258 enum { WINDOW_CLOSE, MENU_ITEM_CHOSEN };
263 Element(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0)
264 { extents.x = x, extents.y = y, extents.w = w, extents.h = h; }
265 virtual void HandleKey(SDLKey key) = 0; // These are "pure" virtual functions...
266 virtual void HandleMouseMove(uint32 x, uint32 y) = 0;
267 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) = 0;
268 virtual void Draw(uint32, uint32) = 0;
269 virtual void Notify(Element *) = 0;
270 //Needed? virtual ~Element() = 0;
271 //We're not allocating anything in the base class, so the answer would be NO.
272 bool Inside(uint32 x, uint32 y);
274 static void SetScreenAndPitch(int16 * s, uint32 p) { screenBuffer = s, pitch = p; }
279 // Class variables...
280 static int16 * screenBuffer;
284 // Initialize class variables (Element)
285 int16 * Element::screenBuffer = NULL;
286 uint32 Element::pitch = 0;
288 bool Element::Inside(uint32 x, uint32 y)
290 return (x >= (uint32)extents.x && x < (uint32)(extents.x + extents.w)
291 && y >= (uint32)extents.y && y < (uint32)(extents.y + extents.h) ? true : false);
295 class Button: public Element
298 Button(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
299 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
300 bgColor(0x03E0), pic(NULL), elementToTell(NULL) {}
301 Button(uint32 x, uint32 y, uint32 w, uint32 h, uint16 * p): Element(x, y, w, h),
302 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
303 bgColor(0x03E0), pic(p), elementToTell(NULL) {}
304 Button(uint32 x, uint32 y, uint16 * p): Element(x, y, 0, 0),
305 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
306 bgColor(0x03E0), pic(p), elementToTell(NULL)
307 { if (pic) extents.w = pic[0], extents.h = pic[1]; }
308 Button(uint32 x, uint32 y, uint32 w, uint32 h, string s): Element(x, y, w, h),
309 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
310 bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL) {}
311 Button(uint32 x, uint32 y, string s): Element(x, y, 0, 8),
312 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
313 bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL)
314 { extents.w = s.length() * 8; }
315 virtual void HandleKey(SDLKey key) {}
316 virtual void HandleMouseMove(uint32 x, uint32 y);
317 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
318 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
319 virtual void Notify(Element *) {}
320 bool ButtonClicked(void) { return activated; }
321 void SetNotificationElement(Element * e) { elementToTell = e; }
324 bool activated, clicked, inside;
325 uint16 fgColor, bgColor;
328 Element * elementToTell;
331 void Button::HandleMouseMove(uint32 x, uint32 y)
333 inside = Inside(x, y);
336 void Button::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
343 if (clicked && !mouseDown)
345 clicked = false, activated = true;
347 // Send a message that we're activated (if there's someone to tell, that is)
349 elementToTell->Notify(this);
353 clicked = activated = false;
356 void Button::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
358 uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
360 for(uint32 y=0; y<extents.h; y++)
362 for(uint32 x=0; x<extents.w; x++)
364 // Doesn't clip in y axis! !!! FIX !!!
365 if (extents.x + x < pitch)
366 screenBuffer[addr + x + (y * pitch)]
367 = (clicked && inside ? fgColor : (inside ? 0x43F0 : bgColor));
372 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, pic);
374 if (text.length() > 0)
375 DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY, false, "%s", text.c_str());
379 class PushButton: public Element
382 // Save state externally?
383 //We pass in a state variable if we want to track it externally, otherwise we use our own
384 //internal state var. Still need to do some kind of callback for pushbuttons that do things
385 //like change from fullscreen to windowed... !!! FIX !!!
388 // PushButton(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
389 // activated(false), clicked(false), inside(false), fgColor(0xFFFF),
390 // bgColor(0x03E0), pic(NULL), elementToTell(NULL) {}
391 PushButton(uint32 x, uint32 y, bool * st, string s): Element(x, y, 8, 8), state(st),
392 inside(false), text(s) { if (st == NULL) state = &internalState; }
393 /* Button(uint32 x, uint32 y, uint32 w, uint32 h, uint16 * p): Element(x, y, w, h),
394 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
395 bgColor(0x03E0), pic(p), elementToTell(NULL) {}
396 Button(uint32 x, uint32 y, uint16 * p): Element(x, y, 0, 0),
397 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
398 bgColor(0x03E0), pic(p), elementToTell(NULL)
399 { if (pic) extents.w = pic[0], extents.h = pic[1]; }
400 Button(uint32 x, uint32 y, uint32 w, uint32 h, string s): Element(x, y, w, h),
401 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
402 bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL) {}
403 PushButton(uint32 x, uint32 y, string s): Element(x, y, 0, 8),
404 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
405 bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL)
406 { extents.w = s.length() * 8; }*/
407 virtual void HandleKey(SDLKey key) {}
408 virtual void HandleMouseMove(uint32 x, uint32 y);
409 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
410 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
411 virtual void Notify(Element *) {}
412 // bool ButtonClicked(void) { return activated; }
413 // void SetNotificationElement(Element * e) { elementToTell = e; }
418 // bool activated, clicked, inside;
419 // uint16 fgColor, bgColor;
422 // Element * elementToTell;
426 void PushButton::HandleMouseMove(uint32 x, uint32 y)
428 inside = Inside(x, y);
431 void PushButton::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
433 if (inside && mouseDown)
438 if (clicked && !mouseDown)
440 clicked = false, activated = true;
442 // Send a message that we're activated (if there's someone to tell, that is)
444 elementToTell->Notify(this);
449 // clicked = activated = false;
452 void PushButton::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
454 /* uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
456 for(uint32 y=0; y<extents.h; y++)
458 for(uint32 x=0; x<extents.w; x++)
460 // Doesn't clip in y axis! !!! FIX !!!
461 if (extents.x + x < pitch)
462 screenBuffer[addr + x + (y * pitch)]
463 = (clicked && inside ? fgColor : (inside ? 0x43F0 : bgColor));
467 // DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, (*state ? pushButtonDown : pushButtonUp));
468 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, (*state ? pushButtonDown : pushButtonUp), (*state ? pbdAlpha : pbuAlpha));
469 if (text.length() > 0)
470 DrawString(screenBuffer, extents.x + offsetX + 12, extents.y + offsetY, false, "%s", text.c_str());
474 class SlideSwitch: public Element
477 // Save state externally?
478 //Seems to be handled the same as PushButton, but without sanity checks. !!! FIX !!!
481 SlideSwitch(uint32 x, uint32 y, bool * st, string s1, string s2): Element(x, y, 8, 16), state(st),
482 inside(false), text1(s1), text2(s2) {}
483 virtual void HandleKey(SDLKey key) {}
484 virtual void HandleMouseMove(uint32 x, uint32 y);
485 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
486 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
487 virtual void Notify(Element *) {}
488 // bool ButtonClicked(void) { return activated; }
489 // void SetNotificationElement(Element * e) { elementToTell = e; }
494 // bool activated, clicked, inside;
495 // uint16 fgColor, bgColor;
498 // Element * elementToTell;
501 void SlideSwitch::HandleMouseMove(uint32 x, uint32 y)
503 inside = Inside(x, y);
506 void SlideSwitch::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
508 if (inside && mouseDown)
513 if (clicked && !mouseDown)
515 clicked = false, activated = true;
517 // Send a message that we're activated (if there's someone to tell, that is)
519 elementToTell->Notify(this);
524 // clicked = activated = false;
527 void SlideSwitch::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
529 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, (*state ? slideSwitchDown : slideSwitchUp));
530 if (text1.length() > 0)
531 DrawString(screenBuffer, extents.x + offsetX + 12, extents.y + offsetY, false, "%s", text1.c_str());
532 if (text2.length() > 0)
533 DrawString(screenBuffer, extents.x + offsetX + 12, extents.y + offsetY + 8, false, "%s", text2.c_str());
537 class Window: public Element
540 /* Window(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
541 fgColor(0x4FF0), bgColor(0xFE10)
542 { close = new Button(w - 8, 1, closeBox); list.push_back(close); }*/
543 Window(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0,
544 void (* f)(Element *) = NULL): Element(x, y, w, h),
545 /*clicked(false), inside(false),*/ fgColor(0x4FF0), bgColor(0x1E10),
547 { close = new Button(w - 8, 1, closeBox); list.push_back(close);
548 close->SetNotificationElement(this); }
550 virtual void HandleKey(SDLKey key);
551 virtual void HandleMouseMove(uint32 x, uint32 y);
552 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
553 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
554 virtual void Notify(Element * e);
555 void AddElement(Element * e);
556 // bool WindowActive(void) { return true; }//return !close->ButtonClicked(); }
559 // bool clicked, inside;
560 uint16 fgColor, bgColor;
561 void (* handler)(Element *);
563 //We have to use a list of Element *pointers* because we can't make a list that will hold
564 //all the different object types in the same list...
565 vector<Element *> list;
570 for(uint32 i=0; i<list.size(); i++)
575 void Window::HandleKey(SDLKey key)
577 if (key == SDLK_ESCAPE)
580 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
581 SDL_PushEvent(&event);
584 // Handle the items this window contains...
585 for(uint32 i=0; i<list.size(); i++)
586 // Make coords relative to upper right corner of this window...
587 list[i]->HandleKey(key);
590 void Window::HandleMouseMove(uint32 x, uint32 y)
592 // Handle the items this window contains...
593 for(uint32 i=0; i<list.size(); i++)
594 // Make coords relative to upper right corner of this window...
595 list[i]->HandleMouseMove(x - extents.x, y - extents.y);
598 void Window::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
600 // Handle the items this window contains...
601 for(uint32 i=0; i<list.size(); i++)
602 // Make coords relative to upper right corner of this window...
603 list[i]->HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
606 void Window::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
608 uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
610 for(uint32 y=0; y<extents.h; y++)
612 for(uint32 x=0; x<extents.w; x++)
614 // Doesn't clip in y axis! !!! FIX !!!
615 if (extents.x + x < pitch)
616 screenBuffer[addr + x + (y * pitch)] = bgColor;
620 // Handle the items this window contains...
621 for(uint32 i=0; i<list.size(); i++)
622 list[i]->Draw(extents.x, extents.y);
625 void Window::AddElement(Element * e)
630 void Window::Notify(Element * e)
635 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
636 SDL_PushEvent(&event);
641 class Text: public Element
644 Text(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
645 fgColor(0x4FF0), bgColor(0xFE10) {}
646 Text(uint32 x, uint32 y, string s, uint16 fg = 0x4FF0, uint16 bg = 0xFE10): Element(x, y, 0, 0),
647 fgColor(fg), bgColor(bg), text(s) {}
648 virtual void HandleKey(SDLKey key) {}
649 virtual void HandleMouseMove(uint32 x, uint32 y) {}
650 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) {}
651 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
652 virtual void Notify(Element *) {}
655 uint16 fgColor, bgColor;
659 void Text::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
661 if (text.length() > 0)
662 // DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY, false, "%s", text.c_str());
663 DrawStringOpaque(screenBuffer, extents.x + offsetX, extents.y + offsetY, fgColor, bgColor, "%s", text.c_str());
667 class ListBox: public Element
668 //class ListBox: public Window
671 // ListBox(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
672 ListBox(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0);//: Window(x, y, w, h),
673 // windowPtr(0), cursor(0), limit(0), charWidth((w / 8) - 1), charHeight(h / 8),
674 // elementToTell(NULL), upArrow(w - 8, 0, upArrowBox),
675 // downArrow(w - 8, h - 8, downArrowBox), upArrow2(w - 8, h - 16, upArrowBox) {}
676 virtual void HandleKey(SDLKey key);
677 virtual void HandleMouseMove(uint32 x, uint32 y);
678 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
679 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
680 virtual void Notify(Element * e);
681 void SetNotificationElement(Element * e) { elementToTell = e; }
682 void AddItem(string s);
683 string GetSelectedItem(void);
687 uint32 windowPtr, cursor, limit;
688 uint32 charWidth, charHeight; // Box width/height in characters
689 Element * elementToTell;
690 Button upArrow, downArrow, upArrow2;
694 uint32 yRelativePoint;
697 ListBox::ListBox(uint32 x, uint32 y, uint32 w, uint32 h): Element(x, y, w, h),
698 thumbClicked(false), windowPtr(0), cursor(0), limit(0), charWidth((w / 8) - 1),
699 charHeight(h / 8), elementToTell(NULL), upArrow(w - 8, 0, upArrowBox),
700 downArrow(w - 8, h - 8, downArrowBox), upArrow2(w - 8, h - 16, upArrowBox)
702 upArrow.SetNotificationElement(this);
703 downArrow.SetNotificationElement(this);
704 upArrow2.SetNotificationElement(this);
705 extents.w -= 8; // Make room for scrollbar...
708 void ListBox::HandleKey(SDLKey key)
710 if (key == SDLK_DOWN)
712 if (cursor != limit - 1) // Cursor is within its window
714 else // Otherwise, scroll the window...
716 if (cursor + windowPtr != item.size() - 1)
720 else if (key == SDLK_UP)
730 else if (key == SDLK_PAGEDOWN)
732 if (cursor != limit - 1)
737 if (windowPtr > item.size() - limit)
738 windowPtr = item.size() - limit;
741 else if (key == SDLK_PAGEUP)
747 if (windowPtr < limit)
753 else if (key >= SDLK_a && key <= SDLK_z)
755 // Advance cursor to filename with first letter pressed...
756 uint8 which = (key - SDLK_a) + 65; // Convert key to A-Z char
758 for(uint32 i=0; i<item.size(); i++)
760 if ((item[i][0] & 0xDF) == which)
762 cursor = i - windowPtr;
763 if (i > windowPtr + limit - 1)
764 windowPtr = i - limit + 1, cursor = limit - 1;
766 windowPtr = i, cursor = 0;
773 void ListBox::HandleMouseMove(uint32 x, uint32 y)
775 upArrow.HandleMouseMove(x - extents.x, y - extents.y);
776 downArrow.HandleMouseMove(x - extents.x, y - extents.y);
777 upArrow2.HandleMouseMove(x - extents.x, y - extents.y);
781 uint32 sbHeight = extents.h - 24,
782 thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight);
784 //yRelativePoint is the spot on the thumb where we clicked...
785 int32 newThumbStart = y - yRelativePoint;
787 if (newThumbStart < 0)
790 if ((uint32)newThumbStart > sbHeight - thumb)
791 newThumbStart = sbHeight - thumb;
793 windowPtr = (uint32)(((float)newThumbStart / (float)sbHeight) * (float)item.size());
794 //Check for cursor bounds as well... Or do we need to???
795 //Actually, we don't...!
799 void ListBox::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
801 if (Inside(x, y) && mouseDown)
803 // Why do we have to do this??? (- extents.y?)
804 // I guess it's because only the Window class has offsetting implemented... !!! FIX !!!
805 cursor = (y - extents.y) / 8;
808 // Check for a hit on the scrollbar...
809 if (x > (uint32)(extents.x + extents.w) && x <= (uint32)(extents.x + extents.w + 8)
810 && y > (uint32)(extents.y + 8) && y <= (uint32)(extents.y + extents.h - 16))
814 // This shiaut should be calculated in AddItem(), not here... (or in Draw() for that matter)
815 uint32 sbHeight = extents.h - 24,
816 thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight),
817 thumbStart = (uint32)(((float)windowPtr / (float)item.size()) * (float)sbHeight);
819 // Did we hit the thumb?
820 if (y >= (extents.y + 8 + thumbStart) && y < (extents.y + 8 + thumbStart + thumb))
821 thumbClicked = true, yRelativePoint = y - thumbStart;
823 //Seems that this is useless--never reached except in rare cases and that the code outside is
826 // thumbClicked = false;
830 thumbClicked = false;
832 upArrow.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
833 downArrow.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
834 upArrow2.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
837 void ListBox::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
839 for(uint32 i=0; i<limit; i++)
841 // Strip off the extension
842 // (extension stripping should be an option, not default!)
843 string s(item[windowPtr + i], 0, item[windowPtr + i].length() - 4);
844 DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY + i*8,
845 (cursor == i ? true : false), "%-*.*s", charWidth, charWidth, s.c_str());
848 upArrow.Draw(extents.x + offsetX, extents.y + offsetY);
849 downArrow.Draw(extents.x + offsetX, extents.y + offsetY);
850 upArrow2.Draw(extents.x + offsetX, extents.y + offsetY);
852 uint32 sbHeight = extents.h - 24,
853 thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight),
854 thumbStart = (uint32)(((float)windowPtr / (float)item.size()) * (float)sbHeight);
856 for(uint32 y=extents.y+offsetY+8; y<extents.y+offsetY+extents.h-16; y++)
858 // for(uint32 x=extents.x+offsetX+extents.w-8; x<extents.x+offsetX+extents.w; x++)
859 for(uint32 x=extents.x+offsetX+extents.w; x<extents.x+offsetX+extents.w+8; x++)
861 if (y >= thumbStart + (extents.y+offsetY+8) && y < thumbStart + thumb + (extents.y+offsetY+8))
862 screenBuffer[x + (y * pitch)] = (thumbClicked ? 0x458E : 0xFFFF);
864 screenBuffer[x + (y * pitch)] = 0x0200;
869 void ListBox::Notify(Element * e)
871 if (e == &upArrow || e == &upArrow2)
877 if (cursor < limit - 1)
881 else if (e == &downArrow)
883 if (windowPtr < item.size() - limit)
893 void ListBox::AddItem(string s)
895 // Do a simple insertion sort
896 bool inserted = false;
898 for(vector<string>::iterator i=item.begin(); i<item.end(); i++)
900 if (stringCmpi(s, *i) == -1)
911 limit = (item.size() > charHeight ? charHeight : item.size());
914 string ListBox::GetSelectedItem(void)
916 return item[windowPtr + cursor];
920 class FileList: public Window
923 FileList(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0);
924 virtual ~FileList() {}
925 virtual void HandleKey(SDLKey key);
926 virtual void HandleMouseMove(uint32 x, uint32 y) { Window::HandleMouseMove(x, y); }
927 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) { Window::HandleMouseButton(x, y, mouseDown); }
928 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0) { Window::Draw(offsetX, offsetY); }
929 virtual void Notify(Element * e);
936 //Need 4 buttons, one scrollbar...
937 FileList::FileList(uint32 x, uint32 y, uint32 w, uint32 h): Window(x, y, w, h)
939 files = new ListBox(8, 8, w - 16, h - 32);
941 load = new Button(8, h - 16, " Load ");
943 load->SetNotificationElement(this);
945 //!!! FIX !!! Directory might not exist--this shouldn't cause VJ to crash!
946 DIR * dp = opendir(vjs.ROMPath);
949 while ((de = readdir(dp)) != NULL)
951 char * ext = strrchr(de->d_name, '.');
954 if (strcasecmp(ext, ".zip") == 0 || strcasecmp(ext, ".j64") == 0
955 || strcasecmp(ext, ".abs") == 0 || strcasecmp(ext, ".jag") == 0
956 || strcasecmp(ext, ".rom") == 0)
957 files->AddItem(string(de->d_name));
963 void FileList::HandleKey(SDLKey key)
965 if (key == SDLK_RETURN)
968 Window::HandleKey(key);
971 void FileList::Notify(Element * e)
975 char filename[MAX_PATH];
976 strcpy(filename, vjs.ROMPath);
978 if (strlen(filename) > 0)
979 if (filename[strlen(filename) - 1] != '/')
980 strcat(filename, "/");
982 strcat(filename, files->GetSelectedItem().c_str());
984 // uint32 romSize = JaguarLoadROM(jaguar_mainRom, filename);
985 // JaguarLoadCart(jaguar_mainRom, filename);
986 if (JaguarLoadFile(filename))
989 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
990 SDL_PushEvent(&event);
992 event.type = SDL_USEREVENT, event.user.code = MENU_ITEM_CHOSEN;
993 event.user.data1 = (void *)ResetJaguar;
994 SDL_PushEvent(&event);
999 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
1000 SDL_PushEvent(&event);
1002 // Handle the error, but don't run...
1003 // Tell the user that we couldn't run their file for some reason... !!! FIX !!!
1004 //how to kludge: Make a function like ResetJaguar which creates the dialog window
1015 Window * (* action)(void);
1018 NameAction(string n, Window * (* a)(void) = NULL, SDLKey k = SDLK_UNKNOWN): name(n),
1019 action(a), hotKey(k) {}
1026 MenuItems(): charLength(0) {}
1027 bool Inside(uint32 x, uint32 y)
1028 { return (x >= (uint32)extents.x && x < (uint32)(extents.x + extents.w)
1029 && y >= (uint32)extents.y && y < (uint32)(extents.y + extents.h) ? true : false); }
1032 vector<NameAction> item;
1037 class Menu: public Element
1040 Menu(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 8,
1041 uint16 fgc = 0x1CFF, uint16 bgc = 0x000F, uint16 fgch = 0x421F,
1042 uint16 bgch = 0x1CFF): Element(x, y, w, h), activated(false), clicked(false),
1043 inside(0), insidePopup(0), fgColor(fgc), bgColor(bgc), fgColorHL(fgch),
1044 bgColorHL(bgch), menuChosen(-1), menuItemChosen(-1) {}
1045 virtual void HandleKey(SDLKey key);
1046 virtual void HandleMouseMove(uint32 x, uint32 y);
1047 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
1048 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
1049 virtual void Notify(Element *) {}
1050 void Add(MenuItems mi);
1053 bool activated, clicked;
1054 uint32 inside, insidePopup;
1055 uint16 fgColor, bgColor, fgColorHL, bgColorHL;
1056 int menuChosen, menuItemChosen;
1059 vector<MenuItems> itemList;
1062 void Menu::HandleKey(SDLKey key)
1064 for(uint32 i=0; i<itemList.size(); i++)
1066 for(uint32 j=0; j<itemList[i].item.size(); j++)
1068 if (itemList[i].item[j].hotKey == key)
1071 event.type = SDL_USEREVENT;
1072 event.user.code = MENU_ITEM_CHOSEN;
1073 event.user.data1 = (void *)itemList[i].item[j].action;
1074 SDL_PushEvent(&event);
1076 clicked = false, menuChosen = menuItemChosen = -1;
1083 void Menu::HandleMouseMove(uint32 x, uint32 y)
1085 inside = insidePopup = 0;
1089 // Find out *where* we are inside the menu bar
1090 uint32 xpos = extents.x;
1092 for(uint32 i=0; i<itemList.size(); i++)
1094 uint32 width = (itemList[i].title.length() + 2) * 8;
1096 if (x >= xpos && x < xpos + width)
1107 if (!Inside(x, y) && !clicked)
1112 if (itemList[menuChosen].Inside(x, y) && clicked)
1114 insidePopup = ((y - itemList[menuChosen].extents.y) / 8) + 1;
1115 menuItemChosen = insidePopup - 1;
1119 void Menu::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
1128 menuChosen = -1; // clicked is already false...!
1131 else // clicked == true
1133 if (insidePopup && !mouseDown) // I.e., mouse-button-up
1136 if (itemList[menuChosen].item[menuItemChosen].action != NULL)
1138 // itemList[menuChosen].item[menuItemChosen].action();
1140 event.type = SDL_USEREVENT;
1141 event.user.code = MENU_ITEM_CHOSEN;
1142 event.user.data1 = (void *)itemList[menuChosen].item[menuItemChosen].action;
1143 SDL_PushEvent(&event);
1145 clicked = false, menuChosen = menuItemChosen = -1;
1148 while (SDL_PollEvent(&event)); // Flush the event queue...
1149 event.type = SDL_MOUSEMOTION;
1151 SDL_GetMouseState(&mx, &my);
1152 event.motion.x = mx, event.motion.y = my;
1153 SDL_PushEvent(&event); // & update mouse position...!
1157 if (!inside && !insidePopup && mouseDown)
1158 clicked = false, menuChosen = menuItemChosen = -1;
1162 void Menu::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
1164 uint32 xpos = extents.x + offsetX;
1166 for(uint32 i=0; i<itemList.size(); i++)
1168 uint16 color1 = fgColor, color2 = bgColor;
1169 if (inside == (i + 1) || (menuChosen != -1 && (uint32)menuChosen == i))
1170 color1 = fgColorHL, color2 = bgColorHL;
1172 DrawStringOpaque(screenBuffer, xpos, extents.y + offsetY, color1, color2,
1173 " %s ", itemList[i].title.c_str());
1174 xpos += (itemList[i].title.length() + 2) * 8;
1177 // Draw sub menu (but only if active)
1180 uint32 ypos = extents.y + 9;
1182 for(uint32 i=0; i<itemList[menuChosen].item.size(); i++)
1184 uint16 color1 = fgColor, color2 = bgColor;
1186 if (insidePopup == i + 1)
1187 color1 = fgColorHL, color2 = bgColorHL, menuItemChosen = i;
1189 if (itemList[menuChosen].item[i].name.length() > 0)
1190 DrawStringOpaque(screenBuffer, itemList[menuChosen].extents.x, ypos,
1191 color1, color2, " %-*.*s ", itemList[menuChosen].charLength,
1192 itemList[menuChosen].charLength, itemList[menuChosen].item[i].name.c_str());
1194 DrawStringOpaque(screenBuffer, itemList[menuChosen].extents.x, ypos,
1195 fgColor, bgColor, "%.*s", itemList[menuChosen].charLength + 2, separator);
1202 void Menu::Add(MenuItems mi)
1204 for(uint32 i=0; i<mi.item.size(); i++)
1205 if (mi.item[i].name.length() > mi.charLength)
1206 mi.charLength = mi.item[i].name.length();
1208 // Set extents here as well...
1209 mi.extents.x = extents.x + extents.w, mi.extents.y = extents.y + 9;
1210 mi.extents.w = (mi.charLength + 2) * 8, mi.extents.h = mi.item.size() * 8;
1212 itemList.push_back(mi);
1213 extents.w += (mi.title.length() + 2) * 8;
1217 //Do we even *need* this?
1218 //Doesn't seem like it...
1219 /*class RootWindow: public Window
1222 RootWindow(Menu * m, Window * w = NULL): menu(m), window(w) {}
1223 //Do we even need to care about this crap?
1224 // { extents.x = extents.y = 0, extents.w = 320, extents.h = 240; }
1225 virtual void HandleKey(SDLKey key) {}
1226 virtual void HandleMouseMove(uint32 x, uint32 y) {}
1227 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) {}
1228 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0) {}
1229 virtual void Notify(Element *) {}
1234 int16 * rootImage[1280 * 240 * 2];
1239 // Draw text at the given x/y coordinates. Can invert text as well.
1241 void DrawString(int16 * screen, uint32 x, uint32 y, bool invert, const char * text, ...)
1246 va_start(arg, text);
1247 vsprintf(string, text, arg);
1250 uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1251 uint32 length = strlen(string), address = x + (y * pitch);
1253 for(uint32 i=0; i<length; i++)
1255 uint32 fontAddr = (uint32)string[i] * 64;
1257 for(uint32 yy=0; yy<8; yy++)
1259 for(uint32 xx=0; xx<8; xx++)
1261 if ((font1[fontAddr] && !invert) || (!font1[fontAddr] && invert))
1262 *(screen + address + xx + (yy * pitch)) = 0xFE00;
1272 // Draw text at the given x/y coordinates, using FG/BG colors.
1274 void DrawStringOpaque(int16 * screen, uint32 x, uint32 y, uint16 color1, uint16 color2, const char * text, ...)
1279 va_start(arg, text);
1280 vsprintf(string, text, arg);
1283 uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1284 uint32 length = strlen(string), address = x + (y * pitch);
1286 for(uint32 i=0; i<length; i++)
1288 uint32 fontAddr = (uint32)string[i] * 64;
1290 for(uint32 yy=0; yy<8; yy++)
1292 for(uint32 xx=0; xx<8; xx++)
1294 *(screen + address + xx + (yy * pitch)) = (font1[fontAddr] ? color1 : color2);
1304 // Draw text at the given x/y coordinates with transparency (0 is fully opaque, 32 is fully transparent).
1306 void DrawStringTrans(int16 * screen, uint32 x, uint32 y, uint16 color, uint8 trans, const char * text, ...)
1311 va_start(arg, text);
1312 vsprintf(string, text, arg);
1315 uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1316 uint32 length = strlen(string), address = x + (y * pitch);
1318 for(uint32 i=0; i<length; i++)
1320 uint32 fontAddr = (uint32)string[i] * 64;
1322 for(uint32 yy=0; yy<8; yy++)
1324 for(uint32 xx=0; xx<8; xx++)
1326 if (font1[fontAddr])
1328 uint16 existingColor = *(screen + address + xx + (yy * pitch));
1330 uint8 eRed = (existingColor >> 10) & 0x1F,
1331 eGreen = (existingColor >> 5) & 0x1F,
1332 eBlue = existingColor & 0x1F,
1333 //This could be done ahead of time, instead of on each pixel...
1334 nRed = (color >> 10) & 0x1F,
1335 nGreen = (color >> 5) & 0x1F,
1336 nBlue = color & 0x1F;
1338 //This could be sped up by using a table of 5 + 5 + 5 bits (32 levels transparency -> 32768 entries)
1339 //Here we've modified it to have 33 levels of transparency (could have any # we want!)
1340 //because dividing by 32 is faster than dividing by 31...!
1341 uint8 invTrans = 32 - trans;
1342 uint16 bRed = (eRed * trans + nRed * invTrans) / 32;
1343 uint16 bGreen = (eGreen * trans + nGreen * invTrans) / 32;
1344 uint16 bBlue = (eBlue * trans + nBlue * invTrans) / 32;
1346 uint16 blendedColor = (bRed << 10) | (bGreen << 5) | bBlue;
1348 *(screen + address + xx + (yy * pitch)) = blendedColor;
1361 // Uses zero as transparent color
1362 // Can also use an optional alpha channel
1364 void DrawTransparentBitmap(int16 * screen, uint32 x, uint32 y, uint16 * bitmap, uint8 * alpha/*=NULL*/)
1366 uint16 width = bitmap[0], height = bitmap[1];
1369 uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1370 uint32 address = x + (y * pitch);
1372 for(int yy=0; yy<height; yy++)
1374 for(int xx=0; xx<width; xx++)
1378 if (*bitmap && x + xx < pitch) // NOTE: Still doesn't clip the Y val...
1379 *(screen + address + xx + (yy * pitch)) = *bitmap;
1383 uint8 trans = *alpha;
1384 uint16 color = *bitmap;
1385 uint16 existingColor = *(screen + address + xx + (yy * pitch));
1387 uint8 eRed = (existingColor >> 10) & 0x1F,
1388 eGreen = (existingColor >> 5) & 0x1F,
1389 eBlue = existingColor & 0x1F,
1391 nRed = (color >> 10) & 0x1F,
1392 nGreen = (color >> 5) & 0x1F,
1393 nBlue = color & 0x1F;
1395 uint8 invTrans = 255 - trans;
1396 uint16 bRed = (eRed * trans + nRed * invTrans) / 255;
1397 uint16 bGreen = (eGreen * trans + nGreen * invTrans) / 255;
1398 uint16 bBlue = (eBlue * trans + nBlue * invTrans) / 255;
1400 uint16 blendedColor = (bRed << 10) | (bGreen << 5) | bBlue;
1402 *(screen + address + xx + (yy * pitch)) = blendedColor;
1414 // GUI stuff--it's not crunchy, it's GUI! ;-)
1419 SDL_ShowCursor(SDL_DISABLE);
1420 SDL_GetMouseState(&mouseX, &mouseY);
1430 //bool GUIMain(void)
1431 bool GUIMain(char * filename)
1433 WriteLog("GUI: Inside GUIMain...\n");
1434 // Need to set things up so that it loads and runs a file if given on the command line. !!! FIX !!!
1435 extern int16 * backbuffer;
1436 // bool done = false;
1438 Window * mainWindow = NULL;
1440 // Set up the GUI classes...
1441 Element::SetScreenAndPitch(backbuffer, GetSDLScreenPitch() / 2);
1445 mi.title = "Jaguar";
1446 mi.item.push_back(NameAction("Load...", LoadROM, SDLK_l));
1447 mi.item.push_back(NameAction("Reset", ResetJaguar, SDLK_r));
1449 mi.item.push_back(NameAction("Reset CD", ResetJaguarCD, SDLK_c));
1450 mi.item.push_back(NameAction("Run", RunEmu, SDLK_ESCAPE));
1451 mi.item.push_back(NameAction(""));
1452 mi.item.push_back(NameAction("Quit", Quit, SDLK_q));
1454 mi.title = "Settings";
1456 mi.item.push_back(NameAction("Video..."));
1457 mi.item.push_back(NameAction("Audio..."));
1458 mi.item.push_back(NameAction("Misc...", MiscOptions, SDLK_m));
1462 mi.item.push_back(NameAction("About...", About));
1465 bool showMouse = true;
1467 //This is crappy!!! !!! FIX !!!
1468 //Is this even needed any more? Hmm. Maybe. Dunno.
1469 WriteLog("GUI: Resetting Jaguar...\n");
1472 WriteLog("GUI: Clearing BG save...\n");
1473 // Set up our background save...
1474 memset(background, 0x11, tom_getVideoModeWidth() * 240 * 2);
1476 // Handle loading file passed in on the command line...!
1480 if (JaguarLoadFile(filename))
1482 event.type = SDL_USEREVENT, event.user.code = MENU_ITEM_CHOSEN;
1483 event.user.data1 = (void *)ResetJaguar;
1484 SDL_PushEvent(&event);
1488 // Create error dialog...
1490 sprintf(errText, "The file %40s could no be loaded.", filename);
1492 mainWindow = new Window(8, 16, 304, 160);
1493 mainWindow->AddElement(new Text(8, 8, "Error!"));
1494 mainWindow->AddElement(new Text(8, 24, errText));
1498 WriteLog("GUI: Entering main loop...\n");
1501 if (SDL_PollEvent(&event))
1503 if (event.type == SDL_USEREVENT)
1505 if (event.user.code == WINDOW_CLOSE)
1510 else if (event.user.code == MENU_ITEM_CHOSEN)
1512 // Confused? Let me enlighten... What we're doing here is casting
1513 // data1 as a pointer to a function which returns a Window pointer and
1514 // which takes no parameters (the "(Window *(*)(void))" part), then
1515 // derefencing it (the "*" in front of that) in order to call the
1516 // function that it points to. Clear as mud? Yeah, I hate function
1517 // pointers too, but what else are you gonna do?
1518 mainWindow = (*(Window *(*)(void))event.user.data1)();
1520 while (SDL_PollEvent(&event)); // Flush the event queue...
1521 event.type = SDL_MOUSEMOTION;
1523 SDL_GetMouseState(&mx, &my);
1524 event.motion.x = mx, event.motion.y = my;
1525 SDL_PushEvent(&event); // & update mouse position...!
1527 mouseX = mx, mouseY = my; // This prevents "mouse flash"...
1529 mouseX /= 2, mouseY /= 2;
1532 else if (event.type == SDL_ACTIVEEVENT)
1534 if (event.active.state == SDL_APPMOUSEFOCUS)
1535 showMouse = (event.active.gain ? true : false);
1537 else if (event.type == SDL_KEYDOWN)
1540 mainWindow->HandleKey(event.key.keysym.sym);
1542 mainMenu.HandleKey(event.key.keysym.sym);
1544 else if (event.type == SDL_MOUSEMOTION)
1546 mouseX = event.motion.x, mouseY = event.motion.y;
1549 mouseX /= 2, mouseY /= 2;
1552 mainWindow->HandleMouseMove(mouseX, mouseY);
1554 mainMenu.HandleMouseMove(mouseX, mouseY);
1556 else if (event.type == SDL_MOUSEBUTTONDOWN)
1558 uint32 mx = event.button.x, my = event.button.y;
1564 mainWindow->HandleMouseButton(mx, my, true);
1566 mainMenu.HandleMouseButton(mx, my, true);
1568 else if (event.type == SDL_MOUSEBUTTONUP)
1570 uint32 mx = event.button.x, my = event.button.y;
1576 mainWindow->HandleMouseButton(mx, my, false);
1578 mainMenu.HandleMouseButton(mx, my, false);
1582 // The way we do things here is kinda stupid (redrawing the screen every frame), but
1583 // it's simple. Perhaps there may be a reason down the road to be more selective with
1584 // our clearing, but for now, this will suffice.
1585 // memset(backbuffer, 0x11, tom_getVideoModeWidth() * 240 * 2);
1586 memcpy(backbuffer, background, tom_getVideoModeWidth() * 256 * 2);
1589 //Could do multiple windows here by using a vector + priority info...
1590 //Though the way ZSNES does it seems to be by a bool (i.e., they're always active, just not shown)
1595 DrawTransparentBitmap(backbuffer, mouseX, mouseY, mousePic);
1605 // GUI "action" functions
1608 Window * LoadROM(void)
1610 FileList * fileList = new FileList(8, 16, 304, 216);
1612 return (Window *)fileList;
1615 Window * ResetJaguar(void)
1622 Window * ResetJaguarCD(void)
1624 memcpy(jaguar_mainRom, jaguar_CDBootROM, 0x40000);
1625 jaguarRunAddress = 0x802000;
1626 jaguar_mainRom_crc32 = crc32_calcCheckSum(jaguar_mainRom, 0x40000);
1628 //This is a quick kludge to get the CDBIOS to boot properly...
1629 //Wild speculation: It could be that this memory location is wired into the CD unit
1630 //somehow, which lets it know whether or not a cart is present in the unit...
1631 jaguar_mainRom[0x0040B] = 0x03;
1636 bool debounceRunKey = true;
1637 Window * RunEmu(void)
1639 //This is crappy... !!! FIX !!!
1640 extern int16 * backbuffer;
1641 extern bool finished, showGUI;
1643 uint32 nFrame = 0, nFrameskip = 0;
1644 uint32 totalFrames = 0;
1646 bool showMessage = true;
1647 uint32 showMsgFrames = 120;
1648 uint8 transparency = 0;
1649 // Pass a message to the "joystick" code to debounce the ESC key...
1650 debounceRunKey = true;
1652 uint32 cartType = 4;
1653 if (jaguarRomSize == 0x200000)
1655 else if (jaguarRomSize == 0x400000)
1657 else if (jaguar_mainRom_crc32 == 0x687068D5)
1659 else if (jaguar_mainRom_crc32 == 0x55A0669C)
1662 char * cartTypeName[5] = { "2M Cartridge", "4M Cartridge", "CD BIOS", "CD Dev BIOS", "Homebrew" };
1664 // while (!finished)
1667 // Set up new backbuffer with new pixels and data
1668 JaguarExecute(backbuffer, true);
1670 //WriteLog("Frame #%u...\n", totalFrames);
1671 //extern bool doDSPDis;
1672 //if (totalFrames == 373)
1675 //This sucks... !!! FIX !!!
1677 //This is done here so that the crud below doesn't get on our GUI background...
1681 // Some QnD GUI stuff here...
1684 extern uint32 gpu_pc, dsp_pc;
1685 DrawString(backbuffer, 8, 8, false, "GPU PC: %08X", gpu_pc);
1686 DrawString(backbuffer, 8, 16, false, "DSP PC: %08X", dsp_pc);
1691 DrawStringTrans(backbuffer, 8, 24*8, 0xFF0F, transparency, "Running...");
1692 DrawStringTrans(backbuffer, 8, 26*8, 0x3FE3, transparency, "%s, run address: %06X", cartTypeName[cartType], jaguarRunAddress);
1693 DrawStringTrans(backbuffer, 8, 27*8, 0x3FE3, transparency, "CRC: %08X", jaguar_mainRom_crc32);
1695 if (showMsgFrames == 0)
1699 if (transparency == 33)
1701 showMessage = false;
1702 /*extern bool doGPUDis;
1703 doGPUDis = true;//*/
1712 if (nFrame == nFrameskip)
1721 // Reset the pitch, since it may have been changed in-game...
1722 Element::SetScreenAndPitch(backbuffer, GetSDLScreenPitch() / 2);
1724 // Save the background for the GUI...
1725 // memcpy(background, backbuffer, tom_getVideoModeWidth() * 240 * 2);
1726 // In this case, we squash the color to monochrome, then force it to blue + green...
1727 for(uint32 i=0; i<tom_getVideoModeWidth() * 256; i++)
1729 uint16 word = backbuffer[i];
1730 uint8 r = (word >> 10) & 0x1F, g = (word >> 5) & 0x1F, b = word & 0x1F;
1731 word = ((r + g + b) / 3) & 0x001F;
1732 word = (word << 5) | word;
1733 background[i] = word;
1741 WriteLog("GUI: Quitting due to user request.\n");
1747 Window * About(void)
1749 Window * window = new Window(8, 16, 304, 160);
1750 window->AddElement(new Text(8, 8, "Virtual Jaguar 1.0.7"));
1751 // window->AddElement(new Text(8, 8, "Virtual Jaguar CVS 20040417"));
1752 window->AddElement(new Text(8, 24, "Coders:"));
1753 window->AddElement(new Text(16, 32, "Niels Wagenaar (nwagenaar)"));
1754 window->AddElement(new Text(16, 40, "Carwin Jones (Caz)"));
1755 window->AddElement(new Text(16, 48, "James L. Hammons (shamus)"));
1756 window->AddElement(new Text(16, 56, "Adam Green"));
1757 window->AddElement(new Text(8, 72, "Testers:"));
1758 window->AddElement(new Text(16, 80, "Guruma"));
1759 window->AddElement(new Text(8, 96, "Thanks go out to:"));
1760 window->AddElement(new Text(16, 104, "Aaron Giles (original CoJag)"));
1761 window->AddElement(new Text(16, 112, "David Raingeard (original VJ)"));
1762 window->AddElement(new Text(16, 120, "Karl Stenerud (Musashi 68K emu)"));
1763 window->AddElement(new Text(16, 128, "Sam Lantinga (amazing SDL libs)"));
1764 window->AddElement(new Text(16, 136, "Ryan C. Gordon (VJ's web presence)"));
1765 window->AddElement(new Text(16, 144, "The guys over at Atari Age ;-)"));
1770 Window * MiscOptions(void)
1772 Window * window = new Window(8, 16, 304, 160);
1773 window->AddElement(new PushButton(8, 8, &vjs.useJaguarBIOS, "BIOS"));
1774 window->AddElement(new SlideSwitch(8, 20, &vjs.hardwareTypeNTSC, "PAL", "NTSC"));
1775 window->AddElement(new PushButton(8, 40, &vjs.DSPEnabled, "DSP"));
1776 window->AddElement(new SlideSwitch(16, 52, &vjs.usePipelinedDSP, "Original", "Pipelined"));
1777 window->AddElement(new SlideSwitch(8, 72, (bool *)&vjs.glFilter, "Sharp", "Blurry"));
1787 // * Window/fullscreen
1794 // Generic ROM loading
1796 uint32 JaguarLoadROM(uint8 * rom, char * path)
1798 // We really should have some kind of sanity checking for the ROM size here to prevent
1799 // a buffer overflow... !!! FIX !!!
1802 char * ext = strrchr(path, '.');
1805 WriteLog("VJ: Loading \"%s\"...", path);
1807 if (strcasecmp(ext, ".zip") == 0)
1809 // Handle ZIP file loading here...
1810 WriteLog("(ZIPped)...");
1812 if (load_zipped_file(0, 0, path, NULL, &rom, &romSize) == -1)
1814 WriteLog("Failed!\n");
1820 /* FILE * fp = fopen(path, "rb");
1824 WriteLog("Failed!\n");
1828 fseek(fp, 0, SEEK_END);
1829 romSize = ftell(fp);
1830 fseek(fp, 0, SEEK_SET);
1831 fread(rom, 1, romSize, fp);
1834 // Handle gzipped files transparently [Adam Green]...
1836 gzFile fp = gzopen(path, "rb");
1840 WriteLog("Failed!\n");
1844 romSize = gzfilelength(fp);
1845 gzseek(fp, 0, SEEK_SET);
1846 gzread(fp, rom, romSize);
1850 WriteLog("OK (%i bytes)\n", romSize);
1857 // Jaguar file loading
1859 bool JaguarLoadFile(char * path)
1861 // jaguarRomSize = JaguarLoadROM(mem, path);
1862 jaguarRomSize = JaguarLoadROM(jaguar_mainRom, path);
1864 /*//This is not *nix friendly for some reason...
1865 // if (!UserSelectFile(path, newPath))
1866 if (!UserSelectFile((strlen(path) == 0 ? (char *)"." : path), newPath))
1868 WriteLog("VJ: Could not find valid ROM in directory \"%s\"...\nAborting!\n", path);
1873 if (jaguarRomSize == 0)
1875 // WriteLog("VJ: Could not load ROM from file \"%s\"...\nAborting!\n", newPath);
1876 WriteLog("GUI: Could not load ROM from file \"%s\"...\nAborting load!\n", path);
1877 // Need to do something else here, like throw up an error dialog instead of aborting. !!! FIX !!!
1880 return false; // This is a start...
1883 jaguar_mainRom_crc32 = crc32_calcCheckSum(jaguar_mainRom, jaguarRomSize);
1884 WriteLog("CRC: %08X\n", (unsigned int)jaguar_mainRom_crc32);
1887 jaguarRunAddress = 0x802000;
1889 char * ext = strrchr(path, '.'); // Get the file's extension for non-cartridge checking
1891 //NOTE: Should fix JaguarLoadROM() to replace .zip with what's *in* the zip (.abs, .j64, etc.)
1892 if (strcasecmp(ext, ".rom") == 0)
1894 // File extension ".ROM": Alpine image that loads/runs at $802000
1895 WriteLog("GUI: Setting up homebrew (ROM)... Run address: 00802000, length: %08X\n", jaguarRomSize);
1897 for(int i=jaguarRomSize-1; i>=0; i--)
1898 jaguar_mainRom[0x2000 + i] = jaguar_mainRom[i];
1900 memset(jaguar_mainRom, 0xFF, 0x2000);
1901 /* memcpy(jaguar_mainRam, jaguar_mainRom, jaguarRomSize);
1902 memset(jaguar_mainRom, 0xFF, 0x600000);
1903 memcpy(jaguar_mainRom + 0x2000, jaguar_mainRam, jaguarRomSize);
1904 memset(jaguar_mainRam, 0x00, 0x400000);*/
1907 Stubulator ROM vectors...
1908 handler 001 at $00E00008
1909 handler 002 at $00E008DE
1910 handler 003 at $00E008E2
1911 handler 004 at $00E008E6
1912 handler 005 at $00E008EA
1913 handler 006 at $00E008EE
1914 handler 007 at $00E008F2
1915 handler 008 at $00E0054A
1916 handler 009 at $00E008FA
1917 handler 010 at $00000000
1918 handler 011 at $00000000
1919 handler 012 at $00E008FE
1920 handler 013 at $00E00902
1921 handler 014 at $00E00906
1922 handler 015 at $00E0090A
1923 handler 016 at $00E0090E
1924 handler 017 at $00E00912
1925 handler 018 at $00E00916
1926 handler 019 at $00E0091A
1927 handler 020 at $00E0091E
1928 handler 021 at $00E00922
1929 handler 022 at $00E00926
1930 handler 023 at $00E0092A
1931 handler 024 at $00E0092E
1932 handler 025 at $00E0107A
1933 handler 026 at $00E0107A
1934 handler 027 at $00E0107A
1935 handler 028 at $00E008DA
1936 handler 029 at $00E0107A
1937 handler 030 at $00E0107A
1938 handler 031 at $00E0107A
1939 handler 032 at $00000000
1941 Let's try setting up the illegal instruction vector for a stubulated jaguar...
1943 /* SET32(jaguar_mainRam, 0x08, 0x00E008DE);
1944 SET32(jaguar_mainRam, 0x0C, 0x00E008E2);
1945 SET32(jaguar_mainRam, 0x10, 0x00E008E6); // <-- Should be here (it is)...
1946 SET32(jaguar_mainRam, 0x14, 0x00E008EA);//*/
1948 // Try setting the vector to say, $1000 and putting an instruction there that loops forever:
1949 // This kludge works! Yeah!
1950 SET32(jaguar_mainRam, 0x10, 0x00001000);
1951 SET16(jaguar_mainRam, 0x1000, 0x60FE); // Here: bra Here
1953 else if (strcasecmp(ext, ".abs") == 0)
1955 // File extension ".ABS": Atari linker output file with header (w/o is useless to us here)
1958 ABS Format sleuthing (LBUGDEMO.ABS):
1960 000000 60 1B 00 00 05 0C 00 04 62 C0 00 00 04 28 00 00
1961 000010 12 A6 00 00 00 00 00 80 20 00 FF FF 00 80 25 0C
1964 DRI-format file detected...
1965 Text segment size = 0x0000050c bytes
1966 Data segment size = 0x000462c0 bytes
1967 BSS Segment size = 0x00000428 bytes
1968 Symbol Table size = 0x000012a6 bytes
1969 Absolute Address for text segment = 0x00802000
1970 Absolute Address for data segment = 0x0080250c
1971 Absolute Address for BSS segment = 0x00004000
1974 000000 01 50 00 03 00 00 00 00 00 03 83 10 00 00 05 3b
1975 000010 00 1c 00 03 00 00 01 07 00 00 1d d0 00 03 64 98
1976 000020 00 06 8b 80 00 80 20 00 00 80 20 00 00 80 3d d0
1978 000030 2e 74 78 74 00 00 00 00 00 80 20 00 00 80 20 00 .txt (+36 bytes)
1979 000040 00 00 1d d0 00 00 00 a8 00 00 00 00 00 00 00 00
1980 000050 00 00 00 00 00 00 00 20
1981 000058 2e 64 74 61 00 00 00 00 00 80 3d d0 00 80 3d d0 .dta (+36 bytes)
1982 000068 00 03 64 98 00 00 1e 78 00 00 00 00 00 00 00 00
1983 000078 00 00 00 00 00 00 00 40
1984 000080 2e 62 73 73 00 00 00 00 00 00 50 00 00 00 50 00 .bss (+36 bytes)
1985 000090 00 06 8b 80 00 03 83 10 00 00 00 00 00 00 00 00
1986 0000a0 00 00 00 00 00 00 00 80
1988 Header size is $A8 bytes...
1990 BSD/COFF format file detected...
1991 3 sections specified
1992 Symbol Table offset = 230160 ($00038310)
1993 Symbol Table contains 1339 symbol entries ($0000053B)
1994 The additional header size is 28 bytes ($001C)
1995 Magic Number for RUN_HDR = 0x00000107
1996 Text Segment Size = 7632 ($00001DD0)
1997 Data Segment Size = 222360 ($00036498)
1998 BSS Segment Size = 428928 ($00068B80)
1999 Starting Address for executable = 0x00802000
2000 Start of Text Segment = 0x00802000
2001 Start of Data Segment = 0x00803dd0
2003 if (jaguar_mainRom[0] == 0x60 && jaguar_mainRom[1] == 0x1B)
2005 uint32 loadAddress = GET32(jaguar_mainRom, 0x16), //runAddress = GET32(jaguar_mainRom, 0x2A),
2006 codeSize = GET32(jaguar_mainRom, 0x02) + GET32(jaguar_mainRom, 0x06);
2007 WriteLog("GUI: Setting up homebrew (ABS-1)... Run address: %08X, length: %08X\n", loadAddress, codeSize);
2009 if (loadAddress < 0x800000)
2010 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x24, codeSize);
2013 for(int i=codeSize-1; i>=0; i--)
2014 jaguar_mainRom[(loadAddress - 0x800000) + i] = jaguar_mainRom[i + 0x24];
2015 /* memcpy(jaguar_mainRam, jaguar_mainRom + 0x24, codeSize);
2016 memset(jaguar_mainRom, 0xFF, 0x600000);
2017 memcpy(jaguar_mainRom + (loadAddress - 0x800000), jaguar_mainRam, codeSize);
2018 memset(jaguar_mainRam, 0x00, 0x400000);*/
2021 jaguarRunAddress = loadAddress;
2023 else if (jaguar_mainRom[0] == 0x01 && jaguar_mainRom[1] == 0x50)
2025 uint32 loadAddress = GET32(jaguar_mainRom, 0x28), runAddress = GET32(jaguar_mainRom, 0x24),
2026 codeSize = GET32(jaguar_mainRom, 0x18) + GET32(jaguar_mainRom, 0x1C);
2027 WriteLog("GUI: Setting up homebrew (ABS-2)... Run address: %08X, length: %08X\n", runAddress, codeSize);
2029 if (loadAddress < 0x800000)
2030 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0xA8, codeSize);
2033 for(int i=codeSize-1; i>=0; i--)
2034 jaguar_mainRom[(loadAddress - 0x800000) + i] = jaguar_mainRom[i + 0xA8];
2035 /* memcpy(jaguar_mainRam, jaguar_mainRom + 0xA8, codeSize);
2036 memset(jaguar_mainRom, 0xFF, 0x600000);
2037 memcpy(jaguar_mainRom + (loadAddress - 0x800000), jaguar_mainRam, codeSize);
2038 memset(jaguar_mainRam, 0x00, 0x400000);*/
2041 jaguarRunAddress = runAddress;
2045 WriteLog("GUI: Couldn't find correct ABS format: %02X %02X\n", jaguar_mainRom[0], jaguar_mainRom[1]);
2049 else if (strcasecmp(ext, ".jag") == 0)
2051 // File extension ".JAG": Atari server file with header
2052 //NOTE: The bytes 'JAGR' should also be at position $1C...
2053 // Also, there's *always* a $601A header at position $00...
2054 if (jaguar_mainRom[0] == 0x60 && jaguar_mainRom[1] == 0x1A)
2056 uint32 loadAddress = GET32(jaguar_mainRom, 0x22), runAddress = GET32(jaguar_mainRom, 0x2A);
2057 //This is not always right! Especially when converted via bin2jag1!!!
2058 //We should have access to the length of the furshlumiger file that was loaded anyway!
2060 // uint32 progLength = GET32(jaguar_mainRom, 0x02);
2063 // WriteLog("Jaguar: Setting up PD ROM... Run address: %08X, length: %08X\n", runAddress, progLength);
2064 // memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, progLength);
2065 WriteLog("GUI: Setting up homebrew (JAG)... Run address: %08X, length: %08X\n", runAddress, jaguarRomSize - 0x2E);
2066 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, jaguarRomSize - 0x2E);
2067 // SET32(jaguar_mainRam, 4, runAddress);
2068 jaguarRunAddress = runAddress;
2073 // .J64 (Jaguar cartridge ROM image) is implied by the FileList object...
2079 // Get the length of a (possibly) gzipped file
2081 int gzfilelength(gzFile gd)
2083 int size = 0, length = 0;
2084 unsigned char buffer[0x10000];
2090 // Read in chunks until EOF
2091 size = gzread(gd, buffer, 0x10000);