4 // Graphical User Interface support
9 #include <sys/types.h> // For MacOS <dirent.h> dependency
15 #include <ctype.h> // For toupper()
25 using namespace std; // For STL stuff
27 // Private function prototypes
29 class Window; // Forward declaration...
31 void DrawTransparentBitmap(int16 * screen, uint32 x, uint32 y, uint16 * bitmap, uint8 * alpha = NULL);
32 void DrawStringTrans(int16 * screen, uint32 x, uint32 y, uint16 color, uint8 opacity, const char * text, ...);
33 void DrawStringOpaque(int16 * screen, uint32 x, uint32 y, uint16 color1, uint16 color2, const char * text, ...);
34 Window * LoadROM(void);
35 Window * ResetJaguar(void);
36 Window * ResetJaguarCD(void);
37 Window * RunEmu(void);
40 Window * MiscOptions(void);
42 int gzfilelength(gzFile gd);
46 extern uint8 * jaguar_mainRam;
47 extern uint8 * jaguar_mainRom;
48 extern uint8 * jaguar_bootRom;
49 extern uint8 * jaguar_CDBootROM;
50 extern bool BIOSLoaded;
51 extern bool CDBIOSLoaded;
53 // Local global variables
55 bool exitGUI = false; // GUI (emulator) done variable
57 uint16 background[1280 * 240]; // GUI background buffer
62 0x03E0,0x0000,0x0000,0x0000,0x0000,0x0000, // +
63 0x0300,0x03E0,0x0000,0x0000,0x0000,0x0000, // @+
64 0x0300,0x03E0,0x03E0,0x0000,0x0000,0x0000, // @++
65 0x0300,0x0300,0x03E0,0x03E0,0x0000,0x0000, // @@++
66 0x0300,0x0300,0x03E0,0x03E0,0x03E0,0x0000, // @@+++
67 0x0300,0x0300,0x0300,0x03E0,0x03E0,0x03E0, // @@@+++
68 0x0300,0x0300,0x0300,0x0000,0x0000,0x0000, // @@@
69 0x0300,0x0000,0x0000,0x0000,0x0000,0x0000 // @
71 0xFFFF,0x0000,0x0000,0x0000,0x0000,0x0000, // +
72 0xE318,0xFFFF,0x0000,0x0000,0x0000,0x0000, // @+
73 0xE318,0xFFFF,0xFFFF,0x0000,0x0000,0x0000, // @++
74 0xE318,0xE318,0xFFFF,0xFFFF,0x0000,0x0000, // @@++
75 0xE318,0xE318,0xFFFF,0xFFFF,0xFFFF,0x0000, // @@+++
76 0xE318,0xE318,0xE318,0xFFFF,0xFFFF,0xFFFF, // @@@+++
77 0xE318,0xE318,0xE318,0x0000,0x0000,0x0000, // @@@
78 0xE318,0x0000,0x0000,0x0000,0x0000,0x0000 // @
81 // 1 111 00 11 100 1 1100 -> F39C
82 // 1 100 00 10 000 1 0000 -> C210
83 // 1 110 00 11 000 1 1000 -> E318
84 // 0 000 00 11 111 0 0000 -> 03E0
85 // 0 000 00 11 000 0 0000 -> 0300
90 0x0000,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x0000, // +++++
91 0x4B5E,0xFFFF,0x0000,0x0000,0x0000,0xFFFF,0x0217, // +@ @.
92 0x4B5E,0x0000,0xFFFF,0x0000,0xFFFF,0x0000,0x0217, // + @ @ .
93 0x4B5E,0x0000,0x0000,0xFFFF,0x0000,0x0000,0x0217, // + @ .
94 0x4B5E,0x0000,0xFFFF,0x0000,0xFFFF,0x0000,0x0217, // + @ @ .
95 0x4B5E,0xFFFF,0x0000,0x0000,0x0000,0xFFFF,0x0217, // +@ @.
96 0x0000,0x0217,0x0217,0x0217,0x0217,0x0217,0x0000 // .....
99 uint16 upArrowBox[] = {
102 0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E, // ++++++++
103 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
104 0x4B5E,0x0000,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x0000,0x0217, // + @@@@ .
105 0x4B5E,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x0217, // +@@@@@@.
106 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
107 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
108 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
109 0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217 // ........
112 uint16 downArrowBox[] = {
115 0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E, // ++++++++
116 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
117 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
118 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
119 0x4B5E,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x0217, // +@@@@@@.
120 0x4B5E,0x0000,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x0000,0x0217, // + @@@@ .
121 0x4B5E,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0x0217, // + @@ .
122 0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217 // ........
125 uint16 pushButtonUp[] = {
128 0x0000, 0x0C63, 0x394A, 0x494A, 0x4108, 0x2CC6, 0x0421, 0x0000,
129 0x0C63, 0x518C, 0x48E7, 0x48C6, 0x48A5, 0x48A5, 0x3CE7, 0x0421,
130 0x3D4A, 0x48E7, 0x48C6, 0x48C6, 0x44A5, 0x48A5, 0x48A5, 0x2CC6,
131 0x494A, 0x48C6, 0x48C6, 0x44A5, 0x44A5, 0x44A5, 0x48A5, 0x40E7,
132 0x4529, 0x48A5, 0x44A5, 0x44A5, 0x44A5, 0x44A5, 0x4CA5, 0x40E7,
133 0x2CC6, 0x48A5, 0x48A5, 0x44A5, 0x44A5, 0x48A5, 0x4CA5, 0x2CC6,
134 0x0421, 0x3CE7, 0x48A5, 0x48A5, 0x4CA5, 0x4CA5, 0x44E7, 0x0421,
135 0x0000, 0x0421, 0x28C6, 0x40E7, 0x40E7, 0x2CC6, 0x0421, 0x0000
139 0xFF, 0xE4, 0xA0, 0x99, 0xA4, 0xBE, 0xF0, 0xFF,
140 0xE3, 0x85, 0x00, 0x00, 0x00, 0x00, 0xAF, 0xF0,
141 0x9F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0,
142 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAD,
143 0xA3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAC,
144 0xBD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF,
145 0xF1, 0xAD, 0x00, 0x00, 0x00, 0x00, 0xAC, 0xF1,
146 0xFF, 0xF2, 0xC0, 0xAD, 0xAD, 0xC0, 0xF2, 0xFF
149 uint16 pushButtonDown[] = {
152 0x0000, 0x0C63, 0x4A31, 0x5631, 0x4DCE, 0x2D4A, 0x0421, 0x0000,
153 0x0C63, 0x6AF7, 0x714A, 0x7908, 0x7908, 0x6908, 0x418C, 0x0421,
154 0x4A31, 0x714A, 0x7508, 0x6CE7, 0x6CE7, 0x74E7, 0x68E7, 0x2929,
155 0x5A31, 0x7908, 0x6CE7, 0x6CE7, 0x6CE7, 0x6CE7, 0x78E7, 0x3D6B,
156 0x4DCE, 0x7908, 0x6CE7, 0x6CE7, 0x6CE7, 0x6CE7, 0x78E7, 0x416B,
157 0x2D4A, 0x6D08, 0x74E7, 0x6CE7, 0x6CE7, 0x74E7, 0x6CE7, 0x2929,
158 0x0842, 0x418C, 0x6CE7, 0x78E7, 0x78E7, 0x6CE7, 0x416B, 0x0842,
159 0x0000, 0x0842, 0x2929, 0x416B, 0x416B, 0x2929, 0x0842, 0x0000
163 0xFF, 0xE4, 0x72, 0x68, 0x7E, 0xA7, 0xF0, 0xFF,
164 0xE4, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x93, 0xF0,
165 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB2,
166 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A,
167 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A,
168 0xA6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB1,
169 0xEF, 0x91, 0x00, 0x00, 0x00, 0x00, 0x96, 0xEF,
170 0xFF, 0xEF, 0xAE, 0x98, 0x97, 0xAF, 0xEF, 0xFF
173 uint16 slideSwitchUp[] = {
176 0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E, // ++++++++
177 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
178 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
179 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
180 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
181 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
182 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
183 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
184 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
185 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
186 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
187 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
188 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
189 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
190 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
191 0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217 // ........
194 uint16 slideSwitchDown[] = {
197 0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E, // ++++++++
198 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
199 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
200 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
201 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
202 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
203 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
204 0x4B5E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0217, // +.......
205 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
206 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
207 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
208 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
209 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
210 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
211 0x4B5E,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0C7F,0x0217, // + .
212 0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217,0x0217 // ........
218 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
219 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
220 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
221 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
222 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
223 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
224 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
225 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 // ........
228 char separator[] = "--------------------------------------------------------";
231 // Case insensitive string compare function
232 // Taken straight out of Thinking In C++ by Bruce Eckel. Thanks Bruce!
235 int stringCmpi(const string &s1, const string &s2)
237 // Select the first element of each string:
238 string::const_iterator p1 = s1.begin(), p2 = s2.begin();
240 while (p1 != s1.end() && p2 != s2.end()) // Don
\92t run past the end
242 if (toupper(*p1) != toupper(*p2)) // Compare upper-cased chars
243 return (toupper(*p1) < toupper(*p2) ? -1 : 1);// Report which was lexically greater
249 // If they match up to the detected eos, say which was longer. Return 0 if the same.
250 return s2.size() - s1.size();
257 enum { WINDOW_CLOSE, MENU_ITEM_CHOSEN };
262 Element(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0)
263 { extents.x = x, extents.y = y, extents.w = w, extents.h = h; }
264 virtual void HandleKey(SDLKey key) = 0; // These are "pure" virtual functions...
265 virtual void HandleMouseMove(uint32 x, uint32 y) = 0;
266 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) = 0;
267 virtual void Draw(uint32, uint32) = 0;
268 virtual void Notify(Element *) = 0;
269 //Needed? virtual ~Element() = 0;
270 //We're not allocating anything in the base class, so the answer would be NO.
271 bool Inside(uint32 x, uint32 y);
273 static void SetScreenAndPitch(int16 * s, uint32 p) { screenBuffer = s, pitch = p; }
278 // Class variables...
279 static int16 * screenBuffer;
283 // Initialize class variables (Element)
284 int16 * Element::screenBuffer = NULL;
285 uint32 Element::pitch = 0;
287 bool Element::Inside(uint32 x, uint32 y)
289 return (x >= (uint32)extents.x && x < (uint32)(extents.x + extents.w)
290 && y >= (uint32)extents.y && y < (uint32)(extents.y + extents.h) ? true : false);
294 class Button: public Element
297 Button(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
298 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
299 bgColor(0x03E0), pic(NULL), elementToTell(NULL) {}
300 Button(uint32 x, uint32 y, uint32 w, uint32 h, uint16 * p): Element(x, y, w, h),
301 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
302 bgColor(0x03E0), pic(p), elementToTell(NULL) {}
303 Button(uint32 x, uint32 y, uint16 * p): Element(x, y, 0, 0),
304 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
305 bgColor(0x03E0), pic(p), elementToTell(NULL)
306 { if (pic) extents.w = pic[0], extents.h = pic[1]; }
307 Button(uint32 x, uint32 y, uint32 w, uint32 h, string s): Element(x, y, w, h),
308 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
309 bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL) {}
310 Button(uint32 x, uint32 y, string s): Element(x, y, 0, 8),
311 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
312 bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL)
313 { extents.w = s.length() * 8; }
314 virtual void HandleKey(SDLKey key) {}
315 virtual void HandleMouseMove(uint32 x, uint32 y);
316 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
317 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
318 virtual void Notify(Element *) {}
319 bool ButtonClicked(void) { return activated; }
320 void SetNotificationElement(Element * e) { elementToTell = e; }
323 bool activated, clicked, inside;
324 uint16 fgColor, bgColor;
327 Element * elementToTell;
330 void Button::HandleMouseMove(uint32 x, uint32 y)
332 inside = Inside(x, y);
335 void Button::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
342 if (clicked && !mouseDown)
344 clicked = false, activated = true;
346 // Send a message that we're activated (if there's someone to tell, that is)
348 elementToTell->Notify(this);
352 clicked = activated = false;
355 void Button::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
357 uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
359 for(uint32 y=0; y<extents.h; y++)
361 for(uint32 x=0; x<extents.w; x++)
363 // Doesn't clip in y axis! !!! FIX !!!
364 if (extents.x + x < pitch)
365 screenBuffer[addr + x + (y * pitch)]
366 = (clicked && inside ? fgColor : (inside ? 0x43F0 : bgColor));
371 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, pic);
373 if (text.length() > 0)
374 DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY, false, "%s", text.c_str());
378 class PushButton: public Element
381 // Save state externally?
382 //We pass in a state variable if we want to track it externally, otherwise we use our own
383 //internal state var. Still need to do some kind of callback for pushbuttons that do things
384 //like change from fullscreen to windowed... !!! FIX !!!
387 // PushButton(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
388 // activated(false), clicked(false), inside(false), fgColor(0xFFFF),
389 // bgColor(0x03E0), pic(NULL), elementToTell(NULL) {}
390 PushButton(uint32 x, uint32 y, bool * st, string s): Element(x, y, 8, 8), state(st),
391 inside(false), text(s) { if (st == NULL) state = &internalState; }
392 /* Button(uint32 x, uint32 y, uint32 w, uint32 h, uint16 * p): Element(x, y, w, h),
393 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
394 bgColor(0x03E0), pic(p), elementToTell(NULL) {}
395 Button(uint32 x, uint32 y, uint16 * p): Element(x, y, 0, 0),
396 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
397 bgColor(0x03E0), pic(p), elementToTell(NULL)
398 { if (pic) extents.w = pic[0], extents.h = pic[1]; }
399 Button(uint32 x, uint32 y, uint32 w, uint32 h, string s): Element(x, y, w, h),
400 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
401 bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL) {}
402 PushButton(uint32 x, uint32 y, string s): Element(x, y, 0, 8),
403 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
404 bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL)
405 { extents.w = s.length() * 8; }*/
406 virtual void HandleKey(SDLKey key) {}
407 virtual void HandleMouseMove(uint32 x, uint32 y);
408 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
409 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
410 virtual void Notify(Element *) {}
411 // bool ButtonClicked(void) { return activated; }
412 // void SetNotificationElement(Element * e) { elementToTell = e; }
417 // bool activated, clicked, inside;
418 // uint16 fgColor, bgColor;
421 // Element * elementToTell;
425 void PushButton::HandleMouseMove(uint32 x, uint32 y)
427 inside = Inside(x, y);
430 void PushButton::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
432 if (inside && mouseDown)
437 if (clicked && !mouseDown)
439 clicked = false, activated = true;
441 // Send a message that we're activated (if there's someone to tell, that is)
443 elementToTell->Notify(this);
448 // clicked = activated = false;
451 void PushButton::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
453 /* uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
455 for(uint32 y=0; y<extents.h; y++)
457 for(uint32 x=0; x<extents.w; x++)
459 // Doesn't clip in y axis! !!! FIX !!!
460 if (extents.x + x < pitch)
461 screenBuffer[addr + x + (y * pitch)]
462 = (clicked && inside ? fgColor : (inside ? 0x43F0 : bgColor));
466 // DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, (*state ? pushButtonDown : pushButtonUp));
467 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, (*state ? pushButtonDown : pushButtonUp), (*state ? pbdAlpha : pbuAlpha));
468 if (text.length() > 0)
469 DrawString(screenBuffer, extents.x + offsetX + 12, extents.y + offsetY, false, "%s", text.c_str());
473 class SlideSwitch: public Element
476 // Save state externally?
477 //Seems to be handled the same as PushButton, but without sanity checks. !!! FIX !!!
480 SlideSwitch(uint32 x, uint32 y, bool * st, string s1, string s2): Element(x, y, 8, 16), state(st),
481 inside(false), text1(s1), text2(s2) {}
482 virtual void HandleKey(SDLKey key) {}
483 virtual void HandleMouseMove(uint32 x, uint32 y);
484 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
485 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
486 virtual void Notify(Element *) {}
487 // bool ButtonClicked(void) { return activated; }
488 // void SetNotificationElement(Element * e) { elementToTell = e; }
493 // bool activated, clicked, inside;
494 // uint16 fgColor, bgColor;
497 // Element * elementToTell;
500 void SlideSwitch::HandleMouseMove(uint32 x, uint32 y)
502 inside = Inside(x, y);
505 void SlideSwitch::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
507 if (inside && mouseDown)
512 if (clicked && !mouseDown)
514 clicked = false, activated = true;
516 // Send a message that we're activated (if there's someone to tell, that is)
518 elementToTell->Notify(this);
523 // clicked = activated = false;
526 void SlideSwitch::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
528 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, (*state ? slideSwitchDown : slideSwitchUp));
529 if (text1.length() > 0)
530 DrawString(screenBuffer, extents.x + offsetX + 12, extents.y + offsetY, false, "%s", text1.c_str());
531 if (text2.length() > 0)
532 DrawString(screenBuffer, extents.x + offsetX + 12, extents.y + offsetY + 8, false, "%s", text2.c_str());
536 class Window: public Element
539 /* Window(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
540 fgColor(0x4FF0), bgColor(0xFE10)
541 { close = new Button(w - 8, 1, closeBox); list.push_back(close); }*/
542 Window(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0,
543 void (* f)(Element *) = NULL): Element(x, y, w, h),
544 /*clicked(false), inside(false),*/ fgColor(0x4FF0), bgColor(0x1E10),
546 { close = new Button(w - 8, 1, closeBox); list.push_back(close);
547 close->SetNotificationElement(this); }
549 virtual void HandleKey(SDLKey key);
550 virtual void HandleMouseMove(uint32 x, uint32 y);
551 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
552 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
553 virtual void Notify(Element * e);
554 void AddElement(Element * e);
555 // bool WindowActive(void) { return true; }//return !close->ButtonClicked(); }
558 // bool clicked, inside;
559 uint16 fgColor, bgColor;
560 void (* handler)(Element *);
562 //We have to use a list of Element *pointers* because we can't make a list that will hold
563 //all the different object types in the same list...
564 vector<Element *> list;
569 for(uint32 i=0; i<list.size(); i++)
574 void Window::HandleKey(SDLKey key)
576 if (key == SDLK_ESCAPE)
579 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
580 SDL_PushEvent(&event);
583 // Handle the items this window contains...
584 for(uint32 i=0; i<list.size(); i++)
585 // Make coords relative to upper right corner of this window...
586 list[i]->HandleKey(key);
589 void Window::HandleMouseMove(uint32 x, uint32 y)
591 // Handle the items this window contains...
592 for(uint32 i=0; i<list.size(); i++)
593 // Make coords relative to upper right corner of this window...
594 list[i]->HandleMouseMove(x - extents.x, y - extents.y);
597 void Window::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
599 // Handle the items this window contains...
600 for(uint32 i=0; i<list.size(); i++)
601 // Make coords relative to upper right corner of this window...
602 list[i]->HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
605 void Window::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
607 uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
609 for(uint32 y=0; y<extents.h; y++)
611 for(uint32 x=0; x<extents.w; x++)
613 // Doesn't clip in y axis! !!! FIX !!!
614 if (extents.x + x < pitch)
615 screenBuffer[addr + x + (y * pitch)] = bgColor;
619 // Handle the items this window contains...
620 for(uint32 i=0; i<list.size(); i++)
621 list[i]->Draw(extents.x, extents.y);
624 void Window::AddElement(Element * e)
629 void Window::Notify(Element * e)
634 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
635 SDL_PushEvent(&event);
640 class Text: public Element
643 Text(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
644 fgColor(0x4FF0), bgColor(0xFE10) {}
645 Text(uint32 x, uint32 y, string s): Element(x, y, 0, 0),
646 fgColor(0x4FF0), bgColor(0xFE10), text(s) {}
647 virtual void HandleKey(SDLKey key) {}
648 virtual void HandleMouseMove(uint32 x, uint32 y) {}
649 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) {}
650 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
651 virtual void Notify(Element *) {}
654 uint16 fgColor, bgColor;
658 void Text::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
660 if (text.length() > 0)
661 DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY, false, "%s", text.c_str());
665 class ListBox: public Element
666 //class ListBox: public Window
669 // ListBox(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
670 ListBox(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0);//: Window(x, y, w, h),
671 // windowPtr(0), cursor(0), limit(0), charWidth((w / 8) - 1), charHeight(h / 8),
672 // elementToTell(NULL), upArrow(w - 8, 0, upArrowBox),
673 // downArrow(w - 8, h - 8, downArrowBox), upArrow2(w - 8, h - 16, upArrowBox) {}
674 virtual void HandleKey(SDLKey key);
675 virtual void HandleMouseMove(uint32 x, uint32 y);
676 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
677 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
678 virtual void Notify(Element * e);
679 void SetNotificationElement(Element * e) { elementToTell = e; }
680 void AddItem(string s);
681 string GetSelectedItem(void);
685 uint32 windowPtr, cursor, limit;
686 uint32 charWidth, charHeight; // Box width/height in characters
687 Element * elementToTell;
688 Button upArrow, downArrow, upArrow2;
692 uint32 yRelativePoint;
695 ListBox::ListBox(uint32 x, uint32 y, uint32 w, uint32 h): Element(x, y, w, h),
696 thumbClicked(false), windowPtr(0), cursor(0), limit(0), charWidth((w / 8) - 1),
697 charHeight(h / 8), elementToTell(NULL), upArrow(w - 8, 0, upArrowBox),
698 downArrow(w - 8, h - 8, downArrowBox), upArrow2(w - 8, h - 16, upArrowBox)
700 upArrow.SetNotificationElement(this);
701 downArrow.SetNotificationElement(this);
702 upArrow2.SetNotificationElement(this);
703 extents.w -= 8; // Make room for scrollbar...
706 void ListBox::HandleKey(SDLKey key)
708 if (key == SDLK_DOWN)
710 if (cursor != limit - 1) // Cursor is within its window
712 else // Otherwise, scroll the window...
714 if (cursor + windowPtr != item.size() - 1)
718 else if (key == SDLK_UP)
728 else if (key == SDLK_PAGEDOWN)
730 if (cursor != limit - 1)
735 if (windowPtr > item.size() - limit)
736 windowPtr = item.size() - limit;
739 else if (key == SDLK_PAGEUP)
745 if (windowPtr < limit)
751 else if (key >= SDLK_a && key <= SDLK_z)
753 // Advance cursor to filename with first letter pressed...
754 uint8 which = (key - SDLK_a) + 65; // Convert key to A-Z char
756 for(uint32 i=0; i<item.size(); i++)
758 if ((item[i][0] & 0xDF) == which)
760 cursor = i - windowPtr;
761 if (i > windowPtr + limit - 1)
762 windowPtr = i - limit + 1, cursor = limit - 1;
764 windowPtr = i, cursor = 0;
771 void ListBox::HandleMouseMove(uint32 x, uint32 y)
773 upArrow.HandleMouseMove(x - extents.x, y - extents.y);
774 downArrow.HandleMouseMove(x - extents.x, y - extents.y);
775 upArrow2.HandleMouseMove(x - extents.x, y - extents.y);
779 uint32 sbHeight = extents.h - 24,
780 thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight);
782 //yRelativePoint is the spot on the thumb where we clicked...
783 int32 newThumbStart = y - yRelativePoint;
785 if (newThumbStart < 0)
788 if ((uint32)newThumbStart > sbHeight - thumb)
789 newThumbStart = sbHeight - thumb;
791 windowPtr = (uint32)(((float)newThumbStart / (float)sbHeight) * (float)item.size());
792 //Check for cursor bounds as well... Or do we need to???
793 //Actually, we don't...!
797 void ListBox::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
799 if (Inside(x, y) && mouseDown)
801 // Why do we have to do this??? (- extents.y?)
802 // I guess it's because only the Window class has offsetting implemented... !!! FIX !!!
803 cursor = (y - extents.y) / 8;
806 // Check for a hit on the scrollbar...
807 if (x > (uint32)(extents.x + extents.w) && x <= (uint32)(extents.x + extents.w + 8)
808 && y > (uint32)(extents.y + 8) && y <= (uint32)(extents.y + extents.h - 16))
812 // This shiaut should be calculated in AddItem(), not here... (or in Draw() for that matter)
813 uint32 sbHeight = extents.h - 24,
814 thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight),
815 thumbStart = (uint32)(((float)windowPtr / (float)item.size()) * (float)sbHeight);
817 // Did we hit the thumb?
818 if (y >= (extents.y + 8 + thumbStart) && y < (extents.y + 8 + thumbStart + thumb))
819 thumbClicked = true, yRelativePoint = y - thumbStart;
821 //Seems that this is useless--never reached except in rare cases and that the code outside is
824 // thumbClicked = false;
828 thumbClicked = false;
830 upArrow.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
831 downArrow.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
832 upArrow2.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
835 void ListBox::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
837 for(uint32 i=0; i<limit; i++)
839 // Strip off the extension
840 // (extension stripping should be an option, not default!)
841 string s(item[windowPtr + i], 0, item[windowPtr + i].length() - 4);
842 DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY + i*8,
843 (cursor == i ? true : false), "%-*.*s", charWidth, charWidth, s.c_str());
846 upArrow.Draw(extents.x + offsetX, extents.y + offsetY);
847 downArrow.Draw(extents.x + offsetX, extents.y + offsetY);
848 upArrow2.Draw(extents.x + offsetX, extents.y + offsetY);
850 uint32 sbHeight = extents.h - 24,
851 thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight),
852 thumbStart = (uint32)(((float)windowPtr / (float)item.size()) * (float)sbHeight);
854 for(uint32 y=extents.y+offsetY+8; y<extents.y+offsetY+extents.h-16; y++)
856 // for(uint32 x=extents.x+offsetX+extents.w-8; x<extents.x+offsetX+extents.w; x++)
857 for(uint32 x=extents.x+offsetX+extents.w; x<extents.x+offsetX+extents.w+8; x++)
859 if (y >= thumbStart + (extents.y+offsetY+8) && y < thumbStart + thumb + (extents.y+offsetY+8))
860 screenBuffer[x + (y * pitch)] = (thumbClicked ? 0x458E : 0xFFFF);
862 screenBuffer[x + (y * pitch)] = 0x0200;
867 void ListBox::Notify(Element * e)
869 if (e == &upArrow || e == &upArrow2)
875 if (cursor < limit - 1)
879 else if (e == &downArrow)
881 if (windowPtr < item.size() - limit)
891 void ListBox::AddItem(string s)
893 // Do a simple insertion sort
894 bool inserted = false;
896 for(vector<string>::iterator i=item.begin(); i<item.end(); i++)
898 if (stringCmpi(s, *i) == -1)
909 limit = (item.size() > charHeight ? charHeight : item.size());
912 string ListBox::GetSelectedItem(void)
914 return item[windowPtr + cursor];
918 class FileList: public Window
921 FileList(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0);
922 virtual ~FileList() {}
923 virtual void HandleKey(SDLKey key);
924 virtual void HandleMouseMove(uint32 x, uint32 y) { Window::HandleMouseMove(x, y); }
925 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) { Window::HandleMouseButton(x, y, mouseDown); }
926 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0) { Window::Draw(offsetX, offsetY); }
927 virtual void Notify(Element * e);
934 //Need 4 buttons, one scrollbar...
935 FileList::FileList(uint32 x, uint32 y, uint32 w, uint32 h): Window(x, y, w, h)
937 files = new ListBox(8, 8, w - 16, h - 32);
939 load = new Button(8, h - 16, " Load ");
941 load->SetNotificationElement(this);
943 //!!! FIX !!! Directory might not exist--this shouldn't cause VJ to crash!
944 DIR * dp = opendir(vjs.ROMPath);
947 while ((de = readdir(dp)) != NULL)
949 char * ext = strrchr(de->d_name, '.');
952 if (strcasecmp(ext, ".zip") == 0 || strcasecmp(ext, ".j64") == 0
953 || strcasecmp(ext, ".abs") == 0 || strcasecmp(ext, ".jag") == 0
954 || strcasecmp(ext, ".rom") == 0)
955 files->AddItem(string(de->d_name));
961 void FileList::HandleKey(SDLKey key)
963 if (key == SDLK_RETURN)
966 Window::HandleKey(key);
969 void FileList::Notify(Element * e)
973 char filename[MAX_PATH];
974 strcpy(filename, vjs.ROMPath);
976 if (strlen(filename) > 0)
977 if (filename[strlen(filename) - 1] != '/')
978 strcat(filename, "/");
980 strcat(filename, files->GetSelectedItem().c_str());
982 // uint32 romSize = JaguarLoadROM(jaguar_mainRom, filename);
983 // JaguarLoadCart(jaguar_mainRom, filename);
984 if (JaguarLoadFile(filename))
987 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
988 SDL_PushEvent(&event);
990 event.type = SDL_USEREVENT, event.user.code = MENU_ITEM_CHOSEN;
991 event.user.data1 = (void *)ResetJaguar;
992 SDL_PushEvent(&event);
997 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
998 SDL_PushEvent(&event);
1000 // Handle the error, but don't run...
1001 // Tell the user that we couldn't run their file for some reason... !!! FIX !!!
1002 //how to kludge: Make a function like ResetJaguar which creates the dialog window
1013 Window * (* action)(void);
1016 NameAction(string n, Window * (* a)(void) = NULL, SDLKey k = SDLK_UNKNOWN): name(n),
1017 action(a), hotKey(k) {}
1024 MenuItems(): charLength(0) {}
1025 bool Inside(uint32 x, uint32 y)
1026 { return (x >= (uint32)extents.x && x < (uint32)(extents.x + extents.w)
1027 && y >= (uint32)extents.y && y < (uint32)(extents.y + extents.h) ? true : false); }
1030 vector<NameAction> item;
1035 class Menu: public Element
1038 Menu(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 8,
1039 uint16 fgc = 0x1CFF, uint16 bgc = 0x000F, uint16 fgch = 0x421F,
1040 uint16 bgch = 0x1CFF): Element(x, y, w, h), activated(false), clicked(false),
1041 inside(0), insidePopup(0), fgColor(fgc), bgColor(bgc), fgColorHL(fgch),
1042 bgColorHL(bgch), menuChosen(-1), menuItemChosen(-1) {}
1043 virtual void HandleKey(SDLKey key);
1044 virtual void HandleMouseMove(uint32 x, uint32 y);
1045 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
1046 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
1047 virtual void Notify(Element *) {}
1048 void Add(MenuItems mi);
1051 bool activated, clicked;
1052 uint32 inside, insidePopup;
1053 uint16 fgColor, bgColor, fgColorHL, bgColorHL;
1054 int menuChosen, menuItemChosen;
1057 vector<MenuItems> itemList;
1060 void Menu::HandleKey(SDLKey key)
1062 for(uint32 i=0; i<itemList.size(); i++)
1064 for(uint32 j=0; j<itemList[i].item.size(); j++)
1066 if (itemList[i].item[j].hotKey == key)
1069 event.type = SDL_USEREVENT;
1070 event.user.code = MENU_ITEM_CHOSEN;
1071 event.user.data1 = (void *)itemList[i].item[j].action;
1072 SDL_PushEvent(&event);
1074 clicked = false, menuChosen = menuItemChosen = -1;
1081 void Menu::HandleMouseMove(uint32 x, uint32 y)
1083 inside = insidePopup = 0;
1087 // Find out *where* we are inside the menu bar
1088 uint32 xpos = extents.x;
1090 for(uint32 i=0; i<itemList.size(); i++)
1092 uint32 width = (itemList[i].title.length() + 2) * 8;
1094 if (x >= xpos && x < xpos + width)
1105 if (!Inside(x, y) && !clicked)
1110 if (itemList[menuChosen].Inside(x, y) && clicked)
1112 insidePopup = ((y - itemList[menuChosen].extents.y) / 8) + 1;
1113 menuItemChosen = insidePopup - 1;
1117 void Menu::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
1126 menuChosen = -1; // clicked is already false...!
1129 else // clicked == true
1131 if (insidePopup && !mouseDown) // I.e., mouse-button-up
1134 if (itemList[menuChosen].item[menuItemChosen].action != NULL)
1136 // itemList[menuChosen].item[menuItemChosen].action();
1138 event.type = SDL_USEREVENT;
1139 event.user.code = MENU_ITEM_CHOSEN;
1140 event.user.data1 = (void *)itemList[menuChosen].item[menuItemChosen].action;
1141 SDL_PushEvent(&event);
1143 clicked = false, menuChosen = menuItemChosen = -1;
1146 while (SDL_PollEvent(&event)); // Flush the event queue...
1147 event.type = SDL_MOUSEMOTION;
1149 SDL_GetMouseState(&mx, &my);
1150 event.motion.x = mx, event.motion.y = my;
1151 SDL_PushEvent(&event); // & update mouse position...!
1155 if (!inside && !insidePopup && mouseDown)
1156 clicked = false, menuChosen = menuItemChosen = -1;
1160 void Menu::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
1162 uint32 xpos = extents.x + offsetX;
1164 for(uint32 i=0; i<itemList.size(); i++)
1166 uint16 color1 = fgColor, color2 = bgColor;
1167 if (inside == (i + 1) || (menuChosen != -1 && (uint32)menuChosen == i))
1168 color1 = fgColorHL, color2 = bgColorHL;
1170 DrawStringOpaque(screenBuffer, xpos, extents.y + offsetY, color1, color2,
1171 " %s ", itemList[i].title.c_str());
1172 xpos += (itemList[i].title.length() + 2) * 8;
1175 // Draw sub menu (but only if active)
1178 uint32 ypos = extents.y + 9;
1180 for(uint32 i=0; i<itemList[menuChosen].item.size(); i++)
1182 uint16 color1 = fgColor, color2 = bgColor;
1184 if (insidePopup == i + 1)
1185 color1 = fgColorHL, color2 = bgColorHL, menuItemChosen = i;
1187 if (itemList[menuChosen].item[i].name.length() > 0)
1188 DrawStringOpaque(screenBuffer, itemList[menuChosen].extents.x, ypos,
1189 color1, color2, " %-*.*s ", itemList[menuChosen].charLength,
1190 itemList[menuChosen].charLength, itemList[menuChosen].item[i].name.c_str());
1192 DrawStringOpaque(screenBuffer, itemList[menuChosen].extents.x, ypos,
1193 fgColor, bgColor, "%.*s", itemList[menuChosen].charLength + 2, separator);
1200 void Menu::Add(MenuItems mi)
1202 for(uint32 i=0; i<mi.item.size(); i++)
1203 if (mi.item[i].name.length() > mi.charLength)
1204 mi.charLength = mi.item[i].name.length();
1206 // Set extents here as well...
1207 mi.extents.x = extents.x + extents.w, mi.extents.y = extents.y + 9;
1208 mi.extents.w = (mi.charLength + 2) * 8, mi.extents.h = mi.item.size() * 8;
1210 itemList.push_back(mi);
1211 extents.w += (mi.title.length() + 2) * 8;
1215 //Do we even *need* this?
1216 //Doesn't seem like it...
1217 class RootWindow: public Window
1220 RootWindow(Menu * m, Window * w = NULL): menu(m), window(w) {}
1221 //Do we even need to care about this crap?
1222 // { extents.x = extents.y = 0, extents.w = 320, extents.h = 240; }
1223 virtual void HandleKey(SDLKey key) {}
1224 virtual void HandleMouseMove(uint32 x, uint32 y) {}
1225 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) {}
1226 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0) {}
1227 virtual void Notify(Element *) {}
1232 int16 * rootImage[1280 * 240 * 2];
1238 // GUI stuff--it's not crunchy, it's GUI! ;-)
1243 SDL_ShowCursor(SDL_DISABLE);
1244 SDL_GetMouseState(&mouseX, &mouseY);
1252 // Draw text at the given x/y coordinates. Can invert text as well.
1254 void DrawString(int16 * screen, uint32 x, uint32 y, bool invert, const char * text, ...)
1259 va_start(arg, text);
1260 vsprintf(string, text, arg);
1263 uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1264 uint32 length = strlen(string), address = x + (y * pitch);
1266 for(uint32 i=0; i<length; i++)
1268 uint32 fontAddr = (uint32)string[i] * 64;
1270 for(uint32 yy=0; yy<8; yy++)
1272 for(uint32 xx=0; xx<8; xx++)
1274 if ((font1[fontAddr] && !invert) || (!font1[fontAddr] && invert))
1275 *(screen + address + xx + (yy * pitch)) = 0xFE00;
1285 // Draw text at the given x/y coordinates, using FG/BG colors.
1287 void DrawStringOpaque(int16 * screen, uint32 x, uint32 y, uint16 color1, uint16 color2, const char * text, ...)
1292 va_start(arg, text);
1293 vsprintf(string, text, arg);
1296 uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1297 uint32 length = strlen(string), address = x + (y * pitch);
1299 for(uint32 i=0; i<length; i++)
1301 uint32 fontAddr = (uint32)string[i] * 64;
1303 for(uint32 yy=0; yy<8; yy++)
1305 for(uint32 xx=0; xx<8; xx++)
1307 *(screen + address + xx + (yy * pitch)) = (font1[fontAddr] ? color1 : color2);
1317 // Draw text at the given x/y coordinates with transparency (0 is fully opaque, 32 is fully transparent).
1319 void DrawStringTrans(int16 * screen, uint32 x, uint32 y, uint16 color, uint8 trans, const char * text, ...)
1324 va_start(arg, text);
1325 vsprintf(string, text, arg);
1328 uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1329 uint32 length = strlen(string), address = x + (y * pitch);
1331 for(uint32 i=0; i<length; i++)
1333 uint32 fontAddr = (uint32)string[i] * 64;
1335 for(uint32 yy=0; yy<8; yy++)
1337 for(uint32 xx=0; xx<8; xx++)
1339 if (font1[fontAddr])
1341 uint16 existingColor = *(screen + address + xx + (yy * pitch));
1343 uint8 eRed = (existingColor >> 10) & 0x1F,
1344 eGreen = (existingColor >> 5) & 0x1F,
1345 eBlue = existingColor & 0x1F,
1346 //This could be done ahead of time, instead of on each pixel...
1347 nRed = (color >> 10) & 0x1F,
1348 nGreen = (color >> 5) & 0x1F,
1349 nBlue = color & 0x1F;
1351 //This could be sped up by using a table of 5 + 5 + 5 bits (32 levels transparency -> 32768 entries)
1352 //Here we've modified it to have 33 levels of transparency (could have any # we want!)
1353 //because dividing by 32 is faster than dividing by 31...!
1354 uint8 invTrans = 32 - trans;
1355 uint16 bRed = (eRed * trans + nRed * invTrans) / 32;
1356 uint16 bGreen = (eGreen * trans + nGreen * invTrans) / 32;
1357 uint16 bBlue = (eBlue * trans + nBlue * invTrans) / 32;
1359 uint16 blendedColor = (bRed << 10) | (bGreen << 5) | bBlue;
1361 *(screen + address + xx + (yy * pitch)) = blendedColor;
1377 // Need to set things up so that it loads and runs a file if given on the command line. !!! FIX !!!
1378 extern int16 * backbuffer;
1379 // bool done = false;
1381 Window * mainWindow = NULL;
1383 // Set up the GUI classes...
1384 Element::SetScreenAndPitch(backbuffer, GetSDLScreenPitch() / 2);
1388 mi.title = "Jaguar";
1389 mi.item.push_back(NameAction("Load...", LoadROM, SDLK_l));
1390 mi.item.push_back(NameAction("Reset", ResetJaguar, SDLK_r));
1392 mi.item.push_back(NameAction("Reset CD", ResetJaguarCD, SDLK_c));
1393 mi.item.push_back(NameAction("Run", RunEmu, SDLK_ESCAPE));
1394 mi.item.push_back(NameAction(""));
1395 mi.item.push_back(NameAction("Quit", Quit, SDLK_q));
1397 mi.title = "Settings";
1399 mi.item.push_back(NameAction("Video..."));
1400 mi.item.push_back(NameAction("Audio..."));
1401 mi.item.push_back(NameAction("Misc...", MiscOptions, SDLK_m));
1405 mi.item.push_back(NameAction("About...", About));
1408 bool showMouse = true;
1410 //This is crappy!!! !!! FIX !!!
1411 //Is this even needed any more? Hmm. Maybe. Dunno.
1414 // Set up our background save...
1415 memset(background, 0x11, tom_getVideoModeWidth() * 240 * 2);
1420 while (SDL_PollEvent(&event))
1422 if (event.type == SDL_USEREVENT)
1424 if (event.user.code == WINDOW_CLOSE)
1429 else if (event.user.code == MENU_ITEM_CHOSEN)
1431 // Confused? Let me enlighten... What we're doing here is casting
1432 // data1 as a pointer to a function which returns a Window pointer and
1433 // which takes no parameters (the "(Window *(*)(void))" part), then
1434 // derefencing it (the "*" in front of that) in order to call the
1435 // function that it points to. Clear as mud? Yeah, I hate function
1436 // pointers too, but what else are you gonna do?
1437 mainWindow = (*(Window *(*)(void))event.user.data1)();
1439 while (SDL_PollEvent(&event)); // Flush the event queue...
1440 event.type = SDL_MOUSEMOTION;
1442 SDL_GetMouseState(&mx, &my);
1443 event.motion.x = mx, event.motion.y = my;
1444 SDL_PushEvent(&event); // & update mouse position...!
1446 mouseX = mx, mouseY = my; // This prevents "mouse flash"...
1448 mouseX /= 2, mouseY /= 2;
1451 else if (event.type == SDL_ACTIVEEVENT)
1453 if (event.active.state == SDL_APPMOUSEFOCUS)
1454 showMouse = (event.active.gain ? true : false);
1456 else if (event.type == SDL_KEYDOWN)
1459 mainWindow->HandleKey(event.key.keysym.sym);
1461 mainMenu.HandleKey(event.key.keysym.sym);
1463 else if (event.type == SDL_MOUSEMOTION)
1465 mouseX = event.motion.x, mouseY = event.motion.y;
1468 // This is evil, Evil, EVIL! But we'll keep it until we can figure out WTF is going on here.
1470 mouseX /= 2, mouseY = (480 - mouseY) / 2;
1472 mouseX /= 2, mouseY /= 2;
1476 mainWindow->HandleMouseMove(mouseX, mouseY);
1478 mainMenu.HandleMouseMove(mouseX, mouseY);
1480 else if (event.type == SDL_MOUSEBUTTONDOWN)
1482 uint32 mx = event.button.x, my = event.button.y;
1488 mainWindow->HandleMouseButton(mx, my, true);
1490 mainMenu.HandleMouseButton(mx, my, true);
1492 else if (event.type == SDL_MOUSEBUTTONUP)
1494 uint32 mx = event.button.x, my = event.button.y;
1500 mainWindow->HandleMouseButton(mx, my, false);
1502 mainMenu.HandleMouseButton(mx, my, false);
1506 // The way we do things here is kinda stupid (redrawing the screen every frame), but
1507 // it's simple. Perhaps there may be a reason down the road to be more selective with
1508 // our clearing, but for now, this will suffice.
1509 // memset(backbuffer, 0x11, tom_getVideoModeWidth() * 240 * 2);
1510 memcpy(backbuffer, background, tom_getVideoModeWidth() * 240 * 2);
1513 //Could do multiple windows here by using a vector + priority info...
1514 //Though the way ZSNES does it seems to be by a bool (i.e., they're always active, just not shown)
1519 DrawTransparentBitmap(backbuffer, mouseX, mouseY, mousePic);
1529 // GUI "action" functions
1531 Window * LoadROM(void)
1533 FileList * fileList = new FileList(8, 16, 304, 216);
1535 return (Window *)fileList;
1538 Window * ResetJaguar(void)
1544 Window * ResetJaguarCD(void)
1546 memcpy(jaguar_mainRom, jaguar_CDBootROM, 0x40000);
1547 jaguarRunAddress = 0x802000;
1548 jaguar_mainRom_crc32 = crc32_calcCheckSum(jaguar_mainRom, 0x40000);
1554 bool debounceRunKey = true;
1555 Window * RunEmu(void)
1557 //This is crappy... !!! FIX !!!
1558 extern int16 * backbuffer;
1559 extern bool finished, showGUI;
1561 uint32 nFrame = 0, nFrameskip = 0;
1562 uint32 totalFrames = 0;
1564 bool showMessage = true;
1565 uint32 showMsgFrames = 120;
1566 uint8 transparency = 0;
1567 // Pass a message to the "joystick" code to debounce the ESC key...
1568 debounceRunKey = true;
1570 uint32 cartType = 2;
1571 if (jaguarRomSize == 0x200000)
1573 else if (jaguarRomSize == 0x400000)
1576 char * cartTypeName[3] = { "2M Cartridge", "4M Cartridge", "Homebrew" };
1580 // Set up new backbuffer with new pixels and data
1581 JaguarExecute(backbuffer, true);
1583 //WriteLog("Frame #%u...\n", totalFrames);
1584 //extern bool doDSPDis;
1585 //if (totalFrames == 373)
1588 //This sucks... !!! FIX !!!
1590 //This is done here so that the crud below doesn't get on our GUI background...
1594 // Some QnD GUI stuff here...
1597 extern uint32 gpu_pc, dsp_pc;
1598 DrawString(backbuffer, 8, 8, false, "GPU PC: %08X", gpu_pc);
1599 DrawString(backbuffer, 8, 16, false, "DSP PC: %08X", dsp_pc);
1604 DrawStringTrans(backbuffer, 8, 24*8, 0xFF0F, transparency, "Running...");
1605 DrawStringTrans(backbuffer, 8, 26*8, 0x3FE3, transparency, "%s, run address: %06X", cartTypeName[cartType], jaguarRunAddress);
1606 DrawStringTrans(backbuffer, 8, 27*8, 0x3FE3, transparency, "CRC: %08X", jaguar_mainRom_crc32);
1608 if (showMsgFrames == 0)
1612 if (transparency == 33)
1614 showMessage = false;
1615 /*extern bool doGPUDis;
1616 doGPUDis = true;//*/
1625 if (nFrame == nFrameskip)
1634 // Reset the pitch, since it may have been changed in-game...
1635 Element::SetScreenAndPitch(backbuffer, GetSDLScreenPitch() / 2);
1637 // Save the background for the GUI...
1638 // memcpy(background, backbuffer, tom_getVideoModeWidth() * 240 * 2);
1639 // In this case, we squash the color to monochrome, then force it to blue + green...
1640 for(uint32 i=0; i<tom_getVideoModeWidth() * 240; i++)
1642 uint16 word = backbuffer[i];
1643 uint8 r = (word >> 10) & 0x1F, g = (word >> 5) & 0x1F, b = word & 0x1F;
1644 word = ((r + g + b) / 3) & 0x001F;
1645 word = (word << 5) | word;
1646 background[i] = word;
1654 //This is crap. We need some REAL exit code, instead of this psuedo crap... !!! FIX !!! [DONE]
1655 WriteLog("GUI: Quitting due to user request.\n");
1661 VideoDone(); // Free SDL components last...!
1669 Window * About(void)
1671 Window * window = new Window(8, 16, 304, 160);
1672 window->AddElement(new Text(8, 8, "Virtual Jaguar 1.0.7"));
1673 // window->AddElement(new Text(8, 8, "Virtual Jaguar CVS 20040317"));
1674 window->AddElement(new Text(8, 24, "Coders:"));
1675 window->AddElement(new Text(16, 32, "Niels Wagenaar (nwagenaar)"));
1676 window->AddElement(new Text(16, 40, "Carwin Jones (Caz)"));
1677 window->AddElement(new Text(16, 48, "James L. Hammons (shamus)"));
1678 window->AddElement(new Text(16, 56, "Adam Green"));
1679 window->AddElement(new Text(8, 72, "Testers:"));
1680 window->AddElement(new Text(16, 80, "Guruma"));
1685 Window * MiscOptions(void)
1687 Window * window = new Window(8, 16, 304, 160);
1688 window->AddElement(new PushButton(8, 8, &vjs.useJaguarBIOS, "BIOS"));
1689 window->AddElement(new SlideSwitch(8, 20, &vjs.hardwareTypeNTSC, "PAL", "NTSC"));
1690 window->AddElement(new PushButton(8, 40, &vjs.DSPEnabled, "DSP"));
1691 window->AddElement(new SlideSwitch(16, 52, &vjs.usePipelinedDSP, "Original", "Pipelined"));
1692 window->AddElement(new SlideSwitch(8, 72, (bool *)&vjs.glFilter, "Sharp", "Blurry"));
1702 // * Window/fullscreen
1710 // Uses zero as transparent color
1711 // Can also use an optional alpha channel
1713 void DrawTransparentBitmap(int16 * screen, uint32 x, uint32 y, uint16 * bitmap, uint8 * alpha/*=NULL*/)
1715 uint16 width = bitmap[0], height = bitmap[1];
1718 uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1719 uint32 address = x + (y * pitch);
1721 for(int yy=0; yy<height; yy++)
1723 for(int xx=0; xx<width; xx++)
1727 if (*bitmap && x + xx < pitch) // NOTE: Still doesn't clip the Y val...
1728 *(screen + address + xx + (yy * pitch)) = *bitmap;
1732 uint8 trans = *alpha;
1733 uint16 color = *bitmap;
1734 uint16 existingColor = *(screen + address + xx + (yy * pitch));
1736 uint8 eRed = (existingColor >> 10) & 0x1F,
1737 eGreen = (existingColor >> 5) & 0x1F,
1738 eBlue = existingColor & 0x1F,
1740 nRed = (color >> 10) & 0x1F,
1741 nGreen = (color >> 5) & 0x1F,
1742 nBlue = color & 0x1F;
1744 uint8 invTrans = 255 - trans;
1745 uint16 bRed = (eRed * trans + nRed * invTrans) / 255;
1746 uint16 bGreen = (eGreen * trans + nGreen * invTrans) / 255;
1747 uint16 bBlue = (eBlue * trans + nBlue * invTrans) / 255;
1749 uint16 blendedColor = (bRed << 10) | (bGreen << 5) | bBlue;
1751 *(screen + address + xx + (yy * pitch)) = blendedColor;
1762 // Very very crude GUI file selector
1764 /*bool UserSelectFile(char * path, char * filename)
1769 extern int16 * backbuffer;
1770 vector<string> fileList;
1772 // Read in the candidate files from the directory pointed to by "path"
1774 DIR * dp = opendir(path);
1777 while ((de = readdir(dp)) != NULL)
1779 char * ext = strrchr(de->d_name, '.');
1782 if (strcasecmp(ext, ".zip") == 0 || strcasecmp(ext, ".jag") == 0)
1783 fileList.push_back(string(de->d_name));
1788 if (fileList.size() == 0) // Any files found?
1789 return false; // Nope. Bail!
1791 // Main GUI selection loop
1793 uint32 cursor = 0, startFile = 0;
1795 if (fileList.size() > 1) // Only go GUI if more than one possibility!
1797 sort(fileList.begin(), fileList.end());
1800 uint32 limit = (fileList.size() > 30 ? 30 : fileList.size());
1803 // Ensure that the GUI is drawn before any user input...
1804 event.type = SDL_USEREVENT;
1805 SDL_PushEvent(&event);
1809 while (SDL_PollEvent(&event))
1811 if (event.type == SDL_KEYDOWN)
1813 SDLKey key = event.key.keysym.sym;
1815 if (key == SDLK_DOWN)
1817 if (cursor != limit - 1) // Cursor is within its window
1819 else // Otherwise, scroll the window...
1821 if (cursor + startFile != fileList.size() - 1)
1835 if (key == SDLK_PAGEDOWN)
1837 if (cursor != limit - 1)
1842 if (startFile > fileList.size() - limit)
1843 startFile = fileList.size() - limit;
1846 if (key == SDLK_PAGEUP)
1852 if (startFile < limit)
1858 if (key == SDLK_RETURN)
1860 if (key == SDLK_ESCAPE)
1862 WriteLog("GUI: Aborting VJ by user request.\n");
1863 return false; // Bail out!
1865 if (key >= SDLK_a && key <= SDLK_z)
1867 // Advance cursor to filename with first letter pressed...
1868 uint8 which = (key - SDLK_a) + 65; // Convert key to A-Z char
1870 for(uint32 i=0; i<fileList.size(); i++)
1872 if ((fileList[i][0] & 0xDF) == which)
1874 cursor = i - startFile;
1875 if (i > startFile + limit - 1)
1876 startFile = i - limit + 1,
1886 else if (event.type == SDL_MOUSEMOTION)
1888 mouseX = event.motion.x, mouseY = event.motion.y;
1890 mouseX /= 2, mouseY /= 2;
1892 else if (event.type == SDL_MOUSEBUTTONDOWN)
1894 uint32 mx = event.button.x, my = event.button.y;
1901 // memset(backbuffer, 0x11, tom_getVideoModeWidth() * tom_getVideoModeHeight() * 2);
1902 memset(backbuffer, 0x11, tom_getVideoModeWidth() * 240 * 2);
1904 for(uint32 i=0; i<limit; i++)
1906 // Clip our strings to guarantee that they fit on the screen...
1907 // (and strip off the extension too)
1908 string s(fileList[startFile + i], 0, fileList[startFile + i].length() - 4);
1909 if (s.length() > 38)
1911 DrawString(backbuffer, 0, i*8, (cursor == i ? true : false), " %s ", s.c_str());
1914 DrawTransparentBitmap(backbuffer, mouseX, mouseY, mousePic);
1921 strcpy(filename, path);
1923 if (strlen(path) > 0)
1924 if (path[strlen(path) - 1] != '/')
1925 strcat(filename, "/");
1927 strcat(filename, fileList[startFile + cursor].c_str());
1933 // Generic ROM loading
1935 uint32 JaguarLoadROM(uint8 * rom, char * path)
1937 // We really should have some kind of sanity checking for the ROM size here to prevent
1938 // a buffer overflow... !!! FIX !!!
1941 char * ext = strrchr(path, '.');
1944 WriteLog("VJ: Loading \"%s\"...", path);
1946 if (strcasecmp(ext, ".zip") == 0)
1948 // Handle ZIP file loading here...
1949 WriteLog("(ZIPped)...");
1951 if (load_zipped_file(0, 0, path, NULL, &rom, &romSize) == -1)
1953 WriteLog("Failed!\n");
1959 /* FILE * fp = fopen(path, "rb");
1963 WriteLog("Failed!\n");
1967 fseek(fp, 0, SEEK_END);
1968 romSize = ftell(fp);
1969 fseek(fp, 0, SEEK_SET);
1970 fread(rom, 1, romSize, fp);
1973 // Handle gzipped files transparently [Adam Green]...
1975 gzFile fp = gzopen(path, "rb");
1979 WriteLog("Failed!\n");
1983 romSize = gzfilelength(fp);
1984 gzseek(fp, 0, SEEK_SET);
1985 gzread(fp, rom, romSize);
1989 WriteLog("OK (%i bytes)\n", romSize);
1996 // Jaguar file loading
1998 bool JaguarLoadFile(char * path)
2000 // jaguarRomSize = JaguarLoadROM(mem, path);
2001 jaguarRomSize = JaguarLoadROM(jaguar_mainRom, path);
2003 /*//This is not *nix friendly for some reason...
2004 // if (!UserSelectFile(path, newPath))
2005 if (!UserSelectFile((strlen(path) == 0 ? (char *)"." : path), newPath))
2007 WriteLog("VJ: Could not find valid ROM in directory \"%s\"...\nAborting!\n", path);
2012 if (jaguarRomSize == 0)
2014 // WriteLog("VJ: Could not load ROM from file \"%s\"...\nAborting!\n", newPath);
2015 WriteLog("GUI: Could not load ROM from file \"%s\"...\nAborting load!\n", path);
2016 // Need to do something else here, like throw up an error dialog instead of aborting. !!! FIX !!!
2019 return false; // This is a start...
2022 jaguar_mainRom_crc32 = crc32_calcCheckSum(jaguar_mainRom, jaguarRomSize);
2023 WriteLog("CRC: %08X\n", (unsigned int)jaguar_mainRom_crc32);
2026 jaguarRunAddress = 0x802000;
2028 char * ext = strrchr(path, '.'); // Get the file's extension for non-cartridge checking
2030 //NOTE: Should fix JaguarLoadROM() to replace .zip with what's *in* the zip (.abs, .j64, etc.)
2031 if (strcasecmp(ext, ".rom") == 0)
2033 // File extension ".ROM": Alpine image that loads/runs at $802000
2034 WriteLog("GUI: Setting up homebrew (ROM)... Run address: 00802000, length: %08X\n", jaguarRomSize);
2036 for(int i=jaguarRomSize-1; i>=0; i--)
2037 jaguar_mainRom[0x2000 + i] = jaguar_mainRom[i];
2039 memset(jaguar_mainRom, 0xFF, 0x2000);
2040 /* memcpy(jaguar_mainRam, jaguar_mainRom, jaguarRomSize);
2041 memset(jaguar_mainRom, 0xFF, 0x600000);
2042 memcpy(jaguar_mainRom + 0x2000, jaguar_mainRam, jaguarRomSize);
2043 memset(jaguar_mainRam, 0x00, 0x400000);*/
2046 Stubulator ROM vectors...
2047 handler 001 at $00E00008
2048 handler 002 at $00E008DE
2049 handler 003 at $00E008E2
2050 handler 004 at $00E008E6
2051 handler 005 at $00E008EA
2052 handler 006 at $00E008EE
2053 handler 007 at $00E008F2
2054 handler 008 at $00E0054A
2055 handler 009 at $00E008FA
2056 handler 010 at $00000000
2057 handler 011 at $00000000
2058 handler 012 at $00E008FE
2059 handler 013 at $00E00902
2060 handler 014 at $00E00906
2061 handler 015 at $00E0090A
2062 handler 016 at $00E0090E
2063 handler 017 at $00E00912
2064 handler 018 at $00E00916
2065 handler 019 at $00E0091A
2066 handler 020 at $00E0091E
2067 handler 021 at $00E00922
2068 handler 022 at $00E00926
2069 handler 023 at $00E0092A
2070 handler 024 at $00E0092E
2071 handler 025 at $00E0107A
2072 handler 026 at $00E0107A
2073 handler 027 at $00E0107A
2074 handler 028 at $00E008DA
2075 handler 029 at $00E0107A
2076 handler 030 at $00E0107A
2077 handler 031 at $00E0107A
2078 handler 032 at $00000000
2080 Let's try setting up the illegal instruction vector for a stubulated jaguar...
2082 /* SET32(jaguar_mainRam, 0x08, 0x00E008DE);
2083 SET32(jaguar_mainRam, 0x0C, 0x00E008E2);
2084 SET32(jaguar_mainRam, 0x10, 0x00E008E6); // <-- Should be here (it is)...
2085 SET32(jaguar_mainRam, 0x14, 0x00E008EA);//*/
2087 // Try setting the vector to say, $1000 and putting an instruction there that loops forever:
2088 // This kludge works! Yeah!
2089 SET32(jaguar_mainRam, 0x10, 0x00001000);
2090 SET16(jaguar_mainRam, 0x1000, 0x60FE); // Here: bra Here
2092 else if (strcasecmp(ext, ".abs") == 0)
2094 // File extension ".ABS": Atari linker output file with header (w/o is useless to us here)
2097 ABS Format sleuthing (LBUGDEMO.ABS):
2099 000000 60 1B 00 00 05 0C 00 04 62 C0 00 00 04 28 00 00
2100 000010 12 A6 00 00 00 00 00 80 20 00 FF FF 00 80 25 0C
2103 DRI-format file detected...
2104 Text segment size = 0x0000050c bytes
2105 Data segment size = 0x000462c0 bytes
2106 BSS Segment size = 0x00000428 bytes
2107 Symbol Table size = 0x000012a6 bytes
2108 Absolute Address for text segment = 0x00802000
2109 Absolute Address for data segment = 0x0080250c
2110 Absolute Address for BSS segment = 0x00004000
2113 000000 01 50 00 03 00 00 00 00 00 03 83 10 00 00 05 3b
2114 000010 00 1c 00 03 00 00 01 07 00 00 1d d0 00 03 64 98
2115 000020 00 06 8b 80 00 80 20 00 00 80 20 00 00 80 3d d0
2117 000030 2e 74 78 74 00 00 00 00 00 80 20 00 00 80 20 00 .txt (+36 bytes)
2118 000040 00 00 1d d0 00 00 00 a8 00 00 00 00 00 00 00 00
2119 000050 00 00 00 00 00 00 00 20
2120 000058 2e 64 74 61 00 00 00 00 00 80 3d d0 00 80 3d d0 .dta (+36 bytes)
2121 000068 00 03 64 98 00 00 1e 78 00 00 00 00 00 00 00 00
2122 000078 00 00 00 00 00 00 00 40
2123 000080 2e 62 73 73 00 00 00 00 00 00 50 00 00 00 50 00 .bss (+36 bytes)
2124 000090 00 06 8b 80 00 03 83 10 00 00 00 00 00 00 00 00
2125 0000a0 00 00 00 00 00 00 00 80
2127 Header size is $A8 bytes...
2129 BSD/COFF format file detected...
2130 3 sections specified
2131 Symbol Table offset = 230160 ($00038310)
2132 Symbol Table contains 1339 symbol entries ($0000053B)
2133 The additional header size is 28 bytes ($001C)
2134 Magic Number for RUN_HDR = 0x00000107
2135 Text Segment Size = 7632 ($00001DD0)
2136 Data Segment Size = 222360 ($00036498)
2137 BSS Segment Size = 428928 ($00068B80)
2138 Starting Address for executable = 0x00802000
2139 Start of Text Segment = 0x00802000
2140 Start of Data Segment = 0x00803dd0
2142 if (jaguar_mainRom[0] == 0x60 && jaguar_mainRom[1] == 0x1B)
2144 uint32 loadAddress = GET32(jaguar_mainRom, 0x16), //runAddress = GET32(jaguar_mainRom, 0x2A),
2145 codeSize = GET32(jaguar_mainRom, 0x02) + GET32(jaguar_mainRom, 0x06);
2146 WriteLog("GUI: Setting up homebrew (ABS-1)... Run address: %08X, length: %08X\n", loadAddress, codeSize);
2148 if (loadAddress < 0x800000)
2149 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x24, codeSize);
2152 for(int i=codeSize-1; i>=0; i--)
2153 jaguar_mainRom[(loadAddress - 0x800000) + i] = jaguar_mainRom[i + 0x24];
2154 /* memcpy(jaguar_mainRam, jaguar_mainRom + 0x24, codeSize);
2155 memset(jaguar_mainRom, 0xFF, 0x600000);
2156 memcpy(jaguar_mainRom + (loadAddress - 0x800000), jaguar_mainRam, codeSize);
2157 memset(jaguar_mainRam, 0x00, 0x400000);*/
2160 jaguarRunAddress = loadAddress;
2162 else if (jaguar_mainRom[0] == 0x01 && jaguar_mainRom[1] == 0x50)
2164 uint32 loadAddress = GET32(jaguar_mainRom, 0x28), runAddress = GET32(jaguar_mainRom, 0x24),
2165 codeSize = GET32(jaguar_mainRom, 0x18) + GET32(jaguar_mainRom, 0x1C);
2166 WriteLog("GUI: Setting up homebrew (ABS-2)... Run address: %08X, length: %08X\n", runAddress, codeSize);
2168 if (loadAddress < 0x800000)
2169 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0xA8, codeSize);
2172 for(int i=codeSize-1; i>=0; i--)
2173 jaguar_mainRom[(loadAddress - 0x800000) + i] = jaguar_mainRom[i + 0xA8];
2174 /* memcpy(jaguar_mainRam, jaguar_mainRom + 0xA8, codeSize);
2175 memset(jaguar_mainRom, 0xFF, 0x600000);
2176 memcpy(jaguar_mainRom + (loadAddress - 0x800000), jaguar_mainRam, codeSize);
2177 memset(jaguar_mainRam, 0x00, 0x400000);*/
2180 jaguarRunAddress = runAddress;
2184 WriteLog("GUI: Couldn't find correct ABS format: %02X %02X\n", jaguar_mainRom[0], jaguar_mainRom[1]);
2188 else if (strcasecmp(ext, ".jag") == 0)
2190 // File extension ".JAG": Atari server file with header
2191 //NOTE: The bytes 'JAGR' should also be at position $1C...
2192 // Also, there's *always* a $601A header at position $00...
2193 if (jaguar_mainRom[0] == 0x60 && jaguar_mainRom[1] == 0x1A)
2195 uint32 loadAddress = GET32(jaguar_mainRom, 0x22), runAddress = GET32(jaguar_mainRom, 0x2A);
2196 //This is not always right! Especially when converted via bin2jag1!!!
2197 //We should have access to the length of the furshlumiger file that was loaded anyway!
2199 // uint32 progLength = GET32(jaguar_mainRom, 0x02);
2202 // WriteLog("Jaguar: Setting up PD ROM... Run address: %08X, length: %08X\n", runAddress, progLength);
2203 // memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, progLength);
2204 WriteLog("GUI: Setting up homebrew (JAG)... Run address: %08X, length: %08X\n", runAddress, jaguarRomSize - 0x2E);
2205 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, jaguarRomSize - 0x2E);
2206 // SET32(jaguar_mainRam, 4, runAddress);
2207 jaguarRunAddress = runAddress;
2212 // .J64 (Jaguar cartridge ROM image) is implied by the FileList object...
2218 // Get the length of a (possibly) gzipped file
2220 int gzfilelength(gzFile gd)
2222 int size = 0, length = 0;
2223 unsigned char buffer[0x10000];
2229 // Read in chunks until EOF
2230 size = gzread(gd, buffer, 0x10000);