4 // Graphical User Interface support
9 #include <sys/types.h> // For MacOS <dirent.h> dependency
15 #include <ctype.h> // For toupper()
25 using namespace std; // For STL stuff
27 // Private function prototypes
29 class Window; // Forward declaration...
31 //void DrawTransparentBitmap(int16 * screen, uint32 x, uint32 y, uint16 * bitmap, uint8 * alpha = NULL);
32 //void DrawStringTrans(int16 * screen, uint32 x, uint32 y, uint16 color, uint8 opacity, const char * text, ...);
33 //void DrawStringOpaque(int16 * screen, uint32 x, uint32 y, uint16 color1, uint16 color2, const char * text, ...);
34 //void DrawString(int16 * screen, uint32 x, uint32 y, bool invert, const char * text, ...);
35 void DrawTransparentBitmap(uint32 * screen, uint32 x, uint32 y, uint32 * bitmap, uint8 * alpha = NULL);
36 void DrawStringTrans(uint32 * screen, uint32 x, uint32 y, uint32 color, uint8 opacity, const char * text, ...);
37 void DrawStringOpaque(uint32 * screen, uint32 x, uint32 y, uint32 color1, uint32 color2, const char * text, ...);
38 void DrawString(uint32 * screen, uint32 x, uint32 y, bool invert, const char * text, ...);
39 Window * LoadROM(void);
40 Window * ResetJaguar(void);
41 Window * ResetJaguarCD(void);
42 Window * RunEmu(void);
45 Window * MiscOptions(void);
47 int gzfilelength(gzFile gd);
51 extern uint8 * jaguar_mainRam;
52 extern uint8 * jaguar_mainRom;
53 extern uint8 * jaguar_bootRom;
54 extern uint8 * jaguar_CDBootROM;
55 extern bool BIOSLoaded;
56 extern bool CDBIOSLoaded;
58 // Local global variables
60 bool exitGUI = false; // GUI (emulator) done variable
62 //uint16 background[1280 * 256]; // GUI background buffer
63 uint32 background[1280 * 256]; // GUI background buffer
65 //NOTE: 32-bit pixels are in the format of ABGR...
69 0xFF00FF00,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, // +
70 0xFF00C600,0xFF00FF00,0x00000000,0x00000000,0x00000000,0x00000000, // @+
71 0xFF00C600,0xFF00FF00,0xFF00FF00,0x00000000,0x00000000,0x00000000, // @++
72 0xFF00C600,0xFF00C600,0xFF00FF00,0xFF00FF00,0x00000000,0x00000000, // @@++
73 0xFF00C600,0xFF00C600,0xFF00FF00,0xFF00FF00,0xFF00FF00,0x00000000, // @@+++
74 0xFF00C600,0xFF00C600,0xFF00C600,0xFF00FF00,0xFF00FF00,0xFF00FF00, // @@@+++
75 0xFF00C600,0xFF00C600,0xFF00C600,0x00000000,0x00000000,0x00000000, // @@@
76 0xFF00C600,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000 // @
78 0x03E0,0x0000,0x0000,0x0000,0x0000,0x0000, // +
79 0x0300,0x03E0,0x0000,0x0000,0x0000,0x0000, // @+
80 0x0300,0x03E0,0x03E0,0x0000,0x0000,0x0000, // @++
81 0x0300,0x0300,0x03E0,0x03E0,0x0000,0x0000, // @@++
82 0x0300,0x0300,0x03E0,0x03E0,0x03E0,0x0000, // @@+++
83 0x0300,0x0300,0x0300,0x03E0,0x03E0,0x03E0, // @@@+++
84 0x0300,0x0300,0x0300,0x0000,0x0000,0x0000, // @@@
85 0x0300,0x0000,0x0000,0x0000,0x0000,0x0000 // @
88 0xFFFF,0x0000,0x0000,0x0000,0x0000,0x0000, // +
89 0xE318,0xFFFF,0x0000,0x0000,0x0000,0x0000, // @+
90 0xE318,0xFFFF,0xFFFF,0x0000,0x0000,0x0000, // @++
91 0xE318,0xE318,0xFFFF,0xFFFF,0x0000,0x0000, // @@++
92 0xE318,0xE318,0xFFFF,0xFFFF,0xFFFF,0x0000, // @@+++
93 0xE318,0xE318,0xE318,0xFFFF,0xFFFF,0xFFFF, // @@@+++
94 0xE318,0xE318,0xE318,0x0000,0x0000,0x0000, // @@@
95 0xE318,0x0000,0x0000,0x0000,0x0000,0x0000 // @
98 // 1 111 00 11 100 1 1100 -> F39C
99 // 1 100 00 10 000 1 0000 -> C210
100 // 1 110 00 11 000 1 1000 -> E318
101 // 0 000 00 11 111 0 0000 -> 03E0
102 // 0 000 00 11 000 0 0000 -> 0300 -> FF00C600
104 uint32 closeBox[] = {
107 //4B5E -> 010010 11010 11110 -> 0100 1001 1101 0110 1111 0111 -> 49 D6 F7
108 //0217 -> 000000 10000 10111 -> 0000 0000 1000 0100 1011 1101 -> 00 84 BD
109 0x00000000,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0x00000000, // +++++
110 0xFFF7D649,0xFFFFFFFF,0x00000000,0x00000000,0x00000000,0xFFFFFFFF,0xFFBD8400, // +@ @.
111 0xFFF7D649,0x00000000,0xFFFFFFFF,0x00000000,0xFFFFFFFF,0x00000000,0xFFBD8400, // + @ @ .
112 0xFFF7D649,0x00000000,0x00000000,0xFFFFFFFF,0x00000000,0x00000000,0xFFBD8400, // + @ .
113 0xFFF7D649,0x00000000,0xFFFFFFFF,0x00000000,0xFFFFFFFF,0x00000000,0xFFBD8400, // + @ @ .
114 0xFFF7D649,0xFFFFFFFF,0x00000000,0x00000000,0x00000000,0xFFFFFFFF,0xFFBD8400, // +@ @.
115 0x00000000,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0x00000000 // .....
117 0x0000,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x0000, // +++++
118 0x4B5E,0xFFFF,0x0000,0x0000,0x0000,0xFFFF,0x0217, // +@ @.
119 0x4B5E,0x0000,0xFFFF,0x0000,0xFFFF,0x0000,0x0217, // + @ @ .
120 0x4B5E,0x0000,0x0000,0xFFFF,0x0000,0x0000,0x0217, // + @ .
121 0x4B5E,0x0000,0xFFFF,0x0000,0xFFFF,0x0000,0x0217, // + @ @ .
122 0x4B5E,0xFFFF,0x0000,0x0000,0x0000,0xFFFF,0x0217, // +@ @.
123 0x0000,0x0217,0x0217,0x0217,0x0217,0x0217,0x0000 // .....
127 uint32 upArrowBox[] = {
130 0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649, // ++++++++
131 0xFFF7D649,0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0x00000000,0xFFBD8400, // + @@ .
132 0xFFF7D649,0x00000000,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0xFFBD8400, // + @@@@ .
133 0xFFF7D649,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFBD8400, // +@@@@@@.
134 0xFFF7D649,0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0x00000000,0xFFBD8400, // + @@ .
135 0xFFF7D649,0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0x00000000,0xFFBD8400, // + @@ .
136 0xFFF7D649,0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0x00000000,0xFFBD8400, // + @@ .
137 0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400 // ........
140 uint32 downArrowBox[] = {
143 0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649, // ++++++++
144 0xFFF7D649,0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0x00000000,0xFFBD8400, // + @@ .
145 0xFFF7D649,0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0x00000000,0xFFBD8400, // + @@ .
146 0xFFF7D649,0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0x00000000,0xFFBD8400, // + @@ .
147 0xFFF7D649,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFBD8400, // +@@@@@@.
148 0xFFF7D649,0x00000000,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0xFFBD8400, // + @@@@ .
149 0xFFF7D649,0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0x00000000,0xFFBD8400, // + @@ .
150 0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400 // ........
153 uint32 pushButtonUp[] = {
156 0x00000000, 0xFF1B1B1B, 0xFF545477, 0xFF525292, 0xFF474787, 0xFF363659, 0xFF0F0F0F, 0x00000000,
157 0xFF1B1B1C, 0xFF6666A7, 0xFF393995, 0xFF343492, 0xFF2F2F90, 0xFF2C2C90, 0xFF3B3B7E, 0xFF0F0F0F,
158 0xFF555578, 0xFF3A3A95, 0xFF353594, 0xFF303091, 0xFF2D2D8F, 0xFF2B2B90, 0xFF2A2A92, 0xFF333358,
159 0xFF545493, 0xFF343492, 0xFF303092, 0xFF2D2D8B, 0xFF2B2B8A, 0xFF2A2A8D, 0xFF292994, 0xFF3D3D83,
160 0xFF484889, 0xFF2F2F90, 0xFF2D2D8F, 0xFF2B2B8A, 0xFF2A2A89, 0xFF29298E, 0xFF292998, 0xFF3D3D84,
161 0xFF37375A, 0xFF2C2C90, 0xFF2B2B90, 0xFF2A2A8D, 0xFF29298E, 0xFF292995, 0xFF29299D, 0xFF34345B,
162 0xFF0E0E0E, 0xFF3E3E7F, 0xFF2A2A92, 0xFF292994, 0xFF292998, 0xFF29299D, 0xFF3C3C88, 0xFF0E0E0E,
163 0x00000000, 0xFF0D0D0D, 0xFF343456, 0xFF3D3D80, 0xFF3D3D82, 0xFF333358, 0xFF0D0D0D, 0x00000000
167 0xFF, 0xE4, 0xA0, 0x99, 0xA4, 0xBE, 0xF0, 0xFF,
168 0xE3, 0x85, 0x00, 0x00, 0x00, 0x00, 0xAF, 0xF0,
169 0x9F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0,
170 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAD,
171 0xA3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAC,
172 0xBD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF,
173 0xF1, 0xAD, 0x00, 0x00, 0x00, 0x00, 0xAC, 0xF1,
174 0xFF, 0xF2, 0xC0, 0xAD, 0xAD, 0xC0, 0xF2, 0xFF
177 uint32 pushButtonDown[] = {
180 0x00000000, 0xFF1B1B1B, 0xFF8B8B90, 0xFF8C8CAF, 0xFF767699, 0xFF56565B, 0xFF0F0F0F, 0x00000000,
181 0xFF1B1B1B, 0xFFB8B8D6, 0xFF5555E4, 0xFF4444F2, 0xFF4040F1, 0xFF4141D5, 0xFF626282, 0xFF0F0F0F,
182 0xFF8C8C91, 0xFF5555E4, 0xFF4444EF, 0xFF3E3EDC, 0xFF3B3BDB, 0xFF3D3DEC, 0xFF3E3ED4, 0xFF4B4B51,
183 0xFF8D8DB1, 0xFF4444F2, 0xFF3E3EDC, 0xFF3E3EDD, 0xFF3C3CDC, 0xFF3939D9, 0xFF3C3CF3, 0xFF59597E,
184 0xFF77779B, 0xFF4141F1, 0xFF3B3BDB, 0xFF3C3CDC, 0xFF3B3BDC, 0xFF3838D9, 0xFF3C3CF5, 0xFF595980,
185 0xFF57575D, 0xFF4242D8, 0xFF3D3DEC, 0xFF3939D9, 0xFF3838D9, 0xFF3C3CEF, 0xFF3D3DDC, 0xFF4C4C52,
186 0xFF101010, 0xFF636385, 0xFF3E3ED8, 0xFF3D3DF4, 0xFF3D3DF6, 0xFF3D3DDD, 0xFF5D5D83, 0xFF101010,
187 0x00000000, 0xFF101010, 0xFF4E4E55, 0xFF5B5B83, 0xFF5B5B84, 0xFF4D4D54, 0xFF101010, 0x00000000
191 0xFF, 0xE4, 0x72, 0x68, 0x7E, 0xA7, 0xF0, 0xFF,
192 0xE4, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x93, 0xF0,
193 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB2,
194 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A,
195 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A,
196 0xA6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB1,
197 0xEF, 0x91, 0x00, 0x00, 0x00, 0x00, 0x96, 0xEF,
198 0xFF, 0xEF, 0xAE, 0x98, 0x97, 0xAF, 0xEF, 0xFF
201 uint32 slideSwitchUp[] = {
204 //0C7F -> 000011 00011 11111 -> 0000 1100 0001 1000 1111 1111 -> 0C 18 FF
205 0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649, // ++++++++
206 0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400, // + .
207 0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400, // + .
208 0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400, // + .
209 0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400, // + .
210 0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400, // + .
211 0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400, // + .
212 0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400, // + .
213 0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400, // +.......
214 0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400, // +.......
215 0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400, // +.......
216 0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400, // +.......
217 0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400, // +.......
218 0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400, // +.......
219 0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400, // +.......
220 0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400 // ........
223 uint32 slideSwitchDown[] = {
226 0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649,0xFFF7D649, // ++++++++
227 0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400, // +.......
228 0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400, // +.......
229 0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400, // +.......
230 0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400, // +.......
231 0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400, // +.......
232 0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400, // +.......
233 0xFFF7D649,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xFFBD8400, // +.......
234 0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400, // + .
235 0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400, // + .
236 0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400, // + .
237 0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400, // + .
238 0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400, // + .
239 0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400, // + .
240 0xFFF7D649,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFFF180C,0xFFBD8400, // + .
241 0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400,0xFFBD8400 // ........
247 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
248 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
249 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
250 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
251 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
252 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
253 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // ........
254 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 // ........
257 char separator[] = "--------------------------------------------------------";
260 // Case insensitive string compare function
261 // Taken straight out of Thinking In C++ by Bruce Eckel. Thanks Bruce!
264 int stringCmpi(const string &s1, const string &s2)
266 // Select the first element of each string:
267 string::const_iterator p1 = s1.begin(), p2 = s2.begin();
269 while (p1 != s1.end() && p2 != s2.end()) // Don
\92t run past the end
271 if (toupper(*p1) != toupper(*p2)) // Compare upper-cased chars
272 return (toupper(*p1) < toupper(*p2) ? -1 : 1);// Report which was lexically greater
278 // If they match up to the detected eos, say which was longer. Return 0 if the same.
279 return s2.size() - s1.size();
286 enum { WINDOW_CLOSE, MENU_ITEM_CHOSEN };
291 Element(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0)
292 { extents.x = x, extents.y = y, extents.w = w, extents.h = h; }
293 virtual void HandleKey(SDLKey key) = 0; // These are "pure" virtual functions...
294 virtual void HandleMouseMove(uint32 x, uint32 y) = 0;
295 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) = 0;
296 virtual void Draw(uint32, uint32) = 0;
297 virtual void Notify(Element *) = 0;
298 //Needed? virtual ~Element() = 0;
299 //We're not allocating anything in the base class, so the answer would be NO.
300 bool Inside(uint32 x, uint32 y);
302 // static void SetScreenAndPitch(int16 * s, uint32 p) { screenBuffer = s, pitch = p; }
303 static void SetScreenAndPitch(uint32 * s, uint32 p) { screenBuffer = s, pitch = p; }
308 // Class variables...
309 // static int16 * screenBuffer;
310 static uint32 * screenBuffer;
314 // Initialize class variables (Element)
315 //int16 * Element::screenBuffer = NULL;
316 uint32 * Element::screenBuffer = NULL;
317 uint32 Element::pitch = 0;
319 bool Element::Inside(uint32 x, uint32 y)
321 return (x >= (uint32)extents.x && x < (uint32)(extents.x + extents.w)
322 && y >= (uint32)extents.y && y < (uint32)(extents.y + extents.h) ? true : false);
326 class Button: public Element
329 Button(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
330 activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
331 bgColor(0xFF00FF00), pic(NULL), elementToTell(NULL) {}
332 Button(uint32 x, uint32 y, uint32 w, uint32 h, uint32 * p): Element(x, y, w, h),
333 activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
334 bgColor(0xFF00FF00), pic(p), elementToTell(NULL) {}
335 Button(uint32 x, uint32 y, uint32 * p): Element(x, y, 0, 0),
336 activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
337 bgColor(0xFF00FF00), pic(p), elementToTell(NULL)
338 { if (pic) extents.w = pic[0], extents.h = pic[1]; }
339 Button(uint32 x, uint32 y, uint32 w, uint32 h, string s): Element(x, y, w, h),
340 activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
341 bgColor(0xFF00FF00), pic(NULL), text(s), elementToTell(NULL) {}
342 Button(uint32 x, uint32 y, string s): Element(x, y, 0, 8),
343 activated(false), clicked(false), inside(false), fgColor(0xFFFFFFFF),
344 bgColor(0xFF00FF00), pic(NULL), text(s), elementToTell(NULL)
345 { extents.w = s.length() * 8; }
346 virtual void HandleKey(SDLKey key) {}
347 virtual void HandleMouseMove(uint32 x, uint32 y);
348 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
349 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
350 virtual void Notify(Element *) {}
351 bool ButtonClicked(void) { return activated; }
352 void SetNotificationElement(Element * e) { elementToTell = e; }
355 bool activated, clicked, inside;
356 uint32 fgColor, bgColor;
359 Element * elementToTell;
362 void Button::HandleMouseMove(uint32 x, uint32 y)
364 inside = Inside(x, y);
367 void Button::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
374 if (clicked && !mouseDown)
376 clicked = false, activated = true;
378 // Send a message that we're activated (if there's someone to tell, that is)
380 elementToTell->Notify(this);
384 clicked = activated = false;
387 void Button::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
389 uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
391 for(uint32 y=0; y<extents.h; y++)
393 for(uint32 x=0; x<extents.w; x++)
395 // Doesn't clip in y axis! !!! FIX !!!
396 if (extents.x + x < pitch)
397 screenBuffer[addr + x + (y * pitch)]
398 // = (clicked && inside ? fgColor : (inside ? 0x43F0 : bgColor));
399 //43F0 -> 010000 11111 10000 -> 0100 0001 1111 1111 1000 0100 -> 41 FF 84
400 = (clicked && inside ? fgColor : (inside ? 0xFF84FF41 : bgColor));
405 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, pic);
407 if (text.length() > 0)
408 DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY, false, "%s", text.c_str());
412 class PushButton: public Element
415 // Save state externally?
416 //We pass in a state variable if we want to track it externally, otherwise we use our own
417 //internal state var. Still need to do some kind of callback for pushbuttons that do things
418 //like change from fullscreen to windowed... !!! FIX !!!
421 // PushButton(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
422 // activated(false), clicked(false), inside(false), fgColor(0xFFFF),
423 // bgColor(0x03E0), pic(NULL), elementToTell(NULL) {}
424 PushButton(uint32 x, uint32 y, bool * st, string s): Element(x, y, 8, 8), state(st),
425 inside(false), text(s) { if (st == NULL) state = &internalState; }
426 /* Button(uint32 x, uint32 y, uint32 w, uint32 h, uint32 * p): Element(x, y, w, h),
427 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
428 bgColor(0x03E0), pic(p), elementToTell(NULL) {}
429 Button(uint32 x, uint32 y, uint32 * p): Element(x, y, 0, 0),
430 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
431 bgColor(0x03E0), pic(p), elementToTell(NULL)
432 { if (pic) extents.w = pic[0], extents.h = pic[1]; }
433 Button(uint32 x, uint32 y, uint32 w, uint32 h, string s): Element(x, y, w, h),
434 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
435 bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL) {}
436 PushButton(uint32 x, uint32 y, string s): Element(x, y, 0, 8),
437 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
438 bgColor(0x03E0), pic(NULL), text(s), elementToTell(NULL)
439 { extents.w = s.length() * 8; }*/
440 virtual void HandleKey(SDLKey key) {}
441 virtual void HandleMouseMove(uint32 x, uint32 y);
442 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
443 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
444 virtual void Notify(Element *) {}
445 // bool ButtonClicked(void) { return activated; }
446 // void SetNotificationElement(Element * e) { elementToTell = e; }
451 // bool activated, clicked, inside;
452 // uint16 fgColor, bgColor;
455 // Element * elementToTell;
459 void PushButton::HandleMouseMove(uint32 x, uint32 y)
461 inside = Inside(x, y);
464 void PushButton::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
466 if (inside && mouseDown)
471 if (clicked && !mouseDown)
473 clicked = false, activated = true;
475 // Send a message that we're activated (if there's someone to tell, that is)
477 elementToTell->Notify(this);
482 // clicked = activated = false;
485 void PushButton::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
487 /* uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
489 for(uint32 y=0; y<extents.h; y++)
491 for(uint32 x=0; x<extents.w; x++)
493 // Doesn't clip in y axis! !!! FIX !!!
494 if (extents.x + x < pitch)
495 screenBuffer[addr + x + (y * pitch)]
496 = (clicked && inside ? fgColor : (inside ? 0x43F0 : bgColor));
500 // DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, (*state ? pushButtonDown : pushButtonUp));
501 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, (*state ? pushButtonDown : pushButtonUp), (*state ? pbdAlpha : pbuAlpha));
502 if (text.length() > 0)
503 DrawString(screenBuffer, extents.x + offsetX + 12, extents.y + offsetY, false, "%s", text.c_str());
507 class SlideSwitch: public Element
510 // Save state externally?
511 //Seems to be handled the same as PushButton, but without sanity checks. !!! FIX !!!
514 SlideSwitch(uint32 x, uint32 y, bool * st, string s1, string s2): Element(x, y, 8, 16), state(st),
515 inside(false), text1(s1), text2(s2) {}
516 virtual void HandleKey(SDLKey key) {}
517 virtual void HandleMouseMove(uint32 x, uint32 y);
518 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
519 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
520 virtual void Notify(Element *) {}
521 // bool ButtonClicked(void) { return activated; }
522 // void SetNotificationElement(Element * e) { elementToTell = e; }
527 // bool activated, clicked, inside;
528 // uint16 fgColor, bgColor;
531 // Element * elementToTell;
534 void SlideSwitch::HandleMouseMove(uint32 x, uint32 y)
536 inside = Inside(x, y);
539 void SlideSwitch::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
541 if (inside && mouseDown)
546 if (clicked && !mouseDown)
548 clicked = false, activated = true;
550 // Send a message that we're activated (if there's someone to tell, that is)
552 elementToTell->Notify(this);
557 // clicked = activated = false;
560 void SlideSwitch::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
562 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, (*state ? slideSwitchDown : slideSwitchUp));
563 if (text1.length() > 0)
564 DrawString(screenBuffer, extents.x + offsetX + 12, extents.y + offsetY, false, "%s", text1.c_str());
565 if (text2.length() > 0)
566 DrawString(screenBuffer, extents.x + offsetX + 12, extents.y + offsetY + 8, false, "%s", text2.c_str());
570 class Window: public Element
573 /* Window(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
574 fgColor(0x4FF0), bgColor(0xFE10)
575 { close = new Button(w - 8, 1, closeBox); list.push_back(close); }*/
576 Window(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0,
577 void (* f)(Element *) = NULL): Element(x, y, w, h),
578 // /*clicked(false), inside(false),*/ fgColor(0x4FF0), bgColor(0x1E10),
579 //4FF0 -> 010011 11111 10000 -> 0100 1101 1111 1111 1000 0100 -> 4D FF 84
580 //1E10 -> 000111 10000 10000 -> 0001 1111 1000 0100 1000 0100 -> 1F 84 84
581 /*clicked(false), inside(false),*/ fgColor(0xFF84FF4D), bgColor(0xFF84841F),
583 { close = new Button(w - 8, 1, closeBox); list.push_back(close);
584 close->SetNotificationElement(this); }
586 virtual void HandleKey(SDLKey key);
587 virtual void HandleMouseMove(uint32 x, uint32 y);
588 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
589 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
590 virtual void Notify(Element * e);
591 void AddElement(Element * e);
592 // bool WindowActive(void) { return true; }//return !close->ButtonClicked(); }
595 // bool clicked, inside;
596 uint32 fgColor, bgColor;
597 void (* handler)(Element *);
599 //We have to use a list of Element *pointers* because we can't make a list that will hold
600 //all the different object types in the same list...
601 vector<Element *> list;
606 for(uint32 i=0; i<list.size(); i++)
611 void Window::HandleKey(SDLKey key)
613 if (key == SDLK_ESCAPE)
616 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
617 SDL_PushEvent(&event);
620 // Handle the items this window contains...
621 for(uint32 i=0; i<list.size(); i++)
622 // Make coords relative to upper right corner of this window...
623 list[i]->HandleKey(key);
626 void Window::HandleMouseMove(uint32 x, uint32 y)
628 // Handle the items this window contains...
629 for(uint32 i=0; i<list.size(); i++)
630 // Make coords relative to upper right corner of this window...
631 list[i]->HandleMouseMove(x - extents.x, y - extents.y);
634 void Window::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
636 // Handle the items this window contains...
637 for(uint32 i=0; i<list.size(); i++)
638 // Make coords relative to upper right corner of this window...
639 list[i]->HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
642 void Window::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
644 uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
646 for(uint32 y=0; y<extents.h; y++)
648 for(uint32 x=0; x<extents.w; x++)
650 // Doesn't clip in y axis! !!! FIX !!!
651 if (extents.x + x < pitch)
652 screenBuffer[addr + x + (y * pitch)] = bgColor;
656 // Handle the items this window contains...
657 for(uint32 i=0; i<list.size(); i++)
658 list[i]->Draw(extents.x, extents.y);
661 void Window::AddElement(Element * e)
666 void Window::Notify(Element * e)
671 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
672 SDL_PushEvent(&event);
677 class Text: public Element
680 // Text(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
681 // fgColor(0x4FF0), bgColor(0xFE10) {}
682 // Text(uint32 x, uint32 y, string s, uint16 fg = 0x4FF0, uint16 bg = 0xFE10): Element(x, y, 0, 0),
683 // fgColor(fg), bgColor(bg), text(s) {}
684 //4FF0 -> 010011 11111 10000 -> 0100 1101 1111 1111 1000 0100 -> 4D FF 84
685 //FE10 -> 111111 10000 10000 -> 1111 1111 1000 0100 1000 0100 -> FF 84 84
686 Text(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
687 fgColor(0xFF84FF4D), bgColor(0xFF8484FF) {}
688 Text(uint32 x, uint32 y, string s, uint32 fg = 0xFF84FF4D, uint32 bg = 0xFF8484FF): Element(x, y, 0, 0),
689 fgColor(fg), bgColor(bg), text(s) {}
690 virtual void HandleKey(SDLKey key) {}
691 virtual void HandleMouseMove(uint32 x, uint32 y) {}
692 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) {}
693 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
694 virtual void Notify(Element *) {}
697 uint32 fgColor, bgColor;
701 void Text::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
703 if (text.length() > 0)
704 // DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY, false, "%s", text.c_str());
705 DrawStringOpaque(screenBuffer, extents.x + offsetX, extents.y + offsetY, fgColor, bgColor, "%s", text.c_str());
709 class ListBox: public Element
710 //class ListBox: public Window
713 // ListBox(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
714 ListBox(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0);//: Window(x, y, w, h),
715 // windowPtr(0), cursor(0), limit(0), charWidth((w / 8) - 1), charHeight(h / 8),
716 // elementToTell(NULL), upArrow(w - 8, 0, upArrowBox),
717 // downArrow(w - 8, h - 8, downArrowBox), upArrow2(w - 8, h - 16, upArrowBox) {}
718 virtual void HandleKey(SDLKey key);
719 virtual void HandleMouseMove(uint32 x, uint32 y);
720 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
721 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
722 virtual void Notify(Element * e);
723 void SetNotificationElement(Element * e) { elementToTell = e; }
724 void AddItem(string s);
725 string GetSelectedItem(void);
729 uint32 windowPtr, cursor, limit;
730 uint32 charWidth, charHeight; // Box width/height in characters
731 Element * elementToTell;
732 Button upArrow, downArrow, upArrow2;
736 uint32 yRelativePoint;
739 ListBox::ListBox(uint32 x, uint32 y, uint32 w, uint32 h): Element(x, y, w, h),
740 thumbClicked(false), windowPtr(0), cursor(0), limit(0), charWidth((w / 8) - 1),
741 charHeight(h / 8), elementToTell(NULL), upArrow(w - 8, 0, upArrowBox),
742 downArrow(w - 8, h - 8, downArrowBox), upArrow2(w - 8, h - 16, upArrowBox)
744 upArrow.SetNotificationElement(this);
745 downArrow.SetNotificationElement(this);
746 upArrow2.SetNotificationElement(this);
747 extents.w -= 8; // Make room for scrollbar...
750 void ListBox::HandleKey(SDLKey key)
752 if (key == SDLK_DOWN)
754 if (cursor != limit - 1) // Cursor is within its window
756 else // Otherwise, scroll the window...
758 if (cursor + windowPtr != item.size() - 1)
762 else if (key == SDLK_UP)
772 else if (key == SDLK_PAGEDOWN)
774 if (cursor != limit - 1)
779 if (windowPtr > item.size() - limit)
780 windowPtr = item.size() - limit;
783 else if (key == SDLK_PAGEUP)
789 if (windowPtr < limit)
795 else if (key >= SDLK_a && key <= SDLK_z)
797 // Advance cursor to filename with first letter pressed...
798 uint8 which = (key - SDLK_a) + 65; // Convert key to A-Z char
800 for(uint32 i=0; i<item.size(); i++)
802 if ((item[i][0] & 0xDF) == which)
804 cursor = i - windowPtr;
805 if (i > windowPtr + limit - 1)
806 windowPtr = i - limit + 1, cursor = limit - 1;
808 windowPtr = i, cursor = 0;
815 void ListBox::HandleMouseMove(uint32 x, uint32 y)
817 upArrow.HandleMouseMove(x - extents.x, y - extents.y);
818 downArrow.HandleMouseMove(x - extents.x, y - extents.y);
819 upArrow2.HandleMouseMove(x - extents.x, y - extents.y);
823 uint32 sbHeight = extents.h - 24,
824 thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight);
826 //yRelativePoint is the spot on the thumb where we clicked...
827 int32 newThumbStart = y - yRelativePoint;
829 if (newThumbStart < 0)
832 if ((uint32)newThumbStart > sbHeight - thumb)
833 newThumbStart = sbHeight - thumb;
835 windowPtr = (uint32)(((float)newThumbStart / (float)sbHeight) * (float)item.size());
836 //Check for cursor bounds as well... Or do we need to???
837 //Actually, we don't...!
841 void ListBox::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
843 if (Inside(x, y) && mouseDown)
845 // Why do we have to do this??? (- extents.y?)
846 // I guess it's because only the Window class has offsetting implemented... !!! FIX !!!
847 cursor = (y - extents.y) / 8;
850 // Check for a hit on the scrollbar...
851 if (x > (uint32)(extents.x + extents.w) && x <= (uint32)(extents.x + extents.w + 8)
852 && y > (uint32)(extents.y + 8) && y <= (uint32)(extents.y + extents.h - 16))
856 // This shiaut should be calculated in AddItem(), not here... (or in Draw() for that matter)
857 uint32 sbHeight = extents.h - 24,
858 thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight),
859 thumbStart = (uint32)(((float)windowPtr / (float)item.size()) * (float)sbHeight);
861 // Did we hit the thumb?
862 if (y >= (extents.y + 8 + thumbStart) && y < (extents.y + 8 + thumbStart + thumb))
863 thumbClicked = true, yRelativePoint = y - thumbStart;
865 //Seems that this is useless--never reached except in rare cases and that the code outside is
868 // thumbClicked = false;
872 thumbClicked = false;
874 upArrow.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
875 downArrow.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
876 upArrow2.HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
879 void ListBox::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
881 for(uint32 i=0; i<limit; i++)
883 // Strip off the extension
884 // (extension stripping should be an option, not default!)
885 string s(item[windowPtr + i], 0, item[windowPtr + i].length() - 4);
886 DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY + i*8,
887 (cursor == i ? true : false), "%-*.*s", charWidth, charWidth, s.c_str());
890 upArrow.Draw(extents.x + offsetX, extents.y + offsetY);
891 downArrow.Draw(extents.x + offsetX, extents.y + offsetY);
892 upArrow2.Draw(extents.x + offsetX, extents.y + offsetY);
894 uint32 sbHeight = extents.h - 24,
895 thumb = (uint32)(((float)limit / (float)item.size()) * (float)sbHeight),
896 thumbStart = (uint32)(((float)windowPtr / (float)item.size()) * (float)sbHeight);
898 for(uint32 y=extents.y+offsetY+8; y<extents.y+offsetY+extents.h-16; y++)
900 // for(uint32 x=extents.x+offsetX+extents.w-8; x<extents.x+offsetX+extents.w; x++)
901 for(uint32 x=extents.x+offsetX+extents.w; x<extents.x+offsetX+extents.w+8; x++)
903 if (y >= thumbStart + (extents.y+offsetY+8) && y < thumbStart + thumb + (extents.y+offsetY+8))
904 // screenBuffer[x + (y * pitch)] = (thumbClicked ? 0x458E : 0xFFFF);
905 //458E -> 01 0001 0 1100 0 1110 -> 0100 0101 0110 0011 0111 0011 -> 45 63 73
906 screenBuffer[x + (y * pitch)] = (thumbClicked ? 0xFF736345 : 0xFFFFFFFF);
908 // screenBuffer[x + (y * pitch)] = 0x0200;
909 //0200 -> 000000 10000 00000 -> 00 1000 0100 00
910 screenBuffer[x + (y * pitch)] = 0xFF008400;
915 void ListBox::Notify(Element * e)
917 if (e == &upArrow || e == &upArrow2)
923 if (cursor < limit - 1)
927 else if (e == &downArrow)
929 if (windowPtr < item.size() - limit)
939 void ListBox::AddItem(string s)
941 // Do a simple insertion sort
942 bool inserted = false;
944 for(vector<string>::iterator i=item.begin(); i<item.end(); i++)
946 if (stringCmpi(s, *i) == -1)
957 limit = (item.size() > charHeight ? charHeight : item.size());
960 string ListBox::GetSelectedItem(void)
962 return item[windowPtr + cursor];
966 class FileList: public Window
969 FileList(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0);
970 virtual ~FileList() {}
971 virtual void HandleKey(SDLKey key);
972 virtual void HandleMouseMove(uint32 x, uint32 y) { Window::HandleMouseMove(x, y); }
973 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) { Window::HandleMouseButton(x, y, mouseDown); }
974 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0) { Window::Draw(offsetX, offsetY); }
975 virtual void Notify(Element * e);
982 //Need 4 buttons, one scrollbar...
983 FileList::FileList(uint32 x, uint32 y, uint32 w, uint32 h): Window(x, y, w, h)
985 files = new ListBox(8, 8, w - 16, h - 32);
987 load = new Button(8, h - 16, " Load ");
989 load->SetNotificationElement(this);
991 //!!! FIX !!! Directory might not exist--this shouldn't cause VJ to crash!
992 DIR * dp = opendir(vjs.ROMPath);
995 while ((de = readdir(dp)) != NULL)
997 char * ext = strrchr(de->d_name, '.');
1000 if (strcasecmp(ext, ".zip") == 0 || strcasecmp(ext, ".j64") == 0
1001 || strcasecmp(ext, ".abs") == 0 || strcasecmp(ext, ".jag") == 0
1002 || strcasecmp(ext, ".rom") == 0)
1003 files->AddItem(string(de->d_name));
1009 void FileList::HandleKey(SDLKey key)
1011 if (key == SDLK_RETURN)
1014 Window::HandleKey(key);
1017 void FileList::Notify(Element * e)
1021 char filename[MAX_PATH];
1022 strcpy(filename, vjs.ROMPath);
1024 if (strlen(filename) > 0)
1025 if (filename[strlen(filename) - 1] != '/')
1026 strcat(filename, "/");
1028 strcat(filename, files->GetSelectedItem().c_str());
1030 // uint32 romSize = JaguarLoadROM(jaguar_mainRom, filename);
1031 // JaguarLoadCart(jaguar_mainRom, filename);
1032 if (JaguarLoadFile(filename))
1035 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
1036 SDL_PushEvent(&event);
1038 event.type = SDL_USEREVENT, event.user.code = MENU_ITEM_CHOSEN;
1039 event.user.data1 = (void *)ResetJaguar;
1040 SDL_PushEvent(&event);
1045 event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
1046 SDL_PushEvent(&event);
1048 // Handle the error, but don't run...
1049 // Tell the user that we couldn't run their file for some reason... !!! FIX !!!
1050 //how to kludge: Make a function like ResetJaguar which creates the dialog window
1061 Window * (* action)(void);
1064 NameAction(string n, Window * (* a)(void) = NULL, SDLKey k = SDLK_UNKNOWN): name(n),
1065 action(a), hotKey(k) {}
1072 MenuItems(): charLength(0) {}
1073 bool Inside(uint32 x, uint32 y)
1074 { return (x >= (uint32)extents.x && x < (uint32)(extents.x + extents.w)
1075 && y >= (uint32)extents.y && y < (uint32)(extents.y + extents.h) ? true : false); }
1078 vector<NameAction> item;
1083 class Menu: public Element
1086 // 1CFF -> 0 001 11 00 111 1 1111
1087 // 421F -> 0 100 00 10 000 1 1111
1088 Menu(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 8,
1089 /* uint16 fgc = 0x1CFF, uint16 bgc = 0x000F, uint16 fgch = 0x421F,
1090 uint16 bgch = 0x1CFF): Element(x, y, w, h), activated(false), clicked(false),*/
1091 /* uint32 fgc = 0xFF3F3F00, uint32 bgc = 0x7F000000, uint32 fgch = 0xFF878700,
1092 uint32 bgch = 0xFF3F3F00): Element(x, y, w, h), activated(false), clicked(false),*/
1093 uint32 fgc = 0xFFFF3F3F, uint32 bgc = 0xFF7F0000, uint32 fgch = 0xFFFF8787,
1094 uint32 bgch = 0xFFFF3F3F): Element(x, y, w, h), activated(false), clicked(false),
1095 inside(0), insidePopup(0), fgColor(fgc), bgColor(bgc), fgColorHL(fgch),
1096 bgColorHL(bgch), menuChosen(-1), menuItemChosen(-1) {}
1097 virtual void HandleKey(SDLKey key);
1098 virtual void HandleMouseMove(uint32 x, uint32 y);
1099 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
1100 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
1101 virtual void Notify(Element *) {}
1102 void Add(MenuItems mi);
1105 bool activated, clicked;
1106 uint32 inside, insidePopup;
1107 // uint16 fgColor, bgColor, fgColorHL, bgColorHL;
1108 uint32 fgColor, bgColor, fgColorHL, bgColorHL;
1109 int menuChosen, menuItemChosen;
1112 vector<MenuItems> itemList;
1115 void Menu::HandleKey(SDLKey key)
1117 for(uint32 i=0; i<itemList.size(); i++)
1119 for(uint32 j=0; j<itemList[i].item.size(); j++)
1121 if (itemList[i].item[j].hotKey == key)
1124 event.type = SDL_USEREVENT;
1125 event.user.code = MENU_ITEM_CHOSEN;
1126 event.user.data1 = (void *)itemList[i].item[j].action;
1127 SDL_PushEvent(&event);
1129 clicked = false, menuChosen = menuItemChosen = -1;
1136 void Menu::HandleMouseMove(uint32 x, uint32 y)
1138 inside = insidePopup = 0;
1142 // Find out *where* we are inside the menu bar
1143 uint32 xpos = extents.x;
1145 for(uint32 i=0; i<itemList.size(); i++)
1147 uint32 width = (itemList[i].title.length() + 2) * 8;
1149 if (x >= xpos && x < xpos + width)
1160 if (!Inside(x, y) && !clicked)
1165 if (itemList[menuChosen].Inside(x, y) && clicked)
1167 insidePopup = ((y - itemList[menuChosen].extents.y) / 8) + 1;
1168 menuItemChosen = insidePopup - 1;
1172 void Menu::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
1181 menuChosen = -1; // clicked is already false...!
1184 else // clicked == true
1186 if (insidePopup && !mouseDown) // I.e., mouse-button-up
1189 if (itemList[menuChosen].item[menuItemChosen].action != NULL)
1191 // itemList[menuChosen].item[menuItemChosen].action();
1193 event.type = SDL_USEREVENT;
1194 event.user.code = MENU_ITEM_CHOSEN;
1195 event.user.data1 = (void *)itemList[menuChosen].item[menuItemChosen].action;
1196 SDL_PushEvent(&event);
1198 clicked = false, menuChosen = menuItemChosen = -1;
1201 while (SDL_PollEvent(&event)); // Flush the event queue...
1202 event.type = SDL_MOUSEMOTION;
1204 SDL_GetMouseState(&mx, &my);
1205 event.motion.x = mx, event.motion.y = my;
1206 SDL_PushEvent(&event); // & update mouse position...!
1210 if (!inside && !insidePopup && mouseDown)
1211 clicked = false, menuChosen = menuItemChosen = -1;
1215 void Menu::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
1217 uint32 xpos = extents.x + offsetX;
1219 for(uint32 i=0; i<itemList.size(); i++)
1221 // uint16 color1 = fgColor, color2 = bgColor;
1222 uint32 color1 = fgColor, color2 = bgColor;
1223 if (inside == (i + 1) || (menuChosen != -1 && (uint32)menuChosen == i))
1224 color1 = fgColorHL, color2 = bgColorHL;
1226 DrawStringOpaque(screenBuffer, xpos, extents.y + offsetY, color1, color2,
1227 " %s ", itemList[i].title.c_str());
1228 xpos += (itemList[i].title.length() + 2) * 8;
1231 // Draw sub menu (but only if active)
1234 uint32 ypos = extents.y + 9;
1236 for(uint32 i=0; i<itemList[menuChosen].item.size(); i++)
1238 // uint16 color1 = fgColor, color2 = bgColor;
1239 uint32 color1 = fgColor, color2 = bgColor;
1241 if (insidePopup == i + 1)
1242 color1 = fgColorHL, color2 = bgColorHL, menuItemChosen = i;
1244 if (itemList[menuChosen].item[i].name.length() > 0)
1245 DrawStringOpaque(screenBuffer, itemList[menuChosen].extents.x, ypos,
1246 color1, color2, " %-*.*s ", itemList[menuChosen].charLength,
1247 itemList[menuChosen].charLength, itemList[menuChosen].item[i].name.c_str());
1249 DrawStringOpaque(screenBuffer, itemList[menuChosen].extents.x, ypos,
1250 fgColor, bgColor, "%.*s", itemList[menuChosen].charLength + 2, separator);
1257 void Menu::Add(MenuItems mi)
1259 for(uint32 i=0; i<mi.item.size(); i++)
1260 if (mi.item[i].name.length() > mi.charLength)
1261 mi.charLength = mi.item[i].name.length();
1263 // Set extents here as well...
1264 mi.extents.x = extents.x + extents.w, mi.extents.y = extents.y + 9;
1265 mi.extents.w = (mi.charLength + 2) * 8, mi.extents.h = mi.item.size() * 8;
1267 itemList.push_back(mi);
1268 extents.w += (mi.title.length() + 2) * 8;
1272 //Do we even *need* this?
1273 //Doesn't seem like it...
1274 /*class RootWindow: public Window
1277 RootWindow(Menu * m, Window * w = NULL): menu(m), window(w) {}
1278 //Do we even need to care about this crap?
1279 // { extents.x = extents.y = 0, extents.w = 320, extents.h = 240; }
1280 virtual void HandleKey(SDLKey key) {}
1281 virtual void HandleMouseMove(uint32 x, uint32 y) {}
1282 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) {}
1283 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0) {}
1284 virtual void Notify(Element *) {}
1289 int16 * rootImage[1280 * 240 * 2];
1294 // Draw text at the given x/y coordinates. Can invert text as well.
1296 //void DrawString(int16 * screen, uint32 x, uint32 y, bool invert, const char * text, ...)
1297 void DrawString(uint32 * screen, uint32 x, uint32 y, bool invert, const char * text, ...)
1302 va_start(arg, text);
1303 vsprintf(string, text, arg);
1306 // uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1307 uint32 pitch = GetSDLScreenWidthInPixels();
1308 uint32 length = strlen(string), address = x + (y * pitch);
1310 for(uint32 i=0; i<length; i++)
1312 uint32 fontAddr = (uint32)string[i] * 64;
1314 for(uint32 yy=0; yy<8; yy++)
1316 for(uint32 xx=0; xx<8; xx++)
1318 if ((font1[fontAddr] && !invert) || (!font1[fontAddr] && invert))
1319 // *(screen + address + xx + (yy * pitch)) = 0xFE00;
1320 *(screen + address + xx + (yy * pitch)) = 0xFF0080FF;
1330 // Draw text at the given x/y coordinates, using FG/BG colors.
1332 //void DrawStringOpaque(int16 * screen, uint32 x, uint32 y, uint16 color1, uint16 color2, const char * text, ...)
1333 void DrawStringOpaque(uint32 * screen, uint32 x, uint32 y, uint32 color1, uint32 color2, const char * text, ...)
1338 va_start(arg, text);
1339 vsprintf(string, text, arg);
1342 // uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1343 uint32 pitch = GetSDLScreenWidthInPixels();
1344 uint32 length = strlen(string), address = x + (y * pitch);
1346 for(uint32 i=0; i<length; i++)
1348 uint32 fontAddr = (uint32)string[i] * 64;
1350 for(uint32 yy=0; yy<8; yy++)
1352 for(uint32 xx=0; xx<8; xx++)
1354 *(screen + address + xx + (yy * pitch)) = (font1[fontAddr] ? color1 : color2);
1364 // Draw text at the given x/y coordinates with transparency (0 is fully opaque, 32 is fully transparent).
1366 //void DrawStringTrans(int16 * screen, uint32 x, uint32 y, uint16 color, uint8 trans, const char * text, ...)
1367 void DrawStringTrans(uint32 * screen, uint32 x, uint32 y, uint32 color, uint8 trans, const char * text, ...)
1372 va_start(arg, text);
1373 vsprintf(string, text, arg);
1376 // uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1377 uint32 pitch = GetSDLScreenWidthInPixels();
1378 uint32 length = strlen(string), address = x + (y * pitch);
1380 for(uint32 i=0; i<length; i++)
1382 uint32 fontAddr = (uint32)string[i] * 64;
1384 for(uint32 yy=0; yy<8; yy++)
1386 for(uint32 xx=0; xx<8; xx++)
1388 if (font1[fontAddr])
1390 // uint16 existingColor = *(screen + address + xx + (yy * pitch));
1391 uint32 existingColor = *(screen + address + xx + (yy * pitch));
1393 /* uint8 eRed = (existingColor >> 10) & 0x1F,
1394 eGreen = (existingColor >> 5) & 0x1F,
1395 eBlue = existingColor & 0x1F,
1396 //This could be done ahead of time, instead of on each pixel...
1397 nRed = (color >> 10) & 0x1F,
1398 nGreen = (color >> 5) & 0x1F,
1399 nBlue = color & 0x1F;//*/
1400 uint8 eBlue = (existingColor >> 16) & 0xFF,
1401 eGreen = (existingColor >> 8) & 0xFF,
1402 eRed = existingColor & 0xFF,
1403 //This could be done ahead of time, instead of on each pixel...
1404 nBlue = (color >> 16) & 0xFF,
1405 nGreen = (color >> 8) & 0xFF,
1406 nRed = color & 0xFF;
1408 //This could be sped up by using a table of 5 + 5 + 5 bits (32 levels transparency -> 32768 entries)
1409 //Here we've modified it to have 33 levels of transparency (could have any # we want!)
1410 //because dividing by 32 is faster than dividing by 31...!
1411 uint8 invTrans = 32 - trans;
1412 /* uint16 bRed = (eRed * trans + nRed * invTrans) / 32;
1413 uint16 bGreen = (eGreen * trans + nGreen * invTrans) / 32;
1414 uint16 bBlue = (eBlue * trans + nBlue * invTrans) / 32;
1416 uint16 blendedColor = (bRed << 10) | (bGreen << 5) | bBlue;//*/
1418 uint32 bRed = (eRed * trans + nRed * invTrans) / 32;
1419 uint32 bGreen = (eGreen * trans + nGreen * invTrans) / 32;
1420 uint32 bBlue = (eBlue * trans + nBlue * invTrans) / 32;
1422 *(screen + address + xx + (yy * pitch)) = 0xFF000000 | (bBlue << 16) | (bGreen << 8) | bRed;
1435 // Uses zero as transparent color
1436 // Can also use an optional alpha channel
1438 //void DrawTransparentBitmap(int16 * screen, uint32 x, uint32 y, uint16 * bitmap, uint8 * alpha/*=NULL*/)
1439 void DrawTransparentBitmap(uint32 * screen, uint32 x, uint32 y, uint32 * bitmap, uint8 * alpha/*=NULL*/)
1441 uint32 width = bitmap[0], height = bitmap[1];
1444 // uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
1445 uint32 pitch = GetSDLScreenWidthInPixels();
1446 uint32 address = x + (y * pitch);
1448 for(uint32 yy=0; yy<height; yy++)
1450 for(uint32 xx=0; xx<width; xx++)
1454 if (*bitmap && x + xx < pitch) // NOTE: Still doesn't clip the Y val...
1455 *(screen + address + xx + (yy * pitch)) = *bitmap;
1459 uint8 trans = *alpha;
1460 uint32 color = *bitmap;
1461 uint32 existingColor = *(screen + address + xx + (yy * pitch));
1463 uint8 eRed = existingColor & 0xFF,
1464 eGreen = (existingColor >> 8) & 0xFF,
1465 eBlue = (existingColor >> 16) & 0xFF,
1467 nRed = color & 0xFF,
1468 nGreen = (color >> 8) & 0xFF,
1469 nBlue = (color >> 16) & 0xFF;
1471 uint8 invTrans = 255 - trans;
1472 uint32 bRed = (eRed * trans + nRed * invTrans) / 255;
1473 uint32 bGreen = (eGreen * trans + nGreen * invTrans) / 255;
1474 uint32 bBlue = (eBlue * trans + nBlue * invTrans) / 255;
1476 uint32 blendedColor = 0xFF000000 | bRed | (bGreen << 8) | (bBlue << 16);
1478 *(screen + address + xx + (yy * pitch)) = blendedColor;
1490 // GUI stuff--it's not crunchy, it's GUI! ;-)
1495 SDL_ShowCursor(SDL_DISABLE);
1496 SDL_GetMouseState(&mouseX, &mouseY);
1506 //bool GUIMain(void)
1507 bool GUIMain(char * filename)
1509 WriteLog("GUI: Inside GUIMain...\n");
1510 // Need to set things up so that it loads and runs a file if given on the command line. !!! FIX !!!
1511 extern uint32 * backbuffer;
1512 // bool done = false;
1514 Window * mainWindow = NULL;
1516 // Set up the GUI classes...
1517 // Element::SetScreenAndPitch(backbuffer, GetSDLScreenPitch() / 2);
1518 Element::SetScreenAndPitch(backbuffer, GetSDLScreenWidthInPixels());
1522 mi.title = "Jaguar";
1523 mi.item.push_back(NameAction("Load...", LoadROM, SDLK_l));
1524 mi.item.push_back(NameAction("Reset", ResetJaguar, SDLK_r));
1526 mi.item.push_back(NameAction("Reset CD", ResetJaguarCD, SDLK_c));
1527 mi.item.push_back(NameAction("Run", RunEmu, SDLK_ESCAPE));
1528 mi.item.push_back(NameAction(""));
1529 mi.item.push_back(NameAction("Quit", Quit, SDLK_q));
1531 mi.title = "Settings";
1533 mi.item.push_back(NameAction("Video..."));
1534 mi.item.push_back(NameAction("Audio..."));
1535 mi.item.push_back(NameAction("Misc...", MiscOptions, SDLK_m));
1539 mi.item.push_back(NameAction("About...", About));
1542 bool showMouse = true;
1544 //This is crappy!!! !!! FIX !!!
1545 //Is this even needed any more? Hmm. Maybe. Dunno.
1546 WriteLog("GUI: Resetting Jaguar...\n");
1549 WriteLog("GUI: Clearing BG save...\n");
1550 // Set up our background save...
1551 // memset(background, 0x11, tom_getVideoModeWidth() * 240 * 2);
1552 //1111 -> 000100 01000 10001 -> 0001 0000 0100 0010 1000 1100 -> 10 42 8C
1553 for(uint32 i=0; i<tom_getVideoModeWidth()*240; i++)
1554 background[i] = 0xFF8C4210;
1556 // Handle loading file passed in on the command line...! [DONE]
1560 if (JaguarLoadFile(filename))
1562 // event.type = SDL_USEREVENT, event.user.code = MENU_ITEM_CHOSEN;
1563 // event.user.data1 = (void *)ResetJaguar;
1564 // SDL_PushEvent(&event);
1565 // Make it so that if passed in on the command line, we quit right
1566 // away when pressing ESC
1567 WriteLog("GUI: Bypassing GUI since ROM passed in on command line...\n");
1573 // Create error dialog...
1575 sprintf(errText, "The file %40s could not be loaded.", filename);
1577 mainWindow = new Window(8, 16, 304, 160);
1578 mainWindow->AddElement(new Text(8, 8, "Error!"));
1579 mainWindow->AddElement(new Text(8, 24, errText));
1583 WriteLog("GUI: Entering main loop...\n");
1586 if (SDL_PollEvent(&event))
1588 if (event.type == SDL_USEREVENT)
1590 if (event.user.code == WINDOW_CLOSE)
1595 else if (event.user.code == MENU_ITEM_CHOSEN)
1597 // Confused? Let me enlighten... What we're doing here is casting
1598 // data1 as a pointer to a function which returns a Window pointer and
1599 // which takes no parameters (the "(Window *(*)(void))" part), then
1600 // derefencing it (the "*" in front of that) in order to call the
1601 // function that it points to. Clear as mud? Yeah, I hate function
1602 // pointers too, but what else are you gonna do?
1603 mainWindow = (*(Window *(*)(void))event.user.data1)();
1605 while (SDL_PollEvent(&event)); // Flush the event queue...
1606 event.type = SDL_MOUSEMOTION;
1608 SDL_GetMouseState(&mx, &my);
1609 event.motion.x = mx, event.motion.y = my;
1610 SDL_PushEvent(&event); // & update mouse position...!
1612 mouseX = mx, mouseY = my; // This prevents "mouse flash"...
1614 mouseX /= 2, mouseY /= 2;
1617 else if (event.type == SDL_ACTIVEEVENT)
1619 if (event.active.state == SDL_APPMOUSEFOCUS)
1620 showMouse = (event.active.gain ? true : false);
1622 else if (event.type == SDL_KEYDOWN)
1625 mainWindow->HandleKey(event.key.keysym.sym);
1627 mainMenu.HandleKey(event.key.keysym.sym);
1629 else if (event.type == SDL_MOUSEMOTION)
1631 mouseX = event.motion.x, mouseY = event.motion.y;
1634 mouseX /= 2, mouseY /= 2;
1637 mainWindow->HandleMouseMove(mouseX, mouseY);
1639 mainMenu.HandleMouseMove(mouseX, mouseY);
1641 else if (event.type == SDL_MOUSEBUTTONDOWN)
1643 uint32 mx = event.button.x, my = event.button.y;
1649 mainWindow->HandleMouseButton(mx, my, true);
1651 mainMenu.HandleMouseButton(mx, my, true);
1653 else if (event.type == SDL_MOUSEBUTTONUP)
1655 uint32 mx = event.button.x, my = event.button.y;
1661 mainWindow->HandleMouseButton(mx, my, false);
1663 mainMenu.HandleMouseButton(mx, my, false);
1667 // The way we do things here is kinda stupid (redrawing the screen every frame), but
1668 // it's simple. Perhaps there may be a reason down the road to be more selective with
1669 // our clearing, but for now, this will suffice.
1670 // memset(backbuffer, 0x11, tom_getVideoModeWidth() * 240 * 2);
1671 // memcpy(backbuffer, background, tom_getVideoModeWidth() * 256 * 2);
1672 memcpy(backbuffer, background, tom_getVideoModeWidth() * 256 * 4);
1675 //Could do multiple windows here by using a vector + priority info...
1676 //Though the way ZSNES does it seems to be by a bool (i.e., they're always active, just not shown)
1681 // DrawTransparentBitmap(backbuffer, mouseX, mouseY, mousePic);
1682 DrawTransparentBitmap(backbuffer, mouseX, mouseY, mousePic);
1692 // GUI "action" functions
1695 Window * LoadROM(void)
1697 FileList * fileList = new FileList(8, 16, 304, 216);
1699 return (Window *)fileList;
1702 Window * ResetJaguar(void)
1709 Window * ResetJaguarCD(void)
1711 memcpy(jaguar_mainRom, jaguar_CDBootROM, 0x40000);
1712 jaguarRunAddress = 0x802000;
1713 jaguar_mainRom_crc32 = crc32_calcCheckSum(jaguar_mainRom, 0x40000);
1715 //This is a quick kludge to get the CDBIOS to boot properly...
1716 //Wild speculation: It could be that this memory location is wired into the CD unit
1717 //somehow, which lets it know whether or not a cart is present in the unit...
1718 jaguar_mainRom[0x0040B] = 0x03;
1723 bool debounceRunKey = true;
1724 Window * RunEmu(void)
1726 //This is crappy... !!! FIX !!!
1727 extern uint32 * backbuffer;
1728 extern bool finished, showGUI;
1730 uint32 nFrame = 0, nFrameskip = 0;
1731 uint32 totalFrames = 0;
1733 bool showMessage = true;
1734 uint32 showMsgFrames = 120;
1735 uint8 transparency = 0;
1736 // Pass a message to the "joystick" code to debounce the ESC key...
1737 debounceRunKey = true;
1739 uint32 cartType = 4;
1740 if (jaguarRomSize == 0x200000)
1742 else if (jaguarRomSize == 0x400000)
1744 else if (jaguar_mainRom_crc32 == 0x687068D5)
1746 else if (jaguar_mainRom_crc32 == 0x55A0669C)
1749 char * cartTypeName[5] = { "2M Cartridge", "4M Cartridge", "CD BIOS", "CD Dev BIOS", "Homebrew" };
1751 // while (!finished)
1754 // Set up new backbuffer with new pixels and data
1755 JaguarExecute(backbuffer, true);
1757 //WriteLog("Frame #%u...\n", totalFrames);
1758 //extern bool doDSPDis;
1759 //if (totalFrames == 373)
1762 //This sucks... !!! FIX !!!
1764 //This is done here so that the crud below doesn't get on our GUI background...
1768 // Some QnD GUI stuff here...
1771 extern uint32 gpu_pc, dsp_pc;
1772 DrawString((uint32 *)backbuffer, 8, 8, false, "GPU PC: %08X", gpu_pc);
1773 DrawString((uint32 *)backbuffer, 8, 16, false, "DSP PC: %08X", dsp_pc);
1778 // FF0F -> 1111 11 11 000 0 1111 -> 3F 18 0F
1779 // 3FE3 -> 0011 11 11 111 0 0011 -> 0F 3F 03
1780 /* DrawStringTrans((uint32 *)backbuffer, 8, 24*8, 0xFF0F, transparency, "Running...");
1781 DrawStringTrans((uint32 *)backbuffer, 8, 26*8, 0x3FE3, transparency, "%s, run address: %06X", cartTypeName[cartType], jaguarRunAddress);
1782 DrawStringTrans((uint32 *)backbuffer, 8, 27*8, 0x3FE3, transparency, "CRC: %08X", jaguar_mainRom_crc32);//*/
1783 //first has wrong color. !!! FIX !!!
1784 DrawStringTrans((uint32 *)backbuffer, 8, 24*8, 0xFF7F63FF, transparency, "Running...");
1785 DrawStringTrans((uint32 *)backbuffer, 8, 26*8, 0xFF1FFF3F, transparency, "%s, run address: %06X", cartTypeName[cartType], jaguarRunAddress);
1786 DrawStringTrans((uint32 *)backbuffer, 8, 27*8, 0xFF1FFF3F, transparency, "CRC: %08X", jaguar_mainRom_crc32);
1788 if (showMsgFrames == 0)
1792 if (transparency == 33)
1794 showMessage = false;
1795 /*extern bool doGPUDis;
1796 doGPUDis = true;//*/
1805 if (nFrame == nFrameskip)
1814 // Reset the pitch, since it may have been changed in-game...
1815 // Element::SetScreenAndPitch(backbuffer, GetSDLScreenPitch() / 2);
1816 Element::SetScreenAndPitch((uint32 *)backbuffer, GetSDLScreenWidthInPixels());
1818 // Save the background for the GUI...
1819 // memcpy(background, backbuffer, tom_getVideoModeWidth() * 240 * 2);
1820 // In this case, we squash the color to monochrome, then force it to blue + green...
1821 for(uint32 i=0; i<tom_getVideoModeWidth() * 256; i++)
1823 // uint32 word = backbuffer[i];
1824 // uint8 r = (word >> 10) & 0x1F, g = (word >> 5) & 0x1F, b = word & 0x1F;
1825 // word = ((r + g + b) / 3) & 0x001F;
1826 // word = (word << 5) | word;
1827 // background[i] = word;
1829 uint32 pixel = backbuffer[i];
1830 uint8 b = (pixel >> 16) & 0xFF, g = (pixel >> 8) & 0xFF, r = pixel & 0xFF;
1831 pixel = ((r + g + b) / 3) & 0x00FF;
1832 background[i] = 0xFF000000 | (pixel << 16) | (pixel << 8);
1840 WriteLog("GUI: Quitting due to user request.\n");
1846 Window * About(void)
1848 Window * window = new Window(8, 16, 304, 160);
1849 // window->AddElement(new Text(8, 8, "Virtual Jaguar 1.0.8"));
1850 window->AddElement(new Text(8, 8, "Virtual Jaguar CVS 20041224"));
1851 window->AddElement(new Text(8, 24, "Coders:"));
1852 window->AddElement(new Text(16, 32, "Niels Wagenaar (nwagenaar)"));
1853 window->AddElement(new Text(16, 40, "Carwin Jones (Caz)"));
1854 window->AddElement(new Text(16, 48, "James L. Hammons (shamus)"));
1855 window->AddElement(new Text(16, 56, "Adam Green"));
1856 window->AddElement(new Text(8, 72, "Testers:"));
1857 window->AddElement(new Text(16, 80, "Guruma"));
1858 window->AddElement(new Text(8, 96, "Thanks go out to:"));
1859 window->AddElement(new Text(16, 104, "Aaron Giles (original CoJag)"));
1860 window->AddElement(new Text(16, 112, "David Raingeard (original VJ)"));
1861 window->AddElement(new Text(16, 120, "Karl Stenerud (Musashi 68K emu)"));
1862 window->AddElement(new Text(16, 128, "Sam Lantinga (amazing SDL libs)"));
1863 window->AddElement(new Text(16, 136, "Ryan C. Gordon (VJ's web presence)"));
1864 window->AddElement(new Text(16, 144, "The guys over at Atari Age ;-)"));
1869 Window * MiscOptions(void)
1871 Window * window = new Window(8, 16, 304, 160);
1872 window->AddElement(new PushButton(8, 8, &vjs.useJaguarBIOS, "BIOS"));
1873 window->AddElement(new SlideSwitch(8, 20, &vjs.hardwareTypeNTSC, "PAL", "NTSC"));
1874 window->AddElement(new PushButton(8, 40, &vjs.DSPEnabled, "DSP"));
1875 window->AddElement(new SlideSwitch(16, 52, &vjs.usePipelinedDSP, "Original", "Pipelined"));
1876 window->AddElement(new SlideSwitch(8, 72, (bool *)&vjs.glFilter, "Sharp", "Blurry"));
1886 // * Window/fullscreen
1893 // Generic ROM loading
1895 uint32 JaguarLoadROM(uint8 * rom, char * path)
1897 // We really should have some kind of sanity checking for the ROM size here to prevent
1898 // a buffer overflow... !!! FIX !!!
1901 char * ext = strrchr(path, '.');
1904 WriteLog("VJ: Loading \"%s\"...", path);
1906 if (strcasecmp(ext, ".zip") == 0)
1908 // Handle ZIP file loading here...
1909 WriteLog("(ZIPped)...");
1911 if (load_zipped_file(0, 0, path, NULL, &rom, &romSize) == -1)
1913 WriteLog("Failed!\n");
1919 /* FILE * fp = fopen(path, "rb");
1923 WriteLog("Failed!\n");
1927 fseek(fp, 0, SEEK_END);
1928 romSize = ftell(fp);
1929 fseek(fp, 0, SEEK_SET);
1930 fread(rom, 1, romSize, fp);
1933 // Handle gzipped files transparently [Adam Green]...
1935 gzFile fp = gzopen(path, "rb");
1939 WriteLog("Failed!\n");
1943 romSize = gzfilelength(fp);
1944 gzseek(fp, 0, SEEK_SET);
1945 gzread(fp, rom, romSize);
1949 WriteLog("OK (%i bytes)\n", romSize);
1956 // Jaguar file loading
1958 bool JaguarLoadFile(char * path)
1960 // jaguarRomSize = JaguarLoadROM(mem, path);
1961 jaguarRomSize = JaguarLoadROM(jaguar_mainRom, path);
1963 /*//This is not *nix friendly for some reason...
1964 // if (!UserSelectFile(path, newPath))
1965 if (!UserSelectFile((strlen(path) == 0 ? (char *)"." : path), newPath))
1967 WriteLog("VJ: Could not find valid ROM in directory \"%s\"...\nAborting!\n", path);
1972 if (jaguarRomSize == 0)
1974 // WriteLog("VJ: Could not load ROM from file \"%s\"...\nAborting!\n", newPath);
1975 WriteLog("GUI: Could not load ROM from file \"%s\"...\nAborting load!\n", path);
1976 // Need to do something else here, like throw up an error dialog instead of aborting. !!! FIX !!!
1979 return false; // This is a start...
1982 jaguar_mainRom_crc32 = crc32_calcCheckSum(jaguar_mainRom, jaguarRomSize);
1983 WriteLog("CRC: %08X\n", (unsigned int)jaguar_mainRom_crc32);
1986 jaguarRunAddress = 0x802000;
1988 char * ext = strrchr(path, '.'); // Get the file's extension for non-cartridge checking
1990 //NOTE: Should fix JaguarLoadROM() to replace .zip with what's *in* the zip (.abs, .j64, etc.)
1991 if (strcasecmp(ext, ".rom") == 0)
1993 // File extension ".ROM": Alpine image that loads/runs at $802000
1994 WriteLog("GUI: Setting up homebrew (ROM)... Run address: 00802000, length: %08X\n", jaguarRomSize);
1996 for(int i=jaguarRomSize-1; i>=0; i--)
1997 jaguar_mainRom[0x2000 + i] = jaguar_mainRom[i];
1999 memset(jaguar_mainRom, 0xFF, 0x2000);
2000 /* memcpy(jaguar_mainRam, jaguar_mainRom, jaguarRomSize);
2001 memset(jaguar_mainRom, 0xFF, 0x600000);
2002 memcpy(jaguar_mainRom + 0x2000, jaguar_mainRam, jaguarRomSize);
2003 memset(jaguar_mainRam, 0x00, 0x400000);*/
2006 Stubulator ROM vectors...
2007 handler 001 at $00E00008
2008 handler 002 at $00E008DE
2009 handler 003 at $00E008E2
2010 handler 004 at $00E008E6
2011 handler 005 at $00E008EA
2012 handler 006 at $00E008EE
2013 handler 007 at $00E008F2
2014 handler 008 at $00E0054A
2015 handler 009 at $00E008FA
2016 handler 010 at $00000000
2017 handler 011 at $00000000
2018 handler 012 at $00E008FE
2019 handler 013 at $00E00902
2020 handler 014 at $00E00906
2021 handler 015 at $00E0090A
2022 handler 016 at $00E0090E
2023 handler 017 at $00E00912
2024 handler 018 at $00E00916
2025 handler 019 at $00E0091A
2026 handler 020 at $00E0091E
2027 handler 021 at $00E00922
2028 handler 022 at $00E00926
2029 handler 023 at $00E0092A
2030 handler 024 at $00E0092E
2031 handler 025 at $00E0107A
2032 handler 026 at $00E0107A
2033 handler 027 at $00E0107A
2034 handler 028 at $00E008DA
2035 handler 029 at $00E0107A
2036 handler 030 at $00E0107A
2037 handler 031 at $00E0107A
2038 handler 032 at $00000000
2040 Let's try setting up the illegal instruction vector for a stubulated jaguar...
2042 /* SET32(jaguar_mainRam, 0x08, 0x00E008DE);
2043 SET32(jaguar_mainRam, 0x0C, 0x00E008E2);
2044 SET32(jaguar_mainRam, 0x10, 0x00E008E6); // <-- Should be here (it is)...
2045 SET32(jaguar_mainRam, 0x14, 0x00E008EA);//*/
2047 // Try setting the vector to say, $1000 and putting an instruction there that loops forever:
2048 // This kludge works! Yeah!
2049 SET32(jaguar_mainRam, 0x10, 0x00001000);
2050 SET16(jaguar_mainRam, 0x1000, 0x60FE); // Here: bra Here
2052 else if (strcasecmp(ext, ".abs") == 0)
2054 // File extension ".ABS": Atari linker output file with header (w/o is useless to us here)
2057 ABS Format sleuthing (LBUGDEMO.ABS):
2059 000000 60 1B 00 00 05 0C 00 04 62 C0 00 00 04 28 00 00
2060 000010 12 A6 00 00 00 00 00 80 20 00 FF FF 00 80 25 0C
2063 DRI-format file detected...
2064 Text segment size = 0x0000050c bytes
2065 Data segment size = 0x000462c0 bytes
2066 BSS Segment size = 0x00000428 bytes
2067 Symbol Table size = 0x000012a6 bytes
2068 Absolute Address for text segment = 0x00802000
2069 Absolute Address for data segment = 0x0080250c
2070 Absolute Address for BSS segment = 0x00004000
2073 000000 01 50 00 03 00 00 00 00 00 03 83 10 00 00 05 3b
2074 000010 00 1c 00 03 00 00 01 07 00 00 1d d0 00 03 64 98
2075 000020 00 06 8b 80 00 80 20 00 00 80 20 00 00 80 3d d0
2077 000030 2e 74 78 74 00 00 00 00 00 80 20 00 00 80 20 00 .txt (+36 bytes)
2078 000040 00 00 1d d0 00 00 00 a8 00 00 00 00 00 00 00 00
2079 000050 00 00 00 00 00 00 00 20
2080 000058 2e 64 74 61 00 00 00 00 00 80 3d d0 00 80 3d d0 .dta (+36 bytes)
2081 000068 00 03 64 98 00 00 1e 78 00 00 00 00 00 00 00 00
2082 000078 00 00 00 00 00 00 00 40
2083 000080 2e 62 73 73 00 00 00 00 00 00 50 00 00 00 50 00 .bss (+36 bytes)
2084 000090 00 06 8b 80 00 03 83 10 00 00 00 00 00 00 00 00
2085 0000a0 00 00 00 00 00 00 00 80
2087 Header size is $A8 bytes...
2089 BSD/COFF format file detected...
2090 3 sections specified
2091 Symbol Table offset = 230160 ($00038310)
2092 Symbol Table contains 1339 symbol entries ($0000053B)
2093 The additional header size is 28 bytes ($001C)
2094 Magic Number for RUN_HDR = 0x00000107
2095 Text Segment Size = 7632 ($00001DD0)
2096 Data Segment Size = 222360 ($00036498)
2097 BSS Segment Size = 428928 ($00068B80)
2098 Starting Address for executable = 0x00802000
2099 Start of Text Segment = 0x00802000
2100 Start of Data Segment = 0x00803dd0
2102 if (jaguar_mainRom[0] == 0x60 && jaguar_mainRom[1] == 0x1B)
2104 uint32 loadAddress = GET32(jaguar_mainRom, 0x16), //runAddress = GET32(jaguar_mainRom, 0x2A),
2105 codeSize = GET32(jaguar_mainRom, 0x02) + GET32(jaguar_mainRom, 0x06);
2106 WriteLog("GUI: Setting up homebrew (ABS-1)... Run address: %08X, length: %08X\n", loadAddress, codeSize);
2108 if (loadAddress < 0x800000)
2109 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x24, codeSize);
2112 for(int i=codeSize-1; i>=0; i--)
2113 jaguar_mainRom[(loadAddress - 0x800000) + i] = jaguar_mainRom[i + 0x24];
2114 /* memcpy(jaguar_mainRam, jaguar_mainRom + 0x24, codeSize);
2115 memset(jaguar_mainRom, 0xFF, 0x600000);
2116 memcpy(jaguar_mainRom + (loadAddress - 0x800000), jaguar_mainRam, codeSize);
2117 memset(jaguar_mainRam, 0x00, 0x400000);*/
2120 jaguarRunAddress = loadAddress;
2122 else if (jaguar_mainRom[0] == 0x01 && jaguar_mainRom[1] == 0x50)
2124 uint32 loadAddress = GET32(jaguar_mainRom, 0x28), runAddress = GET32(jaguar_mainRom, 0x24),
2125 codeSize = GET32(jaguar_mainRom, 0x18) + GET32(jaguar_mainRom, 0x1C);
2126 WriteLog("GUI: Setting up homebrew (ABS-2)... Run address: %08X, length: %08X\n", runAddress, codeSize);
2128 if (loadAddress < 0x800000)
2129 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0xA8, codeSize);
2132 for(int i=codeSize-1; i>=0; i--)
2133 jaguar_mainRom[(loadAddress - 0x800000) + i] = jaguar_mainRom[i + 0xA8];
2134 /* memcpy(jaguar_mainRam, jaguar_mainRom + 0xA8, codeSize);
2135 memset(jaguar_mainRom, 0xFF, 0x600000);
2136 memcpy(jaguar_mainRom + (loadAddress - 0x800000), jaguar_mainRam, codeSize);
2137 memset(jaguar_mainRam, 0x00, 0x400000);*/
2140 jaguarRunAddress = runAddress;
2144 WriteLog("GUI: Couldn't find correct ABS format: %02X %02X\n", jaguar_mainRom[0], jaguar_mainRom[1]);
2148 else if (strcasecmp(ext, ".jag") == 0)
2150 // File extension ".JAG": Atari server file with header
2151 //NOTE: The bytes 'JAGR' should also be at position $1C...
2152 // Also, there's *always* a $601A header at position $00...
2153 if (jaguar_mainRom[0] == 0x60 && jaguar_mainRom[1] == 0x1A)
2155 uint32 loadAddress = GET32(jaguar_mainRom, 0x22), runAddress = GET32(jaguar_mainRom, 0x2A);
2156 //This is not always right! Especially when converted via bin2jag1!!!
2157 //We should have access to the length of the furshlumiger file that was loaded anyway!
2159 // uint32 progLength = GET32(jaguar_mainRom, 0x02);
2162 // WriteLog("Jaguar: Setting up PD ROM... Run address: %08X, length: %08X\n", runAddress, progLength);
2163 // memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, progLength);
2164 WriteLog("GUI: Setting up homebrew (JAG)... Run address: %08X, length: %08X\n", runAddress, jaguarRomSize - 0x2E);
2165 memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, jaguarRomSize - 0x2E);
2166 // SET32(jaguar_mainRam, 4, runAddress);
2167 jaguarRunAddress = runAddress;
2172 // .J64 (Jaguar cartridge ROM image) is implied by the FileList object...
2178 // Get the length of a (possibly) gzipped file
2180 int gzfilelength(gzFile gd)
2182 int size = 0, length = 0;
2183 unsigned char buffer[0x10000];
2189 // Read in chunks until EOF
2190 size = gzread(gd, buffer, 0x10000);