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 DrawTransparentBitmapDeprecated(uint32 * screen, uint32 x, uint32 y, uint32 * bitmap);
37 void DrawTransparentBitmap(uint32 * screen, uint32 x, uint32 y, const void * bitmap);
38 void DrawStringTrans(uint32 * screen, uint32 x, uint32 y, uint32 color, uint8 opacity, const char * text, ...);
39 void DrawStringOpaque(uint32 * screen, uint32 x, uint32 y, uint32 color1, uint32 color2, const char * text, ...);
40 void DrawString(uint32 * screen, uint32 x, uint32 y, bool invert, const char * text, ...);
41 Window * LoadROM(void);
42 Window * ResetJaguar(void);
43 Window * ResetJaguarCD(void);
44 Window * RunEmu(void);
47 Window * MiscOptions(void);
49 int gzfilelength(gzFile gd);
53 extern uint8 * jaguar_mainRam;
54 extern uint8 * jaguar_mainRom;
55 extern uint8 * jaguar_bootRom;
56 extern uint8 * jaguar_CDBootROM;
57 extern bool BIOSLoaded;
58 extern bool CDBIOSLoaded;
60 // Local global variables
62 bool exitGUI = false; // GUI (emulator) done variable
63 int mouseX = 0, mouseY = 0;
64 uint32 background[1280 * 256]; // GUI background buffer
66 char separator[] = "--------------------------------------------------------";
69 // Case insensitive string compare function
70 // Taken straight out of Thinking In C++ by Bruce Eckel. Thanks Bruce!
73 int stringCmpi(const string &s1, const string &s2)
75 // Select the first element of each string:
76 string::const_iterator p1 = s1.begin(), p2 = s2.begin();
78 while (p1 != s1.end() && p2 != s2.end()) // Don
\92t run past the end
80 if (toupper(*p1) != toupper(*p2)) // Compare upper-cased chars
81 return (toupper(*p1) < toupper(*p2) ? -1 : 1);// Report which was lexically greater
87 // If they match up to the detected eos, say which was longer. Return 0 if the same.
88 return s2.size() - s1.size();
95 enum { WINDOW_CLOSE, MENU_ITEM_CHOSEN };
100 Element(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0)
101 { extents.x = x, extents.y = y, extents.w = w, extents.h = h; }
102 virtual void HandleKey(SDLKey key) = 0; // These are "pure" virtual functions...
103 virtual void HandleMouseMove(uint32 x, uint32 y) = 0;
104 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) = 0;
105 virtual void Draw(uint32, uint32) = 0;
106 virtual void Notify(Element *) = 0;
107 //Needed? virtual ~Element() = 0;
108 //We're not allocating anything in the base class, so the answer would be NO.
109 bool Inside(uint32 x, uint32 y);
111 // static void SetScreenAndPitch(int16 * s, uint32 p) { screenBuffer = s, pitch = p; }
112 static void SetScreenAndPitch(uint32 * s, uint32 p) { screenBuffer = s, pitch = p; }
117 // Class variables...
118 // static int16 * screenBuffer;
119 static uint32 * screenBuffer;
123 // Initialize class variables (Element)
124 //int16 * Element::screenBuffer = NULL;
125 uint32 * Element::screenBuffer = NULL;
126 uint32 Element::pitch = 0;
128 bool Element::Inside(uint32 x, uint32 y)
130 return (x >= (uint32)extents.x && x < (uint32)(extents.x + extents.w)
131 && y >= (uint32)extents.y && y < (uint32)(extents.y + extents.h) ? true : false);
135 class Button: public Element
138 Button(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
139 activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
140 bgColor(0xFF00FF00), pic(NULL), elementToTell(NULL) {}
141 Button(uint32 x, uint32 y, uint32 w, uint32 h, uint32 * p): Element(x, y, w, h),
142 activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
143 bgColor(0xFF00FF00), pic(p), elementToTell(NULL) {}
144 // Button(uint32 x, uint32 y, uint32 * p): Element(x, y, 0, 0),
145 Button(uint32 x, uint32 y, uint32 * p, uint32 * pH = NULL, uint32 * pD = NULL): Element(x, y, 0, 0),
146 activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
147 bgColor(0xFF00FF00), pic(p), picHover(pH), picDown(pD), elementToTell(NULL)
148 { if (pic) extents.w = pic[0], extents.h = pic[1]; }
149 Button(uint32 x, uint32 y, uint32 w, uint32 h, string s): Element(x, y, w, h),
150 activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
151 bgColor(0xFF00FF00), pic(NULL), text(s), elementToTell(NULL) {}
152 Button(uint32 x, uint32 y, string s): Element(x, y, 0, FONT_HEIGHT),
153 activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
154 bgColor(0xFF00FF00), pic(NULL), text(s), elementToTell(NULL)
155 { extents.w = s.length() * FONT_WIDTH; }
156 virtual void HandleKey(SDLKey key) {}
157 virtual void HandleMouseMove(uint32 x, uint32 y);
158 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
159 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
160 virtual void Notify(Element *) {}
161 bool ButtonClicked(void) { return activated; }
162 void SetNotificationElement(Element * e) { elementToTell = e; }
165 bool activated, clicked, inside;
166 uint32 fgColor, bgColor;
167 uint32 * pic, * picHover, * picDown;
169 Element * elementToTell;
172 void Button::HandleMouseMove(uint32 x, uint32 y)
174 inside = Inside(x, y);
177 void Button::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
184 if (clicked && !mouseDown)
186 clicked = false, activated = true;
188 // Send a message that we're activated (if there's someone to tell, that is)
190 elementToTell->Notify(this);
194 clicked = activated = false;
197 void Button::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
199 uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
201 if (text.length() > 0) // Simple text button
204 for(uint32 y=0; y<extents.h; y++)
206 for(uint32 x=0; x<extents.w; x++)
208 // Doesn't clip in y axis! !!! FIX !!!
209 if (extents.x + x < pitch)
210 screenBuffer[addr + x + (y * pitch)]
211 // = (clicked && inside ? fgColor : (inside ? 0x43F0 : bgColor));
212 //43F0 -> 010000 11111 10000 -> 0100 0001 1111 1111 1000 0100 -> 41 FF 84
213 = (clicked && inside ? fgColor : (inside ? 0xFF84FF41 : bgColor));
217 DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY, false, "%s", text.c_str());
219 else // Graphical button
221 uint32 * picToShow = pic;
223 if (picHover != NULL && inside && !clicked)
224 picToShow = picHover;
226 if (picDown != NULL && inside && clicked)
229 DrawTransparentBitmapDeprecated(screenBuffer, extents.x + offsetX, extents.y + offsetY, picToShow);
234 class PushButton: public Element
237 // Save state externally?
238 //We pass in a state variable if we want to track it externally, otherwise we use our own
239 //internal state var. Still need to do some kind of callback for pushbuttons that do things
240 //like change from fullscreen to windowed... !!! FIX !!!
243 // PushButton(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
244 // activated(false), clicked(false), inside(false), fgColor(0xFFFF),
245 // bgColor(0x03E0), pic(NULL), elementToTell(NULL) {}
246 // PushButton(uint32 x, uint32 y, bool * st, string s): Element(x, y, 8, 8), state(st),
247 // inside(false), text(s) { if (st == NULL) state = &internalState; }
248 PushButton(uint32 x, uint32 y, bool * st, string s): Element(x, y, 16, 16), state(st),
249 inside(false), text(s) { if (st == NULL) state = &internalState; }
250 /* Button(uint32 x, uint32 y, uint32 w, uint32 h, uint32 * p): Element(x, y, w, h),
251 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
252 bgColor(0x03E0), pic(p), elementToTell(NULL) {}
253 Button(uint32 x, uint32 y, uint32 * p): Element(x, y, 0, 0),
254 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
255 bgColor(0x03E0), pic(p), elementToTell(NULL)
256 { if (pic) extents.w = pic[0], extents.h = pic[1]; }
257 Button(uint32 x, uint32 y, uint32 w, uint32 h, string s): Element(x, y, w, h),
258 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
259 bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL) {}
260 PushButton(uint32 x, uint32 y, string s): Element(x, y, 0, 8),
261 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
262 bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL)
263 { extents.w = s.length() * 8; }*/
264 virtual void HandleKey(SDLKey key) {}
265 virtual void HandleMouseMove(uint32 x, uint32 y);
266 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
267 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
268 virtual void Notify(Element *) {}
269 // bool ButtonClicked(void) { return activated; }
270 // void SetNotificationElement(Element * e) { elementToTell = e; }
275 // bool activated, clicked, inside;
276 // uint16 fgColor, bgColor;
279 // Element * elementToTell;
283 void PushButton::HandleMouseMove(uint32 x, uint32 y)
285 inside = Inside(x, y);
288 void PushButton::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
290 if (inside && mouseDown)
295 if (clicked && !mouseDown)
297 clicked = false, activated = true;
299 // Send a message that we're activated (if there's someone to tell, that is)
301 elementToTell->Notify(this);
306 // clicked = activated = false;
309 void PushButton::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
311 /* uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
313 for(uint32 y=0; y<extents.h; y++)
315 for(uint32 x=0; x<extents.w; x++)
317 // Doesn't clip in y axis! !!! FIX !!!
318 if (extents.x + x < pitch)
319 screenBuffer[addr + x + (y * pitch)]
320 = (clicked && inside ? fgColor : (inside ? 0x43F0 : bgColor));
325 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, &pbDown);
327 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, &pbUp);
329 if (text.length() > 0)
330 DrawString(screenBuffer, extents.x + offsetX + 24, extents.y + offsetY, false, "%s", text.c_str());
334 class SlideSwitch: public Element
337 // Save state externally?
338 //Seems to be handled the same as PushButton, but without sanity checks. !!! FIX !!!
341 SlideSwitch(uint32 x, uint32 y, bool * st, string s1, string s2): Element(x, y, 16, 32), state(st),
342 inside(false), text1(s1), text2(s2) {}
343 virtual void HandleKey(SDLKey key) {}
344 virtual void HandleMouseMove(uint32 x, uint32 y);
345 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
346 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
347 virtual void Notify(Element *) {}
348 // bool ButtonClicked(void) { return activated; }
349 // void SetNotificationElement(Element * e) { elementToTell = e; }
354 // bool activated, clicked, inside;
355 // uint16 fgColor, bgColor;
358 // Element * elementToTell;
361 void SlideSwitch::HandleMouseMove(uint32 x, uint32 y)
363 inside = Inside(x, y);
366 void SlideSwitch::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
368 if (inside && mouseDown)
373 if (clicked && !mouseDown)
375 clicked = false, activated = true;
377 // Send a message that we're activated (if there's someone to tell, that is)
379 elementToTell->Notify(this);
384 // clicked = activated = false;
387 void SlideSwitch::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
389 DrawTransparentBitmapDeprecated(screenBuffer, extents.x + offsetX, extents.y + offsetY, (*state ? slideSwitchDown : slideSwitchUp));
391 if (text1.length() > 0)
392 DrawString(screenBuffer, extents.x + offsetX + 24, extents.y + offsetY, false, "%s", text1.c_str());
394 if (text2.length() > 0)
395 DrawString(screenBuffer, extents.x + offsetX + 24, extents.y + offsetY + 16, false, "%s", text2.c_str());
399 class Window: public Element
402 /* Window(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
403 fgColor(0x4FF0), bgColor(0xFE10)
404 { close = new Button(w - 8, 1, closeBox); list.push_back(close); }*/
405 Window(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0,
406 void (* f)(Element *) = NULL): Element(x, y, w, h),
407 // /*clicked(false), inside(false),*/ fgColor(0x4FF0), bgColor(0x1E10),
408 //4FF0 -> 010011 11111 10000 -> 0100 1101 1111 1111 1000 0100 -> 4D FF 84
409 //1E10 -> 000111 10000 10000 -> 0001 1111 1000 0100 1000 0100 -> 1F 84 84
410 /*clicked(false), inside(false),*/ fgColor(0xFF84FF4D), bgColor(0xFF84841F),
412 { close = new Button(w - (CLOSEBOX_WIDTH + 1), 1, closeBox, closeBoxHover, closeBoxDown);
413 list.push_back(close);
414 close->SetNotificationElement(this); }
416 virtual void HandleKey(SDLKey key);
417 virtual void HandleMouseMove(uint32 x, uint32 y);
418 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
419 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
420 virtual void Notify(Element * e);
421 void AddElement(Element * e);
422 // bool WindowActive(void) { return true; }//return !close->ButtonClicked(); }
425 // bool clicked, inside;
426 uint32 fgColor, bgColor;
427 void (* handler)(Element *);
429 //We have to use a list of Element *pointers* because we can't make a list that will hold
430 //all the different object types in the same list...
431 vector<Element *> list;
436 for(uint32 i=0; i<list.size(); i++)
441 void Window::HandleKey(SDLKey key)
443 if (key == SDLK_ESCAPE)
446 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
447 SDL_PushEvent(&event);
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]->HandleKey(key);
456 void Window::HandleMouseMove(uint32 x, uint32 y)
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]->HandleMouseMove(x - extents.x, y - extents.y);
464 void Window::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
466 // Handle the items this window contains...
467 for(uint32 i=0; i<list.size(); i++)
468 // Make coords relative to upper right corner of this window...
469 list[i]->HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
472 void Window::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
474 uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
476 for(uint32 y=0; y<extents.h; y++)
478 for(uint32 x=0; x<extents.w; x++)
480 // Doesn't clip in y axis! !!! FIX !!!
481 if (extents.x + x < pitch)
482 screenBuffer[addr + x + (y * pitch)] = bgColor;
486 // Handle the items this window contains...
487 for(uint32 i=0; i<list.size(); i++)
488 list[i]->Draw(extents.x, extents.y);
491 void Window::AddElement(Element * e)
496 void Window::Notify(Element * e)
501 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
502 SDL_PushEvent(&event);
507 class Text: public Element
510 // Text(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
511 // fgColor(0x4FF0), bgColor(0xFE10) {}
512 // Text(uint32 x, uint32 y, string s, uint16 fg = 0x4FF0, uint16 bg = 0xFE10): Element(x, y, 0, 0),
513 // fgColor(fg), bgColor(bg), text(s) {}
514 //4FF0 -> 010011 11111 10000 -> 0100 1101 1111 1111 1000 0100 -> 4D FF 84
515 //FE10 -> 111111 10000 10000 -> 1111 1111 1000 0100 1000 0100 -> FF 84 84
516 Text(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
517 fgColor(0xFF8484FF), bgColor(0xFF84FF4D) {}
518 Text(uint32 x, uint32 y, string s, uint32 fg = 0xFF8484FF, uint32 bg = 0xFF84FF4D):
519 Element(x, y, 0, 0), fgColor(fg), bgColor(bg), text(s) {}
520 virtual void HandleKey(SDLKey key) {}
521 virtual void HandleMouseMove(uint32 x, uint32 y) {}
522 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) {}
523 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
524 virtual void Notify(Element *) {}
527 uint32 fgColor, bgColor;
531 void Text::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
533 if (text.length() > 0)
534 // DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY, false, "%s", text.c_str());
535 DrawStringOpaque(screenBuffer, extents.x + offsetX, extents.y + offsetY, fgColor, bgColor, "%s", text.c_str());
539 class ListBox: public Element
540 //class ListBox: public Window
543 // ListBox(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
544 ListBox(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0);//: Window(x, y, w, h),
545 // windowPtr(0), cursor(0), limit(0), charWidth((w / 8) - 1), charHeight(h / 8),
546 // elementToTell(NULL), upArrow(w - 8, 0, upArrowBox),
547 // downArrow(w - 8, h - 8, downArrowBox), upArrow2(w - 8, h - 16, upArrowBox) {}
548 virtual void HandleKey(SDLKey key);
549 virtual void HandleMouseMove(uint32 x, uint32 y);
550 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
551 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
552 virtual void Notify(Element * e);
553 void SetNotificationElement(Element * e) { elementToTell = e; }
554 void AddItem(string s);
555 string GetSelectedItem(void);
559 uint32 windowPtr, cursor, limit;
560 uint32 charWidth, charHeight; // Box width/height in characters
561 Element * elementToTell;
562 Button upArrow, downArrow, upArrow2;
566 uint32 yRelativePoint;
569 ListBox::ListBox(uint32 x, uint32 y, uint32 w, uint32 h): Element(x, y, w, h),
570 thumbClicked(false), windowPtr(0), cursor(0), limit(0), charWidth((w / FONT_WIDTH) - 1),
571 charHeight(h / FONT_HEIGHT), elementToTell(NULL), upArrow(w - 8, 0, upArrowBox),
572 downArrow(w - 8, h - 8, downArrowBox), upArrow2(w - 8, h - 16, upArrowBox)
574 upArrow.SetNotificationElement(this);
575 downArrow.SetNotificationElement(this);
576 upArrow2.SetNotificationElement(this);
577 extents.w -= 8; // Make room for scrollbar...
580 void ListBox::HandleKey(SDLKey key)
582 if (key == SDLK_DOWN)
584 if (cursor != limit - 1) // Cursor is within its window
586 else // Otherwise, scroll the window...
588 if (cursor + windowPtr != item.size() - 1)
592 else if (key == SDLK_UP)
602 else if (key == SDLK_PAGEDOWN)
604 if (cursor != limit - 1)
609 if (windowPtr > item.size() - limit)
610 windowPtr = item.size() - limit;
613 else if (key == SDLK_PAGEUP)
619 if (windowPtr < limit)
625 else if (key >= SDLK_a && key <= SDLK_z)
627 // Advance cursor to filename with first letter pressed...
628 uint8 which = (key - SDLK_a) + 65; // Convert key to A-Z char
630 for(uint32 i=0; i<item.size(); i++)
632 if ((item[i][0] & 0xDF) == which)
634 cursor = i - windowPtr;
635 if (i > windowPtr + limit - 1)
636 windowPtr = i - limit + 1, cursor = limit - 1;
638 windowPtr = i, cursor = 0;
645 void ListBox::HandleMouseMove(uint32 x, uint32 y)
647 upArrow.HandleMouseMove(x - extents.x, y - extents.y);
648 downArrow.HandleMouseMove(x - extents.x, y - extents.y);
649 upArrow2.HandleMouseMove(x - extents.x, y - extents.y);
653 uint32 sbHeight = extents.h - 24,
654 thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight);
656 //yRelativePoint is the spot on the thumb where we clicked...
657 int32 newThumbStart = y - yRelativePoint;
659 if (newThumbStart < 0)
662 if ((uint32)newThumbStart > sbHeight - thumb)
663 newThumbStart = sbHeight - thumb;
665 windowPtr = (uint32)(((float)newThumbStart / (float)sbHeight) * (float)item.size());
666 //Check for cursor bounds as well... Or do we need to???
667 //Actually, we don't...!
671 void ListBox::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
673 if (Inside(x, y) && mouseDown)
675 // Why do we have to do this??? (- extents.y?)
676 // I guess it's because only the Window class has offsetting implemented... !!! FIX !!!
677 // cursor = (y - extents.y) / 8;
678 cursor = (y - extents.y) / FONT_HEIGHT;
681 // Check for a hit on the scrollbar...
682 if (x > (uint32)(extents.x + extents.w) && x <= (uint32)(extents.x + extents.w + 8)
683 && y > (uint32)(extents.y + 8) && y <= (uint32)(extents.y + extents.h - 16))
687 // This shiaut should be calculated in AddItem(), not here... (or in Draw() for that matter)
688 uint32 sbHeight = extents.h - 24,
689 thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight),
690 thumbStart = (uint32)(((float)windowPtr / (float)item.size()) * (float)sbHeight);
692 // Did we hit the thumb?
693 if (y >= (extents.y + 8 + thumbStart) && y < (extents.y + 8 + thumbStart + thumb))
694 thumbClicked = true, yRelativePoint = y - thumbStart;
696 //Seems that this is useless--never reached except in rare cases and that the code outside is
699 // thumbClicked = false;
703 thumbClicked = false;
705 upArrow.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
706 downArrow.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
707 upArrow2.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
710 void ListBox::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
712 for(uint32 i=0; i<limit; i++)
714 // Strip off the extension
715 // (extension stripping should be an option, not default!)
716 string s(item[windowPtr + i], 0, item[windowPtr + i].length() - 4);
717 // DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY + i*8,
718 DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY + i*FONT_HEIGHT,
719 (cursor == i ? true : false), "%-*.*s", charWidth, charWidth, s.c_str());
722 upArrow.Draw(extents.x + offsetX, extents.y + offsetY);
723 downArrow.Draw(extents.x + offsetX, extents.y + offsetY);
724 upArrow2.Draw(extents.x + offsetX, extents.y + offsetY);
726 uint32 sbHeight = extents.h - 24,
727 thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight),
728 thumbStart = (uint32)(((float)windowPtr / (float)item.size()) * (float)sbHeight);
730 for(uint32 y=extents.y+offsetY+8; y<extents.y+offsetY+extents.h-16; y++)
732 // for(uint32 x=extents.x+offsetX+extents.w-8; x<extents.x+offsetX+extents.w; x++)
733 for(uint32 x=extents.x+offsetX+extents.w; x<extents.x+offsetX+extents.w+8; x++)
735 if (y >= thumbStart + (extents.y+offsetY+8) && y < thumbStart + thumb + (extents.y+offsetY+8))
736 // screenBuffer[x + (y * pitch)] = (thumbClicked ? 0x458E : 0xFFFF);
737 //458E -> 01 0001 0 1100 0 1110 -> 0100 0101 0110 0011 0111 0011 -> 45 63 73
738 screenBuffer[x + (y * pitch)] = (thumbClicked ? 0xFF736345 : 0xFFFFFFFF);
740 // screenBuffer[x + (y * pitch)] = 0x0200;
741 //0200 -> 000000 10000 00000 -> 00 1000 0100 00
742 screenBuffer[x + (y * pitch)] = 0xFF008400;
747 void ListBox::Notify(Element * e)
749 if (e == &upArrow || e == &upArrow2)
755 if (cursor < limit - 1)
759 else if (e == &downArrow)
761 if (windowPtr < item.size() - limit)
771 void ListBox::AddItem(string s)
773 // Do a simple insertion sort
774 bool inserted = false;
776 for(vector<string>::iterator i=item.begin(); i<item.end(); i++)
778 if (stringCmpi(s, *i) == -1)
789 limit = (item.size() > charHeight ? charHeight : item.size());
792 string ListBox::GetSelectedItem(void)
794 return item[windowPtr + cursor];
798 class FileList: public Window
801 FileList(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0);
802 virtual ~FileList() {}
803 virtual void HandleKey(SDLKey key);
804 virtual void HandleMouseMove(uint32 x, uint32 y) { Window::HandleMouseMove(x, y); }
805 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) { Window::HandleMouseButton(x, y, mouseDown); }
806 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0) { Window::Draw(offsetX, offsetY); }
807 virtual void Notify(Element * e);
814 //Need 4 buttons, one scrollbar...
815 FileList::FileList(uint32 x, uint32 y, uint32 w, uint32 h): Window(x, y, w, h)
817 files = new ListBox(8, 8, w - 16, h - 32);
819 load = new Button(8, h - 16, " Load ");
821 load->SetNotificationElement(this);
823 //!!! FIX !!! Directory might not exist--this shouldn't cause VJ to crash!
824 DIR * dp = opendir(vjs.ROMPath);
829 while ((de = readdir(dp)) != NULL)
831 char * ext = strrchr(de->d_name, '.');
834 if (strcasecmp(ext, ".zip") == 0 || strcasecmp(ext, ".j64") == 0
835 || strcasecmp(ext, ".abs") == 0 || strcasecmp(ext, ".jag") == 0
836 || strcasecmp(ext, ".rom") == 0)
837 files->AddItem(string(de->d_name));
844 //Give a diagnostic message here so that the (l)user can figure out what went wrong. !!! FIX !!!
848 void FileList::HandleKey(SDLKey key)
850 if (key == SDLK_RETURN)
853 Window::HandleKey(key);
856 void FileList::Notify(Element * e)
860 char filename[MAX_PATH];
861 strcpy(filename, vjs.ROMPath);
863 if (strlen(filename) > 0)
864 if (filename[strlen(filename) - 1] != '/')
865 strcat(filename, "/");
867 strcat(filename, files->GetSelectedItem().c_str());
869 // uint32 romSize = JaguarLoadROM(jaguar_mainRom, filename);
870 // JaguarLoadCart(jaguar_mainRom, filename);
871 if (JaguarLoadFile(filename))
874 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
875 SDL_PushEvent(&event);
877 event.type = SDL_USEREVENT, event.user.code = MENU_ITEM_CHOSEN;
878 event.user.data1 = (void *)ResetJaguar;
879 SDL_PushEvent(&event);
884 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
885 SDL_PushEvent(&event);
887 // Handle the error, but don't run...
888 // Tell the user that we couldn't run their file for some reason... !!! FIX !!!
889 //how to kludge: Make a function like ResetJaguar which creates the dialog window
900 Window * (* action)(void);
903 NameAction(string n, Window * (* a)(void) = NULL, SDLKey k = SDLK_UNKNOWN): name(n),
904 action(a), hotKey(k) {}
911 MenuItems(): charLength(0) {}
912 bool Inside(uint32 x, uint32 y)
913 { return (x >= (uint32)extents.x && x < (uint32)(extents.x + extents.w)
914 && y >= (uint32)extents.y && y < (uint32)(extents.y + extents.h) ? true : false); }
917 vector<NameAction> item;
922 class Menu: public Element
925 // 1CFF -> 0 001 11 00 111 1 1111
926 // 421F -> 0 100 00 10 000 1 1111
927 Menu(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = FONT_HEIGHT,
928 /* uint16 fgc = 0x1CFF, uint16 bgc = 0x000F, uint16 fgch = 0x421F,
929 uint16 bgch = 0x1CFF): Element(x, y, w, h), activated(false), clicked(false),*/
930 /* uint32 fgc = 0xFF3F3F00, uint32 bgc = 0x7F000000, uint32 fgch = 0xFF878700,
931 uint32 bgch = 0xFF3F3F00): Element(x, y, w, h), activated(false), clicked(false),*/
932 /* uint32 fgc = 0xFFFF3F3F, uint32 bgc = 0xFF7F0000, uint32 fgch = 0xFFFF8787,
933 uint32 bgch = 0xFFFF3F3F): Element(x, y, w, h), activated(false), clicked(false),*/
934 uint32 fgc = 0xFF7F0000, uint32 bgc = 0xFFFF3F3F, uint32 fgch = 0xFFFF3F3F,
935 uint32 bgch = 0xFFFF8787): Element(x, y, w, h), activated(false), clicked(false),
936 inside(0), insidePopup(0), fgColor(fgc), bgColor(bgc), fgColorHL(fgch),
937 bgColorHL(bgch), menuChosen(-1), menuItemChosen(-1) {}
938 virtual void HandleKey(SDLKey key);
939 virtual void HandleMouseMove(uint32 x, uint32 y);
940 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
941 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
942 virtual void Notify(Element *) {}
943 void Add(MenuItems mi);
946 bool activated, clicked;
947 uint32 inside, insidePopup;
948 // uint16 fgColor, bgColor, fgColorHL, bgColorHL;
949 uint32 fgColor, bgColor, fgColorHL, bgColorHL;
950 int menuChosen, menuItemChosen;
953 vector<MenuItems> itemList;
956 void Menu::HandleKey(SDLKey key)
958 for(uint32 i=0; i<itemList.size(); i++)
960 for(uint32 j=0; j<itemList[i].item.size(); j++)
962 if (itemList[i].item[j].hotKey == key)
965 event.type = SDL_USEREVENT;
966 event.user.code = MENU_ITEM_CHOSEN;
967 event.user.data1 = (void *)itemList[i].item[j].action;
968 SDL_PushEvent(&event);
970 clicked = false, menuChosen = menuItemChosen = -1;
977 void Menu::HandleMouseMove(uint32 x, uint32 y)
979 inside = insidePopup = 0;
983 // Find out *where* we are inside the menu bar
984 uint32 xpos = extents.x;
986 for(uint32 i=0; i<itemList.size(); i++)
988 uint32 width = (itemList[i].title.length() + 2) * FONT_WIDTH;
990 if (x >= xpos && x < xpos + width)
1001 if (!Inside(x, y) && !clicked)
1006 if (itemList[menuChosen].Inside(x, y) && clicked)
1008 insidePopup = ((y - itemList[menuChosen].extents.y) / FONT_HEIGHT) + 1;
1009 menuItemChosen = insidePopup - 1;
1013 void Menu::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
1022 menuChosen = -1; // clicked is already false...!
1025 else // clicked == true
1027 if (insidePopup && !mouseDown) // I.e., mouse-button-up
1030 if (itemList[menuChosen].item[menuItemChosen].action != NULL)
1032 // itemList[menuChosen].item[menuItemChosen].action();
1034 event.type = SDL_USEREVENT;
1035 event.user.code = MENU_ITEM_CHOSEN;
1036 event.user.data1 = (void *)itemList[menuChosen].item[menuItemChosen].action;
1037 SDL_PushEvent(&event);
1039 clicked = false, menuChosen = menuItemChosen = -1;
1042 while (SDL_PollEvent(&event)); // Flush the event queue...
1043 event.type = SDL_MOUSEMOTION;
1045 SDL_GetMouseState(&mx, &my);
1046 event.motion.x = mx, event.motion.y = my;
1047 SDL_PushEvent(&event); // & update mouse position...!
1051 if (!inside && !insidePopup && mouseDown)
1052 clicked = false, menuChosen = menuItemChosen = -1;
1056 void Menu::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
1058 uint32 xpos = extents.x + offsetX;
1060 for(uint32 i=0; i<itemList.size(); i++)
1062 // uint16 color1 = fgColor, color2 = bgColor;
1063 uint32 color1 = fgColor, color2 = bgColor;
1064 if (inside == (i + 1) || (menuChosen != -1 && (uint32)menuChosen == i))
1065 color1 = fgColorHL, color2 = bgColorHL;
1067 DrawStringOpaque(screenBuffer, xpos, extents.y + offsetY, color1, color2,
1068 " %s ", itemList[i].title.c_str());
1069 xpos += (itemList[i].title.length() + 2) * FONT_WIDTH;
1072 // Draw sub menu (but only if active)
1075 uint32 ypos = extents.y + FONT_HEIGHT + 1;
1077 for(uint32 i=0; i<itemList[menuChosen].item.size(); i++)
1079 // uint16 color1 = fgColor, color2 = bgColor;
1080 uint32 color1 = fgColor, color2 = bgColor;
1082 if (insidePopup == i + 1)
1083 color1 = fgColorHL, color2 = bgColorHL, menuItemChosen = i;
1085 if (itemList[menuChosen].item[i].name.length() > 0)
1086 DrawStringOpaque(screenBuffer, itemList[menuChosen].extents.x, ypos,
1087 color1, color2, " %-*.*s ", itemList[menuChosen].charLength,
1088 itemList[menuChosen].charLength, itemList[menuChosen].item[i].name.c_str());
1090 DrawStringOpaque(screenBuffer, itemList[menuChosen].extents.x, ypos,
1091 fgColor, bgColor, "%.*s", itemList[menuChosen].charLength + 2, separator);
1093 ypos += FONT_HEIGHT;
1098 void Menu::Add(MenuItems mi)
1100 for(uint32 i=0; i<mi.item.size(); i++)
1101 if (mi.item[i].name.length() > mi.charLength)
1102 mi.charLength = mi.item[i].name.length();
1104 // Set extents here as well...
1105 mi.extents.x = extents.x + extents.w, mi.extents.y = extents.y + FONT_HEIGHT + 1;
1106 mi.extents.w = (mi.charLength + 2) * FONT_WIDTH, mi.extents.h = mi.item.size() * FONT_HEIGHT;
1108 itemList.push_back(mi);
1109 extents.w += (mi.title.length() + 2) * FONT_WIDTH;
1113 //Do we even *need* this?
1114 //Doesn't seem like it...
1115 /*class RootWindow: public Window
1118 RootWindow(Menu * m, Window * w = NULL): menu(m), window(w) {}
1119 //Do we even need to care about this crap?
1120 // { extents.x = extents.y = 0, extents.w = 320, extents.h = 240; }
1121 virtual void HandleKey(SDLKey key) {}
1122 virtual void HandleMouseMove(uint32 x, uint32 y) {}
1123 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) {}
1124 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0) {}
1125 virtual void Notify(Element *) {}
1130 int16 * rootImage[1280 * 240 * 2];
1135 // Draw text at the given x/y coordinates. Can invert text as well.
1137 void DrawString(uint32 * screen, uint32 x, uint32 y, bool invert, const char * text, ...)
1142 va_start(arg, text);
1143 vsprintf(string, text, arg);
1146 uint32 pitch = sdlemuGetOverlayWidthInPixels();//GetSDLScreenWidthInPixels();
1147 uint32 length = strlen(string), address = x + (y * pitch);
1149 uint32 color1 = 0x0080FF;
1150 uint8 nBlue = (color1 >> 16) & 0xFF, nGreen = (color1 >> 8) & 0xFF, nRed = color1 & 0xFF;
1151 uint8 xorMask = (invert ? 0xFF : 0x00);
1153 for(uint32 i=0; i<length; i++)
1155 uint8 c = string[i];
1156 uint32 fontAddr = (uint32)(c < 32 ? 0 : c - 32) * FONT_WIDTH * FONT_HEIGHT;
1158 for(uint32 yy=0; yy<FONT_HEIGHT; yy++)
1160 for(uint32 xx=0; xx<FONT_WIDTH; xx++)
1162 uint32 existingColor = *(screen + address + xx + (yy * pitch));
1164 uint8 eBlue = (existingColor >> 16) & 0xFF,
1165 eGreen = (existingColor >> 8) & 0xFF,
1166 eRed = existingColor & 0xFF;
1168 uint8 trans = font2[fontAddr] ^ xorMask;
1169 uint8 invTrans = trans ^ 0xFF;
1171 uint32 bRed = (eRed * invTrans + nRed * trans) / 255,
1172 bGreen = (eGreen * invTrans + nGreen * trans) / 255,
1173 bBlue = (eBlue * invTrans + nBlue * trans) / 255;
1175 *(screen + address + xx + (yy * pitch)) = 0xFF000000 | (bBlue << 16) | (bGreen << 8) | bRed;
1180 address += FONT_WIDTH;
1185 // Draw text at the given x/y coordinates, using FG/BG colors.
1187 void DrawStringOpaque(uint32 * screen, uint32 x, uint32 y, uint32 color1, uint32 color2, const char * text, ...)
1192 va_start(arg, text);
1193 vsprintf(string, text, arg);
1196 uint32 pitch = sdlemuGetOverlayWidthInPixels();
1197 uint32 length = strlen(string), address = x + (y * pitch);
1199 uint8 eBlue = (color2 >> 16) & 0xFF, eGreen = (color2 >> 8) & 0xFF, eRed = color2 & 0xFF,
1200 nBlue = (color1 >> 16) & 0xFF, nGreen = (color1 >> 8) & 0xFF, nRed = color1 & 0xFF;
1202 for(uint32 i=0; i<length; i++)
1204 uint8 c = string[i];
1205 c = (c < 32 ? 0 : c - 32);
1206 uint32 fontAddr = (uint32)c * FONT_WIDTH * FONT_HEIGHT;
1208 for(uint32 yy=0; yy<FONT_HEIGHT; yy++)
1210 for(uint32 xx=0; xx<FONT_WIDTH; xx++)
1212 uint8 trans = font2[fontAddr++];
1213 uint8 invTrans = trans ^ 0xFF;
1215 uint32 bRed = (eRed * invTrans + nRed * trans) / 255;
1216 uint32 bGreen = (eGreen * invTrans + nGreen * trans) / 255;
1217 uint32 bBlue = (eBlue * invTrans + nBlue * trans) / 255;
1219 *(screen + address + xx + (yy * pitch)) = 0xFF000000 | (bBlue << 16) | (bGreen << 8) | bRed;
1223 address += FONT_WIDTH;
1228 // Draw text at the given x/y coordinates with transparency (0 is fully opaque, 32 is fully transparent).
1230 void DrawStringTrans(uint32 * screen, uint32 x, uint32 y, uint32 color, uint8 trans, const char * text, ...)
1235 va_start(arg, text);
1236 vsprintf(string, text, arg);
1239 uint32 pitch = sdlemuGetOverlayWidthInPixels();//GetSDLScreenWidthInPixels();
1240 uint32 length = strlen(string), address = x + (y * pitch);
1242 for(uint32 i=0; i<length; i++)
1244 uint32 fontAddr = (uint32)string[i] * 64;
1246 for(uint32 yy=0; yy<8; yy++)
1248 for(uint32 xx=0; xx<8; xx++)
1250 if (font1[fontAddr])
1252 uint32 existingColor = *(screen + address + xx + (yy * pitch));
1254 uint8 eBlue = (existingColor >> 16) & 0xFF,
1255 eGreen = (existingColor >> 8) & 0xFF,
1256 eRed = existingColor & 0xFF,
1257 //This could be done ahead of time, instead of on each pixel...
1258 nBlue = (color >> 16) & 0xFF,
1259 nGreen = (color >> 8) & 0xFF,
1260 nRed = color & 0xFF;
1262 //This could be sped up by using a table of 5 + 5 + 5 bits (32 levels transparency -> 32768 entries)
1263 //Here we've modified it to have 33 levels of transparency (could have any # we want!)
1264 //because dividing by 32 is faster than dividing by 31...!
1265 uint8 invTrans = 32 - trans;
1267 uint32 bRed = (eRed * trans + nRed * invTrans) / 32;
1268 uint32 bGreen = (eGreen * trans + nGreen * invTrans) / 32;
1269 uint32 bBlue = (eBlue * trans + nBlue * invTrans) / 32;
1271 *(screen + address + xx + (yy * pitch)) = 0xFF000000 | (bBlue << 16) | (bGreen << 8) | bRed;
1284 // Uses zero as transparent color
1285 // Can also use an optional alpha channel
1286 // Alpha channel is now mandatory! ;-)
1288 //void DrawTransparentBitmap(int16 * screen, uint32 x, uint32 y, uint16 * bitmap, uint8 * alpha/*=NULL*/)
1289 /*void DrawTransparentBitmap(uint32 * screen, uint32 x, uint32 y, uint32 * bitmap, uint8 * alpha)
1291 uint32 width = bitmap[0], height = bitmap[1];
1294 // uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1295 uint32 pitch = sdlemuGetOverlayWidthInPixels();//GetSDLScreenWidthInPixels();
1296 uint32 address = x + (y * pitch);
1298 for(uint32 yy=0; yy<height; yy++)
1300 for(uint32 xx=0; xx<width; xx++)
1304 if (*bitmap && x + xx < pitch) // NOTE: Still doesn't clip the Y val...
1305 *(screen + address + xx + (yy * pitch)) = *bitmap;
1309 uint8 trans = *alpha;
1310 uint32 color = *bitmap;
1311 uint32 existingColor = *(screen + address + xx + (yy * pitch));
1313 uint8 eRed = existingColor & 0xFF,
1314 eGreen = (existingColor >> 8) & 0xFF,
1315 eBlue = (existingColor >> 16) & 0xFF,
1317 nRed = color & 0xFF,
1318 nGreen = (color >> 8) & 0xFF,
1319 nBlue = (color >> 16) & 0xFF;
1321 uint8 invTrans = 255 - trans;
1322 uint32 bRed = (eRed * trans + nRed * invTrans) / 255;
1323 uint32 bGreen = (eGreen * trans + nGreen * invTrans) / 255;
1324 uint32 bBlue = (eBlue * trans + nBlue * invTrans) / 255;
1326 uint32 blendedColor = 0xFF000000 | bRed | (bGreen << 8) | (bBlue << 16);
1328 *(screen + address + xx + (yy * pitch)) = blendedColor;
1337 void DrawTransparentBitmapDeprecated(uint32 * screen, uint32 x, uint32 y, uint32 * bitmap)
1339 uint32 width = bitmap[0], height = bitmap[1];
1342 uint32 pitch = sdlemuGetOverlayWidthInPixels();//GetSDLScreenWidthInPixels();
1343 uint32 address = x + (y * pitch);
1345 for(uint32 yy=0; yy<height; yy++)
1347 for(uint32 xx=0; xx<width; xx++)
1349 uint32 color = *bitmap;
1350 uint32 blendedColor = color;
1351 uint32 existingColor = *(screen + address + xx + (yy * pitch));
1353 if (existingColor >> 24 != 0x00) // Pixel needs blending
1355 uint8 trans = color >> 24;
1356 uint8 invTrans = trans ^ 0xFF;//255 - trans;
1358 uint8 eRed = existingColor & 0xFF,
1359 eGreen = (existingColor >> 8) & 0xFF,
1360 eBlue = (existingColor >> 16) & 0xFF,
1362 nRed = color & 0xFF,
1363 nGreen = (color >> 8) & 0xFF,
1364 nBlue = (color >> 16) & 0xFF;
1366 uint32 bRed = (eRed * invTrans + nRed * trans) / 255;
1367 uint32 bGreen = (eGreen * invTrans + nGreen * trans) / 255;
1368 uint32 bBlue = (eBlue * invTrans + nBlue * trans) / 255;
1370 blendedColor = 0xFF000000 | bRed | (bGreen << 8) | (bBlue << 16);
1373 *(screen + address + xx + (yy * pitch)) = blendedColor;
1379 void DrawTransparentBitmap(uint32 * screen, uint32 x, uint32 y, const void * bitmap)
1381 uint32 pitch = sdlemuGetOverlayWidthInPixels();
1382 uint32 address = x + (y * pitch);
1385 for(uint32 yy=0; yy<((Bitmap *)bitmap)->height; yy++)
1387 for(uint32 xx=0; xx<((Bitmap *)bitmap)->width; xx++)
1389 uint32 color = ((uint32 *)((Bitmap *)bitmap)->pixelData)[count];
1390 uint32 blendedColor = color;
1391 uint32 existingColor = *(screen + address + xx + (yy * pitch));
1393 if (existingColor >> 24 != 0x00) // Pixel needs blending
1395 uint8 trans = color >> 24;
1396 uint8 invTrans = trans ^ 0xFF;
1398 uint8 eRed = existingColor & 0xFF,
1399 eGreen = (existingColor >> 8) & 0xFF,
1400 eBlue = (existingColor >> 16) & 0xFF,
1402 nRed = color & 0xFF,
1403 nGreen = (color >> 8) & 0xFF,
1404 nBlue = (color >> 16) & 0xFF;
1406 uint32 bRed = (eRed * invTrans + nRed * trans) / 255;
1407 uint32 bGreen = (eGreen * invTrans + nGreen * trans) / 255;
1408 uint32 bBlue = (eBlue * invTrans + nBlue * trans) / 255;
1410 blendedColor = 0xFF000000 | bRed | (bGreen << 8) | (bBlue << 16);
1413 *(screen + address + xx + (yy * pitch)) = blendedColor;
1420 // GUI stuff--it's not crunchy, it's GUI! ;-)
1425 SDL_ShowCursor(SDL_DISABLE);
1426 SDL_GetMouseState(&mouseX, &mouseY);
1436 //bool GUIMain(void)
1437 bool GUIMain(char * filename)
1439 WriteLog("GUI: Inside GUIMain...\n");
1441 uint32 pointerBGSave[6 * 8 + 2];
1442 pointerBGSave[0] = 6;
1443 pointerBGSave[1] = 8;
1445 // Need to set things up so that it loads and runs a file if given on the command line. !!! FIX !!! [DONE]
1446 extern uint32 * backbuffer;
1447 // bool done = false;
1449 Window * mainWindow = NULL;
1451 // Set up the GUI classes...
1452 // Element::SetScreenAndPitch(backbuffer, GetSDLScreenWidthInPixels());
1453 Element::SetScreenAndPitch((uint32 *)sdlemuGetOverlayPixels(), sdlemuGetOverlayWidthInPixels());
1454 sdlemuEnableOverlay();
1458 mi.title = "Jaguar";
1459 mi.item.push_back(NameAction("Load...", LoadROM, SDLK_l));
1460 mi.item.push_back(NameAction("Reset", ResetJaguar, SDLK_r));
1462 mi.item.push_back(NameAction("Reset CD", ResetJaguarCD, SDLK_c));
1463 mi.item.push_back(NameAction("Run", RunEmu, SDLK_ESCAPE));
1464 mi.item.push_back(NameAction(""));
1465 mi.item.push_back(NameAction("Quit", Quit, SDLK_q));
1467 mi.title = "Settings";
1469 mi.item.push_back(NameAction("Video..."));
1470 mi.item.push_back(NameAction("Audio..."));
1471 mi.item.push_back(NameAction("Misc...", MiscOptions, SDLK_m));
1475 mi.item.push_back(NameAction("About...", About));
1478 bool showMouse = true;
1480 // Grab the BG where the mouse will be painted (prime the backstore)
1484 Bitmap ptr = { 6, 8, 4,
1485 ""//"000011112222333344445555"
1486 //"000011112222333344445555"
1487 //"000011112222333344445555"
1488 //"000011112222333344445555"
1489 //"000011112222333344445555"
1490 //"000011112222333344445555"
1491 //"000011112222333344445555"
1492 //"000011112222333344445555"
1494 uint32 * overlayPixels = (uint32 *)sdlemuGetOverlayPixels();
1497 for(uint32 y=0; y<pointerBGSave[1]; y++)
1498 for(uint32 x=0; x<pointerBGSave[0]; x++)
1499 pointerBGSave[count++] = overlayPixels[((mouseY + y) * sdlemuGetOverlayWidthInPixels()) + (mouseX + x)];
1501 uint32 oldMouseX = mouseX, oldMouseY = mouseY;
1503 //This is crappy!!! !!! FIX !!!
1504 //Is this even needed any more? Hmm. Maybe. Dunno.
1505 WriteLog("GUI: Resetting Jaguar...\n");
1508 WriteLog("GUI: Clearing BG save...\n");
1509 // Set up our background save...
1510 // memset(background, 0x11, tom_getVideoModeWidth() * 240 * 2);
1511 //1111 -> 000100 01000 10001 -> 0001 0000 0100 0010 1000 1100 -> 10 42 8C
1512 for(uint32 i=0; i<tom_getVideoModeWidth()*240; i++)
1513 // background[i] = 0xFF8C4210;
1514 backbuffer[i] = 0xFF8C4210;
1516 /* uint32 * overlayPix = (uint32 *)sdlemuGetOverlayPixels();
1517 for(uint32 i=0; i<sdlemuGetOverlayWidthInPixels()*480; i++)
1518 overlayPix[i] = 0x00000000;*/
1520 // Handle loading file passed in on the command line...! [DONE]
1524 if (JaguarLoadFile(filename))
1526 // event.type = SDL_USEREVENT, event.user.code = MENU_ITEM_CHOSEN;
1527 // event.user.data1 = (void *)ResetJaguar;
1528 // SDL_PushEvent(&event);
1529 // Make it so that if passed in on the command line, we quit right
1530 // away when pressing ESC
1531 WriteLog("GUI: Bypassing GUI since ROM passed in on command line...\n");
1537 // Create error dialog...
1539 sprintf(errText, "The file %40s could not be loaded.", filename);
1541 mainWindow = new Window(8, 16, 304, 160);
1542 mainWindow->AddElement(new Text(8, 8, "Error!"));
1543 mainWindow->AddElement(new Text(8, 24, errText));
1547 WriteLog("GUI: Entering main loop...\n");
1550 if (SDL_PollEvent(&event))
1552 if (event.type == SDL_USEREVENT)
1554 if (event.user.code == WINDOW_CLOSE)
1559 else if (event.user.code == MENU_ITEM_CHOSEN)
1561 // Confused? Let me enlighten... What we're doing here is casting
1562 // data1 as a pointer to a function which returns a Window pointer and
1563 // which takes no parameters (the "(Window *(*)(void))" part), then
1564 // derefencing it (the "*" in front of that) in order to call the
1565 // function that it points to. Clear as mud? Yeah, I hate function
1566 // pointers too, but what else are you gonna do?
1567 mainWindow = (*(Window *(*)(void))event.user.data1)();
1569 while (SDL_PollEvent(&event)); // Flush the event queue...
1570 event.type = SDL_MOUSEMOTION;
1572 SDL_GetMouseState(&mx, &my);
1573 event.motion.x = mx, event.motion.y = my;
1574 SDL_PushEvent(&event); // & update mouse position...!
1576 oldMouseX = mouseX, oldMouseY = mouseY;
1577 mouseX = mx, mouseY = my; // This prevents "mouse flash"...
1580 else if (event.type == SDL_ACTIVEEVENT)
1582 if (event.active.state == SDL_APPMOUSEFOCUS)
1583 showMouse = (event.active.gain ? true : false);
1585 else if (event.type == SDL_KEYDOWN)
1588 mainWindow->HandleKey(event.key.keysym.sym);
1590 mainMenu.HandleKey(event.key.keysym.sym);
1592 else if (event.type == SDL_MOUSEMOTION)
1594 oldMouseX = mouseX, oldMouseY = mouseY;
1595 mouseX = event.motion.x, mouseY = event.motion.y;
1598 mainWindow->HandleMouseMove(mouseX, mouseY);
1600 mainMenu.HandleMouseMove(mouseX, mouseY);
1602 else if (event.type == SDL_MOUSEBUTTONDOWN)
1604 uint32 mx = event.button.x, my = event.button.y;
1607 mainWindow->HandleMouseButton(mx, my, true);
1609 mainMenu.HandleMouseButton(mx, my, true);
1611 else if (event.type == SDL_MOUSEBUTTONUP)
1613 uint32 mx = event.button.x, my = event.button.y;
1616 mainWindow->HandleMouseButton(mx, my, false);
1618 mainMenu.HandleMouseButton(mx, my, false);
1621 //PROBLEM: In order to use the dirty rectangle approach here, we need some way of
1622 // handling it in mainMenu.Draw() and mainWindow->Draw(). !!! FIX !!!
1623 //POSSIBLE SOLUTION:
1624 // When mouse is moving and not on menu or window, can do straight dirty rect.
1625 // When mouse is on menu, need to update screen. Same for buttons on windows...
1626 // What the menu & windows should do is only redraw on a state change. IOW, they
1627 // should call their own/child window's Draw() function instead of doing it top
1629 //#define NEW_BACKSTORE_METHOD
1632 // The way we do things here is kinda stupid (redrawing the screen every frame), but
1633 // it's simple. Perhaps there may be a reason down the road to be more selective with
1634 // our clearing, but for now, this will suffice.
1635 // memset(backbuffer, 0x11, tom_getVideoModeWidth() * 240 * 2);
1636 // memcpy(backbuffer, background, tom_getVideoModeWidth() * 256 * 2);
1637 // memcpy(backbuffer, background, tom_getVideoModeWidth() * 256 * 4);
1638 #ifndef NEW_BACKSTORE_METHOD
1639 memset(sdlemuGetOverlayPixels(), 0, sdlemuGetOverlayWidthInPixels() * 480 * 4);
1642 //Could do multiple windows here by using a vector + priority info...
1643 //Though the way ZSNES does it seems to be by a bool (i.e., they're always active, just not shown)
1648 /*uint32 pBGS[6 * 8 + 3] = { 6, 8, 4,
1658 //This isn't working... Why????
1659 //It's because DrawTransparentBitmap does alpha blending if it detects zero in the alpha channel.
1660 //So why do it that way? Hm.
1661 overlayPixels = (uint32 *)sdlemuGetOverlayPixels();
1663 #ifdef NEW_BACKSTORE_METHOD
1664 // DrawTransparentBitmapDeprecated(overlayPixels, oldMouseX, oldMouseY, pointerBGSave);
1665 // DrawTransparentBitmap(overlayPixels, oldMouseX, oldMouseY, pBGS);
1666 for(uint32 y=0; y<pointerBGSave[1]; y++)
1667 for(uint32 x=0; x<pointerBGSave[0]; x++)
1668 overlayPixels[((oldMouseY + y) * sdlemuGetOverlayWidthInPixels()) + (oldMouseX + x)] = 0x00000000;
1672 for(uint32 y=0; y<pointerBGSave[1]; y++)
1673 for(uint32 x=0; x<pointerBGSave[0]; x++)
1674 pointerBGSave[count++] = overlayPixels[((mouseY + y) * sdlemuGetOverlayWidthInPixels()) + (mouseX + x)];
1678 // DrawTransparentBitmapDeprecated(backbuffer, mouseX, mouseY, mousePic);
1679 DrawTransparentBitmapDeprecated(overlayPixels, mouseX, mouseY, mousePic);
1689 // GUI "action" functions
1692 Window * LoadROM(void)
1694 FileList * fileList = new FileList(20, 20, 600, 440);
1696 return (Window *)fileList;
1699 Window * ResetJaguar(void)
1706 Window * ResetJaguarCD(void)
1708 memcpy(jaguar_mainRom, jaguar_CDBootROM, 0x40000);
1709 jaguarRunAddress = 0x802000;
1710 jaguar_mainRom_crc32 = crc32_calcCheckSum(jaguar_mainRom, 0x40000);
1712 //This is a quick kludge to get the CDBIOS to boot properly...
1713 //Wild speculation: It could be that this memory location is wired into the CD unit
1714 //somehow, which lets it know whether or not a cart is present in the unit...
1715 jaguar_mainRom[0x0040B] = 0x03;
1720 bool debounceRunKey = true;
1721 Window * RunEmu(void)
1723 extern uint32 * backbuffer;
1724 //Temporary, to test the new timer based code...
1725 sdlemuDisableOverlay();
1727 sdlemuEnableOverlay();
1728 // Save the background for the GUI...
1729 // In this case, we squash the color to monochrome, then force it to blue + green...
1730 for(uint32 i=0; i<tom_getVideoModeWidth() * 256; i++)
1732 uint32 pixel = backbuffer[i];
1733 uint8 b = (pixel >> 16) & 0xFF, g = (pixel >> 8) & 0xFF, r = pixel & 0xFF;
1734 pixel = ((r + g + b) / 3) & 0x00FF;
1735 backbuffer[i] = 0xFF000000 | (pixel << 16) | (pixel << 8);
1739 //This is crappy... !!! FIX !!!
1740 extern bool finished, showGUI;
1742 // uint32 nFrame = 0, nFrameskip = 0;
1743 uint32 totalFrames = 0;
1745 bool showMessage = true;
1746 uint32 showMsgFrames = 120;
1747 uint8 transparency = 0;
1748 // Pass a message to the "joystick" code to debounce the ESC key...
1749 debounceRunKey = true;
1751 uint32 cartType = 4;
1752 if (jaguarRomSize == 0x200000)
1754 else if (jaguarRomSize == 0x400000)
1756 else if (jaguar_mainRom_crc32 == 0x687068D5)
1758 else if (jaguar_mainRom_crc32 == 0x55A0669C)
1761 char * cartTypeName[5] = { "2M Cartridge", "4M Cartridge", "CD BIOS", "CD Dev BIOS", "Homebrew" };
1762 uint32 elapsedTicks = SDL_GetTicks(), frameCount = 0, framesPerSecond = 0;
1766 // Set up new backbuffer with new pixels and data
1767 JaguarExecute(backbuffer, true);
1768 // JaguarExecuteNew();
1770 //WriteLog("Frame #%u...\n", totalFrames);
1771 //extern bool doDSPDis;
1772 //if (totalFrames == 373)
1775 //This sucks... !!! FIX !!!
1777 //This is done here so that the crud below doesn't get on our GUI background...
1781 // Some QnD GUI stuff here...
1784 extern uint32 gpu_pc, dsp_pc;
1785 DrawString(backbuffer, 8, 8, false, "GPU PC: %08X", gpu_pc);
1786 DrawString(backbuffer, 8, 16, false, "DSP PC: %08X", dsp_pc);
1787 DrawString(backbuffer, 8, 32, false, "%u FPS", framesPerSecond);
1792 // FF0F -> 1111 11 11 000 0 1111 -> 3F 18 0F
1793 // 3FE3 -> 0011 11 11 111 0 0011 -> 0F 3F 03
1794 /* DrawStringTrans((uint32 *)backbuffer, 8, 24*8, 0xFF0F, transparency, "Running...");
1795 DrawStringTrans((uint32 *)backbuffer, 8, 26*8, 0x3FE3, transparency, "%s, run address: %06X", cartTypeName[cartType], jaguarRunAddress);
1796 DrawStringTrans((uint32 *)backbuffer, 8, 27*8, 0x3FE3, transparency, "CRC: %08X", jaguar_mainRom_crc32);//*/
1797 //first has wrong color. !!! FIX !!!
1798 DrawStringTrans(backbuffer, 8, 24*8, 0xFF7F63FF, transparency, "Running...");
1799 DrawStringTrans(backbuffer, 8, 26*8, 0xFF1FFF3F, transparency, "%s, run address: %06X", cartTypeName[cartType], jaguarRunAddress);
1800 DrawStringTrans(backbuffer, 8, 27*8, 0xFF1FFF3F, transparency, "CRC: %08X", jaguar_mainRom_crc32);
1802 if (showMsgFrames == 0)
1806 if (transparency == 33)
1808 showMessage = false;
1809 /*extern bool doGPUDis;
1810 doGPUDis = true;//*/
1821 if (SDL_GetTicks() - elapsedTicks > 250)
1822 elapsedTicks += 250, framesPerSecond = frameCount * 4, frameCount = 0;
1825 // Reset the pitch, since it may have been changed in-game...
1826 // Element::SetScreenAndPitch(backbuffer, GetSDLScreenPitch() / 2);
1827 Element::SetScreenAndPitch((uint32 *)backbuffer, GetSDLScreenWidthInPixels());
1829 // Save the background for the GUI...
1830 // memcpy(background, backbuffer, tom_getVideoModeWidth() * 240 * 2);
1831 // In this case, we squash the color to monochrome, then force it to blue + green...
1832 for(uint32 i=0; i<tom_getVideoModeWidth() * 256; i++)
1834 // uint32 word = backbuffer[i];
1835 // uint8 r = (word >> 10) & 0x1F, g = (word >> 5) & 0x1F, b = word & 0x1F;
1836 // word = ((r + g + b) / 3) & 0x001F;
1837 // word = (word << 5) | word;
1838 // background[i] = word;
1840 uint32 pixel = backbuffer[i];
1841 uint8 b = (pixel >> 16) & 0xFF, g = (pixel >> 8) & 0xFF, r = pixel & 0xFF;
1842 pixel = ((r + g + b) / 3) & 0x00FF;
1843 background[i] = 0xFF000000 | (pixel << 16) | (pixel << 8);
1851 WriteLog("GUI: Quitting due to user request.\n");
1857 Window * About(void)
1860 sprintf(buf, "Virtual Jaguar CVS %s", __DATE__);
1861 //fprintf(fp, "VirtualJaguar v1.0.8 (Last full build was on %s %s)\n", __DATE__, __TIME__);
1862 //VirtualJaguar v1.0.8 (Last full build was on Dec 30 2004 20:01:31)
1863 Window * window = new Window(8, 16, 40 * FONT_WIDTH, 19 * FONT_HEIGHT);
1864 // window->AddElement(new Text(8, 8, "Virtual Jaguar 1.0.8"));
1865 // window->AddElement(new Text(8, 8, "Virtual Jaguar CVS 20050110", 0xFF3030FF, 0xFF000000));
1866 window->AddElement(new Text(8, 8, buf, 0xFF3030FF, 0xFF000000));
1867 window->AddElement(new Text(8, 8+2*FONT_HEIGHT, "Coders:"));
1868 window->AddElement(new Text(16, 8+3*FONT_HEIGHT, "James L. Hammons (shamus)"));
1869 window->AddElement(new Text(16, 8+4*FONT_HEIGHT, "Niels Wagenaar (nwagenaar)"));
1870 window->AddElement(new Text(16, 8+5*FONT_HEIGHT, "Carwin Jones (Caz)"));
1871 window->AddElement(new Text(16, 8+6*FONT_HEIGHT, "Adam Green"));
1872 window->AddElement(new Text(8, 8+8*FONT_HEIGHT, "Testers:"));
1873 window->AddElement(new Text(16, 8+9*FONT_HEIGHT, "Guruma"));
1874 window->AddElement(new Text(8, 8+11*FONT_HEIGHT, "Thanks go out to:"));
1875 window->AddElement(new Text(16, 8+12*FONT_HEIGHT, "Aaron Giles for the original CoJag"));
1876 window->AddElement(new Text(16, 8+13*FONT_HEIGHT, "David Raingeard for the original VJ"));
1877 window->AddElement(new Text(16, 8+14*FONT_HEIGHT, "Karl Stenerud for his Musashi 68K emu"));
1878 window->AddElement(new Text(16, 8+15*FONT_HEIGHT, "Sam Lantinga for his amazing SDL libs"));
1879 window->AddElement(new Text(16, 8+16*FONT_HEIGHT, "Ryan C. Gordon for VJ's web presence"));
1880 window->AddElement(new Text(16, 8+17*FONT_HEIGHT, "Curt Vendel for various Jaguar goodies"));
1881 window->AddElement(new Text(16, 8+18*FONT_HEIGHT, "The guys over at Atari Age ;-)"));
1886 Window * MiscOptions(void)
1888 Window * window = new Window(8, 16, 304, 192);
1889 window->AddElement(new PushButton(8, 8, &vjs.useJaguarBIOS, "BIOS"));
1890 window->AddElement(new SlideSwitch(8, 32, &vjs.hardwareTypeNTSC, "PAL", "NTSC"));
1891 window->AddElement(new PushButton(8, 64, &vjs.DSPEnabled, "DSP"));
1892 window->AddElement(new SlideSwitch(24, 88, &vjs.usePipelinedDSP, "Original", "Pipelined"));
1893 window->AddElement(new SlideSwitch(8, 120, (bool *)&vjs.glFilter, "Sharp", "Blurry"));
1894 window->AddElement(new SlideSwitch(8, 152, (bool *)&vjs.renderType, "Normal render", "TV style"));
1904 // * Window/fullscreen
1911 // Generic ROM loading
1913 uint32 JaguarLoadROM(uint8 * rom, char * path)
1915 // We really should have some kind of sanity checking for the ROM size here to prevent
1916 // a buffer overflow... !!! FIX !!!
1919 WriteLog("JaguarLoadROM: Attempting to load file '%s'...", path);
1920 char * ext = strrchr(path, '.');
1922 WriteLog("FAILED!\n");
1924 WriteLog("Succeeded in finding extension (%s)!\n", ext);
1928 WriteLog("VJ: Loading \"%s\"...", path);
1930 if (strcasecmp(ext, ".zip") == 0)
1932 // Handle ZIP file loading here...
1933 WriteLog("(ZIPped)...");
1935 if (load_zipped_file(0, 0, path, NULL, &rom, &romSize) == -1)
1937 WriteLog("Failed!\n");
1943 /* FILE * fp = fopen(path, "rb");
1947 WriteLog("Failed!\n");
1951 fseek(fp, 0, SEEK_END);
1952 romSize = ftell(fp);
1953 fseek(fp, 0, SEEK_SET);
1954 fread(rom, 1, romSize, fp);
1957 // Handle gzipped files transparently [Adam Green]...
1959 gzFile fp = gzopen(path, "rb");
1963 WriteLog("Failed!\n");
1967 romSize = gzfilelength(fp);
1968 gzseek(fp, 0, SEEK_SET);
1969 gzread(fp, rom, romSize);
1973 WriteLog("OK (%i bytes)\n", romSize);
1980 // Jaguar file loading
1982 bool JaguarLoadFile(char * path)
1984 // jaguarRomSize = JaguarLoadROM(mem, path);
1985 jaguarRomSize = JaguarLoadROM(jaguar_mainRom, path);
1987 /*//This is not *nix friendly for some reason...
1988 // if (!UserSelectFile(path, newPath))
1989 if (!UserSelectFile((strlen(path) == 0 ? (char *)"." : path), newPath))
1991 WriteLog("VJ: Could not find valid ROM in directory \"%s\"...\nAborting!\n", path);
1996 if (jaguarRomSize == 0)
1998 // WriteLog("VJ: Could not load ROM from file \"%s\"...\nAborting!\n", newPath);
1999 WriteLog("GUI: Could not load ROM from file \"%s\"...\nAborting load!\n", path);
2000 // Need to do something else here, like throw up an error dialog instead of aborting. !!! FIX !!!
2003 return false; // This is a start...
2006 jaguar_mainRom_crc32 = crc32_calcCheckSum(jaguar_mainRom, jaguarRomSize);
2007 WriteLog("CRC: %08X\n", (unsigned int)jaguar_mainRom_crc32);
2010 jaguarRunAddress = 0x802000;
2012 char * ext = strrchr(path, '.'); // Get the file's extension for non-cartridge checking
2014 //NOTE: Should fix JaguarLoadROM() to replace .zip with what's *in* the zip (.abs, .j64, etc.)
2015 if (strcasecmp(ext, ".rom") == 0)
2017 // File extension ".ROM": Alpine image that loads/runs at $802000
2018 WriteLog("GUI: Setting up homebrew (ROM)... Run address: 00802000, length: %08X\n", jaguarRomSize);
2020 for(int i=jaguarRomSize-1; i>=0; i--)
2021 jaguar_mainRom[0x2000 + i] = jaguar_mainRom[i];
2023 memset(jaguar_mainRom, 0xFF, 0x2000);
2024 /* memcpy(jaguar_mainRam, jaguar_mainRom, jaguarRomSize);
2025 memset(jaguar_mainRom, 0xFF, 0x600000);
2026 memcpy(jaguar_mainRom + 0x2000, jaguar_mainRam, jaguarRomSize);
2027 memset(jaguar_mainRam, 0x00, 0x400000);*/
2030 Stubulator ROM vectors...
2031 handler 001 at $00E00008
2032 handler 002 at $00E008DE
2033 handler 003 at $00E008E2
2034 handler 004 at $00E008E6
2035 handler 005 at $00E008EA
2036 handler 006 at $00E008EE
2037 handler 007 at $00E008F2
2038 handler 008 at $00E0054A
2039 handler 009 at $00E008FA
2040 handler 010 at $00000000
2041 handler 011 at $00000000
2042 handler 012 at $00E008FE
2043 handler 013 at $00E00902
2044 handler 014 at $00E00906
2045 handler 015 at $00E0090A
2046 handler 016 at $00E0090E
2047 handler 017 at $00E00912
2048 handler 018 at $00E00916
2049 handler 019 at $00E0091A
2050 handler 020 at $00E0091E
2051 handler 021 at $00E00922
2052 handler 022 at $00E00926
2053 handler 023 at $00E0092A
2054 handler 024 at $00E0092E
2055 handler 025 at $00E0107A
2056 handler 026 at $00E0107A
2057 handler 027 at $00E0107A
2058 handler 028 at $00E008DA
2059 handler 029 at $00E0107A
2060 handler 030 at $00E0107A
2061 handler 031 at $00E0107A
2062 handler 032 at $00000000
2064 Let's try setting up the illegal instruction vector for a stubulated jaguar...
2066 /* SET32(jaguar_mainRam, 0x08, 0x00E008DE);
2067 SET32(jaguar_mainRam, 0x0C, 0x00E008E2);
2068 SET32(jaguar_mainRam, 0x10, 0x00E008E6); // <-- Should be here (it is)...
2069 SET32(jaguar_mainRam, 0x14, 0x00E008EA);//*/
2071 // Try setting the vector to say, $1000 and putting an instruction there that loops forever:
2072 // This kludge works! Yeah!
2073 SET32(jaguar_mainRam, 0x10, 0x00001000);
2074 SET16(jaguar_mainRam, 0x1000, 0x60FE); // Here: bra Here
2076 else if (strcasecmp(ext, ".abs") == 0)
2078 // File extension ".ABS": Atari linker output file with header (w/o is useless to us here)
2081 ABS Format sleuthing (LBUGDEMO.ABS):
2083 000000 60 1B 00 00 05 0C 00 04 62 C0 00 00 04 28 00 00
2084 000010 12 A6 00 00 00 00 00 80 20 00 FF FF 00 80 25 0C
2087 DRI-format file detected...
2088 Text segment size = 0x0000050c bytes
2089 Data segment size = 0x000462c0 bytes
2090 BSS Segment size = 0x00000428 bytes
2091 Symbol Table size = 0x000012a6 bytes
2092 Absolute Address for text segment = 0x00802000
2093 Absolute Address for data segment = 0x0080250c
2094 Absolute Address for BSS segment = 0x00004000
2097 000000 01 50 00 03 00 00 00 00 00 03 83 10 00 00 05 3b
2098 000010 00 1c 00 03 00 00 01 07 00 00 1d d0 00 03 64 98
2099 000020 00 06 8b 80 00 80 20 00 00 80 20 00 00 80 3d d0
2101 000030 2e 74 78 74 00 00 00 00 00 80 20 00 00 80 20 00 .txt (+36 bytes)
2102 000040 00 00 1d d0 00 00 00 a8 00 00 00 00 00 00 00 00
2103 000050 00 00 00 00 00 00 00 20
2104 000058 2e 64 74 61 00 00 00 00 00 80 3d d0 00 80 3d d0 .dta (+36 bytes)
2105 000068 00 03 64 98 00 00 1e 78 00 00 00 00 00 00 00 00
2106 000078 00 00 00 00 00 00 00 40
2107 000080 2e 62 73 73 00 00 00 00 00 00 50 00 00 00 50 00 .bss (+36 bytes)
2108 000090 00 06 8b 80 00 03 83 10 00 00 00 00 00 00 00 00
2109 0000a0 00 00 00 00 00 00 00 80
2111 Header size is $A8 bytes...
2113 BSD/COFF format file detected...
2114 3 sections specified
2115 Symbol Table offset = 230160 ($00038310)
2116 Symbol Table contains 1339 symbol entries ($0000053B)
2117 The additional header size is 28 bytes ($001C)
2118 Magic Number for RUN_HDR = 0x00000107
2119 Text Segment Size = 7632 ($00001DD0)
2120 Data Segment Size = 222360 ($00036498)
2121 BSS Segment Size = 428928 ($00068B80)
2122 Starting Address for executable = 0x00802000
2123 Start of Text Segment = 0x00802000
2124 Start of Data Segment = 0x00803dd0
2126 if (jaguar_mainRom[0] == 0x60 && jaguar_mainRom[1] == 0x1B)
2128 uint32 loadAddress = GET32(jaguar_mainRom, 0x16), //runAddress = GET32(jaguar_mainRom, 0x2A),
2129 codeSize = GET32(jaguar_mainRom, 0x02) + GET32(jaguar_mainRom, 0x06);
2130 WriteLog("GUI: Setting up homebrew (ABS-1)... Run address: %08X, length: %08X\n", loadAddress, codeSize);
2132 if (loadAddress < 0x800000)
2133 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x24, codeSize);
2136 for(int i=codeSize-1; i>=0; i--)
2137 jaguar_mainRom[(loadAddress - 0x800000) + i] = jaguar_mainRom[i + 0x24];
2138 /* memcpy(jaguar_mainRam, jaguar_mainRom + 0x24, codeSize);
2139 memset(jaguar_mainRom, 0xFF, 0x600000);
2140 memcpy(jaguar_mainRom + (loadAddress - 0x800000), jaguar_mainRam, codeSize);
2141 memset(jaguar_mainRam, 0x00, 0x400000);*/
2144 jaguarRunAddress = loadAddress;
2146 else if (jaguar_mainRom[0] == 0x01 && jaguar_mainRom[1] == 0x50)
2148 uint32 loadAddress = GET32(jaguar_mainRom, 0x28), runAddress = GET32(jaguar_mainRom, 0x24),
2149 codeSize = GET32(jaguar_mainRom, 0x18) + GET32(jaguar_mainRom, 0x1C);
2150 WriteLog("GUI: Setting up homebrew (ABS-2)... Run address: %08X, length: %08X\n", runAddress, codeSize);
2152 if (loadAddress < 0x800000)
2153 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0xA8, codeSize);
2156 for(int i=codeSize-1; i>=0; i--)
2157 jaguar_mainRom[(loadAddress - 0x800000) + i] = jaguar_mainRom[i + 0xA8];
2158 /* memcpy(jaguar_mainRam, jaguar_mainRom + 0xA8, codeSize);
2159 memset(jaguar_mainRom, 0xFF, 0x600000);
2160 memcpy(jaguar_mainRom + (loadAddress - 0x800000), jaguar_mainRam, codeSize);
2161 memset(jaguar_mainRam, 0x00, 0x400000);*/
2164 jaguarRunAddress = runAddress;
2168 WriteLog("GUI: Couldn't find correct ABS format: %02X %02X\n", jaguar_mainRom[0], jaguar_mainRom[1]);
2172 else if (strcasecmp(ext, ".jag") == 0)
2174 // File extension ".JAG": Atari server file with header
2175 //NOTE: The bytes 'JAGR' should also be at position $1C...
2176 // Also, there's *always* a $601A header at position $00...
2177 if (jaguar_mainRom[0] == 0x60 && jaguar_mainRom[1] == 0x1A)
2179 uint32 loadAddress = GET32(jaguar_mainRom, 0x22), runAddress = GET32(jaguar_mainRom, 0x2A);
2180 //This is not always right! Especially when converted via bin2jag1!!!
2181 //We should have access to the length of the furshlumiger file that was loaded anyway!
2183 // uint32 progLength = GET32(jaguar_mainRom, 0x02);
2186 // WriteLog("Jaguar: Setting up PD ROM... Run address: %08X, length: %08X\n", runAddress, progLength);
2187 // memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, progLength);
2188 WriteLog("GUI: Setting up homebrew (JAG)... Run address: %08X, length: %08X\n", runAddress, jaguarRomSize - 0x2E);
2189 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, jaguarRomSize - 0x2E);
2190 // SET32(jaguar_mainRam, 4, runAddress);
2191 jaguarRunAddress = runAddress;
2196 // .J64 (Jaguar cartridge ROM image) is implied by the FileList object...
2202 // Get the length of a (possibly) gzipped file
2204 int gzfilelength(gzFile gd)
2206 int size = 0, length = 0;
2207 unsigned char buffer[0x10000];
2213 // Read in chunks until EOF
2214 size = gzread(gd, buffer, 0x10000);