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 ((uint32)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 > (uint32)(extents.x + extents.w) && x <= (uint32)(extents.x + extents.w + 8)
798 && y > (uint32)(extents.y + 8) && y <= (uint32)(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, ".j64") == 0
937 || stricmp(ext, ".abs") == 0 || stricmp(ext, ".jag") == 0
938 || stricmp(ext, ".rom") == 0)
939 files->AddItem(string(de->d_name));
945 void FileList::HandleKey(SDLKey key)
947 if (key == SDLK_RETURN)
950 Window::HandleKey(key);
953 void FileList::Notify(Element * e)
957 char filename[MAX_PATH];
958 strcpy(filename, vjs.ROMPath);
960 if (strlen(filename) > 0)
961 if (filename[strlen(filename) - 1] != '/')
962 strcat(filename, "/");
964 strcat(filename, files->GetSelectedItem().c_str());
966 // uint32 romSize = JaguarLoadROM(jaguar_mainRom, filename);
967 // JaguarLoadCart(jaguar_mainRom, filename);
968 if (JaguarLoadFile(filename))
971 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
972 SDL_PushEvent(&event);
974 event.type = SDL_USEREVENT, event.user.code = MENU_ITEM_CHOSEN;
975 event.user.data1 = (void *)ResetJaguar;
976 SDL_PushEvent(&event);
981 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
982 SDL_PushEvent(&event);
984 // Handle the error, but don't run...
985 // Tell the user that we couldn't run their file for some reason... !!! FIX !!!
996 Window * (* action)(void);
999 NameAction(string n, Window * (* a)(void) = NULL, SDLKey k = SDLK_UNKNOWN): name(n),
1000 action(a), hotKey(k) {}
1007 MenuItems(): charLength(0) {}
1008 bool Inside(uint32 x, uint32 y)
1009 { return (x >= (uint32)extents.x && x < (uint32)(extents.x + extents.w)
1010 && y >= (uint32)extents.y && y < (uint32)(extents.y + extents.h) ? true : false); }
1013 vector<NameAction> item;
1018 class Menu: public Element
1021 Menu(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 8,
1022 uint16 fgc = 0x1CFF, uint16 bgc = 0x000F, uint16 fgch = 0x421F,
1023 uint16 bgch = 0x1CFF): Element(x, y, w, h), activated(false), clicked(false),
1024 inside(0), insidePopup(0), fgColor(fgc), bgColor(bgc), fgColorHL(fgch),
1025 bgColorHL(bgch), menuChosen(-1), menuItemChosen(-1) {}
1026 virtual void HandleKey(SDLKey key);
1027 virtual void HandleMouseMove(uint32 x, uint32 y);
1028 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
1029 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
1030 virtual void Notify(Element *) {}
1031 void Add(MenuItems mi);
1034 bool activated, clicked;
1035 uint32 inside, insidePopup;
1036 uint16 fgColor, bgColor, fgColorHL, bgColorHL;
1037 int menuChosen, menuItemChosen;
1040 vector<MenuItems> itemList;
1043 void Menu::HandleKey(SDLKey key)
1045 for(uint32 i=0; i<itemList.size(); i++)
1047 for(uint32 j=0; j<itemList[i].item.size(); j++)
1049 if (itemList[i].item[j].hotKey == key)
1052 event.type = SDL_USEREVENT;
1053 event.user.code = MENU_ITEM_CHOSEN;
1054 event.user.data1 = (void *)itemList[i].item[j].action;
1055 SDL_PushEvent(&event);
1057 clicked = false, menuChosen = menuItemChosen = -1;
1064 void Menu::HandleMouseMove(uint32 x, uint32 y)
1066 inside = insidePopup = 0;
1070 // Find out *where* we are inside the menu bar
1071 uint32 xpos = extents.x;
1073 for(uint32 i=0; i<itemList.size(); i++)
1075 uint32 width = (itemList[i].title.length() + 2) * 8;
1077 if (x >= xpos && x < xpos + width)
1088 if (!Inside(x, y) && !clicked)
1093 if (itemList[menuChosen].Inside(x, y) && clicked)
1095 insidePopup = ((y - itemList[menuChosen].extents.y) / 8) + 1;
1096 menuItemChosen = insidePopup - 1;
1100 void Menu::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
1109 menuChosen = -1; // clicked is already false...!
1112 else // clicked == true
1114 if (insidePopup && !mouseDown) // I.e., mouse-button-up
1117 if (itemList[menuChosen].item[menuItemChosen].action != NULL)
1119 // itemList[menuChosen].item[menuItemChosen].action();
1121 event.type = SDL_USEREVENT;
1122 event.user.code = MENU_ITEM_CHOSEN;
1123 event.user.data1 = (void *)itemList[menuChosen].item[menuItemChosen].action;
1124 SDL_PushEvent(&event);
1126 clicked = false, menuChosen = menuItemChosen = -1;
1129 while (SDL_PollEvent(&event)); // Flush the event queue...
1130 event.type = SDL_MOUSEMOTION;
1132 SDL_GetMouseState(&mx, &my);
1133 event.motion.x = mx, event.motion.y = my;
1134 SDL_PushEvent(&event); // & update mouse position...!
1138 if (!inside && !insidePopup && mouseDown)
1139 clicked = false, menuChosen = menuItemChosen = -1;
1143 void Menu::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
1145 uint32 xpos = extents.x + offsetX;
1147 for(uint32 i=0; i<itemList.size(); i++)
1149 uint16 color1 = fgColor, color2 = bgColor;
1150 if (inside == (i + 1) || (menuChosen != -1 && (uint32)menuChosen == i))
1151 color1 = fgColorHL, color2 = bgColorHL;
1153 DrawStringOpaque(screenBuffer, xpos, extents.y + offsetY, color1, color2,
1154 " %s ", itemList[i].title.c_str());
1155 xpos += (itemList[i].title.length() + 2) * 8;
1158 // Draw sub menu (but only if active)
1161 uint32 ypos = extents.y + 9;
1163 for(uint32 i=0; i<itemList[menuChosen].item.size(); i++)
1165 uint16 color1 = fgColor, color2 = bgColor;
1167 if (insidePopup == i + 1)
1168 color1 = fgColorHL, color2 = bgColorHL, menuItemChosen = i;
1170 if (itemList[menuChosen].item[i].name.length() > 0)
1171 DrawStringOpaque(screenBuffer, itemList[menuChosen].extents.x, ypos,
1172 color1, color2, " %-*.*s ", itemList[menuChosen].charLength,
1173 itemList[menuChosen].charLength, itemList[menuChosen].item[i].name.c_str());
1175 DrawStringOpaque(screenBuffer, itemList[menuChosen].extents.x, ypos,
1176 fgColor, bgColor, "%.*s", itemList[menuChosen].charLength + 2, separator);
1183 void Menu::Add(MenuItems mi)
1185 for(uint32 i=0; i<mi.item.size(); i++)
1186 if (mi.item[i].name.length() > mi.charLength)
1187 mi.charLength = mi.item[i].name.length();
1189 // Set extents here as well...
1190 mi.extents.x = extents.x + extents.w, mi.extents.y = extents.y + 9;
1191 mi.extents.w = (mi.charLength + 2) * 8, mi.extents.h = mi.item.size() * 8;
1193 itemList.push_back(mi);
1194 extents.w += (mi.title.length() + 2) * 8;
1198 //Do we even *need* this?
1199 class RootWindow: public Window
1202 RootWindow(Menu * m, Window * w = NULL): menu(m), window(w) {}
1203 //Do we even need to care about this crap?
1204 // { extents.x = extents.y = 0, extents.w = 320, extents.h = 240; }
1205 virtual void HandleKey(SDLKey key) {}
1206 virtual void HandleMouseMove(uint32 x, uint32 y) {}
1207 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) {}
1208 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0) {}
1209 virtual void Notify(Element *) {}
1214 int16 * rootImage[1280 * 240 * 2];
1220 // GUI stuff--it's not crunchy, it's GUI! ;-)
1225 SDL_ShowCursor(SDL_DISABLE);
1226 SDL_GetMouseState(&mouseX, &mouseY);
1234 // Draw text at the given x/y coordinates. Can invert text as well.
1236 void DrawString(int16 * screen, uint32 x, uint32 y, bool invert, const char * text, ...)
1241 va_start(arg, text);
1242 vsprintf(string, text, arg);
1245 uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1246 uint32 length = strlen(string), address = x + (y * pitch);
1248 for(uint32 i=0; i<length; i++)
1250 uint32 fontAddr = (uint32)string[i] * 64;
1252 for(uint32 yy=0; yy<8; yy++)
1254 for(uint32 xx=0; xx<8; xx++)
1256 if ((font1[fontAddr] && !invert) || (!font1[fontAddr] && invert))
1257 *(screen + address + xx + (yy * pitch)) = 0xFE00;
1267 // Draw text at the given x/y coordinates, using FG/BG colors.
1269 void DrawStringOpaque(int16 * screen, uint32 x, uint32 y, uint16 color1, uint16 color2, const char * text, ...)
1274 va_start(arg, text);
1275 vsprintf(string, text, arg);
1278 uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1279 uint32 length = strlen(string), address = x + (y * pitch);
1281 for(uint32 i=0; i<length; i++)
1283 uint32 fontAddr = (uint32)string[i] * 64;
1285 for(uint32 yy=0; yy<8; yy++)
1287 for(uint32 xx=0; xx<8; xx++)
1289 *(screen + address + xx + (yy * pitch)) = (font1[fontAddr] ? color1 : color2);
1299 // Draw text at the given x/y coordinates with transparency (0 is fully opaque, 32 is fully transparent).
1301 void DrawStringTrans(int16 * screen, uint32 x, uint32 y, uint16 color, uint8 trans, const char * text, ...)
1306 va_start(arg, text);
1307 vsprintf(string, text, arg);
1310 uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1311 uint32 length = strlen(string), address = x + (y * pitch);
1313 for(uint32 i=0; i<length; i++)
1315 uint32 fontAddr = (uint32)string[i] * 64;
1317 for(uint32 yy=0; yy<8; yy++)
1319 for(uint32 xx=0; xx<8; xx++)
1321 if (font1[fontAddr])
1323 uint16 existingColor = *(screen + address + xx + (yy * pitch));
1325 uint8 eRed = (existingColor >> 10) & 0x1F,
1326 eGreen = (existingColor >> 5) & 0x1F,
1327 eBlue = existingColor & 0x1F,
1328 //This could be done ahead of time, instead of on each pixel...
1329 nRed = (color >> 10) & 0x1F,
1330 nGreen = (color >> 5) & 0x1F,
1331 nBlue = color & 0x1F;
1333 //This could be sped up by using a table of 5 + 5 + 5 bits (32 levels transparency -> 32768 entries)
1334 //Here we've modified it to have 33 levels of transparency (could have any # we want!)
1335 //because dividing by 32 is faster than dividing by 31...!
1336 uint8 invTrans = 32 - trans;
1337 uint16 bRed = (eRed * trans + nRed * invTrans) / 32;
1338 uint16 bGreen = (eGreen * trans + nGreen * invTrans) / 32;
1339 uint16 bBlue = (eBlue * trans + nBlue * invTrans) / 32;
1341 uint16 blendedColor = (bRed << 10) | (bGreen << 5) | bBlue;
1343 *(screen + address + xx + (yy * pitch)) = blendedColor;
1359 // Need to set things up so that it loads and runs a file if given on the command line. !!! FIX !!!
1360 extern int16 * backbuffer;
1363 Window * mainWindow = NULL;
1365 // Set up the GUI classes...
1366 Element::SetScreenAndPitch(backbuffer, GetSDLScreenPitch() / 2);
1371 mi.item.push_back(NameAction("Load...", LoadROM, SDLK_l));
1372 mi.item.push_back(NameAction("Reset", ResetJaguar));
1373 mi.item.push_back(NameAction("Run", RunEmu, SDLK_ESCAPE));
1374 mi.item.push_back(NameAction(""));
1375 mi.item.push_back(NameAction("Quit", Quit, SDLK_q));
1377 mi.title = "Settings";
1379 mi.item.push_back(NameAction("Video..."));
1380 mi.item.push_back(NameAction("Audio..."));
1381 mi.item.push_back(NameAction("Misc...", MiscOptions, SDLK_m));
1385 mi.item.push_back(NameAction("About...", About));
1388 bool showMouse = true;
1390 //This is crappy!!! !!! FIX !!!
1393 // Set up our background save...
1394 memset(background, 0x11, tom_getVideoModeWidth() * 240 * 2);
1398 while (SDL_PollEvent(&event))
1400 if (event.type == SDL_USEREVENT)
1402 if (event.user.code == WINDOW_CLOSE)
1407 else if (event.user.code == MENU_ITEM_CHOSEN)
1409 // Confused? Let me enlighten... What we're doing here is casting
1410 // data1 as a pointer to a function which returns a Window pointer and
1411 // which takes no parameters (the "(Window *(*)(void))" part), then
1412 // derefencing it (the "*" in front of that) in order to call the
1413 // function that it points to. Clear as mud? Yeah, I hate function
1414 // pointers too, but what else are you gonna do?
1415 mainWindow = (*(Window *(*)(void))event.user.data1)();
1417 while (SDL_PollEvent(&event)); // Flush the event queue...
1418 event.type = SDL_MOUSEMOTION;
1420 SDL_GetMouseState(&mx, &my);
1421 event.motion.x = mx, event.motion.y = my;
1422 SDL_PushEvent(&event); // & update mouse position...!
1424 mouseX = mx, mouseY = my; // This prevents "mouse flash"...
1426 mouseX /= 2, mouseY /= 2;
1429 else if (event.type == SDL_ACTIVEEVENT)
1431 if (event.active.state == SDL_APPMOUSEFOCUS)
1432 showMouse = (event.active.gain ? true : false);
1434 else if (event.type == SDL_KEYDOWN)
1437 mainWindow->HandleKey(event.key.keysym.sym);
1439 mainMenu.HandleKey(event.key.keysym.sym);
1441 else if (event.type == SDL_MOUSEMOTION)
1443 mouseX = event.motion.x, mouseY = event.motion.y;
1446 mouseX /= 2, mouseY /= 2;
1449 mainWindow->HandleMouseMove(mouseX, mouseY);
1451 mainMenu.HandleMouseMove(mouseX, mouseY);
1453 else if (event.type == SDL_MOUSEBUTTONDOWN)
1455 uint32 mx = event.button.x, my = event.button.y;
1461 mainWindow->HandleMouseButton(mx, my, true);
1463 mainMenu.HandleMouseButton(mx, my, true);
1465 else if (event.type == SDL_MOUSEBUTTONUP)
1467 uint32 mx = event.button.x, my = event.button.y;
1473 mainWindow->HandleMouseButton(mx, my, false);
1475 mainMenu.HandleMouseButton(mx, my, false);
1479 // The way we do things here is kinda stupid (redrawing the screen every frame), but
1480 // it's simple. Perhaps there may be a reason down the road to be more selective with
1481 // our clearing, but for now, this will suffice.
1482 // memset(backbuffer, 0x11, tom_getVideoModeWidth() * 240 * 2);
1483 memcpy(backbuffer, background, tom_getVideoModeWidth() * 240 * 2);
1490 DrawTransparentBitmap(backbuffer, mouseX, mouseY, mousePic);
1500 // GUI "action" functions
1502 Window * LoadROM(void)
1504 FileList * fileList = new FileList(8, 16, 304, 216);
1506 return (Window *)fileList;
1509 Window * ResetJaguar(void)
1515 bool debounceRunKey = true;
1516 Window * RunEmu(void)
1518 //This is crappy... !!! FIX !!!
1519 extern int16 * backbuffer;
1520 extern bool finished, showGUI;
1522 uint32 nFrame = 0, nFrameskip = 0;
1523 uint32 totalFrames = 0;
1525 bool showMessage = true;
1526 uint32 showMsgFrames = 120;
1527 uint8 transparency = 0;
1528 // Pass a message to the "joystick" code to debounce the ESC key...
1529 debounceRunKey = true;
1531 uint32 cartType = 2;
1532 if (jaguarRomSize == 0x200000)
1534 else if (jaguarRomSize == 0x400000)
1537 char * cartTypeName[3] = { "2M Cartridge", "4M Cartridge", "Homebrew" };
1541 // Set up new backbuffer with new pixels and data
1542 JaguarExecute(backbuffer, true);
1544 //WriteLog("Frame #%u...\n", totalFrames);
1545 //extern bool doDSPDis;
1546 //if (totalFrames == 373)
1549 //This sucks... !!! FIX !!!
1554 // Some QnD GUI stuff here...
1557 extern uint32 gpu_pc, dsp_pc;
1558 DrawString(backbuffer, 8, 8, false, "GPU PC: %08X", gpu_pc);
1559 DrawString(backbuffer, 8, 16, false, "DSP PC: %08X", dsp_pc);
1564 DrawStringTrans(backbuffer, 8, 24*8, 0xFF0F, transparency, "Running...");
1565 DrawStringTrans(backbuffer, 8, 26*8, 0x3FE3, transparency, "%s, run address: %06X", cartTypeName[cartType], jaguarRunAddress);
1566 DrawStringTrans(backbuffer, 8, 27*8, 0x3FE3, transparency, "CRC: %08X", jaguar_mainRom_crc32);
1568 if (showMsgFrames == 0)
1572 if (transparency == 33)
1574 showMessage = false;
1575 /*extern bool doGPUDis;
1576 doGPUDis = true;//*/
1585 if (nFrame == nFrameskip)
1594 // Reset the pitch, since it may have been changed in-game...
1595 Element::SetScreenAndPitch(backbuffer, GetSDLScreenPitch() / 2);
1597 // Save the background for the GUI...
1598 // memcpy(background, backbuffer, tom_getVideoModeWidth() * 240 * 2);
1599 // In this case, we squash the color to monochrome, then force it to blue + green...
1600 for(uint32 i=0; i<tom_getVideoModeWidth() * 240; i++)
1602 uint16 word = backbuffer[i];
1603 uint8 r = (word >> 10) & 0x1F, g = (word >> 5) & 0x1F, b = word & 0x1F;
1604 word = ((r + g + b) / 3) & 0x001F;
1605 word = (word << 5) | word;
1606 background[i] = word;
1614 //This is crap. We need some REAL exit code, instead of this psuedo crap... !!! FIX !!!
1615 WriteLog("GUI: Quitting due to user request.\n");
1621 VideoDone(); // Free SDL components last...!
1626 return NULL; // We never get here...
1629 Window * About(void)
1631 Window * window = new Window(8, 16, 304, 160);
1632 window->AddElement(new Text(8, 8, "Virtual Jaguar 1.0.7"));
1633 window->AddElement(new Text(8, 24, "Coders:"));
1634 window->AddElement(new Text(16, 32, "Niels Wagenaar (nwagenaar)"));
1635 window->AddElement(new Text(16, 40, "Carwin Jones (Caz)"));
1636 window->AddElement(new Text(16, 48, "James L. Hammons (shamus)"));
1637 window->AddElement(new Text(16, 56, "Adam Green"));
1642 Window * MiscOptions(void)
1644 Window * window = new Window(8, 16, 304, 160);
1645 window->AddElement(new PushButton(8, 8, &vjs.useJaguarBIOS, "BIOS"));
1646 window->AddElement(new SlideSwitch(8, 20, &vjs.hardwareTypeNTSC, "PAL", "NTSC"));
1647 window->AddElement(new PushButton(8, 40, &vjs.DSPEnabled, "DSP"));
1648 window->AddElement(new SlideSwitch(16, 52, &vjs.usePipelinedDSP, "Original", "Pipelined"));
1649 window->AddElement(new SlideSwitch(8, 72, (bool *)&vjs.glFilter, "Sharp", "Blurry"));
1659 // * Window/fullscreen
1667 // Uses zero as transparent color
1668 // Can also use an optional alpha channel
1670 void DrawTransparentBitmap(int16 * screen, uint32 x, uint32 y, uint16 * bitmap, uint8 * alpha/*=NULL*/)
1672 uint16 width = bitmap[0], height = bitmap[1];
1675 uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1676 uint32 address = x + (y * pitch);
1678 for(int yy=0; yy<height; yy++)
1680 for(int xx=0; xx<width; xx++)
1684 if (*bitmap && x + xx < pitch) // NOTE: Still doesn't clip the Y val...
1685 *(screen + address + xx + (yy * pitch)) = *bitmap;
1689 uint8 trans = *alpha;
1690 uint16 color = *bitmap;
1691 uint16 existingColor = *(screen + address + xx + (yy * pitch));
1693 uint8 eRed = (existingColor >> 10) & 0x1F,
1694 eGreen = (existingColor >> 5) & 0x1F,
1695 eBlue = existingColor & 0x1F,
1697 nRed = (color >> 10) & 0x1F,
1698 nGreen = (color >> 5) & 0x1F,
1699 nBlue = color & 0x1F;
1701 uint8 invTrans = 255 - trans;
1702 uint16 bRed = (eRed * trans + nRed * invTrans) / 255;
1703 uint16 bGreen = (eGreen * trans + nGreen * invTrans) / 255;
1704 uint16 bBlue = (eBlue * trans + nBlue * invTrans) / 255;
1706 uint16 blendedColor = (bRed << 10) | (bGreen << 5) | bBlue;
1708 *(screen + address + xx + (yy * pitch)) = blendedColor;
1719 // Very very crude GUI file selector
1721 /*bool UserSelectFile(char * path, char * filename)
1726 extern int16 * backbuffer;
1727 vector<string> fileList;
1729 // Read in the candidate files from the directory pointed to by "path"
1731 DIR * dp = opendir(path);
1734 while ((de = readdir(dp)) != NULL)
1736 char * ext = strrchr(de->d_name, '.');
1739 if (stricmp(ext, ".zip") == 0 || stricmp(ext, ".jag") == 0)
1740 fileList.push_back(string(de->d_name));
1745 if (fileList.size() == 0) // Any files found?
1746 return false; // Nope. Bail!
1748 // Main GUI selection loop
1750 uint32 cursor = 0, startFile = 0;
1752 if (fileList.size() > 1) // Only go GUI if more than one possibility!
1754 sort(fileList.begin(), fileList.end());
1757 uint32 limit = (fileList.size() > 30 ? 30 : fileList.size());
1760 // Ensure that the GUI is drawn before any user input...
1761 event.type = SDL_USEREVENT;
1762 SDL_PushEvent(&event);
1766 while (SDL_PollEvent(&event))
1768 if (event.type == SDL_KEYDOWN)
1770 SDLKey key = event.key.keysym.sym;
1772 if (key == SDLK_DOWN)
1774 if (cursor != limit - 1) // Cursor is within its window
1776 else // Otherwise, scroll the window...
1778 if (cursor + startFile != fileList.size() - 1)
1792 if (key == SDLK_PAGEDOWN)
1794 if (cursor != limit - 1)
1799 if (startFile > fileList.size() - limit)
1800 startFile = fileList.size() - limit;
1803 if (key == SDLK_PAGEUP)
1809 if (startFile < limit)
1815 if (key == SDLK_RETURN)
1817 if (key == SDLK_ESCAPE)
1819 WriteLog("GUI: Aborting VJ by user request.\n");
1820 return false; // Bail out!
1822 if (key >= SDLK_a && key <= SDLK_z)
1824 // Advance cursor to filename with first letter pressed...
1825 uint8 which = (key - SDLK_a) + 65; // Convert key to A-Z char
1827 for(uint32 i=0; i<fileList.size(); i++)
1829 if ((fileList[i][0] & 0xDF) == which)
1831 cursor = i - startFile;
1832 if (i > startFile + limit - 1)
1833 startFile = i - limit + 1,
1843 else if (event.type == SDL_MOUSEMOTION)
1845 mouseX = event.motion.x, mouseY = event.motion.y;
1847 mouseX /= 2, mouseY /= 2;
1849 else if (event.type == SDL_MOUSEBUTTONDOWN)
1851 uint32 mx = event.button.x, my = event.button.y;
1858 // memset(backbuffer, 0x11, tom_getVideoModeWidth() * tom_getVideoModeHeight() * 2);
1859 memset(backbuffer, 0x11, tom_getVideoModeWidth() * 240 * 2);
1861 for(uint32 i=0; i<limit; i++)
1863 // Clip our strings to guarantee that they fit on the screen...
1864 // (and strip off the extension too)
1865 string s(fileList[startFile + i], 0, fileList[startFile + i].length() - 4);
1866 if (s.length() > 38)
1868 DrawString(backbuffer, 0, i*8, (cursor == i ? true : false), " %s ", s.c_str());
1871 DrawTransparentBitmap(backbuffer, mouseX, mouseY, mousePic);
1878 strcpy(filename, path);
1880 if (strlen(path) > 0)
1881 if (path[strlen(path) - 1] != '/')
1882 strcat(filename, "/");
1884 strcat(filename, fileList[startFile + cursor].c_str());
1890 // Generic ROM loading
1892 uint32 JaguarLoadROM(uint8 * rom, char * path)
1894 // We really should have some kind of sanity checking for the ROM size here to prevent
1895 // a buffer overflow... !!! FIX !!!
1898 char * ext = strrchr(path, '.');
1901 WriteLog("VJ: Loading \"%s\"...", path);
1903 if (stricmp(ext, ".zip") == 0)
1905 // Handle ZIP file loading here...
1906 WriteLog("(ZIPped)...");
1908 if (load_zipped_file(0, 0, path, NULL, &rom, &romSize) == -1)
1910 WriteLog("Failed!\n");
1916 /* FILE * fp = fopen(path, "rb");
1920 WriteLog("Failed!\n");
1924 fseek(fp, 0, SEEK_END);
1925 romSize = ftell(fp);
1926 fseek(fp, 0, SEEK_SET);
1927 fread(rom, 1, romSize, fp);
1930 gzFile fp = gzopen(path, "rb");
1934 WriteLog("Failed!\n");
1938 romSize = gzfilelength(fp);
1939 gzseek(fp, 0, SEEK_SET);
1940 gzread(fp, rom, romSize);
1944 WriteLog("OK (%i bytes)\n", romSize);
1951 // Jaguar file loading
1953 //void JaguarLoadCart(uint8 * mem, char * path)
1954 bool JaguarLoadFile(char * path)
1956 // jaguarRomSize = JaguarLoadROM(mem, path);
1957 jaguarRomSize = JaguarLoadROM(jaguar_mainRom, path);
1959 /*//This is not *nix friendly for some reason...
1960 // if (!UserSelectFile(path, newPath))
1961 if (!UserSelectFile((strlen(path) == 0 ? (char *)"." : path), newPath))
1963 WriteLog("VJ: Could not find valid ROM in directory \"%s\"...\nAborting!\n", path);
1968 if (jaguarRomSize == 0)
1970 // WriteLog("VJ: Could not load ROM from file \"%s\"...\nAborting!\n", newPath);
1971 WriteLog("GUI: Could not load ROM from file \"%s\"...\nAborting load!\n", path);
1972 // Need to do something else here, like throw up an error dialog instead of aborting. !!! FIX !!!
1975 return false; // This is a start...
1978 jaguar_mainRom_crc32 = crc32_calcCheckSum(jaguar_mainRom, jaguarRomSize);
1979 WriteLog("CRC: %08X\n", (unsigned int)jaguar_mainRom_crc32);
1982 jaguarRunAddress = 0x802000;
1984 char * ext = strrchr(path, '.'); // Get the file's extension for non-cartridge checking
1986 //NOTE: Should fix JaguarLoadROM() to replace .zip with what's *in* the zip (.abs, .j64, etc.)
1987 if (stricmp(ext, ".rom") == 0)
1989 // File extension ".ROM": Alpine image that loads/runs at $802000
1990 WriteLog("GUI: Setting up homebrew (ROM)... Run address: 00802000, length: %08X\n", jaguarRomSize);
1992 for(int i=jaguarRomSize-1; i>=0; i--)
1993 jaguar_mainRom[0x2000 + i] = jaguar_mainRom[i];
1995 memset(jaguar_mainRom, 0xFF, 0x2000);
1996 /* memcpy(jaguar_mainRam, jaguar_mainRom, jaguarRomSize);
1997 memset(jaguar_mainRom, 0xFF, 0x600000);
1998 memcpy(jaguar_mainRom + 0x2000, jaguar_mainRam, jaguarRomSize);
1999 memset(jaguar_mainRam, 0x00, 0x400000);*/
2002 handler 001 at $00E00008
2003 handler 002 at $00E008DE
2004 handler 003 at $00E008E2
2005 handler 004 at $00E008E6
2006 handler 005 at $00E008EA
2007 handler 006 at $00E008EE
2008 handler 007 at $00E008F2
2009 handler 008 at $00E0054A
2010 handler 009 at $00E008FA
2011 handler 010 at $00000000
2012 handler 011 at $00000000
2013 handler 012 at $00E008FE
2014 handler 013 at $00E00902
2015 handler 014 at $00E00906
2016 handler 015 at $00E0090A
2017 handler 016 at $00E0090E
2018 handler 017 at $00E00912
2019 handler 018 at $00E00916
2020 handler 019 at $00E0091A
2021 handler 020 at $00E0091E
2022 handler 021 at $00E00922
2023 handler 022 at $00E00926
2024 handler 023 at $00E0092A
2025 handler 024 at $00E0092E
2026 handler 025 at $00E0107A
2027 handler 026 at $00E0107A
2028 handler 027 at $00E0107A
2029 handler 028 at $00E008DA
2030 handler 029 at $00E0107A
2031 handler 030 at $00E0107A
2032 handler 031 at $00E0107A
2033 handler 032 at $00000000
2035 Let's try setting up the illegal instruction vector for a stubulated jaguar...
2037 /* SET32(jaguar_mainRam, 0x08, 0x00E008DE);
2038 SET32(jaguar_mainRam, 0x0C, 0x00E008E2);
2039 SET32(jaguar_mainRam, 0x10, 0x00E008E6); // <-- Should be here (it is)...
2040 SET32(jaguar_mainRam, 0x14, 0x00E008EA);//*/
2042 // Try setting the vector to say, $1000 and putting an instruction there that loops forever:
2043 // This kludge works! Yeah!
2044 SET32(jaguar_mainRam, 0x10, 0x00001000);
2045 SET16(jaguar_mainRam, 0x1000, 0x60FE); // Here: bra Here
2047 else if (stricmp(ext, ".abs") == 0)
2049 // File extension ".ABS": Atari linker output file with header (w/o is useless to us here)
2052 ABS Format sleuthing (LBUGDEMO.ABS):
2054 000000 60 1B 00 00 05 0C 00 04 62 C0 00 00 04 28 00 00
2055 000010 12 A6 00 00 00 00 00 80 20 00 FF FF 00 80 25 0C
2058 DRI-format file detected...
2059 Text segment size = 0x0000050c bytes
2060 Data segment size = 0x000462c0 bytes
2061 BSS Segment size = 0x00000428 bytes
2062 Symbol Table size = 0x000012a6 bytes
2063 Absolute Address for text segment = 0x00802000
2064 Absolute Address for data segment = 0x0080250c
2065 Absolute Address for BSS segment = 0x00004000
2068 000000 01 50 00 03 00 00 00 00 00 03 83 10 00 00 05 3b
2069 000010 00 1c 00 03 00 00 01 07 00 00 1d d0 00 03 64 98
2070 000020 00 06 8b 80 00 80 20 00 00 80 20 00 00 80 3d d0
2072 000030 2e 74 78 74 00 00 00 00 00 80 20 00 00 80 20 00 .txt (+36 bytes)
2073 000040 00 00 1d d0 00 00 00 a8 00 00 00 00 00 00 00 00
2074 000050 00 00 00 00 00 00 00 20
2075 000058 2e 64 74 61 00 00 00 00 00 80 3d d0 00 80 3d d0 .dta (+36 bytes)
2076 000068 00 03 64 98 00 00 1e 78 00 00 00 00 00 00 00 00
2077 000078 00 00 00 00 00 00 00 40
2078 000080 2e 62 73 73 00 00 00 00 00 00 50 00 00 00 50 00 .bss (+36 bytes)
2079 000090 00 06 8b 80 00 03 83 10 00 00 00 00 00 00 00 00
2080 0000a0 00 00 00 00 00 00 00 80
2082 Header size is $A8 bytes...
2084 BSD/COFF format file detected...
2085 3 sections specified
2086 Symbol Table offset = 230160 ($00038310)
2087 Symbol Table contains 1339 symbol entries ($0000053B)
2088 The additional header size is 28 bytes ($001C)
2089 Magic Number for RUN_HDR = 0x00000107
2090 Text Segment Size = 7632 ($00001DD0)
2091 Data Segment Size = 222360 ($00036498)
2092 BSS Segment Size = 428928 ($00068B80)
2093 Starting Address for executable = 0x00802000
2094 Start of Text Segment = 0x00802000
2095 Start of Data Segment = 0x00803dd0
2097 if (jaguar_mainRom[0] == 0x60 && jaguar_mainRom[1] == 0x1B)
2099 uint32 loadAddress = GET32(jaguar_mainRom, 0x16), //runAddress = GET32(jaguar_mainRom, 0x2A),
2100 codeSize = GET32(jaguar_mainRom, 0x02) + GET32(jaguar_mainRom, 0x06);
2101 WriteLog("GUI: Setting up homebrew (ABS-1)... Run address: %08X, length: %08X\n", loadAddress, codeSize);
2103 if (loadAddress < 0x800000)
2104 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x24, codeSize);
2107 for(int i=codeSize-1; i>=0; i--)
2108 jaguar_mainRom[(loadAddress - 0x800000) + i] = jaguar_mainRom[i + 0x24];
2109 /* memcpy(jaguar_mainRam, jaguar_mainRom + 0x24, codeSize);
2110 memset(jaguar_mainRom, 0xFF, 0x600000);
2111 memcpy(jaguar_mainRom + (loadAddress - 0x800000), jaguar_mainRam, codeSize);
2112 memset(jaguar_mainRam, 0x00, 0x400000);*/
2115 jaguarRunAddress = loadAddress;
2117 else if (jaguar_mainRom[0] == 0x01 && jaguar_mainRom[1] == 0x50)
2119 uint32 loadAddress = GET32(jaguar_mainRom, 0x28), runAddress = GET32(jaguar_mainRom, 0x24),
2120 codeSize = GET32(jaguar_mainRom, 0x18) + GET32(jaguar_mainRom, 0x1C);
2121 WriteLog("GUI: Setting up homebrew (ABS-2)... Run address: %08X, length: %08X\n", runAddress, codeSize);
2123 if (loadAddress < 0x800000)
2124 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0xA8, codeSize);
2127 for(int i=codeSize-1; i>=0; i--)
2128 jaguar_mainRom[(loadAddress - 0x800000) + i] = jaguar_mainRom[i + 0xA8];
2129 /* memcpy(jaguar_mainRam, jaguar_mainRom + 0xA8, codeSize);
2130 memset(jaguar_mainRom, 0xFF, 0x600000);
2131 memcpy(jaguar_mainRom + (loadAddress - 0x800000), jaguar_mainRam, codeSize);
2132 memset(jaguar_mainRam, 0x00, 0x400000);*/
2135 jaguarRunAddress = runAddress;
2139 WriteLog("GUI: Couldn't find correct ABS format: %02X %02X\n", jaguar_mainRom[0], jaguar_mainRom[1]);
2143 else if (stricmp(ext, ".jag") == 0)
2145 // File extension ".JAG": Atari server file with header
2146 //NOTE: The bytes 'JAGR' should also be at position $1C...
2147 // Also, there's *always* a $601A header at position $00...
2148 if (jaguar_mainRom[0] == 0x60 && jaguar_mainRom[1] == 0x1A)
2150 uint32 loadAddress = GET32(jaguar_mainRom, 0x22), runAddress = GET32(jaguar_mainRom, 0x2A);
2151 //This is not always right! Especially when converted via bin2jag1!!!
2152 //We should have access to the length of the furshlumiger file that was loaded anyway!
2154 // uint32 progLength = GET32(jaguar_mainRom, 0x02);
2157 // WriteLog("Jaguar: Setting up PD ROM... Run address: %08X, length: %08X\n", runAddress, progLength);
2158 // memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, progLength);
2159 WriteLog("GUI: Setting up homebrew (JAG)... Run address: %08X, length: %08X\n", runAddress, jaguarRomSize - 0x2E);
2160 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, jaguarRomSize - 0x2E);
2161 // SET32(jaguar_mainRam, 4, runAddress);
2162 jaguarRunAddress = runAddress;
2167 // .J64 (Jaguar cartridge ROM image) is implied by the FileList object...
2173 // Get the length of a (possibly) gzipped file
2175 int gzfilelength(gzFile gd)
2177 int size = 0, length = 0;
2178 unsigned char buffer[0x10000];
2184 // Read in chunks until EOF
2185 size = gzread(gd, buffer, 0x10000);