4 // Graphical User Interface support
9 #include <sys/types.h> // For MacOS <dirent.h> dependency
15 #include <ctype.h> // For toupper()
21 #include "font14pt.h" // Also 15, 16, 17, 18
22 #include "guielements.h"
26 #include "sdlemu_opengl.h"
29 using namespace std; // For STL stuff
31 // Private function prototypes
33 class Window; // Forward declaration...
35 //void DrawTransparentBitmap(uint32 * screen, uint32 x, uint32 y, uint32 * bitmap, uint8 * alpha = NULL);
36 void DrawTransparentBitmap(uint32 * screen, uint32 x, uint32 y, uint32 * bitmap);
37 void DrawStringTrans(uint32 * screen, uint32 x, uint32 y, uint32 color, uint8 opacity, const char * text, ...);
38 void DrawStringOpaque(uint32 * screen, uint32 x, uint32 y, uint32 color1, uint32 color2, const char * text, ...);
39 void DrawString(uint32 * screen, uint32 x, uint32 y, bool invert, const char * text, ...);
40 Window * LoadROM(void);
41 Window * ResetJaguar(void);
42 Window * ResetJaguarCD(void);
43 Window * RunEmu(void);
46 Window * MiscOptions(void);
48 int gzfilelength(gzFile gd);
52 extern uint8 * jaguar_mainRam;
53 extern uint8 * jaguar_mainRom;
54 extern uint8 * jaguar_bootRom;
55 extern uint8 * jaguar_CDBootROM;
56 extern bool BIOSLoaded;
57 extern bool CDBIOSLoaded;
59 // Local global variables
61 bool exitGUI = false; // GUI (emulator) done variable
63 uint32 background[1280 * 256]; // GUI background buffer
65 char separator[] = "--------------------------------------------------------";
68 // Case insensitive string compare function
69 // Taken straight out of Thinking In C++ by Bruce Eckel. Thanks Bruce!
72 int stringCmpi(const string &s1, const string &s2)
74 // Select the first element of each string:
75 string::const_iterator p1 = s1.begin(), p2 = s2.begin();
77 while (p1 != s1.end() && p2 != s2.end()) // Don
\92t run past the end
79 if (toupper(*p1) != toupper(*p2)) // Compare upper-cased chars
80 return (toupper(*p1) < toupper(*p2) ? -1 : 1);// Report which was lexically greater
86 // If they match up to the detected eos, say which was longer. Return 0 if the same.
87 return s2.size() - s1.size();
94 enum { WINDOW_CLOSE, MENU_ITEM_CHOSEN };
99 Element(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0)
100 { extents.x = x, extents.y = y, extents.w = w, extents.h = h; }
101 virtual void HandleKey(SDLKey key) = 0; // These are "pure" virtual functions...
102 virtual void HandleMouseMove(uint32 x, uint32 y) = 0;
103 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) = 0;
104 virtual void Draw(uint32, uint32) = 0;
105 virtual void Notify(Element *) = 0;
106 //Needed? virtual ~Element() = 0;
107 //We're not allocating anything in the base class, so the answer would be NO.
108 bool Inside(uint32 x, uint32 y);
110 // static void SetScreenAndPitch(int16 * s, uint32 p) { screenBuffer = s, pitch = p; }
111 static void SetScreenAndPitch(uint32 * s, uint32 p) { screenBuffer = s, pitch = p; }
116 // Class variables...
117 // static int16 * screenBuffer;
118 static uint32 * screenBuffer;
122 // Initialize class variables (Element)
123 //int16 * Element::screenBuffer = NULL;
124 uint32 * Element::screenBuffer = NULL;
125 uint32 Element::pitch = 0;
127 bool Element::Inside(uint32 x, uint32 y)
129 return (x >= (uint32)extents.x && x < (uint32)(extents.x + extents.w)
130 && y >= (uint32)extents.y && y < (uint32)(extents.y + extents.h) ? true : false);
134 class Button: public Element
137 Button(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
138 activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
139 bgColor(0xFF00FF00), pic(NULL), elementToTell(NULL) {}
140 Button(uint32 x, uint32 y, uint32 w, uint32 h, uint32 * p): Element(x, y, w, h),
141 activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
142 bgColor(0xFF00FF00), pic(p), elementToTell(NULL) {}
143 // Button(uint32 x, uint32 y, uint32 * p): Element(x, y, 0, 0),
144 Button(uint32 x, uint32 y, uint32 * p, uint32 * pH = NULL, uint32 * pD = NULL): Element(x, y, 0, 0),
145 activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
146 bgColor(0xFF00FF00), pic(p), picHover(pH), picDown(pD), elementToTell(NULL)
147 { if (pic) extents.w = pic[0], extents.h = pic[1]; }
148 Button(uint32 x, uint32 y, uint32 w, uint32 h, string s): Element(x, y, w, h),
149 activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
150 bgColor(0xFF00FF00), pic(NULL), text(s), elementToTell(NULL) {}
151 Button(uint32 x, uint32 y, string s): Element(x, y, 0, FONT_HEIGHT),
152 activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
153 bgColor(0xFF00FF00), pic(NULL), text(s), elementToTell(NULL)
154 { extents.w = s.length() * FONT_WIDTH; }
155 virtual void HandleKey(SDLKey key) {}
156 virtual void HandleMouseMove(uint32 x, uint32 y);
157 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
158 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
159 virtual void Notify(Element *) {}
160 bool ButtonClicked(void) { return activated; }
161 void SetNotificationElement(Element * e) { elementToTell = e; }
164 bool activated, clicked, inside;
165 uint32 fgColor, bgColor;
166 uint32 * pic, * picHover, * picDown;
168 Element * elementToTell;
171 void Button::HandleMouseMove(uint32 x, uint32 y)
173 inside = Inside(x, y);
176 void Button::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
183 if (clicked && !mouseDown)
185 clicked = false, activated = true;
187 // Send a message that we're activated (if there's someone to tell, that is)
189 elementToTell->Notify(this);
193 clicked = activated = false;
196 void Button::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
198 uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
200 if (text.length() > 0) // Simple text button
203 for(uint32 y=0; y<extents.h; y++)
205 for(uint32 x=0; x<extents.w; x++)
207 // Doesn't clip in y axis! !!! FIX !!!
208 if (extents.x + x < pitch)
209 screenBuffer[addr + x + (y * pitch)]
210 // = (clicked && inside ? fgColor : (inside ? 0x43F0 : bgColor));
211 //43F0 -> 010000 11111 10000 -> 0100 0001 1111 1111 1000 0100 -> 41 FF 84
212 = (clicked && inside ? fgColor : (inside ? 0xFF84FF41 : bgColor));
216 DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY, false, "%s", text.c_str());
218 else // Graphical button
220 uint32 * picToShow = pic;
222 if (picHover != NULL && inside && !clicked)
223 picToShow = picHover;
225 if (picDown != NULL && inside && clicked)
228 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, picToShow);
233 class PushButton: public Element
236 // Save state externally?
237 //We pass in a state variable if we want to track it externally, otherwise we use our own
238 //internal state var. Still need to do some kind of callback for pushbuttons that do things
239 //like change from fullscreen to windowed... !!! FIX !!!
242 // PushButton(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
243 // activated(false), clicked(false), inside(false), fgColor(0xFFFF),
244 // bgColor(0x03E0), pic(NULL), elementToTell(NULL) {}
245 PushButton(uint32 x, uint32 y, bool * st, string s): Element(x, y, 8, 8), state(st),
246 inside(false), text(s) { if (st == NULL) state = &internalState; }
247 /* Button(uint32 x, uint32 y, uint32 w, uint32 h, uint32 * p): Element(x, y, w, h),
248 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
249 bgColor(0x03E0), pic(p), elementToTell(NULL) {}
250 Button(uint32 x, uint32 y, uint32 * p): Element(x, y, 0, 0),
251 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
252 bgColor(0x03E0), pic(p), elementToTell(NULL)
253 { if (pic) extents.w = pic[0], extents.h = pic[1]; }
254 Button(uint32 x, uint32 y, uint32 w, uint32 h, string s): Element(x, y, w, h),
255 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
256 bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL) {}
257 PushButton(uint32 x, uint32 y, string s): Element(x, y, 0, 8),
258 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
259 bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL)
260 { extents.w = s.length() * 8; }*/
261 virtual void HandleKey(SDLKey key) {}
262 virtual void HandleMouseMove(uint32 x, uint32 y);
263 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
264 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
265 virtual void Notify(Element *) {}
266 // bool ButtonClicked(void) { return activated; }
267 // void SetNotificationElement(Element * e) { elementToTell = e; }
272 // bool activated, clicked, inside;
273 // uint16 fgColor, bgColor;
276 // Element * elementToTell;
280 void PushButton::HandleMouseMove(uint32 x, uint32 y)
282 inside = Inside(x, y);
285 void PushButton::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
287 if (inside && mouseDown)
292 if (clicked && !mouseDown)
294 clicked = false, activated = true;
296 // Send a message that we're activated (if there's someone to tell, that is)
298 elementToTell->Notify(this);
303 // clicked = activated = false;
306 void PushButton::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
308 /* uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
310 for(uint32 y=0; y<extents.h; y++)
312 for(uint32 x=0; x<extents.w; x++)
314 // Doesn't clip in y axis! !!! FIX !!!
315 if (extents.x + x < pitch)
316 screenBuffer[addr + x + (y * pitch)]
317 = (clicked && inside ? fgColor : (inside ? 0x43F0 : bgColor));
321 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, (*state ? pushButtonDown : pushButtonUp));
322 // DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, (*state ? pushButtonDown : pushButtonUp), (*state ? pbdAlpha : pbuAlpha));
323 if (text.length() > 0)
324 DrawString(screenBuffer, extents.x + offsetX + 12, extents.y + offsetY, false, "%s", text.c_str());
328 class SlideSwitch: public Element
331 // Save state externally?
332 //Seems to be handled the same as PushButton, but without sanity checks. !!! FIX !!!
335 SlideSwitch(uint32 x, uint32 y, bool * st, string s1, string s2): Element(x, y, 8, 16), state(st),
336 inside(false), text1(s1), text2(s2) {}
337 virtual void HandleKey(SDLKey key) {}
338 virtual void HandleMouseMove(uint32 x, uint32 y);
339 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
340 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
341 virtual void Notify(Element *) {}
342 // bool ButtonClicked(void) { return activated; }
343 // void SetNotificationElement(Element * e) { elementToTell = e; }
348 // bool activated, clicked, inside;
349 // uint16 fgColor, bgColor;
352 // Element * elementToTell;
355 void SlideSwitch::HandleMouseMove(uint32 x, uint32 y)
357 inside = Inside(x, y);
360 void SlideSwitch::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
362 if (inside && mouseDown)
367 if (clicked && !mouseDown)
369 clicked = false, activated = true;
371 // Send a message that we're activated (if there's someone to tell, that is)
373 elementToTell->Notify(this);
378 // clicked = activated = false;
381 void SlideSwitch::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
383 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, (*state ? slideSwitchDown : slideSwitchUp));
384 if (text1.length() > 0)
385 DrawString(screenBuffer, extents.x + offsetX + 12, extents.y + offsetY, false, "%s", text1.c_str());
386 if (text2.length() > 0)
387 DrawString(screenBuffer, extents.x + offsetX + 12, extents.y + offsetY + 8, false, "%s", text2.c_str());
391 class Window: public Element
394 /* Window(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
395 fgColor(0x4FF0), bgColor(0xFE10)
396 { close = new Button(w - 8, 1, closeBox); list.push_back(close); }*/
397 Window(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0,
398 void (* f)(Element *) = NULL): Element(x, y, w, h),
399 // /*clicked(false), inside(false),*/ fgColor(0x4FF0), bgColor(0x1E10),
400 //4FF0 -> 010011 11111 10000 -> 0100 1101 1111 1111 1000 0100 -> 4D FF 84
401 //1E10 -> 000111 10000 10000 -> 0001 1111 1000 0100 1000 0100 -> 1F 84 84
402 /*clicked(false), inside(false),*/ fgColor(0xFF84FF4D), bgColor(0xFF84841F),
404 { close = new Button(w - (CLOSEBOX_WIDTH + 1), 1, closeBox, closeBoxHover, closeBoxDown);
405 list.push_back(close);
406 close->SetNotificationElement(this); }
408 virtual void HandleKey(SDLKey key);
409 virtual void HandleMouseMove(uint32 x, uint32 y);
410 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
411 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
412 virtual void Notify(Element * e);
413 void AddElement(Element * e);
414 // bool WindowActive(void) { return true; }//return !close->ButtonClicked(); }
417 // bool clicked, inside;
418 uint32 fgColor, bgColor;
419 void (* handler)(Element *);
421 //We have to use a list of Element *pointers* because we can't make a list that will hold
422 //all the different object types in the same list...
423 vector<Element *> list;
428 for(uint32 i=0; i<list.size(); i++)
433 void Window::HandleKey(SDLKey key)
435 if (key == SDLK_ESCAPE)
438 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
439 SDL_PushEvent(&event);
442 // Handle the items this window contains...
443 for(uint32 i=0; i<list.size(); i++)
444 // Make coords relative to upper right corner of this window...
445 list[i]->HandleKey(key);
448 void Window::HandleMouseMove(uint32 x, uint32 y)
450 // Handle the items this window contains...
451 for(uint32 i=0; i<list.size(); i++)
452 // Make coords relative to upper right corner of this window...
453 list[i]->HandleMouseMove(x - extents.x, y - extents.y);
456 void Window::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
458 // Handle the items this window contains...
459 for(uint32 i=0; i<list.size(); i++)
460 // Make coords relative to upper right corner of this window...
461 list[i]->HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
464 void Window::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
466 uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
468 for(uint32 y=0; y<extents.h; y++)
470 for(uint32 x=0; x<extents.w; x++)
472 // Doesn't clip in y axis! !!! FIX !!!
473 if (extents.x + x < pitch)
474 screenBuffer[addr + x + (y * pitch)] = bgColor;
478 // Handle the items this window contains...
479 for(uint32 i=0; i<list.size(); i++)
480 list[i]->Draw(extents.x, extents.y);
483 void Window::AddElement(Element * e)
488 void Window::Notify(Element * e)
493 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
494 SDL_PushEvent(&event);
499 class Text: public Element
502 // Text(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
503 // fgColor(0x4FF0), bgColor(0xFE10) {}
504 // Text(uint32 x, uint32 y, string s, uint16 fg = 0x4FF0, uint16 bg = 0xFE10): Element(x, y, 0, 0),
505 // fgColor(fg), bgColor(bg), text(s) {}
506 //4FF0 -> 010011 11111 10000 -> 0100 1101 1111 1111 1000 0100 -> 4D FF 84
507 //FE10 -> 111111 10000 10000 -> 1111 1111 1000 0100 1000 0100 -> FF 84 84
508 Text(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
509 fgColor(0xFF8484FF), bgColor(0xFF84FF4D) {}
510 Text(uint32 x, uint32 y, string s, uint32 fg = 0xFF8484FF, uint32 bg = 0xFF84FF4D):
511 Element(x, y, 0, 0), fgColor(fg), bgColor(bg), text(s) {}
512 virtual void HandleKey(SDLKey key) {}
513 virtual void HandleMouseMove(uint32 x, uint32 y) {}
514 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) {}
515 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
516 virtual void Notify(Element *) {}
519 uint32 fgColor, bgColor;
523 void Text::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
525 if (text.length() > 0)
526 // DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY, false, "%s", text.c_str());
527 DrawStringOpaque(screenBuffer, extents.x + offsetX, extents.y + offsetY, fgColor, bgColor, "%s", text.c_str());
531 class ListBox: public Element
532 //class ListBox: public Window
535 // ListBox(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
536 ListBox(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0);//: Window(x, y, w, h),
537 // windowPtr(0), cursor(0), limit(0), charWidth((w / 8) - 1), charHeight(h / 8),
538 // elementToTell(NULL), upArrow(w - 8, 0, upArrowBox),
539 // downArrow(w - 8, h - 8, downArrowBox), upArrow2(w - 8, h - 16, upArrowBox) {}
540 virtual void HandleKey(SDLKey key);
541 virtual void HandleMouseMove(uint32 x, uint32 y);
542 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
543 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
544 virtual void Notify(Element * e);
545 void SetNotificationElement(Element * e) { elementToTell = e; }
546 void AddItem(string s);
547 string GetSelectedItem(void);
551 uint32 windowPtr, cursor, limit;
552 uint32 charWidth, charHeight; // Box width/height in characters
553 Element * elementToTell;
554 Button upArrow, downArrow, upArrow2;
558 uint32 yRelativePoint;
561 ListBox::ListBox(uint32 x, uint32 y, uint32 w, uint32 h): Element(x, y, w, h),
562 thumbClicked(false), windowPtr(0), cursor(0), limit(0), charWidth((w / FONT_WIDTH) - 1),
563 charHeight(h / FONT_HEIGHT), elementToTell(NULL), upArrow(w - 8, 0, upArrowBox),
564 downArrow(w - 8, h - 8, downArrowBox), upArrow2(w - 8, h - 16, upArrowBox)
566 upArrow.SetNotificationElement(this);
567 downArrow.SetNotificationElement(this);
568 upArrow2.SetNotificationElement(this);
569 extents.w -= 8; // Make room for scrollbar...
572 void ListBox::HandleKey(SDLKey key)
574 if (key == SDLK_DOWN)
576 if (cursor != limit - 1) // Cursor is within its window
578 else // Otherwise, scroll the window...
580 if (cursor + windowPtr != item.size() - 1)
584 else if (key == SDLK_UP)
594 else if (key == SDLK_PAGEDOWN)
596 if (cursor != limit - 1)
601 if (windowPtr > item.size() - limit)
602 windowPtr = item.size() - limit;
605 else if (key == SDLK_PAGEUP)
611 if (windowPtr < limit)
617 else if (key >= SDLK_a && key <= SDLK_z)
619 // Advance cursor to filename with first letter pressed...
620 uint8 which = (key - SDLK_a) + 65; // Convert key to A-Z char
622 for(uint32 i=0; i<item.size(); i++)
624 if ((item[i][0] & 0xDF) == which)
626 cursor = i - windowPtr;
627 if (i > windowPtr + limit - 1)
628 windowPtr = i - limit + 1, cursor = limit - 1;
630 windowPtr = i, cursor = 0;
637 void ListBox::HandleMouseMove(uint32 x, uint32 y)
639 upArrow.HandleMouseMove(x - extents.x, y - extents.y);
640 downArrow.HandleMouseMove(x - extents.x, y - extents.y);
641 upArrow2.HandleMouseMove(x - extents.x, y - extents.y);
645 uint32 sbHeight = extents.h - 24,
646 thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight);
648 //yRelativePoint is the spot on the thumb where we clicked...
649 int32 newThumbStart = y - yRelativePoint;
651 if (newThumbStart < 0)
654 if ((uint32)newThumbStart > sbHeight - thumb)
655 newThumbStart = sbHeight - thumb;
657 windowPtr = (uint32)(((float)newThumbStart / (float)sbHeight) * (float)item.size());
658 //Check for cursor bounds as well... Or do we need to???
659 //Actually, we don't...!
663 void ListBox::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
665 if (Inside(x, y) && mouseDown)
667 // Why do we have to do this??? (- extents.y?)
668 // I guess it's because only the Window class has offsetting implemented... !!! FIX !!!
669 // cursor = (y - extents.y) / 8;
670 cursor = (y - extents.y) / FONT_HEIGHT;
673 // Check for a hit on the scrollbar...
674 if (x > (uint32)(extents.x + extents.w) && x <= (uint32)(extents.x + extents.w + 8)
675 && y > (uint32)(extents.y + 8) && y <= (uint32)(extents.y + extents.h - 16))
679 // This shiaut should be calculated in AddItem(), not here... (or in Draw() for that matter)
680 uint32 sbHeight = extents.h - 24,
681 thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight),
682 thumbStart = (uint32)(((float)windowPtr / (float)item.size()) * (float)sbHeight);
684 // Did we hit the thumb?
685 if (y >= (extents.y + 8 + thumbStart) && y < (extents.y + 8 + thumbStart + thumb))
686 thumbClicked = true, yRelativePoint = y - thumbStart;
688 //Seems that this is useless--never reached except in rare cases and that the code outside is
691 // thumbClicked = false;
695 thumbClicked = false;
697 upArrow.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
698 downArrow.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
699 upArrow2.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
702 void ListBox::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
704 for(uint32 i=0; i<limit; i++)
706 // Strip off the extension
707 // (extension stripping should be an option, not default!)
708 string s(item[windowPtr + i], 0, item[windowPtr + i].length() - 4);
709 // DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY + i*8,
710 DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY + i*FONT_HEIGHT,
711 (cursor == i ? true : false), "%-*.*s", charWidth, charWidth, s.c_str());
714 upArrow.Draw(extents.x + offsetX, extents.y + offsetY);
715 downArrow.Draw(extents.x + offsetX, extents.y + offsetY);
716 upArrow2.Draw(extents.x + offsetX, extents.y + offsetY);
718 uint32 sbHeight = extents.h - 24,
719 thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight),
720 thumbStart = (uint32)(((float)windowPtr / (float)item.size()) * (float)sbHeight);
722 for(uint32 y=extents.y+offsetY+8; y<extents.y+offsetY+extents.h-16; y++)
724 // for(uint32 x=extents.x+offsetX+extents.w-8; x<extents.x+offsetX+extents.w; x++)
725 for(uint32 x=extents.x+offsetX+extents.w; x<extents.x+offsetX+extents.w+8; x++)
727 if (y >= thumbStart + (extents.y+offsetY+8) && y < thumbStart + thumb + (extents.y+offsetY+8))
728 // screenBuffer[x + (y * pitch)] = (thumbClicked ? 0x458E : 0xFFFF);
729 //458E -> 01 0001 0 1100 0 1110 -> 0100 0101 0110 0011 0111 0011 -> 45 63 73
730 screenBuffer[x + (y * pitch)] = (thumbClicked ? 0xFF736345 : 0xFFFFFFFF);
732 // screenBuffer[x + (y * pitch)] = 0x0200;
733 //0200 -> 000000 10000 00000 -> 00 1000 0100 00
734 screenBuffer[x + (y * pitch)] = 0xFF008400;
739 void ListBox::Notify(Element * e)
741 if (e == &upArrow || e == &upArrow2)
747 if (cursor < limit - 1)
751 else if (e == &downArrow)
753 if (windowPtr < item.size() - limit)
763 void ListBox::AddItem(string s)
765 // Do a simple insertion sort
766 bool inserted = false;
768 for(vector<string>::iterator i=item.begin(); i<item.end(); i++)
770 if (stringCmpi(s, *i) == -1)
781 limit = (item.size() > charHeight ? charHeight : item.size());
784 string ListBox::GetSelectedItem(void)
786 return item[windowPtr + cursor];
790 class FileList: public Window
793 FileList(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0);
794 virtual ~FileList() {}
795 virtual void HandleKey(SDLKey key);
796 virtual void HandleMouseMove(uint32 x, uint32 y) { Window::HandleMouseMove(x, y); }
797 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) { Window::HandleMouseButton(x, y, mouseDown); }
798 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0) { Window::Draw(offsetX, offsetY); }
799 virtual void Notify(Element * e);
806 //Need 4 buttons, one scrollbar...
807 FileList::FileList(uint32 x, uint32 y, uint32 w, uint32 h): Window(x, y, w, h)
809 files = new ListBox(8, 8, w - 16, h - 32);
811 load = new Button(8, h - 16, " Load ");
813 load->SetNotificationElement(this);
815 //!!! FIX !!! Directory might not exist--this shouldn't cause VJ to crash!
816 DIR * dp = opendir(vjs.ROMPath);
821 while ((de = readdir(dp)) != NULL)
823 char * ext = strrchr(de->d_name, '.');
826 if (strcasecmp(ext, ".zip") == 0 || strcasecmp(ext, ".j64") == 0
827 || strcasecmp(ext, ".abs") == 0 || strcasecmp(ext, ".jag") == 0
828 || strcasecmp(ext, ".rom") == 0)
829 files->AddItem(string(de->d_name));
836 //Give a diagnostic message here so that the (l)user can figure out what went wrong. !!! FIX !!!
840 void FileList::HandleKey(SDLKey key)
842 if (key == SDLK_RETURN)
845 Window::HandleKey(key);
848 void FileList::Notify(Element * e)
852 char filename[MAX_PATH];
853 strcpy(filename, vjs.ROMPath);
855 if (strlen(filename) > 0)
856 if (filename[strlen(filename) - 1] != '/')
857 strcat(filename, "/");
859 strcat(filename, files->GetSelectedItem().c_str());
861 // uint32 romSize = JaguarLoadROM(jaguar_mainRom, filename);
862 // JaguarLoadCart(jaguar_mainRom, filename);
863 if (JaguarLoadFile(filename))
866 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
867 SDL_PushEvent(&event);
869 event.type = SDL_USEREVENT, event.user.code = MENU_ITEM_CHOSEN;
870 event.user.data1 = (void *)ResetJaguar;
871 SDL_PushEvent(&event);
876 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
877 SDL_PushEvent(&event);
879 // Handle the error, but don't run...
880 // Tell the user that we couldn't run their file for some reason... !!! FIX !!!
881 //how to kludge: Make a function like ResetJaguar which creates the dialog window
892 Window * (* action)(void);
895 NameAction(string n, Window * (* a)(void) = NULL, SDLKey k = SDLK_UNKNOWN): name(n),
896 action(a), hotKey(k) {}
903 MenuItems(): charLength(0) {}
904 bool Inside(uint32 x, uint32 y)
905 { return (x >= (uint32)extents.x && x < (uint32)(extents.x + extents.w)
906 && y >= (uint32)extents.y && y < (uint32)(extents.y + extents.h) ? true : false); }
909 vector<NameAction> item;
914 class Menu: public Element
917 // 1CFF -> 0 001 11 00 111 1 1111
918 // 421F -> 0 100 00 10 000 1 1111
919 Menu(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = FONT_HEIGHT,
920 /* uint16 fgc = 0x1CFF, uint16 bgc = 0x000F, uint16 fgch = 0x421F,
921 uint16 bgch = 0x1CFF): Element(x, y, w, h), activated(false), clicked(false),*/
922 /* uint32 fgc = 0xFF3F3F00, uint32 bgc = 0x7F000000, uint32 fgch = 0xFF878700,
923 uint32 bgch = 0xFF3F3F00): Element(x, y, w, h), activated(false), clicked(false),*/
924 /* uint32 fgc = 0xFFFF3F3F, uint32 bgc = 0xFF7F0000, uint32 fgch = 0xFFFF8787,
925 uint32 bgch = 0xFFFF3F3F): Element(x, y, w, h), activated(false), clicked(false),*/
926 uint32 fgc = 0xFF7F0000, uint32 bgc = 0xFFFF3F3F, uint32 fgch = 0xFFFF3F3F,
927 uint32 bgch = 0xFFFF8787): Element(x, y, w, h), activated(false), clicked(false),
928 inside(0), insidePopup(0), fgColor(fgc), bgColor(bgc), fgColorHL(fgch),
929 bgColorHL(bgch), menuChosen(-1), menuItemChosen(-1) {}
930 virtual void HandleKey(SDLKey key);
931 virtual void HandleMouseMove(uint32 x, uint32 y);
932 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
933 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
934 virtual void Notify(Element *) {}
935 void Add(MenuItems mi);
938 bool activated, clicked;
939 uint32 inside, insidePopup;
940 // uint16 fgColor, bgColor, fgColorHL, bgColorHL;
941 uint32 fgColor, bgColor, fgColorHL, bgColorHL;
942 int menuChosen, menuItemChosen;
945 vector<MenuItems> itemList;
948 void Menu::HandleKey(SDLKey key)
950 for(uint32 i=0; i<itemList.size(); i++)
952 for(uint32 j=0; j<itemList[i].item.size(); j++)
954 if (itemList[i].item[j].hotKey == key)
957 event.type = SDL_USEREVENT;
958 event.user.code = MENU_ITEM_CHOSEN;
959 event.user.data1 = (void *)itemList[i].item[j].action;
960 SDL_PushEvent(&event);
962 clicked = false, menuChosen = menuItemChosen = -1;
969 void Menu::HandleMouseMove(uint32 x, uint32 y)
971 inside = insidePopup = 0;
975 // Find out *where* we are inside the menu bar
976 uint32 xpos = extents.x;
978 for(uint32 i=0; i<itemList.size(); i++)
980 uint32 width = (itemList[i].title.length() + 2) * FONT_WIDTH;
982 if (x >= xpos && x < xpos + width)
993 if (!Inside(x, y) && !clicked)
998 if (itemList[menuChosen].Inside(x, y) && clicked)
1000 insidePopup = ((y - itemList[menuChosen].extents.y) / FONT_HEIGHT) + 1;
1001 menuItemChosen = insidePopup - 1;
1005 void Menu::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
1014 menuChosen = -1; // clicked is already false...!
1017 else // clicked == true
1019 if (insidePopup && !mouseDown) // I.e., mouse-button-up
1022 if (itemList[menuChosen].item[menuItemChosen].action != NULL)
1024 // itemList[menuChosen].item[menuItemChosen].action();
1026 event.type = SDL_USEREVENT;
1027 event.user.code = MENU_ITEM_CHOSEN;
1028 event.user.data1 = (void *)itemList[menuChosen].item[menuItemChosen].action;
1029 SDL_PushEvent(&event);
1031 clicked = false, menuChosen = menuItemChosen = -1;
1034 while (SDL_PollEvent(&event)); // Flush the event queue...
1035 event.type = SDL_MOUSEMOTION;
1037 SDL_GetMouseState(&mx, &my);
1038 event.motion.x = mx, event.motion.y = my;
1039 SDL_PushEvent(&event); // & update mouse position...!
1043 if (!inside && !insidePopup && mouseDown)
1044 clicked = false, menuChosen = menuItemChosen = -1;
1048 void Menu::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
1050 uint32 xpos = extents.x + offsetX;
1052 for(uint32 i=0; i<itemList.size(); i++)
1054 // uint16 color1 = fgColor, color2 = bgColor;
1055 uint32 color1 = fgColor, color2 = bgColor;
1056 if (inside == (i + 1) || (menuChosen != -1 && (uint32)menuChosen == i))
1057 color1 = fgColorHL, color2 = bgColorHL;
1059 DrawStringOpaque(screenBuffer, xpos, extents.y + offsetY, color1, color2,
1060 " %s ", itemList[i].title.c_str());
1061 xpos += (itemList[i].title.length() + 2) * FONT_WIDTH;
1064 // Draw sub menu (but only if active)
1067 uint32 ypos = extents.y + FONT_HEIGHT + 1;
1069 for(uint32 i=0; i<itemList[menuChosen].item.size(); i++)
1071 // uint16 color1 = fgColor, color2 = bgColor;
1072 uint32 color1 = fgColor, color2 = bgColor;
1074 if (insidePopup == i + 1)
1075 color1 = fgColorHL, color2 = bgColorHL, menuItemChosen = i;
1077 if (itemList[menuChosen].item[i].name.length() > 0)
1078 DrawStringOpaque(screenBuffer, itemList[menuChosen].extents.x, ypos,
1079 color1, color2, " %-*.*s ", itemList[menuChosen].charLength,
1080 itemList[menuChosen].charLength, itemList[menuChosen].item[i].name.c_str());
1082 DrawStringOpaque(screenBuffer, itemList[menuChosen].extents.x, ypos,
1083 fgColor, bgColor, "%.*s", itemList[menuChosen].charLength + 2, separator);
1085 ypos += FONT_HEIGHT;
1090 void Menu::Add(MenuItems mi)
1092 for(uint32 i=0; i<mi.item.size(); i++)
1093 if (mi.item[i].name.length() > mi.charLength)
1094 mi.charLength = mi.item[i].name.length();
1096 // Set extents here as well...
1097 mi.extents.x = extents.x + extents.w, mi.extents.y = extents.y + FONT_HEIGHT + 1;
1098 mi.extents.w = (mi.charLength + 2) * FONT_WIDTH, mi.extents.h = mi.item.size() * FONT_HEIGHT;
1100 itemList.push_back(mi);
1101 extents.w += (mi.title.length() + 2) * FONT_WIDTH;
1105 //Do we even *need* this?
1106 //Doesn't seem like it...
1107 /*class RootWindow: public Window
1110 RootWindow(Menu * m, Window * w = NULL): menu(m), window(w) {}
1111 //Do we even need to care about this crap?
1112 // { extents.x = extents.y = 0, extents.w = 320, extents.h = 240; }
1113 virtual void HandleKey(SDLKey key) {}
1114 virtual void HandleMouseMove(uint32 x, uint32 y) {}
1115 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) {}
1116 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0) {}
1117 virtual void Notify(Element *) {}
1122 int16 * rootImage[1280 * 240 * 2];
1127 // Draw text at the given x/y coordinates. Can invert text as well.
1129 void DrawString(uint32 * screen, uint32 x, uint32 y, bool invert, const char * text, ...)
1134 va_start(arg, text);
1135 vsprintf(string, text, arg);
1138 uint32 pitch = sdlemuGetOverlayWidthInPixels();//GetSDLScreenWidthInPixels();
1139 uint32 length = strlen(string), address = x + (y * pitch);
1141 uint32 color1 = 0x0080FF;
1142 uint8 nBlue = (color1 >> 16) & 0xFF, nGreen = (color1 >> 8) & 0xFF, nRed = color1 & 0xFF;
1143 uint8 xorMask = (invert ? 0xFF : 0x00);
1145 for(uint32 i=0; i<length; i++)
1147 uint8 c = string[i];
1148 uint32 fontAddr = (uint32)(c < 32 ? 0 : c - 32) * FONT_WIDTH * FONT_HEIGHT;
1150 for(uint32 yy=0; yy<FONT_HEIGHT; yy++)
1152 for(uint32 xx=0; xx<FONT_WIDTH; xx++)
1154 uint32 existingColor = *(screen + address + xx + (yy * pitch));
1156 uint8 eBlue = (existingColor >> 16) & 0xFF,
1157 eGreen = (existingColor >> 8) & 0xFF,
1158 eRed = existingColor & 0xFF;
1160 uint8 trans = font2[fontAddr] ^ xorMask;
1161 uint8 invTrans = trans ^ 0xFF;
1163 uint32 bRed = (eRed * invTrans + nRed * trans) / 255,
1164 bGreen = (eGreen * invTrans + nGreen * trans) / 255,
1165 bBlue = (eBlue * invTrans + nBlue * trans) / 255;
1167 *(screen + address + xx + (yy * pitch)) = 0xFF000000 | (bBlue << 16) | (bGreen << 8) | bRed;
1172 address += FONT_WIDTH;
1177 // Draw text at the given x/y coordinates, using FG/BG colors.
1179 void DrawStringOpaque(uint32 * screen, uint32 x, uint32 y, uint32 color1, uint32 color2, const char * text, ...)
1184 va_start(arg, text);
1185 vsprintf(string, text, arg);
1188 uint32 pitch = sdlemuGetOverlayWidthInPixels();
1189 uint32 length = strlen(string), address = x + (y * pitch);
1191 uint8 eBlue = (color2 >> 16) & 0xFF, eGreen = (color2 >> 8) & 0xFF, eRed = color2 & 0xFF,
1192 nBlue = (color1 >> 16) & 0xFF, nGreen = (color1 >> 8) & 0xFF, nRed = color1 & 0xFF;
1194 for(uint32 i=0; i<length; i++)
1196 uint8 c = string[i];
1197 c = (c < 32 ? 0 : c - 32);
1198 uint32 fontAddr = (uint32)c * FONT_WIDTH * FONT_HEIGHT;
1200 for(uint32 yy=0; yy<FONT_HEIGHT; yy++)
1202 for(uint32 xx=0; xx<FONT_WIDTH; xx++)
1204 uint8 trans = font2[fontAddr++];
1205 uint8 invTrans = trans ^ 0xFF;
1207 uint32 bRed = (eRed * invTrans + nRed * trans) / 255;
1208 uint32 bGreen = (eGreen * invTrans + nGreen * trans) / 255;
1209 uint32 bBlue = (eBlue * invTrans + nBlue * trans) / 255;
1211 *(screen + address + xx + (yy * pitch)) = 0xFF000000 | (bBlue << 16) | (bGreen << 8) | bRed;
1215 address += FONT_WIDTH;
1220 // Draw text at the given x/y coordinates with transparency (0 is fully opaque, 32 is fully transparent).
1222 void DrawStringTrans(uint32 * screen, uint32 x, uint32 y, uint32 color, uint8 trans, const char * text, ...)
1227 va_start(arg, text);
1228 vsprintf(string, text, arg);
1231 uint32 pitch = sdlemuGetOverlayWidthInPixels();//GetSDLScreenWidthInPixels();
1232 uint32 length = strlen(string), address = x + (y * pitch);
1234 for(uint32 i=0; i<length; i++)
1236 uint32 fontAddr = (uint32)string[i] * 64;
1238 for(uint32 yy=0; yy<8; yy++)
1240 for(uint32 xx=0; xx<8; xx++)
1242 if (font1[fontAddr])
1244 uint32 existingColor = *(screen + address + xx + (yy * pitch));
1246 uint8 eBlue = (existingColor >> 16) & 0xFF,
1247 eGreen = (existingColor >> 8) & 0xFF,
1248 eRed = existingColor & 0xFF,
1249 //This could be done ahead of time, instead of on each pixel...
1250 nBlue = (color >> 16) & 0xFF,
1251 nGreen = (color >> 8) & 0xFF,
1252 nRed = color & 0xFF;
1254 //This could be sped up by using a table of 5 + 5 + 5 bits (32 levels transparency -> 32768 entries)
1255 //Here we've modified it to have 33 levels of transparency (could have any # we want!)
1256 //because dividing by 32 is faster than dividing by 31...!
1257 uint8 invTrans = 32 - trans;
1259 uint32 bRed = (eRed * trans + nRed * invTrans) / 32;
1260 uint32 bGreen = (eGreen * trans + nGreen * invTrans) / 32;
1261 uint32 bBlue = (eBlue * trans + nBlue * invTrans) / 32;
1263 *(screen + address + xx + (yy * pitch)) = 0xFF000000 | (bBlue << 16) | (bGreen << 8) | bRed;
1276 // Uses zero as transparent color
1277 // Can also use an optional alpha channel
1278 // Alpha channel is now mandatory! ;-)
1280 //void DrawTransparentBitmap(int16 * screen, uint32 x, uint32 y, uint16 * bitmap, uint8 * alpha/*=NULL*/)
1281 /*void DrawTransparentBitmap(uint32 * screen, uint32 x, uint32 y, uint32 * bitmap, uint8 * alpha)
1283 uint32 width = bitmap[0], height = bitmap[1];
1286 // uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1287 uint32 pitch = sdlemuGetOverlayWidthInPixels();//GetSDLScreenWidthInPixels();
1288 uint32 address = x + (y * pitch);
1290 for(uint32 yy=0; yy<height; yy++)
1292 for(uint32 xx=0; xx<width; xx++)
1296 if (*bitmap && x + xx < pitch) // NOTE: Still doesn't clip the Y val...
1297 *(screen + address + xx + (yy * pitch)) = *bitmap;
1301 uint8 trans = *alpha;
1302 uint32 color = *bitmap;
1303 uint32 existingColor = *(screen + address + xx + (yy * pitch));
1305 uint8 eRed = existingColor & 0xFF,
1306 eGreen = (existingColor >> 8) & 0xFF,
1307 eBlue = (existingColor >> 16) & 0xFF,
1309 nRed = color & 0xFF,
1310 nGreen = (color >> 8) & 0xFF,
1311 nBlue = (color >> 16) & 0xFF;
1313 uint8 invTrans = 255 - trans;
1314 uint32 bRed = (eRed * trans + nRed * invTrans) / 255;
1315 uint32 bGreen = (eGreen * trans + nGreen * invTrans) / 255;
1316 uint32 bBlue = (eBlue * trans + nBlue * invTrans) / 255;
1318 uint32 blendedColor = 0xFF000000 | bRed | (bGreen << 8) | (bBlue << 16);
1320 *(screen + address + xx + (yy * pitch)) = blendedColor;
1329 void DrawTransparentBitmap(uint32 * screen, uint32 x, uint32 y, uint32 * bitmap)
1331 uint32 width = bitmap[0], height = bitmap[1];
1334 uint32 pitch = sdlemuGetOverlayWidthInPixels();//GetSDLScreenWidthInPixels();
1335 uint32 address = x + (y * pitch);
1337 for(uint32 yy=0; yy<height; yy++)
1339 for(uint32 xx=0; xx<width; xx++)
1341 uint32 color = *bitmap;
1342 uint32 blendedColor = color;
1343 uint32 existingColor = *(screen + address + xx + (yy * pitch));
1345 if (existingColor >> 24 != 0x00) // Pixel needs blending
1347 uint8 trans = color >> 24;
1348 uint8 invTrans = trans ^ 0xFF;//255 - trans;
1350 uint8 eRed = existingColor & 0xFF,
1351 eGreen = (existingColor >> 8) & 0xFF,
1352 eBlue = (existingColor >> 16) & 0xFF,
1354 nRed = color & 0xFF,
1355 nGreen = (color >> 8) & 0xFF,
1356 nBlue = (color >> 16) & 0xFF;
1358 uint32 bRed = (eRed * invTrans + nRed * trans) / 255;
1359 uint32 bGreen = (eGreen * invTrans + nGreen * trans) / 255;
1360 uint32 bBlue = (eBlue * invTrans + nBlue * trans) / 255;
1362 blendedColor = 0xFF000000 | bRed | (bGreen << 8) | (bBlue << 16);
1365 *(screen + address + xx + (yy * pitch)) = blendedColor;
1373 // GUI stuff--it's not crunchy, it's GUI! ;-)
1378 SDL_ShowCursor(SDL_DISABLE);
1379 SDL_GetMouseState(&mouseX, &mouseY);
1389 //bool GUIMain(void)
1390 bool GUIMain(char * filename)
1392 WriteLog("GUI: Inside GUIMain...\n");
1393 // Need to set things up so that it loads and runs a file if given on the command line. !!! FIX !!!
1394 extern uint32 * backbuffer;
1395 // bool done = false;
1397 Window * mainWindow = NULL;
1399 // Set up the GUI classes...
1400 // Element::SetScreenAndPitch(backbuffer, GetSDLScreenWidthInPixels());
1401 Element::SetScreenAndPitch((uint32 *)sdlemuGetOverlayPixels(), sdlemuGetOverlayWidthInPixels());
1402 sdlemuEnableOverlay();
1406 mi.title = "Jaguar";
1407 mi.item.push_back(NameAction("Load...", LoadROM, SDLK_l));
1408 mi.item.push_back(NameAction("Reset", ResetJaguar, SDLK_r));
1410 mi.item.push_back(NameAction("Reset CD", ResetJaguarCD, SDLK_c));
1411 mi.item.push_back(NameAction("Run", RunEmu, SDLK_ESCAPE));
1412 mi.item.push_back(NameAction(""));
1413 mi.item.push_back(NameAction("Quit", Quit, SDLK_q));
1415 mi.title = "Settings";
1417 mi.item.push_back(NameAction("Video..."));
1418 mi.item.push_back(NameAction("Audio..."));
1419 mi.item.push_back(NameAction("Misc...", MiscOptions, SDLK_m));
1423 mi.item.push_back(NameAction("About...", About));
1426 bool showMouse = true;
1428 //This is crappy!!! !!! FIX !!!
1429 //Is this even needed any more? Hmm. Maybe. Dunno.
1430 WriteLog("GUI: Resetting Jaguar...\n");
1433 WriteLog("GUI: Clearing BG save...\n");
1434 // Set up our background save...
1435 // memset(background, 0x11, tom_getVideoModeWidth() * 240 * 2);
1436 //1111 -> 000100 01000 10001 -> 0001 0000 0100 0010 1000 1100 -> 10 42 8C
1437 for(uint32 i=0; i<tom_getVideoModeWidth()*240; i++)
1438 // background[i] = 0xFF8C4210;
1439 backbuffer[i] = 0xFF8C4210;
1441 /* uint32 * overlayPix = (uint32 *)sdlemuGetOverlayPixels();
1442 for(uint32 i=0; i<sdlemuGetOverlayWidthInPixels()*480; i++)
1443 overlayPix[i] = 0x00000000;*/
1445 // Handle loading file passed in on the command line...! [DONE]
1449 if (JaguarLoadFile(filename))
1451 // event.type = SDL_USEREVENT, event.user.code = MENU_ITEM_CHOSEN;
1452 // event.user.data1 = (void *)ResetJaguar;
1453 // SDL_PushEvent(&event);
1454 // Make it so that if passed in on the command line, we quit right
1455 // away when pressing ESC
1456 WriteLog("GUI: Bypassing GUI since ROM passed in on command line...\n");
1462 // Create error dialog...
1464 sprintf(errText, "The file %40s could not be loaded.", filename);
1466 mainWindow = new Window(8, 16, 304, 160);
1467 mainWindow->AddElement(new Text(8, 8, "Error!"));
1468 mainWindow->AddElement(new Text(8, 24, errText));
1472 WriteLog("GUI: Entering main loop...\n");
1475 if (SDL_PollEvent(&event))
1477 if (event.type == SDL_USEREVENT)
1479 if (event.user.code == WINDOW_CLOSE)
1484 else if (event.user.code == MENU_ITEM_CHOSEN)
1486 // Confused? Let me enlighten... What we're doing here is casting
1487 // data1 as a pointer to a function which returns a Window pointer and
1488 // which takes no parameters (the "(Window *(*)(void))" part), then
1489 // derefencing it (the "*" in front of that) in order to call the
1490 // function that it points to. Clear as mud? Yeah, I hate function
1491 // pointers too, but what else are you gonna do?
1492 mainWindow = (*(Window *(*)(void))event.user.data1)();
1494 while (SDL_PollEvent(&event)); // Flush the event queue...
1495 event.type = SDL_MOUSEMOTION;
1497 SDL_GetMouseState(&mx, &my);
1498 event.motion.x = mx, event.motion.y = my;
1499 SDL_PushEvent(&event); // & update mouse position...!
1501 mouseX = mx, mouseY = my; // This prevents "mouse flash"...
1502 // if (vjs.useOpenGL)
1503 // mouseX /= 2, mouseY /= 2;
1506 else if (event.type == SDL_ACTIVEEVENT)
1508 if (event.active.state == SDL_APPMOUSEFOCUS)
1509 showMouse = (event.active.gain ? true : false);
1511 else if (event.type == SDL_KEYDOWN)
1514 mainWindow->HandleKey(event.key.keysym.sym);
1516 mainMenu.HandleKey(event.key.keysym.sym);
1518 else if (event.type == SDL_MOUSEMOTION)
1520 mouseX = event.motion.x, mouseY = event.motion.y;
1522 // if (vjs.useOpenGL)
1523 // mouseX /= 2, mouseY /= 2;
1526 mainWindow->HandleMouseMove(mouseX, mouseY);
1528 mainMenu.HandleMouseMove(mouseX, mouseY);
1530 else if (event.type == SDL_MOUSEBUTTONDOWN)
1532 uint32 mx = event.button.x, my = event.button.y;
1534 // if (vjs.useOpenGL)
1535 // mx /= 2, my /= 2;
1538 mainWindow->HandleMouseButton(mx, my, true);
1540 mainMenu.HandleMouseButton(mx, my, true);
1542 else if (event.type == SDL_MOUSEBUTTONUP)
1544 uint32 mx = event.button.x, my = event.button.y;
1546 // if (vjs.useOpenGL)
1547 // mx /= 2, my /= 2;
1550 mainWindow->HandleMouseButton(mx, my, false);
1552 mainMenu.HandleMouseButton(mx, my, false);
1556 // The way we do things here is kinda stupid (redrawing the screen every frame), but
1557 // it's simple. Perhaps there may be a reason down the road to be more selective with
1558 // our clearing, but for now, this will suffice.
1559 // memset(backbuffer, 0x11, tom_getVideoModeWidth() * 240 * 2);
1560 // memcpy(backbuffer, background, tom_getVideoModeWidth() * 256 * 2);
1561 // memcpy(backbuffer, background, tom_getVideoModeWidth() * 256 * 4);
1562 memset(sdlemuGetOverlayPixels(), 0, sdlemuGetOverlayWidthInPixels() * 480 * 4);
1565 //Could do multiple windows here by using a vector + priority info...
1566 //Though the way ZSNES does it seems to be by a bool (i.e., they're always active, just not shown)
1571 // DrawTransparentBitmap(backbuffer, mouseX, mouseY, mousePic);
1572 DrawTransparentBitmap((uint32 *)sdlemuGetOverlayPixels(), mouseX, mouseY, mousePic);
1582 // GUI "action" functions
1585 Window * LoadROM(void)
1587 FileList * fileList = new FileList(20, 20, 600, 440);
1589 return (Window *)fileList;
1592 Window * ResetJaguar(void)
1599 Window * ResetJaguarCD(void)
1601 memcpy(jaguar_mainRom, jaguar_CDBootROM, 0x40000);
1602 jaguarRunAddress = 0x802000;
1603 jaguar_mainRom_crc32 = crc32_calcCheckSum(jaguar_mainRom, 0x40000);
1605 //This is a quick kludge to get the CDBIOS to boot properly...
1606 //Wild speculation: It could be that this memory location is wired into the CD unit
1607 //somehow, which lets it know whether or not a cart is present in the unit...
1608 jaguar_mainRom[0x0040B] = 0x03;
1613 bool debounceRunKey = true;
1614 Window * RunEmu(void)
1616 extern uint32 * backbuffer;
1617 //Temporary, to test the new timer based code...
1618 sdlemuDisableOverlay();
1620 sdlemuEnableOverlay();
1621 // Save the background for the GUI...
1622 // memcpy(background, backbuffer, tom_getVideoModeWidth() * 240 * 2);
1623 // In this case, we squash the color to monochrome, then force it to blue + green...
1624 for(uint32 i=0; i<tom_getVideoModeWidth() * 256; i++)
1626 // uint32 word = backbuffer[i];
1627 // uint8 r = (word >> 10) & 0x1F, g = (word >> 5) & 0x1F, b = word & 0x1F;
1628 // word = ((r + g + b) / 3) & 0x001F;
1629 // word = (word << 5) | word;
1630 // background[i] = word;
1632 uint32 pixel = backbuffer[i];
1633 uint8 b = (pixel >> 16) & 0xFF, g = (pixel >> 8) & 0xFF, r = pixel & 0xFF;
1634 pixel = ((r + g + b) / 3) & 0x00FF;
1635 // background[i] = 0xFF000000 | (pixel << 16) | (pixel << 8);
1636 backbuffer[i] = 0xFF000000 | (pixel << 16) | (pixel << 8);
1640 //This is crappy... !!! FIX !!!
1641 extern bool finished, showGUI;
1643 // uint32 nFrame = 0, nFrameskip = 0;
1644 uint32 totalFrames = 0;
1646 bool showMessage = true;
1647 uint32 showMsgFrames = 120;
1648 uint8 transparency = 0;
1649 // Pass a message to the "joystick" code to debounce the ESC key...
1650 debounceRunKey = true;
1652 uint32 cartType = 4;
1653 if (jaguarRomSize == 0x200000)
1655 else if (jaguarRomSize == 0x400000)
1657 else if (jaguar_mainRom_crc32 == 0x687068D5)
1659 else if (jaguar_mainRom_crc32 == 0x55A0669C)
1662 char * cartTypeName[5] = { "2M Cartridge", "4M Cartridge", "CD BIOS", "CD Dev BIOS", "Homebrew" };
1663 uint32 elapsedTicks = SDL_GetTicks(), frameCount = 0, framesPerSecond = 0;
1667 // Set up new backbuffer with new pixels and data
1668 JaguarExecute(backbuffer, true);
1669 // JaguarExecuteNew();
1671 //WriteLog("Frame #%u...\n", totalFrames);
1672 //extern bool doDSPDis;
1673 //if (totalFrames == 373)
1676 //This sucks... !!! FIX !!!
1678 //This is done here so that the crud below doesn't get on our GUI background...
1682 // Some QnD GUI stuff here...
1685 extern uint32 gpu_pc, dsp_pc;
1686 DrawString(backbuffer, 8, 8, false, "GPU PC: %08X", gpu_pc);
1687 DrawString(backbuffer, 8, 16, false, "DSP PC: %08X", dsp_pc);
1688 DrawString(backbuffer, 8, 32, false, "%u FPS", framesPerSecond);
1693 // FF0F -> 1111 11 11 000 0 1111 -> 3F 18 0F
1694 // 3FE3 -> 0011 11 11 111 0 0011 -> 0F 3F 03
1695 /* DrawStringTrans((uint32 *)backbuffer, 8, 24*8, 0xFF0F, transparency, "Running...");
1696 DrawStringTrans((uint32 *)backbuffer, 8, 26*8, 0x3FE3, transparency, "%s, run address: %06X", cartTypeName[cartType], jaguarRunAddress);
1697 DrawStringTrans((uint32 *)backbuffer, 8, 27*8, 0x3FE3, transparency, "CRC: %08X", jaguar_mainRom_crc32);//*/
1698 //first has wrong color. !!! FIX !!!
1699 DrawStringTrans(backbuffer, 8, 24*8, 0xFF7F63FF, transparency, "Running...");
1700 DrawStringTrans(backbuffer, 8, 26*8, 0xFF1FFF3F, transparency, "%s, run address: %06X", cartTypeName[cartType], jaguarRunAddress);
1701 DrawStringTrans(backbuffer, 8, 27*8, 0xFF1FFF3F, transparency, "CRC: %08X", jaguar_mainRom_crc32);
1703 if (showMsgFrames == 0)
1707 if (transparency == 33)
1709 showMessage = false;
1710 /*extern bool doGPUDis;
1711 doGPUDis = true;//*/
1722 if (SDL_GetTicks() - elapsedTicks > 250)
1723 elapsedTicks += 250, framesPerSecond = frameCount * 4, frameCount = 0;
1726 // Reset the pitch, since it may have been changed in-game...
1727 // Element::SetScreenAndPitch(backbuffer, GetSDLScreenPitch() / 2);
1728 Element::SetScreenAndPitch((uint32 *)backbuffer, GetSDLScreenWidthInPixels());
1730 // Save the background for the GUI...
1731 // memcpy(background, backbuffer, tom_getVideoModeWidth() * 240 * 2);
1732 // In this case, we squash the color to monochrome, then force it to blue + green...
1733 for(uint32 i=0; i<tom_getVideoModeWidth() * 256; i++)
1735 // uint32 word = backbuffer[i];
1736 // uint8 r = (word >> 10) & 0x1F, g = (word >> 5) & 0x1F, b = word & 0x1F;
1737 // word = ((r + g + b) / 3) & 0x001F;
1738 // word = (word << 5) | word;
1739 // background[i] = word;
1741 uint32 pixel = backbuffer[i];
1742 uint8 b = (pixel >> 16) & 0xFF, g = (pixel >> 8) & 0xFF, r = pixel & 0xFF;
1743 pixel = ((r + g + b) / 3) & 0x00FF;
1744 background[i] = 0xFF000000 | (pixel << 16) | (pixel << 8);
1752 WriteLog("GUI: Quitting due to user request.\n");
1758 Window * About(void)
1761 sprintf(buf, "Virtual Jaguar CVS %s", __DATE__);
1762 //fprintf(fp, "VirtualJaguar v1.0.8 (Last full build was on %s %s)\n", __DATE__, __TIME__);
1763 //VirtualJaguar v1.0.8 (Last full build was on Dec 30 2004 20:01:31)
1764 Window * window = new Window(8, 16, 40 * FONT_WIDTH, 19 * FONT_HEIGHT);
1765 // window->AddElement(new Text(8, 8, "Virtual Jaguar 1.0.8"));
1766 // window->AddElement(new Text(8, 8, "Virtual Jaguar CVS 20050110", 0xFF3030FF, 0xFF000000));
1767 window->AddElement(new Text(8, 8, buf, 0xFF3030FF, 0xFF000000));
1768 window->AddElement(new Text(8, 8+2*FONT_HEIGHT, "Coders:"));
1769 window->AddElement(new Text(16, 8+3*FONT_HEIGHT, "James L. Hammons (shamus)"));
1770 window->AddElement(new Text(16, 8+4*FONT_HEIGHT, "Niels Wagenaar (nwagenaar)"));
1771 window->AddElement(new Text(16, 8+5*FONT_HEIGHT, "Carwin Jones (Caz)"));
1772 window->AddElement(new Text(16, 8+6*FONT_HEIGHT, "Adam Green"));
1773 window->AddElement(new Text(8, 8+8*FONT_HEIGHT, "Testers:"));
1774 window->AddElement(new Text(16, 8+9*FONT_HEIGHT, "Guruma"));
1775 window->AddElement(new Text(8, 8+11*FONT_HEIGHT, "Thanks go out to:"));
1776 window->AddElement(new Text(16, 8+12*FONT_HEIGHT, "Aaron Giles for the original CoJag"));
1777 window->AddElement(new Text(16, 8+13*FONT_HEIGHT, "David Raingeard for the original VJ"));
1778 window->AddElement(new Text(16, 8+14*FONT_HEIGHT, "Karl Stenerud for his Musashi 68K emu"));
1779 window->AddElement(new Text(16, 8+15*FONT_HEIGHT, "Sam Lantinga for his amazing SDL libs"));
1780 window->AddElement(new Text(16, 8+16*FONT_HEIGHT, "Ryan C. Gordon for VJ's web presence"));
1781 window->AddElement(new Text(16, 8+17*FONT_HEIGHT, "The guys over at Atari Age ;-)"));
1786 Window * MiscOptions(void)
1788 Window * window = new Window(8, 16, 304, 160);
1789 window->AddElement(new PushButton(8, 8, &vjs.useJaguarBIOS, "BIOS"));
1790 window->AddElement(new SlideSwitch(8, 20, &vjs.hardwareTypeNTSC, "PAL", "NTSC"));
1791 window->AddElement(new PushButton(8, 40, &vjs.DSPEnabled, "DSP"));
1792 window->AddElement(new SlideSwitch(16, 52, &vjs.usePipelinedDSP, "Original", "Pipelined"));
1793 window->AddElement(new SlideSwitch(8, 72, (bool *)&vjs.glFilter, "Sharp", "Blurry"));
1803 // * Window/fullscreen
1810 // Generic ROM loading
1812 uint32 JaguarLoadROM(uint8 * rom, char * path)
1814 // We really should have some kind of sanity checking for the ROM size here to prevent
1815 // a buffer overflow... !!! FIX !!!
1818 WriteLog("JaguarLoadROM: Attempting to load file '%s'...", path);
1819 char * ext = strrchr(path, '.');
1821 WriteLog("FAILED!\n");
1823 WriteLog("Succeeded in finding extension (%s)!\n", ext);
1827 WriteLog("VJ: Loading \"%s\"...", path);
1829 if (strcasecmp(ext, ".zip") == 0)
1831 // Handle ZIP file loading here...
1832 WriteLog("(ZIPped)...");
1834 if (load_zipped_file(0, 0, path, NULL, &rom, &romSize) == -1)
1836 WriteLog("Failed!\n");
1842 /* FILE * fp = fopen(path, "rb");
1846 WriteLog("Failed!\n");
1850 fseek(fp, 0, SEEK_END);
1851 romSize = ftell(fp);
1852 fseek(fp, 0, SEEK_SET);
1853 fread(rom, 1, romSize, fp);
1856 // Handle gzipped files transparently [Adam Green]...
1858 gzFile fp = gzopen(path, "rb");
1862 WriteLog("Failed!\n");
1866 romSize = gzfilelength(fp);
1867 gzseek(fp, 0, SEEK_SET);
1868 gzread(fp, rom, romSize);
1872 WriteLog("OK (%i bytes)\n", romSize);
1879 // Jaguar file loading
1881 bool JaguarLoadFile(char * path)
1883 // jaguarRomSize = JaguarLoadROM(mem, path);
1884 jaguarRomSize = JaguarLoadROM(jaguar_mainRom, path);
1886 /*//This is not *nix friendly for some reason...
1887 // if (!UserSelectFile(path, newPath))
1888 if (!UserSelectFile((strlen(path) == 0 ? (char *)"." : path), newPath))
1890 WriteLog("VJ: Could not find valid ROM in directory \"%s\"...\nAborting!\n", path);
1895 if (jaguarRomSize == 0)
1897 // WriteLog("VJ: Could not load ROM from file \"%s\"...\nAborting!\n", newPath);
1898 WriteLog("GUI: Could not load ROM from file \"%s\"...\nAborting load!\n", path);
1899 // Need to do something else here, like throw up an error dialog instead of aborting. !!! FIX !!!
1902 return false; // This is a start...
1905 jaguar_mainRom_crc32 = crc32_calcCheckSum(jaguar_mainRom, jaguarRomSize);
1906 WriteLog("CRC: %08X\n", (unsigned int)jaguar_mainRom_crc32);
1909 jaguarRunAddress = 0x802000;
1911 char * ext = strrchr(path, '.'); // Get the file's extension for non-cartridge checking
1913 //NOTE: Should fix JaguarLoadROM() to replace .zip with what's *in* the zip (.abs, .j64, etc.)
1914 if (strcasecmp(ext, ".rom") == 0)
1916 // File extension ".ROM": Alpine image that loads/runs at $802000
1917 WriteLog("GUI: Setting up homebrew (ROM)... Run address: 00802000, length: %08X\n", jaguarRomSize);
1919 for(int i=jaguarRomSize-1; i>=0; i--)
1920 jaguar_mainRom[0x2000 + i] = jaguar_mainRom[i];
1922 memset(jaguar_mainRom, 0xFF, 0x2000);
1923 /* memcpy(jaguar_mainRam, jaguar_mainRom, jaguarRomSize);
1924 memset(jaguar_mainRom, 0xFF, 0x600000);
1925 memcpy(jaguar_mainRom + 0x2000, jaguar_mainRam, jaguarRomSize);
1926 memset(jaguar_mainRam, 0x00, 0x400000);*/
1929 Stubulator ROM vectors...
1930 handler 001 at $00E00008
1931 handler 002 at $00E008DE
1932 handler 003 at $00E008E2
1933 handler 004 at $00E008E6
1934 handler 005 at $00E008EA
1935 handler 006 at $00E008EE
1936 handler 007 at $00E008F2
1937 handler 008 at $00E0054A
1938 handler 009 at $00E008FA
1939 handler 010 at $00000000
1940 handler 011 at $00000000
1941 handler 012 at $00E008FE
1942 handler 013 at $00E00902
1943 handler 014 at $00E00906
1944 handler 015 at $00E0090A
1945 handler 016 at $00E0090E
1946 handler 017 at $00E00912
1947 handler 018 at $00E00916
1948 handler 019 at $00E0091A
1949 handler 020 at $00E0091E
1950 handler 021 at $00E00922
1951 handler 022 at $00E00926
1952 handler 023 at $00E0092A
1953 handler 024 at $00E0092E
1954 handler 025 at $00E0107A
1955 handler 026 at $00E0107A
1956 handler 027 at $00E0107A
1957 handler 028 at $00E008DA
1958 handler 029 at $00E0107A
1959 handler 030 at $00E0107A
1960 handler 031 at $00E0107A
1961 handler 032 at $00000000
1963 Let's try setting up the illegal instruction vector for a stubulated jaguar...
1965 /* SET32(jaguar_mainRam, 0x08, 0x00E008DE);
1966 SET32(jaguar_mainRam, 0x0C, 0x00E008E2);
1967 SET32(jaguar_mainRam, 0x10, 0x00E008E6); // <-- Should be here (it is)...
1968 SET32(jaguar_mainRam, 0x14, 0x00E008EA);//*/
1970 // Try setting the vector to say, $1000 and putting an instruction there that loops forever:
1971 // This kludge works! Yeah!
1972 SET32(jaguar_mainRam, 0x10, 0x00001000);
1973 SET16(jaguar_mainRam, 0x1000, 0x60FE); // Here: bra Here
1975 else if (strcasecmp(ext, ".abs") == 0)
1977 // File extension ".ABS": Atari linker output file with header (w/o is useless to us here)
1980 ABS Format sleuthing (LBUGDEMO.ABS):
1982 000000 60 1B 00 00 05 0C 00 04 62 C0 00 00 04 28 00 00
1983 000010 12 A6 00 00 00 00 00 80 20 00 FF FF 00 80 25 0C
1986 DRI-format file detected...
1987 Text segment size = 0x0000050c bytes
1988 Data segment size = 0x000462c0 bytes
1989 BSS Segment size = 0x00000428 bytes
1990 Symbol Table size = 0x000012a6 bytes
1991 Absolute Address for text segment = 0x00802000
1992 Absolute Address for data segment = 0x0080250c
1993 Absolute Address for BSS segment = 0x00004000
1996 000000 01 50 00 03 00 00 00 00 00 03 83 10 00 00 05 3b
1997 000010 00 1c 00 03 00 00 01 07 00 00 1d d0 00 03 64 98
1998 000020 00 06 8b 80 00 80 20 00 00 80 20 00 00 80 3d d0
2000 000030 2e 74 78 74 00 00 00 00 00 80 20 00 00 80 20 00 .txt (+36 bytes)
2001 000040 00 00 1d d0 00 00 00 a8 00 00 00 00 00 00 00 00
2002 000050 00 00 00 00 00 00 00 20
2003 000058 2e 64 74 61 00 00 00 00 00 80 3d d0 00 80 3d d0 .dta (+36 bytes)
2004 000068 00 03 64 98 00 00 1e 78 00 00 00 00 00 00 00 00
2005 000078 00 00 00 00 00 00 00 40
2006 000080 2e 62 73 73 00 00 00 00 00 00 50 00 00 00 50 00 .bss (+36 bytes)
2007 000090 00 06 8b 80 00 03 83 10 00 00 00 00 00 00 00 00
2008 0000a0 00 00 00 00 00 00 00 80
2010 Header size is $A8 bytes...
2012 BSD/COFF format file detected...
2013 3 sections specified
2014 Symbol Table offset = 230160 ($00038310)
2015 Symbol Table contains 1339 symbol entries ($0000053B)
2016 The additional header size is 28 bytes ($001C)
2017 Magic Number for RUN_HDR = 0x00000107
2018 Text Segment Size = 7632 ($00001DD0)
2019 Data Segment Size = 222360 ($00036498)
2020 BSS Segment Size = 428928 ($00068B80)
2021 Starting Address for executable = 0x00802000
2022 Start of Text Segment = 0x00802000
2023 Start of Data Segment = 0x00803dd0
2025 if (jaguar_mainRom[0] == 0x60 && jaguar_mainRom[1] == 0x1B)
2027 uint32 loadAddress = GET32(jaguar_mainRom, 0x16), //runAddress = GET32(jaguar_mainRom, 0x2A),
2028 codeSize = GET32(jaguar_mainRom, 0x02) + GET32(jaguar_mainRom, 0x06);
2029 WriteLog("GUI: Setting up homebrew (ABS-1)... Run address: %08X, length: %08X\n", loadAddress, codeSize);
2031 if (loadAddress < 0x800000)
2032 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x24, codeSize);
2035 for(int i=codeSize-1; i>=0; i--)
2036 jaguar_mainRom[(loadAddress - 0x800000) + i] = jaguar_mainRom[i + 0x24];
2037 /* memcpy(jaguar_mainRam, jaguar_mainRom + 0x24, codeSize);
2038 memset(jaguar_mainRom, 0xFF, 0x600000);
2039 memcpy(jaguar_mainRom + (loadAddress - 0x800000), jaguar_mainRam, codeSize);
2040 memset(jaguar_mainRam, 0x00, 0x400000);*/
2043 jaguarRunAddress = loadAddress;
2045 else if (jaguar_mainRom[0] == 0x01 && jaguar_mainRom[1] == 0x50)
2047 uint32 loadAddress = GET32(jaguar_mainRom, 0x28), runAddress = GET32(jaguar_mainRom, 0x24),
2048 codeSize = GET32(jaguar_mainRom, 0x18) + GET32(jaguar_mainRom, 0x1C);
2049 WriteLog("GUI: Setting up homebrew (ABS-2)... Run address: %08X, length: %08X\n", runAddress, codeSize);
2051 if (loadAddress < 0x800000)
2052 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0xA8, codeSize);
2055 for(int i=codeSize-1; i>=0; i--)
2056 jaguar_mainRom[(loadAddress - 0x800000) + i] = jaguar_mainRom[i + 0xA8];
2057 /* memcpy(jaguar_mainRam, jaguar_mainRom + 0xA8, codeSize);
2058 memset(jaguar_mainRom, 0xFF, 0x600000);
2059 memcpy(jaguar_mainRom + (loadAddress - 0x800000), jaguar_mainRam, codeSize);
2060 memset(jaguar_mainRam, 0x00, 0x400000);*/
2063 jaguarRunAddress = runAddress;
2067 WriteLog("GUI: Couldn't find correct ABS format: %02X %02X\n", jaguar_mainRom[0], jaguar_mainRom[1]);
2071 else if (strcasecmp(ext, ".jag") == 0)
2073 // File extension ".JAG": Atari server file with header
2074 //NOTE: The bytes 'JAGR' should also be at position $1C...
2075 // Also, there's *always* a $601A header at position $00...
2076 if (jaguar_mainRom[0] == 0x60 && jaguar_mainRom[1] == 0x1A)
2078 uint32 loadAddress = GET32(jaguar_mainRom, 0x22), runAddress = GET32(jaguar_mainRom, 0x2A);
2079 //This is not always right! Especially when converted via bin2jag1!!!
2080 //We should have access to the length of the furshlumiger file that was loaded anyway!
2082 // uint32 progLength = GET32(jaguar_mainRom, 0x02);
2085 // WriteLog("Jaguar: Setting up PD ROM... Run address: %08X, length: %08X\n", runAddress, progLength);
2086 // memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, progLength);
2087 WriteLog("GUI: Setting up homebrew (JAG)... Run address: %08X, length: %08X\n", runAddress, jaguarRomSize - 0x2E);
2088 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, jaguarRomSize - 0x2E);
2089 // SET32(jaguar_mainRam, 4, runAddress);
2090 jaguarRunAddress = runAddress;
2095 // .J64 (Jaguar cartridge ROM image) is implied by the FileList object...
2101 // Get the length of a (possibly) gzipped file
2103 int gzfilelength(gzFile gd)
2105 int size = 0, length = 0;
2106 unsigned char buffer[0x10000];
2112 // Read in chunks until EOF
2113 size = gzread(gd, buffer, 0x10000);