cc68a136 |
1 | // mainloop with window server event handling\r |
2 | // event polling mechnism was taken from\r |
3 | // Peter van Sebille's projects\r |
4 | \r |
5 | // (c) Copyright 2006, notaz\r |
6 | // All Rights Reserved\r |
7 | \r |
8 | #include <hal.h>\r |
9 | \r |
10 | #include <stdio.h>\r |
11 | #include <stdlib.h>\r |
12 | #include <sys/time.h>\r |
13 | \r |
14 | #include "debug.h"\r |
15 | \r |
16 | #include "pico/picoInt.h"\r |
17 | #include "vid.h"\r |
18 | #include "SimpleServer.h"\r |
19 | #include "ClientServer.h"\r |
20 | //#include "polledAS.h"\r |
21 | #include "audio.h"\r |
22 | \r |
23 | #include <EZlib.h>\r |
24 | #include "zlib/gzio_symb.h"\r |
25 | \r |
26 | \r |
27 | #define BENCHMARK\r |
28 | //#define TEST_FRAMEBUFF\r |
29 | \r |
30 | // keycodes we care about\r |
31 | enum TPxxxKeyCodes {\r |
32 | EKeyPxxxPower = EKeyDevice0, //0xF842\r |
33 | EKeyPxxxBrowser = EKeyApplication0,\r |
34 | EKeyPxxxCamera = EKeyApplication1,\r |
35 | EKeyPxxxJogUp = EKeyDevice1,\r |
36 | EKeyPxxxJogDown = EKeyDevice2,\r |
37 | EKeyPxxxJogLeft = EKeyDevice3,\r |
38 | EKeyPxxxJogRight = EKeyDevice9,\r |
39 | EKeyPxxxJogInward= EKeyDevice8,\r |
40 | // FC keys\r |
41 | //EKeyPxxxFcOk = EKeyDevice8, // don't care about FC keycodes\r |
42 | };\r |
43 | // EKeyScreenDimension1 ~ EStdKeyF24 is sent when flip is closed,\r |
44 | // EKeyScreenDimension0 ~ EStdKeyF23 when opened\r |
45 | \r |
46 | enum TMotAKeyCodes {\r |
47 | EKeyMotAUp = EKeyDevice4, //0xF846\r |
48 | EKeyMotADown = EKeyDevice5,\r |
49 | EKeyMotALeft = EKeyDevice6,\r |
50 | EKeyMotARight = EKeyDevice7,\r |
51 | EKeyMotASelect = EKeyDevice8,\r |
52 | EKeyMotAButton1 = EKeyApplicationA,\r |
53 | EKeyMotAButton2 = EKeyApplicationB,\r |
54 | EKeyMotAHome = EKeyApplication0,\r |
55 | EKeyMotAShortcut = EKeyApplication1,\r |
56 | EKeyMotAVoice = EKeyDeviceA,\r |
57 | EKeyMotACamera = EKeyDeviceB,\r |
58 | EKeyMotAVolUp = EKeyIncVolume,\r |
59 | EKeyMotAVolDn = EKeyDecVolume,\r |
60 | EKeyMotASend = EKeyYes,\r |
61 | EKeyMotAEnd = EKeyNo,\r |
62 | };\r |
63 | \r |
64 | // scancodes we care about\r |
65 | enum TPxxxScanCodes {\r |
66 | EScanPxxxPower = EStdKeyDevice0, // 0xa4\r |
67 | EScanPxxxBrowser = EStdKeyApplication0,\r |
68 | EScanPxxxCamera = EStdKeyApplication1,\r |
69 | EScanPxxxJogUp = EStdKeyDevice1,\r |
70 | EScanPxxxJogDown = EStdKeyDevice2,\r |
71 | EScanPxxxJogLeft = EStdKeyDeviceE, // not consistent\r |
72 | EScanPxxxJogRight = EStdKeyDeviceD,\r |
73 | EScanPxxxJogInward= EStdKeyDevice8,\r |
74 | // FC keys\r |
75 | EScanPxxxFcOk = EStdKeyDeviceF,\r |
76 | EScanPxxxFcBack = EStdKeyDevice3,\r |
77 | EScanPxxxFcC = EStdKeyDeviceA,\r |
78 | EScanPxxxFcMenu = EStdKeyDevice9,\r |
79 | EScanPxxxFc0 = '0',\r |
80 | EScanPxxxFc1 = '1',\r |
81 | EScanPxxxFc2 = '2',\r |
82 | EScanPxxxFc3 = '3',\r |
83 | EScanPxxxFc4 = '4',\r |
84 | EScanPxxxFc5 = '5',\r |
85 | EScanPxxxFc6 = '6',\r |
86 | EScanPxxxFc7 = '7',\r |
87 | EScanPxxxFc8 = '8',\r |
88 | EScanPxxxFc9 = '9',\r |
89 | EScanPxxxFcHash = EStdKeyHash,\r |
90 | EScanPxxxFcAsterisk= EStdKeyNkpAsterisk,\r |
91 | };\r |
92 | \r |
93 | enum TMotAScanCodes {\r |
94 | EScanMotAUp = EStdKeyDevice4,\r |
95 | EScanMotADown = EStdKeyDevice5,\r |
96 | EScanMotALeft = EStdKeyDevice6,\r |
97 | EScanMotARight = EStdKeyDevice7,\r |
98 | EScanMotASelect = EStdKeyDevice8,\r |
99 | EScanMotAButton1 = EStdKeyApplicationA,\r |
100 | EScanMotAButton2 = EStdKeyApplicationB,\r |
101 | EScanMotAHome = EStdKeyApplication0,\r |
102 | EScanMotAShortcut = EStdKeyApplication1,\r |
103 | EScanMotAVoice = EStdKeyDeviceA,\r |
104 | EScanMotACamera = EStdKeyDeviceB,\r |
105 | EScanMotAVolUp = EStdKeyIncVolume,\r |
106 | EScanMotAVolDn = EStdKeyDecVolume,\r |
107 | EScanMotASend = EStdKeyYes,\r |
108 | EScanMotAEnd = EStdKeyNo,\r |
109 | // some extra codes, don't know if these are actually used\r |
110 | EScanMotAExtra = EStdKeyApplicationC,\r |
111 | EScanMotAEsc = EStdKeyApplicationD,\r |
112 | EScanMotAStart = EStdKeyApplicationE,\r |
113 | EScanMotASelect2 = EStdKeyApplicationF,\r |
114 | };\r |
115 | \r |
116 | \r |
117 | // list of key names and codes\r |
118 | TPicoKeyConfigEntry keyConfigPXXX[] = {\r |
119 | { EKeyPxxxPower, EScanPxxxPower, 0, -1, -1, "POWER" }, // 0\r |
120 | { EKeyPxxxBrowser, EScanPxxxBrowser, 0, -1, -1, "BROWSER" },\r |
121 | { EKeyPxxxCamera, EScanPxxxCamera, 0, -1, -1, "CAMERA" },\r |
122 | { EKeyPxxxJogUp, EScanPxxxJogUp, 2, -1, -1, "JOG@UP" },\r |
123 | { EKeyPxxxJogDown, EScanPxxxJogDown, 2, -1, -1, "JOG@DOWN" },\r |
124 | { EKeyPxxxJogLeft, EScanPxxxJogLeft, 0, -1, -1, "JOG@LEFT" }, // 5\r |
125 | { EKeyPxxxJogRight, EScanPxxxJogRight, 0, -1, -1, "JOG@RIGHT" },\r |
126 | { 0, EScanPxxxJogInward, 0, -1, -1, "JOG@INWARD" },\r |
127 | { 0, EScanPxxxFcOk, 0, -1, -1, "FC@OK" },\r |
128 | { 0, EScanPxxxFcBack, 0, -1, -1, "FC@BACK" },\r |
129 | { 0, EScanPxxxFcC, 0, -1, -1, "FC@C" }, // 10\r |
130 | { 0, EScanPxxxFcMenu, 0, -1, -1, "FC@MENU" },\r |
131 | { 0, EScanPxxxFc0, 0, -1, -1, "FC@0" },\r |
132 | { 0, EScanPxxxFc1, 0, -1, -1, "FC@1" },\r |
133 | { 0, EScanPxxxFc2, 0, -1, -1, "FC@2" },\r |
134 | { 0, EScanPxxxFc3, 0, -1, -1, "FC@3" },\r |
135 | { 0, EScanPxxxFc4, 0, -1, -1, "FC@4" },\r |
136 | { 0, EScanPxxxFc5, 0, -1, -1, "FC@5" },\r |
137 | { 0, EScanPxxxFc6, 0, -1, -1, "FC@6" },\r |
138 | { 0, EScanPxxxFc7, 0, -1, -1, "FC@7" },\r |
139 | { 0, EScanPxxxFc8, 0, -1, -1, "FC@8" },\r |
140 | { 0, EScanPxxxFc9, 0, -1, -1, "FC@9" },\r |
141 | { 0, EScanPxxxFcHash, 0, -1, -1, "FC@HASH" },\r |
142 | { 0, EScanPxxxFcAsterisk,0, -1, -1, "FC@AST" },\r |
143 | { 0, 0, 0, 0, 0, 0 }\r |
144 | };\r |
145 | \r |
146 | // Motorola A92x & A1000 support\r |
147 | TPicoKeyConfigEntry keyConfigMotA[] = {\r |
148 | { EKeyMotAUp, EScanMotAUp, 0, -1, -1, "UP" }, // 0\r |
149 | { EKeyMotADown, EScanMotADown, 0, -1, -1, "DOWN" },\r |
150 | { EKeyMotALeft, EScanMotALeft, 0, -1, -1, "LEFT" },\r |
151 | { EKeyMotARight, EScanMotARight, 0, -1, -1, "RIGHT" },\r |
152 | { EKeyMotASelect, EScanMotASelect, 0, -1, -1, "SELECT" },\r |
153 | { EKeyMotAButton1, EScanMotAButton1, 0, -1, -1, "BUTTON1" }, // 5\r |
154 | { EKeyMotAButton2, EScanMotAButton2, 0, -1, -1, "BUTTON2" },\r |
155 | { EKeyMotAHome, EScanMotAHome, 0, -1, -1, "HOME" },\r |
156 | { EKeyMotAShortcut, EScanMotAShortcut, 0, -1, -1, "SHORTCUT" },\r |
157 | { EKeyMotAVoice, EScanMotAVoice, 0, -1, -1, "VOICE" },\r |
158 | { EKeyMotACamera, EScanMotACamera, 0, -1, -1, "CAMERA" }, // 10\r |
159 | { EKeyMotAVolUp, EScanMotAVolUp, 0, -1, -1, "VOL@UP" },\r |
160 | { EKeyMotAVolDn, EScanMotAVolDn, 0, -1, -1, "VOL@DOWN" },\r |
161 | { EKeyMotASend, EScanMotASend, 0, -1, -1, "SEND" },\r |
162 | { EKeyMotAEnd, EScanMotAEnd, 0, -1, -1, "END" },\r |
163 | { 0, EScanMotAExtra, 0, -1, -1, "EXTRA" },\r |
164 | { 0, EScanMotAEsc, 0, -1, -1, "ESC" },\r |
165 | { 0, EScanMotAStart, 0, -1, -1, "START" },\r |
166 | { 0, EScanMotASelect2, 0, -1, -1, "SELECT" },\r |
167 | { 0, 0, 0, 0, 0, 0 }\r |
168 | };\r |
169 | \r |
170 | \r |
171 | // list of areas\r |
172 | TPicoAreaConfigEntry areaConfig[] = {\r |
173 | { TRect( 0, 0, 0, 0) },\r |
174 | // small corner bottons\r |
175 | { TRect( 0, 0, 15, 15) },\r |
176 | { TRect(192, 0, 207, 15) },\r |
177 | { TRect( 0, 304, 15, 319) },\r |
178 | { TRect(192, 304, 207, 319) },\r |
179 | // normal buttons\r |
180 | { TRect( 0, 0, 68, 63) },\r |
181 | { TRect( 69, 0, 138, 63) },\r |
182 | { TRect(139, 0, 207, 63) },\r |
183 | { TRect( 0, 64, 68, 127) },\r |
184 | { TRect( 69, 64, 138, 127) },\r |
185 | { TRect(139, 64, 207, 127) },\r |
186 | { TRect( 0, 128, 68, 191) },\r |
187 | { TRect( 69, 128, 138, 191) },\r |
188 | { TRect(139, 128, 207, 191) },\r |
189 | { TRect( 0, 192, 68, 255) },\r |
190 | { TRect( 69, 192, 138, 255) },\r |
191 | { TRect(139, 192, 207, 255) },\r |
192 | { TRect( 0, 256, 68, 319) },\r |
193 | { TRect( 69, 256, 138, 319) },\r |
194 | { TRect(139, 256, 207, 319) },\r |
195 | { TRect( 0, 0, 0, 0) }\r |
196 | };\r |
197 | \r |
198 | // PicoPad[] format: SACB RLDU\r |
199 | const char *actionNames[] = {\r |
200 | "UP", "DOWN", "LEFT", "RIGHT", "B", "C", "A", "START",\r |
201 | 0, 0, 0, 0, 0, 0, 0, 0, // Z, Y, X, MODE (enabled only when needed), ?, ?, ?, ?\r |
202 | 0, 0, 0, 0, 0, 0, "NEXT@SAVE@SLOT", "PREV@SAVE@SLOT", // ?, ?, ?, ?, mot_vol_up, mot_vol_down, next_slot, prev_slot\r |
203 | 0, 0, "PAUSE@EMU", "SAVE@STATE", "LOAD@STATE", "FRAMESKIP@8", "AUTO@FRAMESKIP", "DONE" // ?, switch_renderer\r |
204 | };\r |
205 | \r |
206 | \r |
207 | // globals are allowed, so why not to (ab)use them?\r |
208 | TInt machineUid = 0;\r |
209 | int gamestate = PGS_Paused, gamestate_prev = PGS_Paused;\r |
210 | TPicoConfig currentConfig;\r |
211 | TPicoKeyConfigEntry *keyConfig = 0; // currently used keys\r |
212 | static char noticeMsg[64]; // notice msg to draw\r |
213 | static timeval noticeMsgTime = { 0, 0 }; // when started showing\r |
214 | static RLibrary gameAudioLib; // audio object library\r |
215 | static _gameAudioNew gameAudioNew; // audio object maker\r |
216 | static IGameAudio *gameAudio = 0; // the audio object itself\r |
217 | static TProcessId launcherProcessId;\r |
218 | static int reset_timing, state_slot = 0;\r |
219 | extern const char *RomFileName;\r |
220 | extern int pico_was_reset; \r |
221 | #ifdef TEST_FRAMEBUFF\r |
222 | static TUint8 *iFrameBuffer = 0;\r |
223 | #endif\r |
224 | \r |
225 | // some forward declarations\r |
226 | static void MainInit();\r |
227 | static void MainExit();\r |
228 | static void CheckForLauncher();\r |
229 | static void DumpMemInfo();\r |
230 | \r |
231 | // just for a nicer grouping of WS related stuff\r |
232 | class CGameWindow\r |
233 | {\r |
234 | public:\r |
235 | static void ConstructResourcesL();\r |
236 | static void FreeResources();\r |
237 | static void DoKeys(timeval &time);\r |
238 | static void DoKeysConfig(TUint &which);\r |
239 | static void RunEvents(TUint32 which);\r |
240 | static void SendClientWsEvent(TInt type);\r |
241 | \r |
242 | static RWsSession iWsSession;\r |
243 | static RWindowGroup iWsWindowGroup;\r |
244 | static RWindow iWsWindow;\r |
245 | static CWsScreenDevice* iWsScreen;\r |
246 | static CWindowGc* iWindowGc;\r |
247 | static TRequestStatus iWsEventStatus;\r |
248 | static TThreadId iLauncherThreadId;\r |
249 | static RDirectScreenAccess* iDSA;\r |
250 | static TRequestStatus iDSAstatus;\r |
251 | };\r |
252 | \r |
253 | \r |
254 | void SkipFrame(int do_sound)\r |
255 | {\r |
256 | PicoSkipFrame=1;\r |
257 | PicoFrame();\r |
258 | PicoSkipFrame=0;\r |
259 | \r |
260 | if(do_sound && PsndOut) {\r |
261 | PsndOut = gameAudio->NextFrameL();\r |
262 | if(!PsndOut) { // sound output problems?\r |
263 | strcpy(noticeMsg, "SOUND@OUTPUT@ERROR;@SOUND@DISABLED");\r |
264 | gettimeofday(¬iceMsgTime, 0);\r |
265 | }\r |
266 | }\r |
267 | \r |
268 | /*\r |
269 | int total=0;\r |
270 | \r |
271 | // V-Blanking period:\r |
272 | if (Pico.video.reg[1]&0x20) SekInterrupt(6); // Set IRQ\r |
273 | Pico.video.status|=0x88; // V-Int happened / go into vblank\r |
274 | total+=SekRun(18560);\r |
275 | \r |
276 | // Active Scan:\r |
277 | if (Pico.video.reg[1]&0x40) Pico.video.status&=~8; // Come out of vblank if display is enabled\r |
278 | SekInterrupt(0); // Clear IRQ\r |
279 | total+=SekRun(127969-total);\r |
280 | */\r |
281 | }\r |
282 | \r |
283 | \r |
284 | void TargetEpocGameL()\r |
285 | {\r |
286 | char buff[24]; // fps count c string\r |
287 | struct timeval tval; // timing\r |
288 | int thissec = 0, frames_done = 0, frames_shown = 0;\r |
289 | int target_fps, target_frametime, too_fast, too_fast_time;\r |
290 | int i, underflow;\r |
291 | TRawEvent blevent;\r |
292 | \r |
293 | MainInit();\r |
294 | buff[0] = 0;\r |
295 | \r |
296 | // just to keep the backlight on..\r |
297 | blevent.Set(TRawEvent::EActive);\r |
298 | \r |
299 | // loop?\r |
300 | for(;;) {\r |
301 | if(gamestate == PGS_Running) {\r |
302 | // prepare window and stuff\r |
303 | CGameWindow::ConstructResourcesL();\r |
304 | \r |
305 | // if the system has something to do, it should better do it now\r |
306 | User::After(50000);\r |
307 | //CPolledActiveScheduler::Instance()->Schedule();\r |
308 | \r |
309 | // pal/ntsc might have changed, reset related stuff\r |
310 | if(Pico.m.pal) {\r |
311 | target_fps = 50;\r |
312 | if(!noticeMsgTime.tv_sec) strcpy(noticeMsg, "PAL@SYSTEM@/@50@FPS");\r |
313 | } else {\r |
314 | target_fps = 60;\r |
315 | if(!noticeMsgTime.tv_sec) strcpy(noticeMsg, "NTSC@SYSTEM@/@60@FPS");\r |
316 | }\r |
317 | target_frametime = 1000000/target_fps;\r |
318 | if(!noticeMsgTime.tv_sec && pico_was_reset)\r |
319 | gettimeofday(¬iceMsgTime, 0);\r |
320 | \r |
321 | pico_was_reset = too_fast = 0;\r |
322 | reset_timing = 1;\r |
323 | \r |
324 | while(gamestate == PGS_Running) {\r |
325 | gettimeofday(&tval, 0);\r |
326 | if(reset_timing) {\r |
327 | reset_timing = 0;\r |
328 | thissec = tval.tv_sec;\r |
329 | frames_done = tval.tv_usec/target_frametime;\r |
330 | }\r |
331 | \r |
332 | // show notice message?\r |
333 | char *notice = 0;\r |
334 | if(noticeMsgTime.tv_sec) {\r |
335 | if((tval.tv_sec*1000000+tval.tv_usec) - (noticeMsgTime.tv_sec*1000000+noticeMsgTime.tv_usec) > 2000000) // > 2.0 sec\r |
336 | noticeMsgTime.tv_sec = noticeMsgTime.tv_usec = 0;\r |
337 | else notice = noticeMsg;\r |
338 | }\r |
339 | \r |
340 | // second changed?\r |
341 | if(thissec != tval.tv_sec) {\r |
342 | #ifdef BENCHMARK\r |
343 | static int bench = 0, bench_fps = 0, bench_fps_s = 0, bfp = 0, bf[4];\r |
344 | if(++bench == 10) {\r |
345 | bench = 0;\r |
346 | bench_fps_s = bench_fps;\r |
347 | bf[bfp++ & 3] = bench_fps;\r |
348 | bench_fps = 0;\r |
349 | }\r |
350 | bench_fps += frames_shown;\r |
351 | sprintf(buff, "%02i/%02i/%02i", frames_shown, bench_fps_s, (bf[0]+bf[1]+bf[2]+bf[3])>>2);\r |
352 | #else\r |
353 | if(currentConfig.iFlags & 2) \r |
354 | sprintf(buff, "%02i/%02i", frames_shown, frames_done);\r |
355 | #endif\r |
356 | thissec = tval.tv_sec;\r |
357 | if((thissec & 7) == 7) UserSvr::AddEvent(blevent);\r |
358 | // in is quite common for this implementation to leave 1 fame unfinished\r |
359 | // when second changes. This creates sound clicks, so it's probably better to\r |
360 | // skip that frame and render sound\r |
361 | if(PsndOut && frames_done < target_fps && frames_done > target_fps-5) {\r |
362 | SkipFrame(1); frames_done++;\r |
363 | }\r |
364 | // try to prevent sound buffer underflows by making sure we did _exactly_\r |
365 | // target_fps sound updates and copying last samples over and over again\r |
366 | if(PsndOut && frames_done < target_fps)\r |
367 | for(; frames_done < target_fps; frames_done++) {\r |
368 | PsndOut = gameAudio->DupeFrameL(underflow);\r |
369 | if(!PsndOut) { // sound output problems?\r |
370 | strcpy(noticeMsg, "SOUND@OUTPUT@ERROR;@SOUND@DISABLED");\r |
371 | gettimeofday(¬iceMsgTime, 0);\r |
372 | break;\r |
373 | }\r |
374 | if(underflow) break;\r |
375 | }\r |
376 | frames_done = frames_shown = 0;\r |
377 | }\r |
378 | \r |
379 | if(currentConfig.iFrameskip >= 0) { // frameskip enabled\r |
380 | for(i = 0; i < currentConfig.iFrameskip; i++) {\r |
381 | SkipFrame(frames_done < target_fps); frames_done++;\r |
382 | CGameWindow::DoKeys(tval);\r |
383 | }\r |
384 | } else if(tval.tv_usec > (frames_done+1)*target_frametime) { // auto frameskip\r |
385 | // no time left for this frame - skip\r |
386 | SkipFrame(1); frames_done++;\r |
387 | CGameWindow::DoKeys(tval);\r |
388 | too_fast = 0;\r |
389 | continue;\r |
390 | } else if(tval.tv_usec < (too_fast_time=frames_done*target_frametime)) { // we are too fast\r |
391 | if(++too_fast > 2) { User::After(too_fast_time-tval.tv_usec); too_fast = 0; }// sleep, but only if we are _really_ fast\r |
392 | }\r |
393 | \r |
394 | // draw\r |
395 | vidDrawFrame(notice, buff, frames_shown);\r |
396 | if(PsndOut && frames_done < target_fps) {\r |
397 | PsndOut = gameAudio->NextFrameL();\r |
398 | if(!PsndOut) { // sound output problems?\r |
399 | strcpy(noticeMsg, "SOUND@OUTPUT@ERROR;@SOUND@DISABLED");\r |
400 | gettimeofday(¬iceMsgTime, 0);\r |
401 | }\r |
402 | }\r |
403 | frames_done++; frames_shown++;\r |
404 | CGameWindow::DoKeys(tval);\r |
405 | }\r |
406 | \r |
407 | // save SRAM\r |
408 | if((currentConfig.iFlags & 1) && SRam.changed) {\r |
409 | saveLoadGame(0, 1);\r |
410 | SRam.changed = 0;\r |
411 | }\r |
412 | CGameWindow::SendClientWsEvent(EEventGamePaused);\r |
413 | CGameWindow::FreeResources();\r |
414 | } else if(gamestate == PGS_Paused) {\r |
415 | for(i = 0; gamestate == PGS_Paused; i++) {\r |
416 | User::After(250000);\r |
417 | if(!(i & 0x7F)) CheckForLauncher(); // every 32 secs\r |
418 | }\r |
419 | } else if(gamestate == PGS_KeyConfig) {\r |
420 | // prepare window and stuff\r |
421 | CGameWindow::ConstructResourcesL();\r |
422 | \r |
423 | TUint whichAction = 0;\r |
424 | while(gamestate == PGS_KeyConfig) {\r |
425 | vidKeyConfigFrame(whichAction, CGameWindow::iWsScreen->CurrentScreenMode());\r |
426 | CGameWindow::DoKeysConfig(whichAction);\r |
427 | User::After(200000);\r |
428 | }\r |
429 | \r |
430 | CGameWindow::SendClientWsEvent(EEventKeyCfgDone);\r |
431 | CGameWindow::SendClientWsEvent(EEventGamePaused);\r |
432 | CGameWindow::FreeResources();\r |
433 | } else if(gamestate == PGS_DebugHeap) {\r |
434 | #ifdef __DEBUG_PRINT\r |
435 | TInt cells = User::CountAllocCells();\r |
436 | TInt mem;\r |
437 | User::AllocSize(mem);\r |
438 | DEBUGPRINT(_L("worker: cels=%d, size=%d KB"), cells, mem/1024);\r |
439 | gamestate = gamestate_prev;\r |
440 | #endif\r |
441 | } else if(gamestate == PGS_Quit) {\r |
442 | break;\r |
443 | }\r |
444 | }\r |
445 | \r |
446 | MainExit();\r |
447 | }\r |
448 | \r |
449 | \r |
450 | // gameAudio default "maker", which simply leaves\r |
451 | IGameAudio *gameAudioNew_failer(TInt aRate, TBool aStereo, TInt aPcmFrames, TInt aBufferedFrames)\r |
452 | {\r |
453 | User::Leave(1);\r |
454 | return 0; // shouldn't happen\r |
455 | }\r |
456 | \r |
457 | \r |
458 | // main initialization\r |
459 | static void MainInit()\r |
460 | {\r |
461 | RProcess thisProcess, launcherProcess;\r |
462 | TInt err = KErrGeneral;\r |
463 | \r |
464 | DEBUGPRINT(_L("\r\n\r\nstarting.."));\r |
465 | \r |
466 | //CPolledActiveScheduler::NewL(); // create Polled AS for the sound engine\r |
467 | \r |
468 | // get launcher id\r |
469 | if(thisProcess.Owner(launcherProcess) == KErrNone) {\r |
470 | launcherProcessId = launcherProcess.Id();\r |
471 | launcherProcess.Close(); // messing with launcherProcess too much strangely reboots my phone\r |
472 | } else {\r |
473 | DEBUGPRINT(_L("%i: couldn't find owner, terminating.."), thisProcess.Id());\r |
474 | thisProcess.Terminate(1);\r |
475 | }\r |
476 | \r |
477 | // also get launcher thread id (for sending events, nasty way)\r |
478 | TFindThread findThread;\r |
479 | TFullName dummy1;\r |
480 | RThread tmpThread;\r |
481 | RProcess tmpProcess;\r |
482 | \r |
483 | while(findThread.Next(dummy1) == KErrNone)\r |
484 | {\r |
485 | tmpThread.Open(findThread);\r |
486 | tmpThread.Process(tmpProcess);\r |
487 | if(tmpProcess.Id() == launcherProcessId) {\r |
488 | CGameWindow::iLauncherThreadId = tmpThread.Id();\r |
489 | break;\r |
490 | }\r |
491 | tmpThread.Close();\r |
492 | tmpProcess.Close();\r |
493 | }\r |
494 | \r |
495 | // start event listening thread, which waits for GUI commands\r |
496 | if(StartThread() < 0) {\r |
497 | // communication thread failed to start, we serve no purpose now, so suicide\r |
498 | DEBUGPRINT(_L("%i: StartThread() failed, terminating.."), thisProcess.Id());\r |
499 | thisProcess.Terminate(1);\r |
500 | }\r |
501 | \r |
502 | HAL::Get(HALData::EMachineUid, machineUid); // find out the machine UID\r |
503 | \r |
504 | // get current dir\r |
505 | TFileName pfName = thisProcess.FileName();\r |
506 | TParse parse;\r |
507 | parse.Set(pfName, 0, 0);\r |
508 | TPtrC currDir = parse.DriveAndPath();\r |
509 | DEBUGPRINT(_L("current dir: %S"), &currDir);\r |
510 | \r |
511 | static TPtrC audio_dlls[] = { _L("audio_motorola.dll"), _L("audio_mediaserver.dll") };\r |
512 | \r |
513 | // find our audio object maker\r |
514 | for(TInt i=0; i < 2; i++) {\r |
515 | DEBUGPRINT(_L("trying audio DLL: %S"), &audio_dlls[i]);\r |
516 | err = gameAudioLib.Load(audio_dlls[i], currDir);\r |
517 | if(err == KErrNone) { // great, we loaded a dll!\r |
518 | gameAudioNew = (_gameAudioNew) gameAudioLib.Lookup(1);\r |
519 | if(!gameAudioNew) {\r |
520 | gameAudioLib.Close();\r |
521 | err = KErrGeneral;\r |
522 | DEBUGPRINT(_L(" loaded, but Lookup(1) failed."));\r |
523 | } else\r |
524 | break; // done\r |
525 | } else\r |
526 | DEBUGPRINT(_L(" load failed! (%i)"), err);;\r |
527 | }\r |
528 | \r |
529 | if(err != KErrNone)\r |
530 | gameAudioNew = gameAudioNew_failer;\r |
531 | else DEBUGPRINT(_L(" audio dll loaded!"));;\r |
532 | \r |
533 | DumpMemInfo();\r |
534 | \r |
535 | // try to start pico\r |
536 | DEBUGPRINT(_L("PicoInit();"));\r |
537 | PicoInit();\r |
538 | \r |
539 | #ifdef TEST_FRAMEBUFF\r |
540 | iFrameBuffer = (TUint8 *) malloc(208*320*4);\r |
541 | #endif\r |
542 | }\r |
543 | \r |
544 | \r |
545 | // does not return\r |
546 | static void MainExit()\r |
547 | {\r |
548 | RProcess thisProcess;\r |
549 | \r |
550 | DEBUGPRINT(_L("%i: cleaning up.."), thisProcess.Id());\r |
551 | \r |
552 | // save SRAM\r |
553 | if((currentConfig.iFlags & 1) && SRam.changed) {\r |
554 | saveLoadGame(0, 1);\r |
555 | SRam.changed = 0;\r |
556 | }\r |
557 | \r |
558 | PicoExit();\r |
559 | \r |
560 | if(gameAudio) delete gameAudio;\r |
561 | \r |
562 | if(gameAudioLib.Handle()) gameAudioLib.Close();\r |
563 | \r |
564 | // Polled AS\r |
565 | //delete CPolledActiveScheduler::Instance();\r |
566 | \r |
567 | DEBUGPRINT(_L("%i: terminating.."), thisProcess.Id()); \r |
568 | thisProcess.Terminate(0);\r |
569 | }\r |
570 | \r |
571 | \r |
572 | static void CheckForLauncher()\r |
573 | {\r |
574 | RProcess launcherProcess;\r |
575 | \r |
576 | // check for launcher, we are useless without it\r |
577 | if(launcherProcess.Open(launcherProcessId) != KErrNone || launcherProcess.ExitCategory().Length() != 0) {\r |
578 | #ifdef __DEBUG_PRINT\r |
579 | RProcess thisProcess;\r |
580 | DEBUGPRINT(_L("%i: launcher process is gone, terminating.."), thisProcess.Id());\r |
581 | if(launcherProcess.Handle()) {\r |
582 | TExitCategoryName ecn = launcherProcess.ExitCategory();\r |
583 | DEBUGPRINT(_L("%i: launcher exit category: %S"), thisProcess.Id(), &ecn);\r |
584 | launcherProcess.Close();\r |
585 | }\r |
586 | #endif\r |
587 | MainExit();\r |
588 | }\r |
589 | launcherProcess.Close();\r |
590 | }\r |
591 | \r |
592 | \r |
593 | void DumpMemInfo()\r |
594 | {\r |
595 | TInt ramSize, ramSizeFree, romSize;\r |
596 | \r |
597 | HAL::Get(HALData::EMemoryRAM, ramSize);\r |
598 | HAL::Get(HALData::EMemoryRAMFree, ramSizeFree);\r |
599 | HAL::Get(HALData::EMemoryROM, romSize);\r |
600 | \r |
601 | DEBUGPRINT(_L("ram=%dKB, ram_free=%dKB, rom=%dKB"), ramSize/1024, ramSizeFree/1024, romSize/1024);\r |
602 | }\r |
603 | \r |
604 | \r |
605 | \r |
606 | TInt E32Main()\r |
607 | {\r |
608 | // first thing's first\r |
609 | RThread().SetExceptionHandler(&ExceptionHandler, -1);\r |
610 | \r |
611 | //TInt pc, sp;\r |
612 | //asm volatile ("str pc, %0" : "=m" (pc) );\r |
613 | //asm volatile ("str sp, %0" : "=m" (sp) );\r |
614 | //RDebug::Print(_L("executing @ 0x%08x, sp=0x%08x"), pc, sp);\r |
615 | \r |
616 | /*\r |
617 | RDebug::Print(_L("Base Bottom Top Size RW Name"));\r |
618 | TBuf<4> l_r(_L("R")), l_w(_L("W")), l_d(_L("-"));\r |
619 | RChunk chunk;\r |
620 | TFullName chunkname;\r |
621 | TFindChunk findChunk(_L("*"));\r |
622 | while( findChunk.Next(chunkname) != KErrNotFound ) {\r |
623 | chunk.Open(findChunk);\r |
624 | RDebug::Print(_L("%08x %08x %08x %08x %S%S %S"), chunk.Base(), chunk.Base()+chunk.Bottom(), chunk.Base()+chunk.Top(), chunk.Size(), chunk.IsReadable() ? &l_r : &l_d, chunk.IsWritable() ? &l_w : &l_d, &chunkname);\r |
625 | chunk.Close();\r |
626 | }\r |
627 | */\r |
628 | \r |
629 | CTrapCleanup* cleanup=CTrapCleanup::New();\r |
630 | \r |
631 | TRAPD(error, TargetEpocGameL());\r |
632 | \r |
633 | __ASSERT_ALWAYS(!error, User::Panic(_L("Picosmall"), error));\r |
634 | delete cleanup;\r |
635 | \r |
636 | return 0;\r |
637 | }\r |
638 | \r |
639 | \r |
640 | void CGameWindow::ConstructResourcesL()\r |
641 | {\r |
642 | \r |
643 | // connect to window server\r |
644 | // tried to create it globally and not re-connect everytime,\r |
645 | // but my window started to lose focus strangely\r |
646 | User::LeaveIfError(iWsSession.Connect());\r |
647 | \r |
648 | // * Tell the Window Server not to mess about with our process priority\r |
649 | // * Also, because of the way legacy games are written, they never sleep\r |
650 | // * and thus never voluntarily yield the CPU. We set our process priority\r |
651 | // * to EPriorityForeground and hope that a Telephony application on\r |
652 | // * this device runs at EPriorityForeground as well. If not, tough! ;-)\r |
653 | \r |
654 | CGameWindow::iWsSession.ComputeMode(RWsSession::EPriorityControlDisabled);\r |
655 | RProcess me;\r |
656 | me.SetPriority(EPriorityForeground);\r |
657 | \r |
658 | iWsScreen=new(ELeave) CWsScreenDevice(iWsSession);\r |
659 | User::LeaveIfError(iWsScreen->Construct());\r |
660 | // User::LeaveIfError(iWsScreen->CreateContext(iWindowGc));\r |
661 | \r |
662 | iWsWindowGroup=RWindowGroup(iWsSession);\r |
663 | User::LeaveIfError(iWsWindowGroup.Construct((TUint32)&iWsWindowGroup));\r |
664 | //iWsWindowGroup.SetOrdinalPosition(0);\r |
665 | //iWsWindowGroup.SetName(KServerWGName);\r |
666 | iWsWindowGroup.EnableScreenChangeEvents(); // flip events (EEventScreenDeviceChanged)\r |
667 | iWsWindowGroup.EnableFocusChangeEvents(); // EEventFocusGroupChanged\r |
668 | iWsWindowGroup.SetOrdinalPosition(0, 1); // TInt aPos, TInt aOrdinalPriority\r |
669 | \r |
670 | iWsWindow=RWindow(iWsSession);\r |
671 | User::LeaveIfError(iWsWindow.Construct(iWsWindowGroup, (TUint32)&iWsWindow));\r |
672 | iWsWindow.SetSize(iWsScreen->SizeInPixels());\r |
673 | iWsWindow.PointerFilter(EPointerFilterDrag, 0);\r |
674 | iWsWindow.SetPointerGrab(ETrue);\r |
675 | iWsWindow.SetVisible(ETrue);\r |
676 | iWsWindow.Activate();\r |
677 | \r |
678 | // request access through RDirectScreenAccess api, but don't care about the result\r |
679 | RRegion *dsa_region = 0;\r |
680 | iDSA = new(ELeave) RDirectScreenAccess(iWsSession);\r |
681 | if(iDSA->Construct() == KErrNone)\r |
682 | iDSA->Request(dsa_region, iDSAstatus, iWsWindow);\r |
683 | DEBUGPRINT(_L("DSA: %i"), dsa_region ? dsa_region->Count() : -1);\r |
684 | \r |
685 | // now get the screenbuffer\r |
686 | TScreenInfoV01 screenInfo;\r |
687 | TPckg<TScreenInfoV01> sI(screenInfo);\r |
688 | UserSvr::ScreenInfo(sI);\r |
689 | \r |
690 | if(!screenInfo.iScreenAddressValid)\r |
691 | User::Leave(KErrNotSupported);\r |
692 | \r |
693 | #ifndef TEST_FRAMEBUFF\r |
694 | TUint8 *iFrameBuffer = (TUint8*) screenInfo.iScreenAddress;\r |
695 | #endif\r |
696 | TInt p800 = 0;\r |
697 | \r |
698 | switch(machineUid)\r |
699 | {\r |
700 | case 0x101f6b26: // A9xx & A10xx\r |
701 | case 0x101f6b27: // Chinese A10xx\r |
702 | case 0x101fd279: // P3x\r |
703 | iFrameBuffer += 32;\r |
704 | keyConfig = keyConfigMotA;\r |
705 | break;\r |
706 | case 0x101f408b: // P800\r |
707 | p800 = 1;\r |
708 | //case 0x101fb2ae: // P900\r |
709 | //case 0x10200ac6: // P910\r |
710 | default: \r |
711 | keyConfig = keyConfigPXXX;\r |
712 | break;\r |
713 | }\r |
714 | DEBUGPRINT(_L("framebuffer=0x%08x (%dx%d)"), iFrameBuffer,\r |
715 | screenInfo.iScreenSize.iWidth, screenInfo.iScreenSize.iHeight);\r |
716 | \r |
717 | // vidInit\r |
718 | User::LeaveIfError(vidInit(iWsScreen->DisplayMode(), iFrameBuffer, p800));\r |
719 | \r |
720 | // register for keyevents\r |
721 | for(TPicoKeyConfigEntry *e = keyConfig; e->name; e++) {\r |
722 | // release all keys\r |
723 | e->flags &= ~1;\r |
724 | if(e->flags & 0x80) {\r |
725 | // key disabled\r |
726 | e->handle1 = e->handle2 = -1;\r |
727 | continue;\r |
728 | }\r |
729 | e->handle1 = iWsWindowGroup.CaptureKeyUpAndDowns(e->scanCode, 0, 0, 2);\r |
730 | // although we only use UpAndDown events, register simple events too,\r |
731 | // just to prevent fireing their default actions.\r |
732 | if(e->keyCode) e->handle2 = iWsWindowGroup.CaptureKey(e->keyCode, 0, 0, 2); // priority of 1 is not enough on my phone\r |
733 | }\r |
734 | \r |
735 | // try to start the audio engine\r |
736 | static int PsndRate_old = 0, PicoOpt_old = 0, pal_old = 0;\r |
737 | \r |
738 | if(gamestate == PGS_Running && (currentConfig.iFlags & 4)) {\r |
739 | TInt err = 0;\r |
740 | if(PsndRate != PsndRate_old || (PicoOpt&11) != (PicoOpt_old&11) || Pico.m.pal != pal_old) {\r |
741 | // if rate changed, reset all enabled chips, else reset only those chips, which were recently enabled\r |
742 | //sound_reset(PsndRate != PsndRate_old ? PicoOpt : (PicoOpt&(PicoOpt^PicoOpt_old)));\r |
743 | sound_rerate();\r |
744 | }\r |
745 | if(!gameAudio || PsndRate != PsndRate_old || ((PicoOpt&8) ^ (PicoOpt_old&8)) || Pico.m.pal != pal_old) { // rate or stereo or pal/ntsc changed\r |
746 | if(gameAudio) delete gameAudio; gameAudio = 0;\r |
747 | DEBUGPRINT(_L("starting audio: %i len: %i stereo: %i, pal: %i"), PsndRate, PsndLen, PicoOpt&8, Pico.m.pal);\r |
748 | TRAP(err, gameAudio = gameAudioNew(PsndRate, (PicoOpt&8) ? 1 : 0, PsndLen, Pico.m.pal ? 10 : 12));\r |
749 | }\r |
750 | if( gameAudio)\r |
751 | TRAP(err, PsndOut = gameAudio->ResumeL());\r |
752 | if(err) {\r |
753 | if(gameAudio) delete gameAudio;\r |
754 | gameAudio = 0;\r |
755 | PsndOut = 0;\r |
756 | strcpy(noticeMsg, "SOUND@STARTUP@FAILED");\r |
757 | gettimeofday(¬iceMsgTime, 0);\r |
758 | }\r |
759 | PsndRate_old = PsndRate;\r |
760 | PicoOpt_old = PicoOpt;\r |
761 | pal_old = Pico.m.pal;\r |
762 | } else {\r |
763 | if(gameAudio) delete gameAudio;\r |
764 | gameAudio = 0;\r |
765 | PsndOut = 0;\r |
766 | }\r |
767 | \r |
768 | // start key WS event polling\r |
769 | iWsSession.EventReady(&iWsEventStatus);\r |
770 | DEBUGPRINT(_L("CGameWindow::ConstructResourcesL() finished."));\r |
771 | }\r |
772 | \r |
773 | \r |
774 | void CGameWindow::FreeResources()\r |
775 | {\r |
776 | if(gameAudio) gameAudio->Pause();\r |
777 | \r |
778 | // free RDirectScreenAccess stuff\r |
779 | iDSA->Cancel();\r |
780 | iDSA->Close();\r |
781 | delete iDSA;\r |
782 | iDSA = NULL;\r |
783 | \r |
784 | iWsSession.EventReadyCancel();\r |
785 | \r |
786 | for(TPicoKeyConfigEntry *e = keyConfig; e->name; e++) {\r |
787 | if(e->handle2 >= 0) iWsWindowGroup.CancelCaptureKey(e->handle2);\r |
788 | if(e->handle1 >= 0) iWsWindowGroup.CancelCaptureKeyUpAndDowns(e->handle1);\r |
789 | }\r |
790 | \r |
791 | if(iWsWindow.WsHandle())\r |
792 | iWsWindow.Close();\r |
793 | \r |
794 | if(iWsWindowGroup.WsHandle())\r |
795 | iWsWindowGroup.Close();\r |
796 | \r |
797 | // these must be deleted before calling iWsSession.Close()\r |
798 | // delete iWindowGc;\r |
799 | // iWindowGc = NULL;\r |
800 | \r |
801 | delete iWsScreen;\r |
802 | iWsScreen = NULL;\r |
803 | \r |
804 | // emu might change renderer by itself, so we may need to sync config\r |
805 | if(PicoOpt != currentConfig.iPicoOpt) {\r |
806 | currentConfig.iFlags |= 0x80;\r |
807 | CGameWindow::SendClientWsEvent(EEventKeyCfgDone);\r |
808 | }\r |
809 | \r |
810 | if(iWsSession.WsHandle())\r |
811 | iWsSession.Close();\r |
812 | \r |
813 | vidFree();\r |
814 | \r |
815 | #ifdef TEST_FRAMEBUFF\r |
816 | FILE *tmp = fopen("d:\\temp\\screen.raw", "wb");\r |
817 | fwrite(iFrameBuffer, 1, 208*320*4, tmp);\r |
818 | fclose(tmp);\r |
819 | #endif\r |
820 | }\r |
821 | \r |
822 | \r |
823 | void CGameWindow::DoKeys(timeval &time)\r |
824 | {\r |
825 | TWsEvent iWsEvent;\r |
826 | TInt iWsEventType;\r |
827 | unsigned long allActions = 0;\r |
828 | static unsigned long areaActions = 0, forceUpdate = 0;\r |
829 | int i, nEvents;\r |
830 | \r |
831 | // detect if user is holding power button\r |
832 | static timeval powerPushed = { 0, 0 };\r |
833 | if(powerPushed.tv_sec) {\r |
834 | if((time.tv_sec*1000000+time.tv_usec) - (powerPushed.tv_sec*1000000+powerPushed.tv_usec) > 1000000) { // > 1 sec\r |
835 | gamestate = PGS_Paused;\r |
836 | powerPushed.tv_sec = powerPushed.tv_usec = 0;\r |
837 | }\r |
838 | }\r |
839 | \r |
840 | for(nEvents = 0; iWsEventStatus != KRequestPending; nEvents++)\r |
841 | {\r |
842 | iWsSession.GetEvent(iWsEvent);\r |
843 | iWsEventType = iWsEvent.Type();\r |
844 | \r |
845 | // pointer events?\r |
846 | if(iWsEventType == EEventPointer) {\r |
847 | if(iWsEvent.Pointer()->iType == TPointerEvent::EButton1Up) {\r |
848 | areaActions = 0; // remove all directionals\r |
849 | } else { // if(iWsEvent.Pointer()->iType == TPointerEvent::EButton1Down) {\r |
850 | TPoint p = iWsEvent.Pointer()->iPosition;\r |
851 | const TPicoAreaConfigEntry *e = areaConfig + 1;\r |
852 | for(i = 0; !e->rect.IsEmpty(); e++, i++)\r |
853 | if(e->rect.Contains(p)) {\r |
854 | areaActions = currentConfig.iAreaBinds[i];\r |
855 | break;\r |
856 | }\r |
857 | }\r |
858 | }\r |
859 | else if(iWsEventType == EEventKeyDown || iWsEventType == EEventKeyUp) {\r |
860 | TInt iScanCode = iWsEvent.Key()->iScanCode;\r |
861 | \r |
862 | for(TPicoKeyConfigEntry *e = keyConfig; e->name; e++)\r |
863 | if(iScanCode == e->scanCode) {\r |
864 | if(iWsEventType == EEventKeyDown) e->flags |= 1;\r |
865 | else if((e->flags & 2) == 0) e->flags &= ~1;\r |
866 | break;\r |
867 | }\r |
868 | \r |
869 | // power?\r |
870 | if(iScanCode == EScanPxxxPower || iScanCode == EScanMotAEnd) {\r |
871 | if(iWsEventType == EEventKeyDown)\r |
872 | powerPushed = time;\r |
873 | else powerPushed.tv_sec = powerPushed.tv_usec = 0;\r |
874 | }\r |
875 | }\r |
876 | else if(iWsEventType == EEventScreenDeviceChanged) {\r |
877 | // we have the priority, so the launcher will not be able to process this, but it has to\r |
878 | User::After(500000);\r |
879 | reset_timing = 1;\r |
880 | }\r |
881 | else if(iWsEventType == EEventFocusGroupChanged) {\r |
882 | TInt launcherGrpId = iWsSession.FindWindowGroupIdentifier(0, iLauncherThreadId);\r |
883 | TInt focusGrpId = iWsSession.GetFocusWindowGroup();\r |
884 | DEBUGPRINT(_L("EEventFocusGroupChanged: %i, our: %i, launcher: %i"),\r |
885 | focusGrpId, iWsWindowGroup.Identifier(), launcherGrpId);\r |
886 | // if it is not us and not launcher that got focus, pause emu\r |
887 | if(focusGrpId != iWsWindowGroup.Identifier() && focusGrpId != launcherGrpId)\r |
888 | gamestate = PGS_Paused;\r |
889 | }\r |
890 | \r |
891 | iWsEventStatus = KRequestPending;\r |
892 | iWsSession.EventReady(&iWsEventStatus);\r |
893 | }\r |
894 | \r |
895 | if(nEvents || forceUpdate) {\r |
896 | allActions = areaActions;\r |
897 | forceUpdate = 0;\r |
898 | \r |
899 | // add all pushed button actions\r |
900 | i = 0;\r |
901 | for(TPicoKeyConfigEntry *e = keyConfig; e->name; e++, i++) {\r |
902 | if(e->flags & 1) allActions |= currentConfig.iKeyBinds[i];\r |
903 | if((e->flags& 3) == 3) forceUpdate = 1;\r |
904 | if(e->flags & 2) e->flags &= ~1;\r |
905 | }\r |
906 | \r |
907 | PicoPad[0] = (unsigned short) allActions;\r |
908 | if(allActions & 0xFFFF0000) {\r |
909 | RunEvents(allActions >> 16);\r |
910 | areaActions = 0;\r |
911 | }\r |
912 | }\r |
913 | }\r |
914 | \r |
915 | \r |
916 | void CGameWindow::DoKeysConfig(TUint &which)\r |
917 | {\r |
918 | TWsEvent iWsEvent;\r |
919 | int i;\r |
920 | \r |
921 | // to detect if user is holding power button\r |
922 | static int powerIters = 0;\r |
923 | \r |
924 | while(iWsEventStatus != KRequestPending)\r |
925 | {\r |
926 | TUint currentActCode = 1 << which;\r |
927 | \r |
928 | iWsSession.GetEvent(iWsEvent);\r |
929 | \r |
930 | // pointer events?\r |
931 | if(iWsEvent.Type() == EEventPointer) {\r |
932 | TPoint p = iWsEvent.Pointer()->iPosition;\r |
933 | TRect prev(190, 112, 208, 126);\r |
934 | TRect next(190, 194, 208, 208);\r |
935 | \r |
936 | if(iWsEvent.Pointer()->iType == TPointerEvent::EButton1Down) {\r |
937 | if(prev.Contains(p)) do { which = (which-1) & 0x1F; } while(!actionNames[which]);\r |
938 | else if(next.Contains(p)) do { which = (which+1) & 0x1F; } while(!actionNames[which]);\r |
939 | else if(which == 31) gamestate = PGS_Paused; // done\r |
940 | else {\r |
941 | const TPicoAreaConfigEntry *e = areaConfig + 1;\r |
942 | for(i = 0; e->rect != TRect(0,0,0,0); e++, i++)\r |
943 | if(e->rect.Contains(p)) {\r |
944 | currentConfig.iAreaBinds[i] ^= currentActCode;\r |
945 | break;\r |
946 | }\r |
947 | }\r |
948 | }\r |
949 | }\r |
950 | else if(iWsEvent.Type() == EEventKeyDown || iWsEvent.Type() == EEventKeyUp)\r |
951 | {\r |
952 | //if(iWsEvent.Type() == EEventKey)\r |
953 | // DEBUGPRINT(_L("iWsEvent.Key()->iCode=0x%08x"), iWsEvent.Key()->iCode);\r |
954 | \r |
955 | //if(iWsEvent.Type() == EEventKeyDown)\r |
956 | // DEBUGPRINT(_L("EEventKeyDown iScanCode=0x%08x"), iWsEvent.Key()->iScanCode);\r |
957 | \r |
958 | //if(iWsEvent.Type() == EEventKeyUp)\r |
959 | // DEBUGPRINT(_L("EEventKeyUp iScanCode=0x%08x"), iWsEvent.Key()->iScanCode);\r |
960 | \r |
961 | // key events?\r |
962 | if(iWsEvent.Type() == EEventKeyDown) {\r |
963 | if(iWsScreen->CurrentScreenMode() == 1 && iWsEvent.Key()->iScanCode == EScanPxxxJogUp) {\r |
964 | do { which = (which-1) & 0x1F; } while(!actionNames[which]);\r |
965 | } else if(iWsScreen->CurrentScreenMode() == 1 && iWsEvent.Key()->iScanCode == EScanPxxxJogDown) {\r |
966 | do { which = (which+1) & 0x1F; } while(!actionNames[which]);\r |
967 | } else if(which == 31) {\r |
968 | gamestate = PGS_Paused;\r |
969 | if(iWsScreen->CurrentScreenMode()) // flip closed\r |
970 | vidDrawFCconfigDone();\r |
971 | } else {\r |
972 | i = 0;\r |
973 | for(TPicoKeyConfigEntry *e = keyConfig; e->name; e++, i++)\r |
974 | if(iWsEvent.Key()->iScanCode == e->scanCode)\r |
975 | if(!(e->flags&0x40)) currentConfig.iKeyBinds[i] ^= currentActCode;\r |
976 | }\r |
977 | }\r |
978 | \r |
979 | // power?\r |
980 | if(iWsEvent.Key()->iScanCode == EScanPxxxPower || iWsEvent.Key()->iScanCode == EScanMotAEnd)\r |
981 | {\r |
982 | if(iWsEvent.Type() == EEventKeyDown) powerIters = 1;\r |
983 | else if(iWsEvent.Type() == EEventKeyUp) powerIters = 0;\r |
984 | }\r |
985 | }\r |
986 | else if(iWsEvent.Type() == EEventScreenDeviceChanged) {\r |
987 | // trying to fix the P910 problem when something steals focus (and returns it after a while?)\r |
988 | User::After(300000);\r |
989 | }\r |
990 | else if(iWsEvent.Type() == EEventFocusGroupChanged) {\r |
991 | TInt launcherGrpId = iWsSession.FindWindowGroupIdentifier(0, iLauncherThreadId);\r |
992 | TInt focusGrpId = iWsSession.GetFocusWindowGroup();\r |
993 | DEBUGPRINT(_L("EEventFocusGroupChanged: %i, our: %i, launcher: %i"),\r |
994 | focusGrpId, iWsWindowGroup.Identifier(), launcherGrpId);\r |
995 | // if it is not us and not launcher that got focus, exit config mode\r |
996 | if(focusGrpId != iWsWindowGroup.Identifier() && focusGrpId != launcherGrpId) {\r |
997 | // don't give up that easily. May be the focus will be given back.\r |
998 | for (int i = 0; i < 4; i++) {\r |
999 | User::After(200000);\r |
1000 | focusGrpId = iWsSession.GetFocusWindowGroup();\r |
1001 | if(focusGrpId == iWsWindowGroup.Identifier() || focusGrpId == launcherGrpId) break;\r |
1002 | }\r |
1003 | if(focusGrpId != iWsWindowGroup.Identifier() && focusGrpId != launcherGrpId) \r |
1004 | // we probably should give up now\r |
1005 | gamestate = PGS_Paused;\r |
1006 | }\r |
1007 | }\r |
1008 | \r |
1009 | iWsEventStatus = KRequestPending;\r |
1010 | iWsSession.EventReady(&iWsEventStatus);\r |
1011 | }\r |
1012 | \r |
1013 | if(powerIters) { // iterations when power was down\r |
1014 | powerIters++;\r |
1015 | if(powerIters > 5) {\r |
1016 | gamestate = PGS_Paused;\r |
1017 | powerIters = 0;\r |
1018 | }\r |
1019 | }\r |
1020 | }\r |
1021 | \r |
1022 | \r |
1023 | void CGameWindow::RunEvents(TUint32 which)\r |
1024 | {\r |
1025 | if(which & 0x4000) currentConfig.iFrameskip = -1;\r |
1026 | if(which & 0x2000) currentConfig.iFrameskip = 8;\r |
1027 | if(which & 0x1800) { // save or load (but not both)\r |
1028 | if(PsndOut) gameAudio->Pause(); // this may take a while, so we pause sound output\r |
1029 | \r |
1030 | vidDrawNotice((which & 0x1000) ? "LOADING@GAME" : "SAVING@GAME");\r |
1031 | saveLoadGame(which & 0x1000);\r |
1032 | \r |
1033 | if(PsndOut) PsndOut = gameAudio->ResumeL();\r |
1034 | reset_timing = 1;\r |
1035 | }\r |
1036 | if(which & 0x0400) gamestate = PGS_Paused;\r |
1037 | if(which & 0x0200) { // switch renderer\r |
1038 | if(currentConfig.iScreenMode == TPicoConfig::PMCenter && !noticeMsgTime.tv_sec &&\r |
1039 | (currentConfig.iScreenRotation == TPicoConfig::PRot90 || currentConfig.iScreenRotation == TPicoConfig::PRot270)) {\r |
1040 | \r |
1041 | PicoOpt^=0x10;\r |
1042 | vidInit(iWsScreen->DisplayMode(), 0, 0, 1);\r |
1043 | \r |
1044 | strcpy(noticeMsg, (PicoOpt&0x10) ? "ALT@RENDERER" : "DEFAULT@RENDERER");\r |
1045 | gettimeofday(¬iceMsgTime, 0);\r |
1046 | }\r |
1047 | }\r |
1048 | if(which & 0x00c0) {\r |
1049 | if(which&0x0080) {\r |
1050 | state_slot -= 1;\r |
1051 | if(state_slot < 0) state_slot = 9;\r |
1052 | } else {\r |
1053 | state_slot += 1;\r |
1054 | if(state_slot > 9) state_slot = 0;\r |
1055 | }\r |
1056 | sprintf(noticeMsg, "SAVE@SLOT@%i@SELECTED", state_slot);\r |
1057 | gettimeofday(¬iceMsgTime, 0);\r |
1058 | }\r |
1059 | if(which & 0x0020) if(gameAudio) gameAudio->ChangeVolume(0); // for Motorolas (broken?)\r |
1060 | if(which & 0x0010) if(gameAudio) gameAudio->ChangeVolume(1);\r |
1061 | }\r |
1062 | \r |
1063 | \r |
1064 | // send event to launcher windowgroup (WS session MUST be alive)\r |
1065 | void CGameWindow::SendClientWsEvent(TInt type)\r |
1066 | {\r |
1067 | if(!iWsSession.Handle()) {\r |
1068 | DEBUGPRINT(_L("SendClientWsEvent(%i) called on dead iWsSession."), type);\r |
1069 | return;\r |
1070 | }\r |
1071 | \r |
1072 | TWsEvent event;\r |
1073 | event.SetType(type);\r |
1074 | event.SetTimeNow();\r |
1075 | \r |
1076 | TInt launcherGrpId = iWsSession.FindWindowGroupIdentifier(0, iLauncherThreadId);\r |
1077 | if(launcherGrpId != KErrNotFound)\r |
1078 | iWsSession.SendEventToWindowGroup(launcherGrpId, event);\r |
1079 | else DEBUGPRINT(_L("failed to send event %i to launcher."), event.Type());\r |
1080 | }\r |
1081 | \r |
1082 | \r |
1083 | size_t gzRead2(void *p, size_t _size, size_t _n, void *file)\r |
1084 | {\r |
1085 | return gzread(file, p, _n);\r |
1086 | }\r |
1087 | \r |
1088 | \r |
1089 | size_t gzWrite2(void *p, size_t _size, size_t _n, void *file)\r |
1090 | {\r |
1091 | return gzwrite(file, p, _n);\r |
1092 | }\r |
1093 | \r |
1094 | \r |
1095 | // this function is shared between both threads\r |
1096 | int saveLoadGame(int load, int sram)\r |
1097 | {\r |
1098 | int res = 0;\r |
1099 | \r |
1100 | if(!RomFileName) return -1;\r |
1101 | \r |
1102 | // make save filename\r |
1103 | char saveFname[KMaxFileName];\r |
1104 | strcpy(saveFname, RomFileName);\r |
1105 | saveFname[KMaxFileName-8] = 0;\r |
1106 | if(saveFname[strlen(saveFname)-4] == '.') saveFname[strlen(saveFname)-4] = 0;\r |
1107 | if(sram) strcat(saveFname, ".srm");\r |
1108 | else {\r |
1109 | if(state_slot > 0 && state_slot < 10) sprintf(saveFname, "%s.%i", saveFname, state_slot);\r |
1110 | strcat(saveFname, ".mds");\r |
1111 | }\r |
1112 | \r |
1113 | DEBUGPRINT(_L("saveLoad (%i, %i): %S"), load, sram, DO_CONV(saveFname));\r |
1114 | \r |
1115 | if(sram) {\r |
1116 | FILE *sramFile;\r |
1117 | int sram_size = SRam.end-SRam.start+1;\r |
1118 | if(SRam.reg_back & 4) sram_size=0x2000;\r |
1119 | if(!SRam.data) return 0; // SRam forcefully disabled for this game\r |
1120 | if(load) {\r |
1121 | sramFile = fopen(saveFname, "rb");\r |
1122 | if(!sramFile) return -1;\r |
1123 | fread(SRam.data, 1, sram_size, sramFile);\r |
1124 | fclose(sramFile);\r |
1125 | } else {\r |
1126 | // sram save needs some special processing\r |
1127 | // see if we have anything to save\r |
1128 | for(; sram_size > 0; sram_size--)\r |
1129 | if(SRam.data[sram_size-1]) break;\r |
1130 | \r |
1131 | if(sram_size) {\r |
1132 | sramFile = fopen(saveFname, "wb");\r |
1133 | res = fwrite(SRam.data, 1, sram_size, sramFile);\r |
1134 | res = (res != sram_size) ? -1 : 0;\r |
1135 | fclose((FILE *) sramFile);\r |
1136 | }\r |
1137 | }\r |
1138 | return res;\r |
1139 | } else {\r |
1140 | void *PmovFile = NULL;\r |
1141 | // try gzip first\r |
1142 | if(currentConfig.iFlags & 0x80) {\r |
1143 | strcat(saveFname, ".gz");\r |
1144 | if( (PmovFile = gzopen(saveFname, load ? "rb" : "wb")) ) {\r |
1145 | areaRead = gzRead2;\r |
1146 | areaWrite = gzWrite2;\r |
1147 | if(!load) gzsetparams(PmovFile, 9, Z_DEFAULT_STRATEGY);\r |
1148 | } else\r |
1149 | saveFname[strlen(saveFname)-3] = 0;\r |
1150 | }\r |
1151 | if(!PmovFile) { // gzip failed or was disabled\r |
1152 | if( (PmovFile = fopen(saveFname, load ? "rb" : "wb")) ) {\r |
1153 | areaRead = fread;\r |
1154 | areaWrite = fwrite;\r |
1155 | }\r |
1156 | }\r |
1157 | if(PmovFile) {\r |
1158 | PmovState(load ? 6 : 5, PmovFile);\r |
1159 | strcpy(noticeMsg, load ? "GAME@LOADED" : "GAME@SAVED");\r |
1160 | if(areaRead == gzRead2)\r |
1161 | gzclose(PmovFile);\r |
1162 | else fclose ((FILE *) PmovFile);\r |
1163 | PmovFile = 0;\r |
1164 | } else {\r |
1165 | strcpy(noticeMsg, load ? "LOAD@FAILED" : "SAVE@FAILED");\r |
1166 | res = -1;\r |
1167 | }\r |
1168 | \r |
1169 | gettimeofday(¬iceMsgTime, 0);\r |
1170 | return res;\r |
1171 | }\r |
1172 | }\r |
1173 | \r |
1174 | // static class members\r |
1175 | RWsSession CGameWindow::iWsSession;\r |
1176 | RWindowGroup CGameWindow::iWsWindowGroup;\r |
1177 | RWindow CGameWindow::iWsWindow;\r |
1178 | CWsScreenDevice* CGameWindow::iWsScreen = NULL;\r |
1179 | CWindowGc* CGameWindow::iWindowGc = NULL;\r |
1180 | TRequestStatus CGameWindow::iWsEventStatus = KRequestPending;\r |
1181 | TThreadId CGameWindow::iLauncherThreadId = 0;\r |
1182 | RDirectScreenAccess* CGameWindow::iDSA;\r |
1183 | TRequestStatus CGameWindow::iDSAstatus = KRequestPending;\r |