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 DrawBitmap(uint32 * screen, uint32 x, uint32 y, const void * bitmap);
39 void ClearScreenRectangle(uint32 * screen, uint32 x, uint32 y, uint32 w, uint32 h);
40 void DrawStringTrans(uint32 * screen, uint32 x, uint32 y, uint32 color, uint8 opacity, const char * text, ...);
41 void DrawStringOpaque(uint32 * screen, uint32 x, uint32 y, uint32 color1, uint32 color2, const char * text, ...);
42 void DrawString(uint32 * screen, uint32 x, uint32 y, bool invert, const char * text, ...);
43 void DrawString2(uint32 * screen, uint32 x, uint32 y, uint32 color, uint8 transparency, const char * text, ...);
44 Window * LoadROM(void);
45 Window * ResetJaguar(void);
46 Window * ResetJaguarCD(void);
47 Window * RunEmu(void);
50 Window * MiscOptions(void);
52 int gzfilelength(gzFile gd);
56 extern uint8 * jaguar_mainRam;
57 extern uint8 * jaguar_mainRom;
58 extern uint8 * jaguar_bootRom;
59 extern uint8 * jaguar_CDBootROM;
60 extern bool BIOSLoaded;
61 extern bool CDBIOSLoaded;
63 // Local global variables
65 bool exitGUI = false; // GUI (emulator) done variable
66 int mouseX = 0, mouseY = 0;
67 uint32 background[1280 * 256]; // GUI background buffer
69 char separator[] = "--------------------------------------------------------";
72 // Case insensitive string compare function
73 // Taken straight out of Thinking In C++ by Bruce Eckel. Thanks Bruce!
76 int stringCmpi(const string &s1, const string &s2)
78 // Select the first element of each string:
79 string::const_iterator p1 = s1.begin(), p2 = s2.begin();
81 while (p1 != s1.end() && p2 != s2.end()) // Don
\92t run past the end
83 if (toupper(*p1) != toupper(*p2)) // Compare upper-cased chars
84 return (toupper(*p1) < toupper(*p2) ? -1 : 1);// Report which was lexically greater
90 // If they match up to the detected eos, say which was longer. Return 0 if the same.
91 return s2.size() - s1.size();
98 enum { WINDOW_CLOSE, MENU_ITEM_CHOSEN };
103 Element(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0)
104 { extents.x = x, extents.y = y, extents.w = w, extents.h = h; }
105 virtual void HandleKey(SDLKey key) = 0; // These are "pure" virtual functions...
106 virtual void HandleMouseMove(uint32 x, uint32 y) = 0;
107 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) = 0;
108 virtual void Draw(uint32, uint32) = 0;
109 virtual void Notify(Element *) = 0;
110 //Needed? virtual ~Element() = 0;
111 //We're not allocating anything in the base class, so the answer would be NO.
112 bool Inside(uint32 x, uint32 y);
114 // static void SetScreenAndPitch(int16 * s, uint32 p) { screenBuffer = s, pitch = p; }
115 static void SetScreenAndPitch(uint32 * s, uint32 p) { screenBuffer = s, pitch = p; }
120 // Class variables...
121 // static int16 * screenBuffer;
122 static uint32 * screenBuffer;
126 // Initialize class variables (Element)
127 //int16 * Element::screenBuffer = NULL;
128 uint32 * Element::screenBuffer = NULL;
129 uint32 Element::pitch = 0;
131 bool Element::Inside(uint32 x, uint32 y)
133 return (x >= (uint32)extents.x && x < (uint32)(extents.x + extents.w)
134 && y >= (uint32)extents.y && y < (uint32)(extents.y + extents.h) ? true : false);
142 class Button: public Element
145 Button(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
146 activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
147 bgColor(0xFF00FF00), pic(NULL), elementToTell(NULL) {}
148 Button(uint32 x, uint32 y, uint32 w, uint32 h, uint32 * p): Element(x, y, w, h),
149 activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
150 bgColor(0xFF00FF00), pic(p), elementToTell(NULL) {}
151 // Button(uint32 x, uint32 y, uint32 * p): Element(x, y, 0, 0),
152 Button(uint32 x, uint32 y, uint32 * p, uint32 * pH = NULL, uint32 * pD = NULL): Element(x, y, 0, 0),
153 activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
154 bgColor(0xFF00FF00), pic(p), picHover(pH), picDown(pD), elementToTell(NULL)
155 { if (pic) extents.w = pic[0], extents.h = pic[1]; }
156 Button(uint32 x, uint32 y, uint32 w, uint32 h, string s): Element(x, y, w, h),
157 activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
158 bgColor(0xFF00FF00), pic(NULL), text(s), elementToTell(NULL) {}
159 Button(uint32 x, uint32 y, string s): Element(x, y, 0, FONT_HEIGHT),
160 activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
161 bgColor(0xFF00FF00), pic(NULL), text(s), elementToTell(NULL)
162 { extents.w = s.length() * FONT_WIDTH; }
163 virtual void HandleKey(SDLKey key) {}
164 virtual void HandleMouseMove(uint32 x, uint32 y);
165 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
166 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
167 virtual void Notify(Element *) {}
168 bool ButtonClicked(void) { return activated; }
169 void SetNotificationElement(Element * e) { elementToTell = e; }
172 bool activated, clicked, inside;
173 uint32 fgColor, bgColor;
174 uint32 * pic, * picHover, * picDown;
176 Element * elementToTell;
179 void Button::HandleMouseMove(uint32 x, uint32 y)
181 inside = Inside(x, y);
184 void Button::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
191 if (clicked && !mouseDown)
193 clicked = false, activated = true;
195 // Send a message that we're activated (if there's someone to tell, that is)
197 elementToTell->Notify(this);
201 clicked = activated = false;
204 void Button::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
206 uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
208 if (text.length() > 0) // Simple text button
211 for(uint32 y=0; y<extents.h; y++)
213 for(uint32 x=0; x<extents.w; x++)
215 // Doesn't clip in y axis! !!! FIX !!!
216 if (extents.x + x < pitch)
217 screenBuffer[addr + x + (y * pitch)]
218 // = (clicked && inside ? fgColor : (inside ? 0x43F0 : bgColor));
219 //43F0 -> 010000 11111 10000 -> 0100 0001 1111 1111 1000 0100 -> 41 FF 84
220 = (clicked && inside ? fgColor : (inside ? 0xFF84FF41 : bgColor));
224 DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY, false, "%s", text.c_str());
226 else // Graphical button
228 uint32 * picToShow = pic;
230 if (picHover != NULL && inside && !clicked)
231 picToShow = picHover;
233 if (picDown != NULL && inside && clicked)
236 DrawTransparentBitmapDeprecated(screenBuffer, extents.x + offsetX, extents.y + offsetY, picToShow);
245 class PushButton: public Element
248 // Save state externally?
249 //We pass in a state variable if we want to track it externally, otherwise we use our own
250 //internal state var. Still need to do some kind of callback for pushbuttons that do things
251 //like change from fullscreen to windowed... !!! FIX !!!
254 // PushButton(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
255 // activated(false), clicked(false), inside(false), fgColor(0xFFFF),
256 // bgColor(0x03E0), pic(NULL), elementToTell(NULL) {}
257 // PushButton(uint32 x, uint32 y, bool * st, string s): Element(x, y, 8, 8), state(st),
258 // inside(false), text(s) { if (st == NULL) state = &internalState; }
259 PushButton(uint32 x, uint32 y, bool * st, string s): Element(x, y, 16, 16), state(st),
260 inside(false), text(s) { if (st == NULL) state = &internalState; }
261 /* Button(uint32 x, uint32 y, uint32 w, uint32 h, uint32 * p): Element(x, y, w, h),
262 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
263 bgColor(0x03E0), pic(p), elementToTell(NULL) {}
264 Button(uint32 x, uint32 y, uint32 * p): Element(x, y, 0, 0),
265 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
266 bgColor(0x03E0), pic(p), elementToTell(NULL)
267 { if (pic) extents.w = pic[0], extents.h = pic[1]; }
268 Button(uint32 x, uint32 y, uint32 w, uint32 h, string s): Element(x, y, w, h),
269 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
270 bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL) {}
271 PushButton(uint32 x, uint32 y, string s): Element(x, y, 0, 8),
272 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
273 bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL)
274 { extents.w = s.length() * 8; }*/
275 virtual void HandleKey(SDLKey key) {}
276 virtual void HandleMouseMove(uint32 x, uint32 y);
277 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
278 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
279 virtual void Notify(Element *) {}
280 // bool ButtonClicked(void) { return activated; }
281 // void SetNotificationElement(Element * e) { elementToTell = e; }
286 // bool activated, clicked, inside;
287 // uint16 fgColor, bgColor;
290 // Element * elementToTell;
294 void PushButton::HandleMouseMove(uint32 x, uint32 y)
296 inside = Inside(x, y);
299 void PushButton::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
301 if (inside && mouseDown)
306 if (clicked && !mouseDown)
308 clicked = false, activated = true;
310 // Send a message that we're activated (if there's someone to tell, that is)
312 elementToTell->Notify(this);
317 // clicked = activated = false;
320 void PushButton::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
322 /* uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
324 for(uint32 y=0; y<extents.h; y++)
326 for(uint32 x=0; x<extents.w; x++)
328 // Doesn't clip in y axis! !!! FIX !!!
329 if (extents.x + x < pitch)
330 screenBuffer[addr + x + (y * pitch)]
331 = (clicked && inside ? fgColor : (inside ? 0x43F0 : bgColor));
336 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, &pbDown);
338 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, &pbUp);
340 if (text.length() > 0)
341 DrawString(screenBuffer, extents.x + offsetX + 24, extents.y + offsetY, false, "%s", text.c_str());
349 class SlideSwitch: public Element
352 // Save state externally?
353 //Seems to be handled the same as PushButton, but without sanity checks. !!! FIX !!!
356 SlideSwitch(uint32 x, uint32 y, bool * st, string s1, string s2): Element(x, y, 16, 32), state(st),
357 inside(false), text1(s1), text2(s2) {}
358 virtual void HandleKey(SDLKey key) {}
359 virtual void HandleMouseMove(uint32 x, uint32 y);
360 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
361 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
362 virtual void Notify(Element *) {}
363 // bool ButtonClicked(void) { return activated; }
364 // void SetNotificationElement(Element * e) { elementToTell = e; }
369 // bool activated, clicked, inside;
370 // uint16 fgColor, bgColor;
373 // Element * elementToTell;
376 void SlideSwitch::HandleMouseMove(uint32 x, uint32 y)
378 inside = Inside(x, y);
381 void SlideSwitch::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
383 if (inside && mouseDown)
388 if (clicked && !mouseDown)
390 clicked = false, activated = true;
392 // Send a message that we're activated (if there's someone to tell, that is)
394 elementToTell->Notify(this);
399 // clicked = activated = false;
402 void SlideSwitch::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
404 DrawTransparentBitmapDeprecated(screenBuffer, extents.x + offsetX, extents.y + offsetY, (*state ? slideSwitchDown : slideSwitchUp));
406 if (text1.length() > 0)
407 DrawString(screenBuffer, extents.x + offsetX + 24, extents.y + offsetY, false, "%s", text1.c_str());
409 if (text2.length() > 0)
410 DrawString(screenBuffer, extents.x + offsetX + 24, extents.y + offsetY + 16, false, "%s", text2.c_str());
418 class Window: public Element
421 /* Window(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
422 fgColor(0x4FF0), bgColor(0xFE10)
423 { close = new Button(w - 8, 1, closeBox); list.push_back(close); }*/
424 Window(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0,
425 void (* f)(Element *) = NULL): Element(x, y, w, h),
426 // /*clicked(false), inside(false),*/ fgColor(0x4FF0), bgColor(0x1E10),
427 //4FF0 -> 010011 11111 10000 -> 0100 1101 1111 1111 1000 0100 -> 4D FF 84
428 //1E10 -> 000111 10000 10000 -> 0001 1111 1000 0100 1000 0100 -> 1F 84 84
429 /*clicked(false), inside(false),*/ fgColor(0xFF84FF4D), bgColor(0xFF84841F),
431 { close = new Button(w - (CLOSEBOX_WIDTH + 1), 1, closeBox, closeBoxHover, closeBoxDown);
432 list.push_back(close);
433 close->SetNotificationElement(this); }
435 virtual void HandleKey(SDLKey key);
436 virtual void HandleMouseMove(uint32 x, uint32 y);
437 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
438 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
439 virtual void Notify(Element * e);
440 void AddElement(Element * e);
441 // bool WindowActive(void) { return true; }//return !close->ButtonClicked(); }
444 // bool clicked, inside;
445 uint32 fgColor, bgColor;
446 void (* handler)(Element *);
448 //We have to use a list of Element *pointers* because we can't make a list that will hold
449 //all the different object types in the same list...
450 vector<Element *> list;
455 for(uint32 i=0; i<list.size(); i++)
460 void Window::HandleKey(SDLKey key)
462 if (key == SDLK_ESCAPE)
465 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
466 SDL_PushEvent(&event);
469 // Handle the items this window contains...
470 for(uint32 i=0; i<list.size(); i++)
471 // Make coords relative to upper right corner of this window...
472 list[i]->HandleKey(key);
475 void Window::HandleMouseMove(uint32 x, uint32 y)
477 // Handle the items this window contains...
478 for(uint32 i=0; i<list.size(); i++)
479 // Make coords relative to upper right corner of this window...
480 list[i]->HandleMouseMove(x - extents.x, y - extents.y);
483 void Window::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
485 // Handle the items this window contains...
486 for(uint32 i=0; i<list.size(); i++)
487 // Make coords relative to upper right corner of this window...
488 list[i]->HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
491 void Window::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
493 uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
495 for(uint32 y=0; y<extents.h; y++)
497 for(uint32 x=0; x<extents.w; x++)
499 // Doesn't clip in y axis! !!! FIX !!!
500 if (extents.x + x < pitch)
501 screenBuffer[addr + x + (y * pitch)] = bgColor;
505 // Handle the items this window contains...
506 for(uint32 i=0; i<list.size(); i++)
507 list[i]->Draw(extents.x, extents.y);
510 void Window::AddElement(Element * e)
515 void Window::Notify(Element * e)
520 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
521 SDL_PushEvent(&event);
530 class Text: public Element
533 // Text(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
534 // fgColor(0x4FF0), bgColor(0xFE10) {}
535 // Text(uint32 x, uint32 y, string s, uint16 fg = 0x4FF0, uint16 bg = 0xFE10): Element(x, y, 0, 0),
536 // fgColor(fg), bgColor(bg), text(s) {}
537 //4FF0 -> 010011 11111 10000 -> 0100 1101 1111 1111 1000 0100 -> 4D FF 84
538 //FE10 -> 111111 10000 10000 -> 1111 1111 1000 0100 1000 0100 -> FF 84 84
539 Text(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
540 fgColor(0xFF8484FF), bgColor(0xFF84FF4D) {}
541 Text(uint32 x, uint32 y, string s, uint32 fg = 0xFF8484FF, uint32 bg = 0xFF84FF4D):
542 Element(x, y, 0, 0), fgColor(fg), bgColor(bg), text(s) {}
543 virtual void HandleKey(SDLKey key) {}
544 virtual void HandleMouseMove(uint32 x, uint32 y) {}
545 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) {}
546 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
547 virtual void Notify(Element *) {}
550 uint32 fgColor, bgColor;
554 void Text::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
556 if (text.length() > 0)
557 // DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY, false, "%s", text.c_str());
558 DrawStringOpaque(screenBuffer, extents.x + offsetX, extents.y + offsetY, fgColor, bgColor, "%s", text.c_str());
563 // Static image class
566 class Image: public Element
569 Image(uint32 x, uint32 y, const void * img): Element(x, y, 0, 0), image(img) {}
570 virtual void HandleKey(SDLKey key) {}
571 virtual void HandleMouseMove(uint32 x, uint32 y) {}
572 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) {}
573 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
574 virtual void Notify(Element *) {}
577 uint32 fgColor, bgColor;
581 void Image::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
584 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, image);
592 class TextEdit: public Element
595 TextEdit(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
596 fgColor(0xFF8484FF), bgColor(0xFF84FF4D), text(""), caretPos(0) {}
597 TextEdit(uint32 x, uint32 y, string s, uint32 fg = 0xFF8484FF, uint32 bg = 0xFF84FF4D):
598 Element(x, y, 0, 0), fgColor(fg), bgColor(bg), text(s), caretPos(0) {}
599 virtual void HandleKey(SDLKey key);
600 virtual void HandleMouseMove(uint32 x, uint32 y) {}
601 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) {}
602 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
603 virtual void Notify(Element *) {}
606 uint32 fgColor, bgColor;
611 //Set different filters depending on type passed in on construction, e.g., filename, amount, etc...?
612 void TextEdit::HandleKey(SDLKey key)
614 if ((key >= SDLK_a && key <= SDLK_z) || (key >= SDLK_0 && key <= SDLK_9) || key == SDLK_PERIOD
615 || key == SDLK_SLASH)
617 //Need to handle shift key as well...
618 text[caretPos++] = key;
620 else if (key == SDLK_BACKSPACE)
623 else if (key == SDLK_DELETE)
629 void TextEdit::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
631 if (text.length() > 0)
632 // DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY, false, "%s", text.c_str());
633 DrawStringOpaque(screenBuffer, extents.x + offsetX, extents.y + offsetY, fgColor, bgColor, "%s", text.c_str());
641 class ListBox: public Element
642 //class ListBox: public Window
645 // ListBox(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
646 ListBox(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0);//: Window(x, y, w, h),
647 // windowPtr(0), cursor(0), limit(0), charWidth((w / 8) - 1), charHeight(h / 8),
648 // elementToTell(NULL), upArrow(w - 8, 0, upArrowBox),
649 // downArrow(w - 8, h - 8, downArrowBox), upArrow2(w - 8, h - 16, upArrowBox) {}
650 virtual void HandleKey(SDLKey key);
651 virtual void HandleMouseMove(uint32 x, uint32 y);
652 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
653 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
654 virtual void Notify(Element * e);
655 void SetNotificationElement(Element * e) { elementToTell = e; }
656 void AddItem(string s);
657 string GetSelectedItem(void);
661 uint32 windowPtr, cursor, limit;
662 uint32 charWidth, charHeight; // Box width/height in characters
663 Element * elementToTell;
664 Button upArrow, downArrow, upArrow2;
668 uint32 yRelativePoint;
671 ListBox::ListBox(uint32 x, uint32 y, uint32 w, uint32 h): Element(x, y, w, h),
672 thumbClicked(false), windowPtr(0), cursor(0), limit(0), charWidth((w / FONT_WIDTH) - 1),
673 charHeight(h / FONT_HEIGHT), elementToTell(NULL), upArrow(w - 8, 0, upArrowBox),
674 downArrow(w - 8, h - 8, downArrowBox), upArrow2(w - 8, h - 16, upArrowBox)
676 upArrow.SetNotificationElement(this);
677 downArrow.SetNotificationElement(this);
678 upArrow2.SetNotificationElement(this);
679 extents.w -= 8; // Make room for scrollbar...
682 void ListBox::HandleKey(SDLKey key)
684 if (key == SDLK_DOWN)
686 if (cursor != limit - 1) // Cursor is within its window
688 else // Otherwise, scroll the window...
690 if (cursor + windowPtr != item.size() - 1)
694 else if (key == SDLK_UP)
704 else if (key == SDLK_PAGEDOWN)
706 if (cursor != limit - 1)
711 if (windowPtr > item.size() - limit)
712 windowPtr = item.size() - limit;
715 else if (key == SDLK_PAGEUP)
721 if (windowPtr < limit)
727 else if (key >= SDLK_a && key <= SDLK_z)
729 // Advance cursor to filename with first letter pressed...
730 uint8 which = (key - SDLK_a) + 65; // Convert key to A-Z char
732 for(uint32 i=0; i<item.size(); i++)
734 if ((item[i][0] & 0xDF) == which)
736 cursor = i - windowPtr;
737 if (i > windowPtr + limit - 1)
738 windowPtr = i - limit + 1, cursor = limit - 1;
740 windowPtr = i, cursor = 0;
747 void ListBox::HandleMouseMove(uint32 x, uint32 y)
749 upArrow.HandleMouseMove(x - extents.x, y - extents.y);
750 downArrow.HandleMouseMove(x - extents.x, y - extents.y);
751 upArrow2.HandleMouseMove(x - extents.x, y - extents.y);
755 uint32 sbHeight = extents.h - 24,
756 thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight);
758 //yRelativePoint is the spot on the thumb where we clicked...
759 int32 newThumbStart = y - yRelativePoint;
761 if (newThumbStart < 0)
764 if ((uint32)newThumbStart > sbHeight - thumb)
765 newThumbStart = sbHeight - thumb;
767 windowPtr = (uint32)(((float)newThumbStart / (float)sbHeight) * (float)item.size());
768 //Check for cursor bounds as well... Or do we need to???
769 //Actually, we don't...!
773 void ListBox::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
775 if (Inside(x, y) && mouseDown)
777 // Why do we have to do this??? (- extents.y?)
778 // I guess it's because only the Window class has offsetting implemented... !!! FIX !!!
779 // cursor = (y - extents.y) / 8;
780 cursor = (y - extents.y) / FONT_HEIGHT;
783 // Check for a hit on the scrollbar...
784 if (x > (uint32)(extents.x + extents.w) && x <= (uint32)(extents.x + extents.w + 8)
785 && y > (uint32)(extents.y + 8) && y <= (uint32)(extents.y + extents.h - 16))
789 // This shiaut should be calculated in AddItem(), not here... (or in Draw() for that matter)
790 uint32 sbHeight = extents.h - 24,
791 thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight),
792 thumbStart = (uint32)(((float)windowPtr / (float)item.size()) * (float)sbHeight);
794 // Did we hit the thumb?
795 if (y >= (extents.y + 8 + thumbStart) && y < (extents.y + 8 + thumbStart + thumb))
796 thumbClicked = true, yRelativePoint = y - thumbStart;
798 //Seems that this is useless--never reached except in rare cases and that the code outside is
801 // thumbClicked = false;
805 thumbClicked = false;
807 upArrow.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
808 downArrow.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
809 upArrow2.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
812 void ListBox::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
814 for(uint32 i=0; i<limit; i++)
816 // Strip off the extension
817 // (extension stripping should be an option, not default!)
818 string s(item[windowPtr + i], 0, item[windowPtr + i].length() - 4);
819 // DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY + i*8,
820 DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY + i*FONT_HEIGHT,
821 (cursor == i ? true : false), "%-*.*s", charWidth, charWidth, s.c_str());
824 upArrow.Draw(extents.x + offsetX, extents.y + offsetY);
825 downArrow.Draw(extents.x + offsetX, extents.y + offsetY);
826 upArrow2.Draw(extents.x + offsetX, extents.y + offsetY);
828 uint32 sbHeight = extents.h - 24,
829 thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight),
830 thumbStart = (uint32)(((float)windowPtr / (float)item.size()) * (float)sbHeight);
832 for(uint32 y=extents.y+offsetY+8; y<extents.y+offsetY+extents.h-16; y++)
834 // for(uint32 x=extents.x+offsetX+extents.w-8; x<extents.x+offsetX+extents.w; x++)
835 for(uint32 x=extents.x+offsetX+extents.w; x<extents.x+offsetX+extents.w+8; x++)
837 if (y >= thumbStart + (extents.y+offsetY+8) && y < thumbStart + thumb + (extents.y+offsetY+8))
838 // screenBuffer[x + (y * pitch)] = (thumbClicked ? 0x458E : 0xFFFF);
839 //458E -> 01 0001 0 1100 0 1110 -> 0100 0101 0110 0011 0111 0011 -> 45 63 73
840 screenBuffer[x + (y * pitch)] = (thumbClicked ? 0xFF736345 : 0xFFFFFFFF);
842 // screenBuffer[x + (y * pitch)] = 0x0200;
843 //0200 -> 000000 10000 00000 -> 00 1000 0100 00
844 screenBuffer[x + (y * pitch)] = 0xFF008400;
849 void ListBox::Notify(Element * e)
851 if (e == &upArrow || e == &upArrow2)
857 if (cursor < limit - 1)
861 else if (e == &downArrow)
863 if (windowPtr < item.size() - limit)
873 void ListBox::AddItem(string s)
875 // Do a simple insertion sort
876 bool inserted = false;
878 for(vector<string>::iterator i=item.begin(); i<item.end(); i++)
880 if (stringCmpi(s, *i) == -1)
891 limit = (item.size() > charHeight ? charHeight : item.size());
894 string ListBox::GetSelectedItem(void)
896 return item[windowPtr + cursor];
904 class FileList: public Window
907 FileList(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0);
908 virtual ~FileList() {}
909 virtual void HandleKey(SDLKey key);
910 virtual void HandleMouseMove(uint32 x, uint32 y) { Window::HandleMouseMove(x, y); }
911 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) { Window::HandleMouseButton(x, y, mouseDown); }
912 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0) { Window::Draw(offsetX, offsetY); }
913 virtual void Notify(Element * e);
920 //Need 4 buttons, one scrollbar...
921 FileList::FileList(uint32 x, uint32 y, uint32 w, uint32 h): Window(x, y, w, h)
923 files = new ListBox(8, 8, w - 16, h - 32);
925 load = new Button(8, h - 16, " Load ");
927 load->SetNotificationElement(this);
929 //!!! FIX !!! Directory might not exist--this shouldn't cause VJ to crash!
930 DIR * dp = opendir(vjs.ROMPath);
935 while ((de = readdir(dp)) != NULL)
937 char * ext = strrchr(de->d_name, '.');
940 if (strcasecmp(ext, ".zip") == 0 || strcasecmp(ext, ".j64") == 0
941 || strcasecmp(ext, ".abs") == 0 || strcasecmp(ext, ".jag") == 0
942 || strcasecmp(ext, ".rom") == 0)
943 files->AddItem(string(de->d_name));
950 //Give a diagnostic message here so that the (l)user can figure out what went wrong. !!! FIX !!!
954 void FileList::HandleKey(SDLKey key)
956 if (key == SDLK_RETURN)
959 Window::HandleKey(key);
962 void FileList::Notify(Element * e)
966 char filename[MAX_PATH];
967 strcpy(filename, vjs.ROMPath);
969 if (strlen(filename) > 0)
970 if (filename[strlen(filename) - 1] != '/')
971 strcat(filename, "/");
973 strcat(filename, files->GetSelectedItem().c_str());
975 // uint32 romSize = JaguarLoadROM(jaguar_mainRom, filename);
976 // JaguarLoadCart(jaguar_mainRom, filename);
977 if (JaguarLoadFile(filename))
980 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
981 SDL_PushEvent(&event);
983 event.type = SDL_USEREVENT, event.user.code = MENU_ITEM_CHOSEN;
984 event.user.data1 = (void *)ResetJaguar;
985 SDL_PushEvent(&event);
990 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
991 SDL_PushEvent(&event);
993 // Handle the error, but don't run...
994 // Tell the user that we couldn't run their file for some reason... !!! FIX !!!
995 //how to kludge: Make a function like ResetJaguar which creates the dialog window
1004 // Menu class & supporting structs/classes
1010 Window * (* action)(void);
1013 NameAction(string n, Window * (* a)(void) = NULL, SDLKey k = SDLK_UNKNOWN): name(n),
1014 action(a), hotKey(k) {}
1020 MenuItems(): charLength(0) {}
1021 bool Inside(uint32 x, uint32 y)
1022 { return (x >= (uint32)extents.x && x < (uint32)(extents.x + extents.w)
1023 && y >= (uint32)extents.y && y < (uint32)(extents.y + extents.h) ? true : false); }
1026 vector<NameAction> item;
1031 class Menu: public Element
1034 // 1CFF -> 0 001 11 00 111 1 1111
1035 // 421F -> 0 100 00 10 000 1 1111
1036 Menu(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = FONT_HEIGHT,
1037 /* uint16 fgc = 0x1CFF, uint16 bgc = 0x000F, uint16 fgch = 0x421F,
1038 uint16 bgch = 0x1CFF): Element(x, y, w, h), activated(false), clicked(false),*/
1039 /* uint32 fgc = 0xFF3F3F00, uint32 bgc = 0x7F000000, uint32 fgch = 0xFF878700,
1040 uint32 bgch = 0xFF3F3F00): Element(x, y, w, h), activated(false), clicked(false),*/
1041 /* uint32 fgc = 0xFFFF3F3F, uint32 bgc = 0xFF7F0000, uint32 fgch = 0xFFFF8787,
1042 uint32 bgch = 0xFFFF3F3F): Element(x, y, w, h), activated(false), clicked(false),*/
1043 uint32 fgc = 0xFF7F0000, uint32 bgc = 0xFFFF3F3F, uint32 fgch = 0xFFFF3F3F,
1044 uint32 bgch = 0xFFFF8787): Element(x, y, w, h), activated(false), clicked(false),
1045 inside(0), insidePopup(0), fgColor(fgc), bgColor(bgc), fgColorHL(fgch),
1046 bgColorHL(bgch), menuChosen(-1), menuItemChosen(-1) {}
1047 virtual void HandleKey(SDLKey key);
1048 virtual void HandleMouseMove(uint32 x, uint32 y);
1049 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
1050 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
1051 virtual void Notify(Element *) {}
1052 void Add(MenuItems mi);
1055 bool activated, clicked;
1056 uint32 inside, insidePopup;
1057 // uint16 fgColor, bgColor, fgColorHL, bgColorHL;
1058 uint32 fgColor, bgColor, fgColorHL, bgColorHL;
1059 int menuChosen, menuItemChosen;
1062 vector<MenuItems> itemList;
1065 void Menu::HandleKey(SDLKey key)
1067 for(uint32 i=0; i<itemList.size(); i++)
1069 for(uint32 j=0; j<itemList[i].item.size(); j++)
1071 if (itemList[i].item[j].hotKey == key)
1074 event.type = SDL_USEREVENT;
1075 event.user.code = MENU_ITEM_CHOSEN;
1076 event.user.data1 = (void *)itemList[i].item[j].action;
1077 SDL_PushEvent(&event);
1079 clicked = false, menuChosen = menuItemChosen = -1;
1086 void Menu::HandleMouseMove(uint32 x, uint32 y)
1088 inside = insidePopup = 0;
1092 // Find out *where* we are inside the menu bar
1093 uint32 xpos = extents.x;
1095 for(uint32 i=0; i<itemList.size(); i++)
1097 uint32 width = (itemList[i].title.length() + 2) * FONT_WIDTH;
1099 if (x >= xpos && x < xpos + width)
1110 if (!Inside(x, y) && !clicked)
1115 if (itemList[menuChosen].Inside(x, y) && clicked)
1117 insidePopup = ((y - itemList[menuChosen].extents.y) / FONT_HEIGHT) + 1;
1118 menuItemChosen = insidePopup - 1;
1122 void Menu::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
1131 menuChosen = -1; // clicked is already false...!
1134 else // clicked == true
1136 if (insidePopup && !mouseDown) // I.e., mouse-button-up
1139 if (itemList[menuChosen].item[menuItemChosen].action != NULL)
1141 // itemList[menuChosen].item[menuItemChosen].action();
1143 event.type = SDL_USEREVENT;
1144 event.user.code = MENU_ITEM_CHOSEN;
1145 event.user.data1 = (void *)itemList[menuChosen].item[menuItemChosen].action;
1146 SDL_PushEvent(&event);
1148 clicked = false, menuChosen = menuItemChosen = -1;
1151 while (SDL_PollEvent(&event)); // Flush the event queue...
1152 event.type = SDL_MOUSEMOTION;
1154 SDL_GetMouseState(&mx, &my);
1155 event.motion.x = mx, event.motion.y = my;
1156 SDL_PushEvent(&event); // & update mouse position...!
1160 if (!inside && !insidePopup && mouseDown)
1161 clicked = false, menuChosen = menuItemChosen = -1;
1165 void Menu::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
1167 uint32 xpos = extents.x + offsetX;
1169 for(uint32 i=0; i<itemList.size(); i++)
1171 // uint16 color1 = fgColor, color2 = bgColor;
1172 uint32 color1 = fgColor, color2 = bgColor;
1173 if (inside == (i + 1) || (menuChosen != -1 && (uint32)menuChosen == i))
1174 color1 = fgColorHL, color2 = bgColorHL;
1176 DrawStringOpaque(screenBuffer, xpos, extents.y + offsetY, color1, color2,
1177 " %s ", itemList[i].title.c_str());
1178 xpos += (itemList[i].title.length() + 2) * FONT_WIDTH;
1181 // Draw sub menu (but only if active)
1184 uint32 ypos = extents.y + FONT_HEIGHT + 1;
1186 for(uint32 i=0; i<itemList[menuChosen].item.size(); i++)
1188 // uint16 color1 = fgColor, color2 = bgColor;
1189 uint32 color1 = fgColor, color2 = bgColor;
1191 if (insidePopup == i + 1)
1192 color1 = fgColorHL, color2 = bgColorHL, menuItemChosen = i;
1194 if (itemList[menuChosen].item[i].name.length() > 0)
1195 DrawStringOpaque(screenBuffer, itemList[menuChosen].extents.x, ypos,
1196 color1, color2, " %-*.*s ", itemList[menuChosen].charLength,
1197 itemList[menuChosen].charLength, itemList[menuChosen].item[i].name.c_str());
1199 DrawStringOpaque(screenBuffer, itemList[menuChosen].extents.x, ypos,
1200 fgColor, bgColor, "%.*s", itemList[menuChosen].charLength + 2, separator);
1202 ypos += FONT_HEIGHT;
1207 void Menu::Add(MenuItems mi)
1209 for(uint32 i=0; i<mi.item.size(); i++)
1210 if (mi.item[i].name.length() > mi.charLength)
1211 mi.charLength = mi.item[i].name.length();
1213 // Set extents here as well...
1214 mi.extents.x = extents.x + extents.w, mi.extents.y = extents.y + FONT_HEIGHT + 1;
1215 mi.extents.w = (mi.charLength + 2) * FONT_WIDTH, mi.extents.h = mi.item.size() * FONT_HEIGHT;
1217 itemList.push_back(mi);
1218 extents.w += (mi.title.length() + 2) * FONT_WIDTH;
1222 //Do we even *need* this?
1223 //Doesn't seem like it...
1224 /*class RootWindow: public Window
1227 RootWindow(Menu * m, Window * w = NULL): menu(m), window(w) {}
1228 //Do we even need to care about this crap?
1229 // { extents.x = extents.y = 0, extents.w = 320, extents.h = 240; }
1230 virtual void HandleKey(SDLKey key) {}
1231 virtual void HandleMouseMove(uint32 x, uint32 y) {}
1232 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) {}
1233 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0) {}
1234 virtual void Notify(Element *) {}
1239 int16 * rootImage[1280 * 240 * 2];
1244 // Draw text at the given x/y coordinates. Can invert text as well.
1246 void DrawString(uint32 * screen, uint32 x, uint32 y, bool invert, const char * text, ...)
1251 va_start(arg, text);
1252 vsprintf(string, text, arg);
1255 uint32 pitch = sdlemuGetOverlayWidthInPixels();//GetSDLScreenWidthInPixels();
1256 uint32 length = strlen(string), address = x + (y * pitch);
1258 uint32 color1 = 0x0080FF;
1259 uint8 nBlue = (color1 >> 16) & 0xFF, nGreen = (color1 >> 8) & 0xFF, nRed = color1 & 0xFF;
1260 uint8 xorMask = (invert ? 0xFF : 0x00);
1262 for(uint32 i=0; i<length; i++)
1264 uint8 c = string[i];
1265 uint32 fontAddr = (uint32)(c < 32 ? 0 : c - 32) * FONT_WIDTH * FONT_HEIGHT;
1267 for(uint32 yy=0; yy<FONT_HEIGHT; yy++)
1269 for(uint32 xx=0; xx<FONT_WIDTH; xx++)
1271 uint32 existingColor = *(screen + address + xx + (yy * pitch));
1273 uint8 eBlue = (existingColor >> 16) & 0xFF,
1274 eGreen = (existingColor >> 8) & 0xFF,
1275 eRed = existingColor & 0xFF;
1277 uint8 trans = font2[fontAddr] ^ xorMask;
1278 uint8 invTrans = trans ^ 0xFF;
1280 uint32 bRed = (eRed * invTrans + nRed * trans) / 255,
1281 bGreen = (eGreen * invTrans + nGreen * trans) / 255,
1282 bBlue = (eBlue * invTrans + nBlue * trans) / 255;
1284 *(screen + address + xx + (yy * pitch)) = 0xFF000000 | (bBlue << 16) | (bGreen << 8) | bRed;
1289 address += FONT_WIDTH;
1294 // Draw text at the given x/y coordinates, using FG/BG colors.
1296 void DrawStringOpaque(uint32 * screen, uint32 x, uint32 y, uint32 color1, uint32 color2, const char * text, ...)
1301 va_start(arg, text);
1302 vsprintf(string, text, arg);
1305 uint32 pitch = sdlemuGetOverlayWidthInPixels();
1306 uint32 length = strlen(string), address = x + (y * pitch);
1308 uint8 eBlue = (color2 >> 16) & 0xFF, eGreen = (color2 >> 8) & 0xFF, eRed = color2 & 0xFF,
1309 nBlue = (color1 >> 16) & 0xFF, nGreen = (color1 >> 8) & 0xFF, nRed = color1 & 0xFF;
1311 for(uint32 i=0; i<length; i++)
1313 uint8 c = string[i];
1314 c = (c < 32 ? 0 : c - 32);
1315 uint32 fontAddr = (uint32)c * FONT_WIDTH * FONT_HEIGHT;
1317 for(uint32 yy=0; yy<FONT_HEIGHT; yy++)
1319 for(uint32 xx=0; xx<FONT_WIDTH; xx++)
1321 uint8 trans = font2[fontAddr++];
1322 uint8 invTrans = trans ^ 0xFF;
1324 uint32 bRed = (eRed * invTrans + nRed * trans) / 255;
1325 uint32 bGreen = (eGreen * invTrans + nGreen * trans) / 255;
1326 uint32 bBlue = (eBlue * invTrans + nBlue * trans) / 255;
1328 *(screen + address + xx + (yy * pitch)) = 0xFF000000 | (bBlue << 16) | (bGreen << 8) | bRed;
1332 address += FONT_WIDTH;
1337 // Draw text at the given x/y coordinates with transparency (0 is fully opaque, 32 is fully transparent).
1339 void DrawStringTrans(uint32 * screen, uint32 x, uint32 y, uint32 color, uint8 trans, const char * text, ...)
1344 va_start(arg, text);
1345 vsprintf(string, text, arg);
1348 uint32 pitch = sdlemuGetOverlayWidthInPixels();//GetSDLScreenWidthInPixels();
1349 uint32 length = strlen(string), address = x + (y * pitch);
1351 for(uint32 i=0; i<length; i++)
1353 uint32 fontAddr = (uint32)string[i] * 64;
1355 for(uint32 yy=0; yy<8; yy++)
1357 for(uint32 xx=0; xx<8; xx++)
1359 if (font1[fontAddr])
1361 uint32 existingColor = *(screen + address + xx + (yy * pitch));
1363 uint8 eBlue = (existingColor >> 16) & 0xFF,
1364 eGreen = (existingColor >> 8) & 0xFF,
1365 eRed = existingColor & 0xFF,
1366 //This could be done ahead of time, instead of on each pixel...
1367 nBlue = (color >> 16) & 0xFF,
1368 nGreen = (color >> 8) & 0xFF,
1369 nRed = color & 0xFF;
1371 //This could be sped up by using a table of 5 + 5 + 5 bits (32 levels transparency -> 32768 entries)
1372 //Here we've modified it to have 33 levels of transparency (could have any # we want!)
1373 //because dividing by 32 is faster than dividing by 31...!
1374 uint8 invTrans = 32 - trans;
1376 uint32 bRed = (eRed * trans + nRed * invTrans) / 32;
1377 uint32 bGreen = (eGreen * trans + nGreen * invTrans) / 32;
1378 uint32 bBlue = (eBlue * trans + nBlue * invTrans) / 32;
1380 *(screen + address + xx + (yy * pitch)) = 0xFF000000 | (bBlue << 16) | (bGreen << 8) | bRed;
1392 // Draw text at the given x/y coordinates, using FG color and overlay alpha blending.
1394 void DrawString2(uint32 * screen, uint32 x, uint32 y, uint32 color, uint8 transparency, const char * text, ...)
1399 va_start(arg, text);
1400 vsprintf(string, text, arg);
1403 uint32 pitch = sdlemuGetOverlayWidthInPixels();
1404 uint32 length = strlen(string), address = x + (y * pitch);
1406 color &= 0x00FFFFFF; // Just in case alpha was passed in...
1408 for(uint32 i=0; i<length; i++)
1410 uint8 c = string[i];
1411 c = (c < 32 ? 0 : c - 32);
1412 uint32 fontAddr = (uint32)c * FONT_WIDTH * FONT_HEIGHT;
1414 for(uint32 yy=0; yy<FONT_HEIGHT; yy++)
1416 for(uint32 xx=0; xx<FONT_WIDTH; xx++)
1418 uint8 fontTrans = font2[fontAddr++];
1419 uint32 newTrans = (fontTrans * transparency / 255) << 24;
1420 uint32 pixel = newTrans | color;
1422 *(screen + address + xx + (yy * pitch)) = pixel;
1426 address += FONT_WIDTH;
1432 // Uses zero as transparent color
1433 // Can also use an optional alpha channel
1434 // Alpha channel is now mandatory! ;-)
1436 //void DrawTransparentBitmap(int16 * screen, uint32 x, uint32 y, uint16 * bitmap, uint8 * alpha/*=NULL*/)
1437 /*void DrawTransparentBitmap(uint32 * screen, uint32 x, uint32 y, uint32 * bitmap, uint8 * alpha)
1439 uint32 width = bitmap[0], height = bitmap[1];
1442 // uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1443 uint32 pitch = sdlemuGetOverlayWidthInPixels();//GetSDLScreenWidthInPixels();
1444 uint32 address = x + (y * pitch);
1446 for(uint32 yy=0; yy<height; yy++)
1448 for(uint32 xx=0; xx<width; xx++)
1452 if (*bitmap && x + xx < pitch) // NOTE: Still doesn't clip the Y val...
1453 *(screen + address + xx + (yy * pitch)) = *bitmap;
1457 uint8 trans = *alpha;
1458 uint32 color = *bitmap;
1459 uint32 existingColor = *(screen + address + xx + (yy * pitch));
1461 uint8 eRed = existingColor & 0xFF,
1462 eGreen = (existingColor >> 8) & 0xFF,
1463 eBlue = (existingColor >> 16) & 0xFF,
1465 nRed = color & 0xFF,
1466 nGreen = (color >> 8) & 0xFF,
1467 nBlue = (color >> 16) & 0xFF;
1469 uint8 invTrans = 255 - trans;
1470 uint32 bRed = (eRed * trans + nRed * invTrans) / 255;
1471 uint32 bGreen = (eGreen * trans + nGreen * invTrans) / 255;
1472 uint32 bBlue = (eBlue * trans + nBlue * invTrans) / 255;
1474 uint32 blendedColor = 0xFF000000 | bRed | (bGreen << 8) | (bBlue << 16);
1476 *(screen + address + xx + (yy * pitch)) = blendedColor;
1485 void DrawTransparentBitmapDeprecated(uint32 * screen, uint32 x, uint32 y, uint32 * bitmap)
1487 uint32 width = bitmap[0], height = bitmap[1];
1490 uint32 pitch = sdlemuGetOverlayWidthInPixels();//GetSDLScreenWidthInPixels();
1491 uint32 address = x + (y * pitch);
1493 for(uint32 yy=0; yy<height; yy++)
1495 for(uint32 xx=0; xx<width; xx++)
1497 uint32 color = *bitmap;
1498 uint32 blendedColor = color;
1499 uint32 existingColor = *(screen + address + xx + (yy * pitch));
1501 if (existingColor >> 24 != 0x00) // Pixel needs blending
1503 uint8 trans = color >> 24;
1504 uint8 invTrans = trans ^ 0xFF;//255 - trans;
1506 uint8 eRed = existingColor & 0xFF,
1507 eGreen = (existingColor >> 8) & 0xFF,
1508 eBlue = (existingColor >> 16) & 0xFF,
1510 nRed = color & 0xFF,
1511 nGreen = (color >> 8) & 0xFF,
1512 nBlue = (color >> 16) & 0xFF;
1514 uint32 bRed = (eRed * invTrans + nRed * trans) / 255;
1515 uint32 bGreen = (eGreen * invTrans + nGreen * trans) / 255;
1516 uint32 bBlue = (eBlue * invTrans + nBlue * trans) / 255;
1518 blendedColor = 0xFF000000 | bRed | (bGreen << 8) | (bBlue << 16);
1521 *(screen + address + xx + (yy * pitch)) = blendedColor;
1527 void DrawTransparentBitmap(uint32 * screen, uint32 x, uint32 y, const void * bitmap)
1529 uint32 pitch = sdlemuGetOverlayWidthInPixels();
1530 uint32 address = x + (y * pitch);
1533 for(uint32 yy=0; yy<((Bitmap *)bitmap)->height; yy++)
1535 for(uint32 xx=0; xx<((Bitmap *)bitmap)->width; xx++)
1537 uint32 color = ((uint32 *)((Bitmap *)bitmap)->pixelData)[count];
1538 uint32 blendedColor = color;
1539 uint32 existingColor = *(screen + address + xx + (yy * pitch));
1541 if (existingColor >> 24 != 0x00) // Pixel needs blending
1543 uint8 trans = color >> 24;
1544 uint8 invTrans = trans ^ 0xFF;
1546 uint8 eRed = existingColor & 0xFF,
1547 eGreen = (existingColor >> 8) & 0xFF,
1548 eBlue = (existingColor >> 16) & 0xFF,
1550 nRed = color & 0xFF,
1551 nGreen = (color >> 8) & 0xFF,
1552 nBlue = (color >> 16) & 0xFF;
1554 uint32 bRed = (eRed * invTrans + nRed * trans) / 255;
1555 uint32 bGreen = (eGreen * invTrans + nGreen * trans) / 255;
1556 uint32 bBlue = (eBlue * invTrans + nBlue * trans) / 255;
1558 // Instead of $FF, should use the alpha from the destination pixel as the final alpha value...
1559 blendedColor = 0xFF000000 | bRed | (bGreen << 8) | (bBlue << 16);
1562 *(screen + address + xx + (yy * pitch)) = blendedColor;
1569 // Draw a bitmap without using blending
1571 void DrawBitmap(uint32 * screen, uint32 x, uint32 y, const void * bitmap)
1573 uint32 pitch = sdlemuGetOverlayWidthInPixels();
1574 uint32 address = x + (y * pitch);
1577 for(uint32 yy=0; yy<((Bitmap *)bitmap)->height; yy++)
1579 for(uint32 xx=0; xx<((Bitmap *)bitmap)->width; xx++)
1581 *(screen + address + xx + (yy * pitch)) = ((uint32 *)((Bitmap *)bitmap)->pixelData)[count];
1588 // Clear a portion of the screen
1590 void ClearScreenRectangle(uint32 * screen, uint32 x, uint32 y, uint32 w, uint32 h)
1592 uint32 pitch = sdlemuGetOverlayWidthInPixels();
1593 uint32 address = x + (y * pitch);
1595 for(uint32 yy=0; yy<h; yy++)
1596 for(uint32 xx=0; xx<w; xx++)
1597 *(screen + address + xx + (yy * pitch)) = 0;
1602 // GUI stuff--it's not crunchy, it's GUI! ;-)
1607 SDL_ShowCursor(SDL_DISABLE);
1608 SDL_GetMouseState(&mouseX, &mouseY);
1618 //bool GUIMain(void)
1619 bool GUIMain(char * filename)
1621 WriteLog("GUI: Inside GUIMain...\n");
1623 uint32 pointerBGSave[6 * 8 + 2];
1624 pointerBGSave[0] = 6;
1625 pointerBGSave[1] = 8;
1627 // Need to set things up so that it loads and runs a file if given on the command line. !!! FIX !!! [DONE]
1628 extern uint32 * backbuffer;
1629 // bool done = false;
1631 Window * mainWindow = NULL;
1633 // Set up the GUI classes...
1634 // Element::SetScreenAndPitch(backbuffer, GetSDLScreenWidthInPixels());
1635 Element::SetScreenAndPitch((uint32 *)sdlemuGetOverlayPixels(), sdlemuGetOverlayWidthInPixels());
1636 sdlemuEnableOverlay();
1640 mi.title = "Jaguar";
1641 mi.item.push_back(NameAction("Load...", LoadROM, SDLK_l));
1642 mi.item.push_back(NameAction("Reset", ResetJaguar, SDLK_r));
1644 mi.item.push_back(NameAction("Reset CD", ResetJaguarCD, SDLK_c));
1645 mi.item.push_back(NameAction("Run", RunEmu, SDLK_ESCAPE));
1646 mi.item.push_back(NameAction(""));
1647 mi.item.push_back(NameAction("Quit", Quit, SDLK_q));
1649 mi.title = "Settings";
1651 mi.item.push_back(NameAction("Video..."));
1652 mi.item.push_back(NameAction("Audio..."));
1653 mi.item.push_back(NameAction("Misc...", MiscOptions, SDLK_m));
1657 mi.item.push_back(NameAction("About...", About));
1660 bool showMouse = true;
1662 // Grab the BG where the mouse will be painted (prime the backstore)
1666 Bitmap ptr = { 6, 8, 4,
1667 ""//"000011112222333344445555"
1668 //"000011112222333344445555"
1669 //"000011112222333344445555"
1670 //"000011112222333344445555"
1671 //"000011112222333344445555"
1672 //"000011112222333344445555"
1673 //"000011112222333344445555"
1674 //"000011112222333344445555"
1676 uint32 * overlayPixels = (uint32 *)sdlemuGetOverlayPixels();
1679 for(uint32 y=0; y<pointerBGSave[1]; y++)
1680 for(uint32 x=0; x<pointerBGSave[0]; x++)
1681 pointerBGSave[count++] = overlayPixels[((mouseY + y) * sdlemuGetOverlayWidthInPixels()) + (mouseX + x)];
1683 uint32 oldMouseX = mouseX, oldMouseY = mouseY;
1685 //This is crappy!!! !!! FIX !!!
1686 //Is this even needed any more? Hmm. Maybe. Dunno.
1687 WriteLog("GUI: Resetting Jaguar...\n");
1690 WriteLog("GUI: Clearing BG save...\n");
1691 // Set up our background save...
1692 // memset(background, 0x11, tom_getVideoModeWidth() * 240 * 2);
1693 //1111 -> 000100 01000 10001 -> 0001 0000 0100 0010 1000 1100 -> 10 42 8C
1694 for(uint32 i=0; i<tom_getVideoModeWidth()*240; i++)
1695 // background[i] = 0xFF8C4210;
1696 backbuffer[i] = 0xFF8C4210;
1698 /* uint32 * overlayPix = (uint32 *)sdlemuGetOverlayPixels();
1699 for(uint32 i=0; i<sdlemuGetOverlayWidthInPixels()*480; i++)
1700 overlayPix[i] = 0x00000000;*/
1702 // Handle loading file passed in on the command line...! [DONE]
1706 if (JaguarLoadFile(filename))
1708 // event.type = SDL_USEREVENT, event.user.code = MENU_ITEM_CHOSEN;
1709 // event.user.data1 = (void *)ResetJaguar;
1710 // SDL_PushEvent(&event);
1711 // Make it so that if passed in on the command line, we quit right
1712 // away when pressing ESC
1713 WriteLog("GUI: Bypassing GUI since ROM passed in on command line...\n");
1719 // Create error dialog...
1721 sprintf(errText, "The file %40s could not be loaded.", filename);
1723 mainWindow = new Window(8, 16, 304, 160);
1724 mainWindow->AddElement(new Text(8, 8, "Error!"));
1725 mainWindow->AddElement(new Text(8, 24, errText));
1729 WriteLog("GUI: Entering main loop...\n");
1732 if (SDL_PollEvent(&event))
1734 if (event.type == SDL_USEREVENT)
1736 if (event.user.code == WINDOW_CLOSE)
1741 else if (event.user.code == MENU_ITEM_CHOSEN)
1743 // Confused? Let me enlighten... What we're doing here is casting
1744 // data1 as a pointer to a function which returns a Window pointer and
1745 // which takes no parameters (the "(Window *(*)(void))" part), then
1746 // derefencing it (the "*" in front of that) in order to call the
1747 // function that it points to. Clear as mud? Yeah, I hate function
1748 // pointers too, but what else are you gonna do?
1749 mainWindow = (*(Window *(*)(void))event.user.data1)();
1751 while (SDL_PollEvent(&event)); // Flush the event queue...
1752 event.type = SDL_MOUSEMOTION;
1754 SDL_GetMouseState(&mx, &my);
1755 event.motion.x = mx, event.motion.y = my;
1756 SDL_PushEvent(&event); // & update mouse position...!
1758 oldMouseX = mouseX, oldMouseY = mouseY;
1759 mouseX = mx, mouseY = my; // This prevents "mouse flash"...
1762 else if (event.type == SDL_ACTIVEEVENT)
1764 if (event.active.state == SDL_APPMOUSEFOCUS)
1765 showMouse = (event.active.gain ? true : false);
1767 else if (event.type == SDL_KEYDOWN)
1770 mainWindow->HandleKey(event.key.keysym.sym);
1772 mainMenu.HandleKey(event.key.keysym.sym);
1774 else if (event.type == SDL_MOUSEMOTION)
1776 oldMouseX = mouseX, oldMouseY = mouseY;
1777 mouseX = event.motion.x, mouseY = event.motion.y;
1780 mainWindow->HandleMouseMove(mouseX, mouseY);
1782 mainMenu.HandleMouseMove(mouseX, mouseY);
1784 else if (event.type == SDL_MOUSEBUTTONDOWN)
1786 uint32 mx = event.button.x, my = event.button.y;
1789 mainWindow->HandleMouseButton(mx, my, true);
1791 mainMenu.HandleMouseButton(mx, my, true);
1793 else if (event.type == SDL_MOUSEBUTTONUP)
1795 uint32 mx = event.button.x, my = event.button.y;
1798 mainWindow->HandleMouseButton(mx, my, false);
1800 mainMenu.HandleMouseButton(mx, my, false);
1803 //PROBLEM: In order to use the dirty rectangle approach here, we need some way of
1804 // handling it in mainMenu.Draw() and mainWindow->Draw(). !!! FIX !!!
1805 //POSSIBLE SOLUTION:
1806 // When mouse is moving and not on menu or window, can do straight dirty rect.
1807 // When mouse is on menu, need to update screen. Same for buttons on windows...
1808 // What the menu & windows should do is only redraw on a state change. IOW, they
1809 // should call their own/child window's Draw() function instead of doing it top
1811 //#define NEW_BACKSTORE_METHOD
1814 // The way we do things here is kinda stupid (redrawing the screen every frame), but
1815 // it's simple. Perhaps there may be a reason down the road to be more selective with
1816 // our clearing, but for now, this will suffice.
1817 // memset(backbuffer, 0x11, tom_getVideoModeWidth() * 240 * 2);
1818 // memcpy(backbuffer, background, tom_getVideoModeWidth() * 256 * 2);
1819 // memcpy(backbuffer, background, tom_getVideoModeWidth() * 256 * 4);
1820 #ifndef NEW_BACKSTORE_METHOD
1821 memset(sdlemuGetOverlayPixels(), 0, sdlemuGetOverlayWidthInPixels() * 480 * 4);
1824 //Could do multiple windows here by using a vector + priority info...
1825 //Though the way ZSNES does it seems to be by a bool (i.e., they're always active, just not shown)
1830 /*uint32 pBGS[6 * 8 + 3] = { 6, 8, 4,
1840 //This isn't working... Why????
1841 //It's because DrawTransparentBitmap does alpha blending if it detects zero in the alpha channel.
1842 //So why do it that way? Hm.
1843 overlayPixels = (uint32 *)sdlemuGetOverlayPixels();
1845 #ifdef NEW_BACKSTORE_METHOD
1846 // DrawTransparentBitmapDeprecated(overlayPixels, oldMouseX, oldMouseY, pointerBGSave);
1847 // DrawTransparentBitmap(overlayPixels, oldMouseX, oldMouseY, pBGS);
1848 for(uint32 y=0; y<pointerBGSave[1]; y++)
1849 for(uint32 x=0; x<pointerBGSave[0]; x++)
1850 overlayPixels[((oldMouseY + y) * sdlemuGetOverlayWidthInPixels()) + (oldMouseX + x)] = 0x00000000;
1854 for(uint32 y=0; y<pointerBGSave[1]; y++)
1855 for(uint32 x=0; x<pointerBGSave[0]; x++)
1856 pointerBGSave[count++] = overlayPixels[((mouseY + y) * sdlemuGetOverlayWidthInPixels()) + (mouseX + x)];
1860 // DrawTransparentBitmapDeprecated(backbuffer, mouseX, mouseY, mousePic);
1861 DrawTransparentBitmapDeprecated(overlayPixels, mouseX, mouseY, mousePic);
1871 // GUI "action" functions
1874 Window * LoadROM(void)
1876 FileList * fileList = new FileList(20, 20, 600, 440);
1878 return (Window *)fileList;
1881 Window * ResetJaguar(void)
1888 Window * ResetJaguarCD(void)
1890 memcpy(jaguar_mainRom, jaguar_CDBootROM, 0x40000);
1891 jaguarRunAddress = 0x802000;
1892 jaguar_mainRom_crc32 = crc32_calcCheckSum(jaguar_mainRom, 0x40000);
1894 //This is a quick kludge to get the CDBIOS to boot properly...
1895 //Wild speculation: It could be that this memory location is wired into the CD unit
1896 //somehow, which lets it know whether or not a cart is present in the unit...
1897 jaguar_mainRom[0x0040B] = 0x03;
1905 bool debounceRunKey = true;
1906 Window * RunEmu(void)
1908 extern uint32 * backbuffer;
1909 //Temporary, to test the new timer based code...
1910 sdlemuDisableOverlay();
1912 sdlemuEnableOverlay();
1913 // Save the background for the GUI...
1914 // In this case, we squash the color to monochrome, then force it to blue + green...
1915 for(uint32 i=0; i<tom_getVideoModeWidth() * 256; i++)
1917 uint32 pixel = backbuffer[i];
1918 uint8 b = (pixel >> 16) & 0xFF, g = (pixel >> 8) & 0xFF, r = pixel & 0xFF;
1919 pixel = ((r + g + b) / 3) & 0x00FF;
1920 backbuffer[i] = 0xFF000000 | (pixel << 16) | (pixel << 8);
1924 //This is crappy... !!! FIX !!!
1925 extern bool finished, showGUI;
1927 // uint32 nFrame = 0, nFrameskip = 0;
1928 uint32 totalFrames = 0;
1930 bool showMessage = true;
1931 uint32 showMsgFrames = 120;
1932 uint8 transparency = 0;
1933 // Pass a message to the "joystick" code to debounce the ESC key...
1934 debounceRunKey = true;
1936 uint32 cartType = 4;
1937 if (jaguarRomSize == 0x200000)
1939 else if (jaguarRomSize == 0x400000)
1941 else if (jaguar_mainRom_crc32 == 0x687068D5)
1943 else if (jaguar_mainRom_crc32 == 0x55A0669C)
1946 char * cartTypeName[5] = { "2M Cartridge", "4M Cartridge", "CD BIOS", "CD Dev BIOS", "Homebrew" };
1947 uint32 elapsedTicks = SDL_GetTicks(), frameCount = 0, framesPerSecond = 0;
1951 // Set up new backbuffer with new pixels and data
1952 JaguarExecute(backbuffer, true);
1953 // JaguarExecuteNew();
1955 //WriteLog("Frame #%u...\n", totalFrames);
1956 //extern bool doDSPDis;
1957 //if (totalFrames == 373)
1960 //This sucks... !!! FIX !!!
1962 //This is done here so that the crud below doesn't get on our GUI background...
1966 // Some QnD GUI stuff here...
1969 extern uint32 gpu_pc, dsp_pc;
1970 DrawString(backbuffer, 8, 8, false, "GPU PC: %08X", gpu_pc);
1971 DrawString(backbuffer, 8, 16, false, "DSP PC: %08X", dsp_pc);
1972 DrawString(backbuffer, 8, 32, false, "%u FPS", framesPerSecond);
1977 // FF0F -> 1111 11 11 000 0 1111 -> 3F 18 0F
1978 // 3FE3 -> 0011 11 11 111 0 0011 -> 0F 3F 03
1979 /* DrawStringTrans((uint32 *)backbuffer, 8, 24*8, 0xFF0F, transparency, "Running...");
1980 DrawStringTrans((uint32 *)backbuffer, 8, 26*8, 0x3FE3, transparency, "%s, run address: %06X", cartTypeName[cartType], jaguarRunAddress);
1981 DrawStringTrans((uint32 *)backbuffer, 8, 27*8, 0x3FE3, transparency, "CRC: %08X", jaguar_mainRom_crc32);//*/
1982 //first has wrong color. !!! FIX !!!
1983 DrawStringTrans(backbuffer, 8, 24*8, 0xFF7F63FF, transparency, "Running...");
1984 DrawStringTrans(backbuffer, 8, 26*8, 0xFF1FFF3F, transparency, "%s, run address: %06X", cartTypeName[cartType], jaguarRunAddress);
1985 DrawStringTrans(backbuffer, 8, 27*8, 0xFF1FFF3F, transparency, "CRC: %08X", jaguar_mainRom_crc32);
1987 if (showMsgFrames == 0)
1991 if (transparency == 33)
1993 showMessage = false;
1994 /*extern bool doGPUDis;
1995 doGPUDis = true;//*/
2006 if (SDL_GetTicks() - elapsedTicks > 250)
2007 elapsedTicks += 250, framesPerSecond = frameCount * 4, frameCount = 0;
2010 // Reset the pitch, since it may have been changed in-game...
2011 Element::SetScreenAndPitch((uint32 *)backbuffer, GetSDLScreenWidthInPixels());
2013 // Save the background for the GUI...
2014 // memcpy(background, backbuffer, tom_getVideoModeWidth() * 240 * 2);
2015 // In this case, we squash the color to monochrome, then force it to blue + green...
2016 for(uint32 i=0; i<tom_getVideoModeWidth() * 256; i++)
2018 uint32 pixel = backbuffer[i];
2019 uint8 b = (pixel >> 16) & 0xFF, g = (pixel >> 8) & 0xFF, r = pixel & 0xFF;
2020 pixel = ((r + g + b) / 3) & 0x00FF;
2021 background[i] = 0xFF000000 | (pixel << 16) | (pixel << 8);
2029 bool debounceRunKey = true;
2030 Window * RunEmu(void)
2032 extern uint32 * backbuffer;
2033 uint32 * overlayPixels = (uint32 *)sdlemuGetOverlayPixels();
2034 memset(overlayPixels, 0x00, 640 * 480 * 4); // Clear out overlay...
2036 //This is crappy... !!! FIX !!!
2037 extern bool finished, showGUI;
2039 sdlemuDisableOverlay();
2041 // uint32 nFrame = 0, nFrameskip = 0;
2042 uint32 totalFrames = 0;
2044 bool showMessage = true;
2045 uint32 showMsgFrames = 120;
2046 uint8 transparency = 0xFF;
2047 // Pass a message to the "joystick" code to debounce the ESC key...
2048 debounceRunKey = true;
2050 uint32 cartType = 4;
2051 if (jaguarRomSize == 0x200000)
2053 else if (jaguarRomSize == 0x400000)
2055 else if (jaguar_mainRom_crc32 == 0x687068D5)
2057 else if (jaguar_mainRom_crc32 == 0x55A0669C)
2060 char * cartTypeName[5] = { "2M Cartridge", "4M Cartridge", "CD BIOS", "CD Dev BIOS", "Homebrew" };
2061 uint32 elapsedTicks = SDL_GetTicks(), frameCount = 0, framesPerSecond = 0;
2065 // Set up new backbuffer with new pixels and data
2068 //WriteLog("Frame #%u...\n", totalFrames);
2069 //extern bool doDSPDis;
2070 //if (totalFrames == 373)
2073 //Problem: Need to do this *only* when the state changes from visible to not...
2074 if (showGUI || showMessage)
2075 sdlemuEnableOverlay();
2077 sdlemuDisableOverlay();
2079 //Add in a new function for clearing patches of screen (ClearOverlayRect)
2081 // Some QnD GUI stuff here...
2084 ClearScreenRectangle(overlayPixels, 8, 1*FONT_HEIGHT, 128, 4*FONT_HEIGHT);
2085 extern uint32 gpu_pc, dsp_pc;
2086 DrawString(overlayPixels, 8, 1*FONT_HEIGHT, false, "GPU PC: %08X", gpu_pc);
2087 DrawString(overlayPixels, 8, 2*FONT_HEIGHT, false, "DSP PC: %08X", dsp_pc);
2088 DrawString(overlayPixels, 8, 4*FONT_HEIGHT, false, "%u FPS", framesPerSecond);
2093 DrawString2(overlayPixels, 8, 24*FONT_HEIGHT, 0x007F63FF, transparency, "Running...");
2094 DrawString2(overlayPixels, 8, 26*FONT_HEIGHT, 0x001FFF3F, transparency, "%s, run address: %06X", cartTypeName[cartType], jaguarRunAddress);
2095 DrawString2(overlayPixels, 8, 27*FONT_HEIGHT, 0x001FFF3F, transparency, "CRC: %08X", jaguar_mainRom_crc32);
2097 if (showMsgFrames == 0)
2101 if (transparency == 0)
2103 showMessage = false;
2104 /*extern bool doGPUDis;
2105 doGPUDis = true;//*/
2115 if (SDL_GetTicks() - elapsedTicks > 250)
2116 elapsedTicks += 250, framesPerSecond = frameCount * 4, frameCount = 0;
2119 // Save the background for the GUI...
2120 // In this case, we squash the color to monochrome, then force it to blue + green...
2121 for(uint32 i=0; i<tom_getVideoModeWidth() * 256; i++)
2123 uint32 pixel = backbuffer[i];
2124 uint8 b = (pixel >> 16) & 0xFF, g = (pixel >> 8) & 0xFF, r = pixel & 0xFF;
2125 pixel = ((r + g + b) / 3) & 0x00FF;
2126 backbuffer[i] = 0xFF000000 | (pixel << 16) | (pixel << 8);
2129 sdlemuEnableOverlay();
2139 WriteLog("GUI: Quitting due to user request.\n");
2145 Window * About(void)
2148 // sprintf(buf, "Virtual Jaguar CVS %s", __DATE__);
2149 sprintf(buf, "CVS %s", __DATE__);
2150 //fprintf(fp, "VirtualJaguar v1.0.8 (Last full build was on %s %s)\n", __DATE__, __TIME__);
2151 //VirtualJaguar v1.0.8 (Last full build was on Dec 30 2004 20:01:31)
2152 //Hardwired, bleh... !!! FIX !!!
2153 uint32 width = 55 * FONT_WIDTH, height = 18 * FONT_HEIGHT;
2154 uint32 xpos = (640 - width) / 2, ypos = (480 - height) / 2;
2155 // Window * window = new Window(8, 16, 50 * FONT_WIDTH, 21 * FONT_HEIGHT);
2156 Window * window = new Window(xpos, ypos, width, height);
2157 // window->AddElement(new Text(8, 8, "Virtual Jaguar 1.0.8"));
2158 // window->AddElement(new Text(8, 8, "Virtual Jaguar CVS 20050110", 0xFF3030FF, 0xFF000000));
2159 // window->AddElement(new Text(208, 8+0*FONT_HEIGHT, buf, 0xFF3030FF, 0xFF000000));
2160 window->AddElement(new Text(248, 8+4*FONT_HEIGHT+5, buf, 0xFF3030FF, 0xFF000000));
2161 window->AddElement(new Text(8, 8+0*FONT_HEIGHT, "Coders:"));
2162 window->AddElement(new Text(16, 8+1*FONT_HEIGHT, "James L. Hammons (shamus)"));
2163 window->AddElement(new Text(16, 8+2*FONT_HEIGHT, "Niels Wagenaar (nwagenaar)"));
2164 window->AddElement(new Text(16, 8+3*FONT_HEIGHT, "Carwin Jones (Caz)"));
2165 window->AddElement(new Text(16, 8+4*FONT_HEIGHT, "Adam Green"));
2166 window->AddElement(new Text(8, 8+6*FONT_HEIGHT, "Testers:"));
2167 window->AddElement(new Text(16, 8+7*FONT_HEIGHT, "Guruma"));
2168 window->AddElement(new Text(8, 8+9*FONT_HEIGHT, "Thanks go out to:"));
2169 window->AddElement(new Text(16, 8+10*FONT_HEIGHT, "Aaron Giles for the original CoJag"));
2170 window->AddElement(new Text(16, 8+11*FONT_HEIGHT, "David Raingeard for the original VJ"));
2171 window->AddElement(new Text(16, 8+12*FONT_HEIGHT, "Karl Stenerud for his Musashi 68K emu"));
2172 window->AddElement(new Text(16, 8+13*FONT_HEIGHT, "Sam Lantinga for his amazing SDL libs"));
2173 window->AddElement(new Text(16, 8+14*FONT_HEIGHT, "Ryan C. Gordon for VJ's web presence"));
2174 window->AddElement(new Text(16, 8+15*FONT_HEIGHT, "Curt Vendel for various Jaguar goodies"));
2175 window->AddElement(new Text(16, 8+16*FONT_HEIGHT, "The guys over at Atari Age ;-)"));
2176 // window->AddElement(new Image(8, 8, &vj_title_small));
2177 window->AddElement(new Image(width - (vj_title_small.width + 8), 8, &vj_title_small));
2182 Window * MiscOptions(void)
2184 Window * window = new Window(8, 16, 304, 192);
2185 window->AddElement(new PushButton(8, 8, &vjs.useJaguarBIOS, "BIOS"));
2186 window->AddElement(new SlideSwitch(8, 32, &vjs.hardwareTypeNTSC, "PAL", "NTSC"));
2187 window->AddElement(new PushButton(8, 64, &vjs.DSPEnabled, "DSP"));
2188 window->AddElement(new SlideSwitch(24, 88, &vjs.usePipelinedDSP, "Original", "Pipelined"));
2189 window->AddElement(new SlideSwitch(8, 120, (bool *)&vjs.glFilter, "Sharp", "Blurry"));
2190 window->AddElement(new SlideSwitch(8, 152, (bool *)&vjs.renderType, "Normal render", "TV style"));
2200 // * Window/fullscreen
2201 // * Key definitions
2208 // Generic ROM loading
2210 uint32 JaguarLoadROM(uint8 * rom, char * path)
2212 // We really should have some kind of sanity checking for the ROM size here to prevent
2213 // a buffer overflow... !!! FIX !!!
2216 WriteLog("JaguarLoadROM: Attempting to load file '%s'...", path);
2217 char * ext = strrchr(path, '.');
2219 WriteLog("FAILED!\n");
2221 WriteLog("Succeeded in finding extension (%s)!\n", ext);
2225 WriteLog("VJ: Loading \"%s\"...", path);
2227 if (strcasecmp(ext, ".zip") == 0)
2229 // Handle ZIP file loading here...
2230 WriteLog("(ZIPped)...");
2232 if (load_zipped_file(0, 0, path, NULL, &rom, &romSize) == -1)
2234 WriteLog("Failed!\n");
2240 /* FILE * fp = fopen(path, "rb");
2244 WriteLog("Failed!\n");
2248 fseek(fp, 0, SEEK_END);
2249 romSize = ftell(fp);
2250 fseek(fp, 0, SEEK_SET);
2251 fread(rom, 1, romSize, fp);
2254 // Handle gzipped files transparently [Adam Green]...
2256 gzFile fp = gzopen(path, "rb");
2260 WriteLog("Failed!\n");
2264 romSize = gzfilelength(fp);
2265 gzseek(fp, 0, SEEK_SET);
2266 gzread(fp, rom, romSize);
2270 WriteLog("OK (%i bytes)\n", romSize);
2277 // Jaguar file loading
2279 bool JaguarLoadFile(char * path)
2281 // jaguarRomSize = JaguarLoadROM(mem, path);
2282 jaguarRomSize = JaguarLoadROM(jaguar_mainRom, path);
2284 /*//This is not *nix friendly for some reason...
2285 // if (!UserSelectFile(path, newPath))
2286 if (!UserSelectFile((strlen(path) == 0 ? (char *)"." : path), newPath))
2288 WriteLog("VJ: Could not find valid ROM in directory \"%s\"...\nAborting!\n", path);
2293 if (jaguarRomSize == 0)
2295 // WriteLog("VJ: Could not load ROM from file \"%s\"...\nAborting!\n", newPath);
2296 WriteLog("GUI: Could not load ROM from file \"%s\"...\nAborting load!\n", path);
2297 // Need to do something else here, like throw up an error dialog instead of aborting. !!! FIX !!!
2300 return false; // This is a start...
2303 jaguar_mainRom_crc32 = crc32_calcCheckSum(jaguar_mainRom, jaguarRomSize);
2304 WriteLog("CRC: %08X\n", (unsigned int)jaguar_mainRom_crc32);
2307 jaguarRunAddress = 0x802000;
2309 char * ext = strrchr(path, '.'); // Get the file's extension for non-cartridge checking
2311 //NOTE: Should fix JaguarLoadROM() to replace .zip with what's *in* the zip (.abs, .j64, etc.)
2312 if (strcasecmp(ext, ".rom") == 0)
2314 // File extension ".ROM": Alpine image that loads/runs at $802000
2315 WriteLog("GUI: Setting up homebrew (ROM)... Run address: 00802000, length: %08X\n", jaguarRomSize);
2317 for(int i=jaguarRomSize-1; i>=0; i--)
2318 jaguar_mainRom[0x2000 + i] = jaguar_mainRom[i];
2320 memset(jaguar_mainRom, 0xFF, 0x2000);
2321 /* memcpy(jaguar_mainRam, jaguar_mainRom, jaguarRomSize);
2322 memset(jaguar_mainRom, 0xFF, 0x600000);
2323 memcpy(jaguar_mainRom + 0x2000, jaguar_mainRam, jaguarRomSize);
2324 memset(jaguar_mainRam, 0x00, 0x400000);*/
2327 Stubulator ROM vectors...
2328 handler 001 at $00E00008
2329 handler 002 at $00E008DE
2330 handler 003 at $00E008E2
2331 handler 004 at $00E008E6
2332 handler 005 at $00E008EA
2333 handler 006 at $00E008EE
2334 handler 007 at $00E008F2
2335 handler 008 at $00E0054A
2336 handler 009 at $00E008FA
2337 handler 010 at $00000000
2338 handler 011 at $00000000
2339 handler 012 at $00E008FE
2340 handler 013 at $00E00902
2341 handler 014 at $00E00906
2342 handler 015 at $00E0090A
2343 handler 016 at $00E0090E
2344 handler 017 at $00E00912
2345 handler 018 at $00E00916
2346 handler 019 at $00E0091A
2347 handler 020 at $00E0091E
2348 handler 021 at $00E00922
2349 handler 022 at $00E00926
2350 handler 023 at $00E0092A
2351 handler 024 at $00E0092E
2352 handler 025 at $00E0107A
2353 handler 026 at $00E0107A
2354 handler 027 at $00E0107A
2355 handler 028 at $00E008DA
2356 handler 029 at $00E0107A
2357 handler 030 at $00E0107A
2358 handler 031 at $00E0107A
2359 handler 032 at $00000000
2361 Let's try setting up the illegal instruction vector for a stubulated jaguar...
2363 /* SET32(jaguar_mainRam, 0x08, 0x00E008DE);
2364 SET32(jaguar_mainRam, 0x0C, 0x00E008E2);
2365 SET32(jaguar_mainRam, 0x10, 0x00E008E6); // <-- Should be here (it is)...
2366 SET32(jaguar_mainRam, 0x14, 0x00E008EA);//*/
2368 // Try setting the vector to say, $1000 and putting an instruction there that loops forever:
2369 // This kludge works! Yeah!
2370 SET32(jaguar_mainRam, 0x10, 0x00001000);
2371 SET16(jaguar_mainRam, 0x1000, 0x60FE); // Here: bra Here
2373 else if (strcasecmp(ext, ".abs") == 0)
2375 // File extension ".ABS": Atari linker output file with header (w/o is useless to us here)
2378 ABS Format sleuthing (LBUGDEMO.ABS):
2380 000000 60 1B 00 00 05 0C 00 04 62 C0 00 00 04 28 00 00
2381 000010 12 A6 00 00 00 00 00 80 20 00 FF FF 00 80 25 0C
2384 DRI-format file detected...
2385 Text segment size = 0x0000050c bytes
2386 Data segment size = 0x000462c0 bytes
2387 BSS Segment size = 0x00000428 bytes
2388 Symbol Table size = 0x000012a6 bytes
2389 Absolute Address for text segment = 0x00802000
2390 Absolute Address for data segment = 0x0080250c
2391 Absolute Address for BSS segment = 0x00004000
2394 000000 01 50 00 03 00 00 00 00 00 03 83 10 00 00 05 3b
2395 000010 00 1c 00 03 00 00 01 07 00 00 1d d0 00 03 64 98
2396 000020 00 06 8b 80 00 80 20 00 00 80 20 00 00 80 3d d0
2398 000030 2e 74 78 74 00 00 00 00 00 80 20 00 00 80 20 00 .txt (+36 bytes)
2399 000040 00 00 1d d0 00 00 00 a8 00 00 00 00 00 00 00 00
2400 000050 00 00 00 00 00 00 00 20
2401 000058 2e 64 74 61 00 00 00 00 00 80 3d d0 00 80 3d d0 .dta (+36 bytes)
2402 000068 00 03 64 98 00 00 1e 78 00 00 00 00 00 00 00 00
2403 000078 00 00 00 00 00 00 00 40
2404 000080 2e 62 73 73 00 00 00 00 00 00 50 00 00 00 50 00 .bss (+36 bytes)
2405 000090 00 06 8b 80 00 03 83 10 00 00 00 00 00 00 00 00
2406 0000a0 00 00 00 00 00 00 00 80
2408 Header size is $A8 bytes...
2410 BSD/COFF format file detected...
2411 3 sections specified
2412 Symbol Table offset = 230160 ($00038310)
2413 Symbol Table contains 1339 symbol entries ($0000053B)
2414 The additional header size is 28 bytes ($001C)
2415 Magic Number for RUN_HDR = 0x00000107
2416 Text Segment Size = 7632 ($00001DD0)
2417 Data Segment Size = 222360 ($00036498)
2418 BSS Segment Size = 428928 ($00068B80)
2419 Starting Address for executable = 0x00802000
2420 Start of Text Segment = 0x00802000
2421 Start of Data Segment = 0x00803dd0
2423 if (jaguar_mainRom[0] == 0x60 && jaguar_mainRom[1] == 0x1B)
2425 uint32 loadAddress = GET32(jaguar_mainRom, 0x16), //runAddress = GET32(jaguar_mainRom, 0x2A),
2426 codeSize = GET32(jaguar_mainRom, 0x02) + GET32(jaguar_mainRom, 0x06);
2427 WriteLog("GUI: Setting up homebrew (ABS-1)... Run address: %08X, length: %08X\n", loadAddress, codeSize);
2429 if (loadAddress < 0x800000)
2430 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x24, codeSize);
2433 for(int i=codeSize-1; i>=0; i--)
2434 jaguar_mainRom[(loadAddress - 0x800000) + i] = jaguar_mainRom[i + 0x24];
2435 /* memcpy(jaguar_mainRam, jaguar_mainRom + 0x24, codeSize);
2436 memset(jaguar_mainRom, 0xFF, 0x600000);
2437 memcpy(jaguar_mainRom + (loadAddress - 0x800000), jaguar_mainRam, codeSize);
2438 memset(jaguar_mainRam, 0x00, 0x400000);*/
2441 jaguarRunAddress = loadAddress;
2443 else if (jaguar_mainRom[0] == 0x01 && jaguar_mainRom[1] == 0x50)
2445 uint32 loadAddress = GET32(jaguar_mainRom, 0x28), runAddress = GET32(jaguar_mainRom, 0x24),
2446 codeSize = GET32(jaguar_mainRom, 0x18) + GET32(jaguar_mainRom, 0x1C);
2447 WriteLog("GUI: Setting up homebrew (ABS-2)... Run address: %08X, length: %08X\n", runAddress, codeSize);
2449 if (loadAddress < 0x800000)
2450 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0xA8, codeSize);
2453 for(int i=codeSize-1; i>=0; i--)
2454 jaguar_mainRom[(loadAddress - 0x800000) + i] = jaguar_mainRom[i + 0xA8];
2455 /* memcpy(jaguar_mainRam, jaguar_mainRom + 0xA8, codeSize);
2456 memset(jaguar_mainRom, 0xFF, 0x600000);
2457 memcpy(jaguar_mainRom + (loadAddress - 0x800000), jaguar_mainRam, codeSize);
2458 memset(jaguar_mainRam, 0x00, 0x400000);*/
2461 jaguarRunAddress = runAddress;
2465 WriteLog("GUI: Couldn't find correct ABS format: %02X %02X\n", jaguar_mainRom[0], jaguar_mainRom[1]);
2469 else if (strcasecmp(ext, ".jag") == 0)
2471 // File extension ".JAG": Atari server file with header
2472 //NOTE: The bytes 'JAGR' should also be at position $1C...
2473 // Also, there's *always* a $601A header at position $00...
2474 if (jaguar_mainRom[0] == 0x60 && jaguar_mainRom[1] == 0x1A)
2476 uint32 loadAddress = GET32(jaguar_mainRom, 0x22), runAddress = GET32(jaguar_mainRom, 0x2A);
2477 //This is not always right! Especially when converted via bin2jag1!!!
2478 //We should have access to the length of the furshlumiger file that was loaded anyway!
2480 // uint32 progLength = GET32(jaguar_mainRom, 0x02);
2483 // WriteLog("Jaguar: Setting up PD ROM... Run address: %08X, length: %08X\n", runAddress, progLength);
2484 // memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, progLength);
2485 WriteLog("GUI: Setting up homebrew (JAG)... Run address: %08X, length: %08X\n", runAddress, jaguarRomSize - 0x2E);
2486 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, jaguarRomSize - 0x2E);
2487 // SET32(jaguar_mainRam, 4, runAddress);
2488 jaguarRunAddress = runAddress;
2493 // .J64 (Jaguar cartridge ROM image) is implied by the FileList object...
2499 // Get the length of a (possibly) gzipped file
2501 int gzfilelength(gzFile gd)
2503 int size = 0, length = 0;
2504 unsigned char buffer[0x10000];
2510 // Read in chunks until EOF
2511 size = gzread(gd, buffer, 0x10000);