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, 8, "Virtual Jaguar CVS 20040107"));
1634 window->AddElement(new Text(8, 24, "Coders:"));
1635 window->AddElement(new Text(16, 32, "Niels Wagenaar (nwagenaar)"));
1636 window->AddElement(new Text(16, 40, "Carwin Jones (Caz)"));
1637 window->AddElement(new Text(16, 48, "James L. Hammons (shamus)"));
1638 window->AddElement(new Text(16, 56, "Adam Green"));
1639 window->AddElement(new Text(8, 72, "Testers:"));
1640 window->AddElement(new Text(16, 80, "Guruma"));
1645 Window * MiscOptions(void)
1647 Window * window = new Window(8, 16, 304, 160);
1648 window->AddElement(new PushButton(8, 8, &vjs.useJaguarBIOS, "BIOS"));
1649 window->AddElement(new SlideSwitch(8, 20, &vjs.hardwareTypeNTSC, "PAL", "NTSC"));
1650 window->AddElement(new PushButton(8, 40, &vjs.DSPEnabled, "DSP"));
1651 window->AddElement(new SlideSwitch(16, 52, &vjs.usePipelinedDSP, "Original", "Pipelined"));
1652 window->AddElement(new SlideSwitch(8, 72, (bool *)&vjs.glFilter, "Sharp", "Blurry"));
1662 // * Window/fullscreen
1670 // Uses zero as transparent color
1671 // Can also use an optional alpha channel
1673 void DrawTransparentBitmap(int16 * screen, uint32 x, uint32 y, uint16 * bitmap, uint8 * alpha/*=NULL*/)
1675 uint16 width = bitmap[0], height = bitmap[1];
1678 uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1679 uint32 address = x + (y * pitch);
1681 for(int yy=0; yy<height; yy++)
1683 for(int xx=0; xx<width; xx++)
1687 if (*bitmap && x + xx < pitch) // NOTE: Still doesn't clip the Y val...
1688 *(screen + address + xx + (yy * pitch)) = *bitmap;
1692 uint8 trans = *alpha;
1693 uint16 color = *bitmap;
1694 uint16 existingColor = *(screen + address + xx + (yy * pitch));
1696 uint8 eRed = (existingColor >> 10) & 0x1F,
1697 eGreen = (existingColor >> 5) & 0x1F,
1698 eBlue = existingColor & 0x1F,
1700 nRed = (color >> 10) & 0x1F,
1701 nGreen = (color >> 5) & 0x1F,
1702 nBlue = color & 0x1F;
1704 uint8 invTrans = 255 - trans;
1705 uint16 bRed = (eRed * trans + nRed * invTrans) / 255;
1706 uint16 bGreen = (eGreen * trans + nGreen * invTrans) / 255;
1707 uint16 bBlue = (eBlue * trans + nBlue * invTrans) / 255;
1709 uint16 blendedColor = (bRed << 10) | (bGreen << 5) | bBlue;
1711 *(screen + address + xx + (yy * pitch)) = blendedColor;
1722 // Very very crude GUI file selector
1724 /*bool UserSelectFile(char * path, char * filename)
1729 extern int16 * backbuffer;
1730 vector<string> fileList;
1732 // Read in the candidate files from the directory pointed to by "path"
1734 DIR * dp = opendir(path);
1737 while ((de = readdir(dp)) != NULL)
1739 char * ext = strrchr(de->d_name, '.');
1742 if (stricmp(ext, ".zip") == 0 || stricmp(ext, ".jag") == 0)
1743 fileList.push_back(string(de->d_name));
1748 if (fileList.size() == 0) // Any files found?
1749 return false; // Nope. Bail!
1751 // Main GUI selection loop
1753 uint32 cursor = 0, startFile = 0;
1755 if (fileList.size() > 1) // Only go GUI if more than one possibility!
1757 sort(fileList.begin(), fileList.end());
1760 uint32 limit = (fileList.size() > 30 ? 30 : fileList.size());
1763 // Ensure that the GUI is drawn before any user input...
1764 event.type = SDL_USEREVENT;
1765 SDL_PushEvent(&event);
1769 while (SDL_PollEvent(&event))
1771 if (event.type == SDL_KEYDOWN)
1773 SDLKey key = event.key.keysym.sym;
1775 if (key == SDLK_DOWN)
1777 if (cursor != limit - 1) // Cursor is within its window
1779 else // Otherwise, scroll the window...
1781 if (cursor + startFile != fileList.size() - 1)
1795 if (key == SDLK_PAGEDOWN)
1797 if (cursor != limit - 1)
1802 if (startFile > fileList.size() - limit)
1803 startFile = fileList.size() - limit;
1806 if (key == SDLK_PAGEUP)
1812 if (startFile < limit)
1818 if (key == SDLK_RETURN)
1820 if (key == SDLK_ESCAPE)
1822 WriteLog("GUI: Aborting VJ by user request.\n");
1823 return false; // Bail out!
1825 if (key >= SDLK_a && key <= SDLK_z)
1827 // Advance cursor to filename with first letter pressed...
1828 uint8 which = (key - SDLK_a) + 65; // Convert key to A-Z char
1830 for(uint32 i=0; i<fileList.size(); i++)
1832 if ((fileList[i][0] & 0xDF) == which)
1834 cursor = i - startFile;
1835 if (i > startFile + limit - 1)
1836 startFile = i - limit + 1,
1846 else if (event.type == SDL_MOUSEMOTION)
1848 mouseX = event.motion.x, mouseY = event.motion.y;
1850 mouseX /= 2, mouseY /= 2;
1852 else if (event.type == SDL_MOUSEBUTTONDOWN)
1854 uint32 mx = event.button.x, my = event.button.y;
1861 // memset(backbuffer, 0x11, tom_getVideoModeWidth() * tom_getVideoModeHeight() * 2);
1862 memset(backbuffer, 0x11, tom_getVideoModeWidth() * 240 * 2);
1864 for(uint32 i=0; i<limit; i++)
1866 // Clip our strings to guarantee that they fit on the screen...
1867 // (and strip off the extension too)
1868 string s(fileList[startFile + i], 0, fileList[startFile + i].length() - 4);
1869 if (s.length() > 38)
1871 DrawString(backbuffer, 0, i*8, (cursor == i ? true : false), " %s ", s.c_str());
1874 DrawTransparentBitmap(backbuffer, mouseX, mouseY, mousePic);
1881 strcpy(filename, path);
1883 if (strlen(path) > 0)
1884 if (path[strlen(path) - 1] != '/')
1885 strcat(filename, "/");
1887 strcat(filename, fileList[startFile + cursor].c_str());
1893 // Generic ROM loading
1895 uint32 JaguarLoadROM(uint8 * rom, char * path)
1897 // We really should have some kind of sanity checking for the ROM size here to prevent
1898 // a buffer overflow... !!! FIX !!!
1901 char * ext = strrchr(path, '.');
1904 WriteLog("VJ: Loading \"%s\"...", path);
1906 if (stricmp(ext, ".zip") == 0)
1908 // Handle ZIP file loading here...
1909 WriteLog("(ZIPped)...");
1911 if (load_zipped_file(0, 0, path, NULL, &rom, &romSize) == -1)
1913 WriteLog("Failed!\n");
1919 /* FILE * fp = fopen(path, "rb");
1923 WriteLog("Failed!\n");
1927 fseek(fp, 0, SEEK_END);
1928 romSize = ftell(fp);
1929 fseek(fp, 0, SEEK_SET);
1930 fread(rom, 1, romSize, fp);
1933 gzFile fp = gzopen(path, "rb");
1937 WriteLog("Failed!\n");
1941 romSize = gzfilelength(fp);
1942 gzseek(fp, 0, SEEK_SET);
1943 gzread(fp, rom, romSize);
1947 WriteLog("OK (%i bytes)\n", romSize);
1954 // Jaguar file loading
1956 //void JaguarLoadCart(uint8 * mem, char * path)
1957 bool JaguarLoadFile(char * path)
1959 // jaguarRomSize = JaguarLoadROM(mem, path);
1960 jaguarRomSize = JaguarLoadROM(jaguar_mainRom, path);
1962 /*//This is not *nix friendly for some reason...
1963 // if (!UserSelectFile(path, newPath))
1964 if (!UserSelectFile((strlen(path) == 0 ? (char *)"." : path), newPath))
1966 WriteLog("VJ: Could not find valid ROM in directory \"%s\"...\nAborting!\n", path);
1971 if (jaguarRomSize == 0)
1973 // WriteLog("VJ: Could not load ROM from file \"%s\"...\nAborting!\n", newPath);
1974 WriteLog("GUI: Could not load ROM from file \"%s\"...\nAborting load!\n", path);
1975 // Need to do something else here, like throw up an error dialog instead of aborting. !!! FIX !!!
1978 return false; // This is a start...
1981 jaguar_mainRom_crc32 = crc32_calcCheckSum(jaguar_mainRom, jaguarRomSize);
1982 WriteLog("CRC: %08X\n", (unsigned int)jaguar_mainRom_crc32);
1985 jaguarRunAddress = 0x802000;
1987 char * ext = strrchr(path, '.'); // Get the file's extension for non-cartridge checking
1989 //NOTE: Should fix JaguarLoadROM() to replace .zip with what's *in* the zip (.abs, .j64, etc.)
1990 if (stricmp(ext, ".rom") == 0)
1992 // File extension ".ROM": Alpine image that loads/runs at $802000
1993 WriteLog("GUI: Setting up homebrew (ROM)... Run address: 00802000, length: %08X\n", jaguarRomSize);
1995 for(int i=jaguarRomSize-1; i>=0; i--)
1996 jaguar_mainRom[0x2000 + i] = jaguar_mainRom[i];
1998 memset(jaguar_mainRom, 0xFF, 0x2000);
1999 /* memcpy(jaguar_mainRam, jaguar_mainRom, jaguarRomSize);
2000 memset(jaguar_mainRom, 0xFF, 0x600000);
2001 memcpy(jaguar_mainRom + 0x2000, jaguar_mainRam, jaguarRomSize);
2002 memset(jaguar_mainRam, 0x00, 0x400000);*/
2005 handler 001 at $00E00008
2006 handler 002 at $00E008DE
2007 handler 003 at $00E008E2
2008 handler 004 at $00E008E6
2009 handler 005 at $00E008EA
2010 handler 006 at $00E008EE
2011 handler 007 at $00E008F2
2012 handler 008 at $00E0054A
2013 handler 009 at $00E008FA
2014 handler 010 at $00000000
2015 handler 011 at $00000000
2016 handler 012 at $00E008FE
2017 handler 013 at $00E00902
2018 handler 014 at $00E00906
2019 handler 015 at $00E0090A
2020 handler 016 at $00E0090E
2021 handler 017 at $00E00912
2022 handler 018 at $00E00916
2023 handler 019 at $00E0091A
2024 handler 020 at $00E0091E
2025 handler 021 at $00E00922
2026 handler 022 at $00E00926
2027 handler 023 at $00E0092A
2028 handler 024 at $00E0092E
2029 handler 025 at $00E0107A
2030 handler 026 at $00E0107A
2031 handler 027 at $00E0107A
2032 handler 028 at $00E008DA
2033 handler 029 at $00E0107A
2034 handler 030 at $00E0107A
2035 handler 031 at $00E0107A
2036 handler 032 at $00000000
2038 Let's try setting up the illegal instruction vector for a stubulated jaguar...
2040 /* SET32(jaguar_mainRam, 0x08, 0x00E008DE);
2041 SET32(jaguar_mainRam, 0x0C, 0x00E008E2);
2042 SET32(jaguar_mainRam, 0x10, 0x00E008E6); // <-- Should be here (it is)...
2043 SET32(jaguar_mainRam, 0x14, 0x00E008EA);//*/
2045 // Try setting the vector to say, $1000 and putting an instruction there that loops forever:
2046 // This kludge works! Yeah!
2047 SET32(jaguar_mainRam, 0x10, 0x00001000);
2048 SET16(jaguar_mainRam, 0x1000, 0x60FE); // Here: bra Here
2050 else if (stricmp(ext, ".abs") == 0)
2052 // File extension ".ABS": Atari linker output file with header (w/o is useless to us here)
2055 ABS Format sleuthing (LBUGDEMO.ABS):
2057 000000 60 1B 00 00 05 0C 00 04 62 C0 00 00 04 28 00 00
2058 000010 12 A6 00 00 00 00 00 80 20 00 FF FF 00 80 25 0C
2061 DRI-format file detected...
2062 Text segment size = 0x0000050c bytes
2063 Data segment size = 0x000462c0 bytes
2064 BSS Segment size = 0x00000428 bytes
2065 Symbol Table size = 0x000012a6 bytes
2066 Absolute Address for text segment = 0x00802000
2067 Absolute Address for data segment = 0x0080250c
2068 Absolute Address for BSS segment = 0x00004000
2071 000000 01 50 00 03 00 00 00 00 00 03 83 10 00 00 05 3b
2072 000010 00 1c 00 03 00 00 01 07 00 00 1d d0 00 03 64 98
2073 000020 00 06 8b 80 00 80 20 00 00 80 20 00 00 80 3d d0
2075 000030 2e 74 78 74 00 00 00 00 00 80 20 00 00 80 20 00 .txt (+36 bytes)
2076 000040 00 00 1d d0 00 00 00 a8 00 00 00 00 00 00 00 00
2077 000050 00 00 00 00 00 00 00 20
2078 000058 2e 64 74 61 00 00 00 00 00 80 3d d0 00 80 3d d0 .dta (+36 bytes)
2079 000068 00 03 64 98 00 00 1e 78 00 00 00 00 00 00 00 00
2080 000078 00 00 00 00 00 00 00 40
2081 000080 2e 62 73 73 00 00 00 00 00 00 50 00 00 00 50 00 .bss (+36 bytes)
2082 000090 00 06 8b 80 00 03 83 10 00 00 00 00 00 00 00 00
2083 0000a0 00 00 00 00 00 00 00 80
2085 Header size is $A8 bytes...
2087 BSD/COFF format file detected...
2088 3 sections specified
2089 Symbol Table offset = 230160 ($00038310)
2090 Symbol Table contains 1339 symbol entries ($0000053B)
2091 The additional header size is 28 bytes ($001C)
2092 Magic Number for RUN_HDR = 0x00000107
2093 Text Segment Size = 7632 ($00001DD0)
2094 Data Segment Size = 222360 ($00036498)
2095 BSS Segment Size = 428928 ($00068B80)
2096 Starting Address for executable = 0x00802000
2097 Start of Text Segment = 0x00802000
2098 Start of Data Segment = 0x00803dd0
2100 if (jaguar_mainRom[0] == 0x60 && jaguar_mainRom[1] == 0x1B)
2102 uint32 loadAddress = GET32(jaguar_mainRom, 0x16), //runAddress = GET32(jaguar_mainRom, 0x2A),
2103 codeSize = GET32(jaguar_mainRom, 0x02) + GET32(jaguar_mainRom, 0x06);
2104 WriteLog("GUI: Setting up homebrew (ABS-1)... Run address: %08X, length: %08X\n", loadAddress, codeSize);
2106 if (loadAddress < 0x800000)
2107 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x24, codeSize);
2110 for(int i=codeSize-1; i>=0; i--)
2111 jaguar_mainRom[(loadAddress - 0x800000) + i] = jaguar_mainRom[i + 0x24];
2112 /* memcpy(jaguar_mainRam, jaguar_mainRom + 0x24, codeSize);
2113 memset(jaguar_mainRom, 0xFF, 0x600000);
2114 memcpy(jaguar_mainRom + (loadAddress - 0x800000), jaguar_mainRam, codeSize);
2115 memset(jaguar_mainRam, 0x00, 0x400000);*/
2118 jaguarRunAddress = loadAddress;
2120 else if (jaguar_mainRom[0] == 0x01 && jaguar_mainRom[1] == 0x50)
2122 uint32 loadAddress = GET32(jaguar_mainRom, 0x28), runAddress = GET32(jaguar_mainRom, 0x24),
2123 codeSize = GET32(jaguar_mainRom, 0x18) + GET32(jaguar_mainRom, 0x1C);
2124 WriteLog("GUI: Setting up homebrew (ABS-2)... Run address: %08X, length: %08X\n", runAddress, codeSize);
2126 if (loadAddress < 0x800000)
2127 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0xA8, codeSize);
2130 for(int i=codeSize-1; i>=0; i--)
2131 jaguar_mainRom[(loadAddress - 0x800000) + i] = jaguar_mainRom[i + 0xA8];
2132 /* memcpy(jaguar_mainRam, jaguar_mainRom + 0xA8, codeSize);
2133 memset(jaguar_mainRom, 0xFF, 0x600000);
2134 memcpy(jaguar_mainRom + (loadAddress - 0x800000), jaguar_mainRam, codeSize);
2135 memset(jaguar_mainRam, 0x00, 0x400000);*/
2138 jaguarRunAddress = runAddress;
2142 WriteLog("GUI: Couldn't find correct ABS format: %02X %02X\n", jaguar_mainRom[0], jaguar_mainRom[1]);
2146 else if (stricmp(ext, ".jag") == 0)
2148 // File extension ".JAG": Atari server file with header
2149 //NOTE: The bytes 'JAGR' should also be at position $1C...
2150 // Also, there's *always* a $601A header at position $00...
2151 if (jaguar_mainRom[0] == 0x60 && jaguar_mainRom[1] == 0x1A)
2153 uint32 loadAddress = GET32(jaguar_mainRom, 0x22), runAddress = GET32(jaguar_mainRom, 0x2A);
2154 //This is not always right! Especially when converted via bin2jag1!!!
2155 //We should have access to the length of the furshlumiger file that was loaded anyway!
2157 // uint32 progLength = GET32(jaguar_mainRom, 0x02);
2160 // WriteLog("Jaguar: Setting up PD ROM... Run address: %08X, length: %08X\n", runAddress, progLength);
2161 // memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, progLength);
2162 WriteLog("GUI: Setting up homebrew (JAG)... Run address: %08X, length: %08X\n", runAddress, jaguarRomSize - 0x2E);
2163 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, jaguarRomSize - 0x2E);
2164 // SET32(jaguar_mainRam, 4, runAddress);
2165 jaguarRunAddress = runAddress;
2170 // .J64 (Jaguar cartridge ROM image) is implied by the FileList object...
2176 // Get the length of a (possibly) gzipped file
2178 int gzfilelength(gzFile gd)
2180 int size = 0, length = 0;
2181 unsigned char buffer[0x10000];
2187 // Read in chunks until EOF
2188 size = gzread(gd, buffer, 0x10000);