1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11 
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16 
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #define FORBIDDEN_SYMBOL_ALLOW_ALL
24 
25 #include <unistd.h>
26 #include <sys/time.h>
27 #include <list>
28 
29 #include <retro_miscellaneous.h>
30 #include <retro_inline.h>
31 
32 #include "graphics/surface.libretro.h"
33 #include "backends/base-backend.h"
34 #include "common/events.h"
35 #include "audio/mixer_intern.h"
36 
37 #if defined(_WIN32)
38 #include "backends/fs/windows/windows-fs-factory.h"
39 #define FS_SYSTEM_FACTORY WindowsFilesystemFactory
40 #else
41 #include "backends/fs/libretro/libretro-fs-factory.h"
42 #define FS_SYSTEM_FACTORY LibRetroFilesystemFactory
43 #endif
44 
45 #include "backends/timer/default/default-timer.h"
46 #include "graphics/colormasks.h"
47 #include "graphics/palette.h"
48 #include "backends/saves/default/default-saves.h"
49 #if defined(_WIN32)
50 #include <direct.h>
51 #ifdef _XBOX
52 #include <xtl.h>
53 #else
54 #include <windows.h>
55 #endif
56 #elif defined(__CELLOS_LV2__)
57 #include <sys/sys_time.h>
58 #elif (defined(GEKKO) && !defined(WIIU))
59 #include <ogc/lwp_watchdog.h>
60 #else
61 #include <time.h>
62 #endif
63 
64 #include "libretro.h"
65 
66 extern retro_log_printf_t log_cb;
67 
68 struct RetroPalette
69 {
70    unsigned char _colors[256 * 3];
71 
RetroPaletteRetroPalette72    RetroPalette()
73    {
74       memset(_colors, 0, sizeof(_colors));
75    }
76 
setRetroPalette77    void set(const byte *colors, uint start, uint num)
78    {
79       memcpy(_colors + start * 3, colors, num * 3);
80    }
81 
getRetroPalette82    void get(byte* colors, uint start, uint num) const
83    {
84       memcpy(colors, _colors + start * 3, num * 3);
85    }
86 
getColorRetroPalette87    unsigned char *getColor(uint aIndex) const
88    {
89       return (unsigned char*)&_colors[aIndex * 3];
90    }
91 };
92 
blit_uint8_uint16_fast(Graphics::Surface & aOut,const Graphics::Surface & aIn,const RetroPalette & aColors)93 static INLINE void blit_uint8_uint16_fast(Graphics::Surface& aOut, const Graphics::Surface& aIn, const RetroPalette& aColors)
94 {
95    for(int i = 0; i < aIn.h; i ++)
96    {
97       if(i >= aOut.h)
98          continue;
99 
100       uint8_t * const in  = (uint8_t*)aIn.pixels + (i * aIn.w);
101       uint16_t* const out = (uint16_t*)aOut.pixels + (i * aOut.w);
102 
103       for(int j = 0; j < aIn.w; j ++)
104       {
105          if (j >= aOut.w)
106             continue;
107 
108          uint8 r, g, b;
109 
110          const uint8_t val = in[j];
111          if(val != 0xFFFFFFFF)
112          {
113             if(aIn.format.bytesPerPixel == 1)
114             {
115                unsigned char *col = aColors.getColor(val);
116                r = *col++;
117                g = *col++;
118                b = *col++;
119             }
120             else
121                aIn.format.colorToRGB(in[j], r, g, b);
122 
123             out[j] = aOut.format.RGBToColor(r, g, b);
124          }
125       }
126    }
127 }
128 
blit_uint32_uint16(Graphics::Surface & aOut,const Graphics::Surface & aIn,const RetroPalette & aColors)129 static INLINE void blit_uint32_uint16(Graphics::Surface& aOut, const Graphics::Surface& aIn, const RetroPalette& aColors)
130 {
131    for(int i = 0; i < aIn.h; i ++)
132    {
133       if(i >= aOut.h)
134          continue;
135 
136       uint32_t* const in = (uint32_t*)aIn.pixels + (i * aIn.w);
137       uint16_t* const out = (uint16_t*)aOut.pixels + (i * aOut.w);
138 
139       for(int j = 0; j < aIn.w; j ++)
140       {
141          if(j >= aOut.w)
142             continue;
143 
144          uint8 r, g, b;
145 
146          const uint32_t val = in[j];
147          if(val != 0xFFFFFFFF)
148          {
149             aIn.format.colorToRGB(in[j], r, g, b);
150             out[j] = aOut.format.RGBToColor(r, g, b);
151          }
152       }
153    }
154 }
155 
blit_uint16_uint16(Graphics::Surface & aOut,const Graphics::Surface & aIn,const RetroPalette & aColors)156 static INLINE void blit_uint16_uint16(Graphics::Surface& aOut, const Graphics::Surface& aIn, const RetroPalette& aColors)
157 {
158    for(int i = 0; i < aIn.h; i ++)
159    {
160       if(i >= aOut.h)
161          continue;
162 
163       uint16_t* const in = (uint16_t*)aIn.pixels + (i * aIn.w);
164       uint16_t* const out = (uint16_t*)aOut.pixels + (i * aOut.w);
165 
166       for(int j = 0; j < aIn.w; j ++)
167       {
168          if(j >= aOut.w)
169             continue;
170 
171          uint8 r, g, b;
172 
173          const uint16_t val = in[j];
174          if(val != 0xFFFFFFFF)
175          {
176             aIn.format.colorToRGB(in[j], r, g, b);
177             out[j] = aOut.format.RGBToColor(r, g, b);
178          }
179       }
180    }
181 }
182 
blit_uint8_uint16(Graphics::Surface & aOut,const Graphics::Surface & aIn,int aX,int aY,const RetroPalette & aColors,uint32 aKeyColor)183 static void blit_uint8_uint16(Graphics::Surface& aOut, const Graphics::Surface& aIn, int aX, int aY, const RetroPalette& aColors, uint32 aKeyColor)
184 {
185    for(int i = 0; i < aIn.h; i ++)
186    {
187       if((i + aY) < 0 || (i + aY) >= aOut.h)
188          continue;
189 
190       uint8_t* const in = (uint8_t*)aIn.pixels + (i * aIn.w);
191       uint16_t* const out = (uint16_t*)aOut.pixels + ((i + aY) * aOut.w);
192 
193       for(int j = 0; j < aIn.w; j ++)
194       {
195          if((j + aX) < 0 || (j + aX) >= aOut.w)
196             continue;
197 
198          uint8 r, g, b;
199 
200          const uint8_t val = in[j];
201          if(val != aKeyColor)
202          {
203             unsigned char *col = aColors.getColor(val);
204             r = *col++;
205             g = *col++;
206             b = *col++;
207             out[j + aX] = aOut.format.RGBToColor(r, g, b);
208          }
209       }
210    }
211 }
212 
blit_uint16_uint16(Graphics::Surface & aOut,const Graphics::Surface & aIn,int aX,int aY,const RetroPalette & aColors,uint32 aKeyColor)213 static void blit_uint16_uint16(Graphics::Surface& aOut, const Graphics::Surface& aIn, int aX, int aY, const RetroPalette& aColors, uint32 aKeyColor)
214 {
215    for(int i = 0; i < aIn.h; i ++)
216    {
217       if((i + aY) < 0 || (i + aY) >= aOut.h)
218          continue;
219 
220       uint16_t* const in = (uint16_t*)aIn.pixels + (i * aIn.w);
221       uint16_t* const out = (uint16_t*)aOut.pixels + ((i + aY) * aOut.w);
222 
223       for(int j = 0; j < aIn.w; j ++)
224       {
225          if((j + aX) < 0 || (j + aX) >= aOut.w)
226             continue;
227 
228          uint8 r, g, b;
229 
230          const uint16_t val = in[j];
231          if(val != aKeyColor)
232          {
233             aIn.format.colorToRGB(in[j], r, g, b);
234             out[j + aX] = aOut.format.RGBToColor(r, g, b);
235          }
236       }
237    }
238 }
239 
copyRectToSurface(uint8_t * pixels,int out_pitch,const uint8_t * src,int pitch,int x,int y,int w,int h,int out_bpp)240 static INLINE void copyRectToSurface(uint8_t *pixels, int out_pitch, const uint8_t *src, int pitch, int x, int y, int w, int h, int out_bpp)
241 {
242    uint8_t *dst = pixels + y * out_pitch + x * out_bpp;
243 
244    do
245    {
246       memcpy(dst, src, w * out_bpp);
247       src += pitch;
248       dst += out_pitch;
249    }while(--h);
250 }
251 
252 static Common::String s_systemDir;
253 static Common::String s_saveDir;
254 
255 #ifdef FRONTEND_SUPPORTS_RGB565
256 #define SURF_BPP 2
257 #define SURF_RBITS 2
258 #define SURF_GBITS 5
259 #define SURF_BBITS 6
260 #define SURF_ABITS 5
261 #define SURF_ALOSS (8-SURF_ABITS)
262 #define SURF_RLOSS (8-SURF_RBITS)
263 #define SURF_GLOSS (8-SURF_GBITS)
264 #define SURF_BLOSS (8-SURF_BBITS)
265 #define SURF_RSHIFT 0
266 #define SURF_GSHIFT 11
267 #define SURF_BSHIFT 5
268 #define SURF_ASHIFT 0
269 #else
270 #define SURF_BPP 2
271 #define SURF_RBITS 5
272 #define SURF_GBITS 5
273 #define SURF_BBITS 5
274 #define SURF_ABITS 1
275 #define SURF_ALOSS (8-SURF_ABITS)
276 #define SURF_RLOSS (8-SURF_RBITS)
277 #define SURF_GLOSS (8-SURF_GBITS)
278 #define SURF_BLOSS (8-SURF_BBITS)
279 #define SURF_RSHIFT 10
280 #define SURF_GSHIFT 5
281 #define SURF_BSHIFT 0
282 #define SURF_ASHIFT 15
283 #endif
284 
285 std::list<Common::Event> _events;
286 
287 class OSystem_RETRO : public EventsBaseBackend, public PaletteManager {
288    public:
289       Graphics::Surface _screen;
290 
291       Graphics::Surface _gameScreen;
292       RetroPalette _gamePalette;
293 
294       Graphics::Surface _overlay;
295       bool _overlayVisible;
296 
297       Graphics::Surface _mouseImage;
298       RetroPalette _mousePalette;
299       bool _mousePaletteEnabled;
300       bool _mouseVisible;
301       int _mouseX;
302       int _mouseY;
303       float _mouseXAcc;
304       float _mouseYAcc;
305       int _mouseHotspotX;
306       int _mouseHotspotY;
307       int _mouseKeyColor;
308       bool _mouseDontScale;
309       bool _mouseButtons[2];
310       bool _joypadmouseButtons[2];
311       bool _joypadkeyboardButtons[8];
312       unsigned _joypadnumpadLast;
313       bool _joypadnumpadActive;
314       bool _ptrmouseButton;
315 
316       uint32 _startTime;
317       uint32 _threadExitTime;
318 
319       bool _speed_hack_enabled;
320 
321 
322       Audio::MixerImpl* _mixer;
323 
324 
OSystem_RETRO(bool aEnableSpeedHack)325       OSystem_RETRO(bool aEnableSpeedHack) :
326          _mousePaletteEnabled(false), _mouseVisible(false),
327          _mouseX(0), _mouseY(0), _mouseXAcc(0.0), _mouseYAcc(0.0), _mouseHotspotX(0), _mouseHotspotY(0),
328          _mouseKeyColor(0), _mouseDontScale(false),
329          _joypadnumpadLast(8), _joypadnumpadActive(false),
330          _mixer(0), _startTime(0), _threadExitTime(10),
331          _speed_hack_enabled(aEnableSpeedHack)
332    {
333       _fsFactory = new FS_SYSTEM_FACTORY();
334       memset(_mouseButtons, 0, sizeof(_mouseButtons));
335       memset(_joypadmouseButtons, 0, sizeof(_joypadmouseButtons));
336       memset(_joypadkeyboardButtons, 0, sizeof(_joypadkeyboardButtons));
337 
338       _startTime = getMillis();
339 
340       if(s_systemDir.empty())
341          s_systemDir = ".";
342 
343       if(s_saveDir.empty())
344          s_saveDir = ".";
345    }
346 
~OSystem_RETRO()347       virtual ~OSystem_RETRO()
348       {
349          _gameScreen.free();
350          _overlay.free();
351          _mouseImage.free();
352          _screen.free();
353 
354          delete _mixer;
355       }
356 
initBackend()357       virtual void initBackend()
358       {
359          _savefileManager = new DefaultSaveFileManager(s_saveDir);
360 #ifdef FRONTEND_SUPPORTS_RGB565
361          _overlay.create(RES_W, RES_H, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
362 #else
363          _overlay.create(RES_W, RES_H, Graphics::PixelFormat(2, 5, 5, 5, 1, 10, 5, 0, 15));
364 #endif
365          _mixer = new Audio::MixerImpl(44100);
366          _timerManager = new DefaultTimerManager();
367 
368          _mixer->setReady(true);
369 
370          BaseBackend::initBackend();
371       }
372 
hasFeature(Feature f)373       virtual bool hasFeature(Feature f)
374       {
375          return (f == OSystem::kFeatureCursorPalette);
376       }
377 
setFeatureState(Feature f,bool enable)378       virtual void setFeatureState(Feature f, bool enable)
379       {
380          if (f == kFeatureCursorPalette)
381             _mousePaletteEnabled = enable;
382       }
383 
getFeatureState(Feature f)384       virtual bool getFeatureState(Feature f)
385       {
386          return (f == kFeatureCursorPalette) ? _mousePaletteEnabled : false;
387       }
388 
getSupportedGraphicsModes() const389       virtual const GraphicsMode *getSupportedGraphicsModes() const
390       {
391          static const OSystem::GraphicsMode s_noGraphicsModes[] = { {0, 0, 0} };
392          return s_noGraphicsModes;
393       }
394 
getDefaultGraphicsMode() const395       virtual int getDefaultGraphicsMode() const
396       {
397          return 0;
398       }
399 
setGraphicsMode(int mode)400       virtual bool setGraphicsMode(int mode)
401       {
402          return true;
403       }
404 
getGraphicsMode() const405       virtual int getGraphicsMode() const
406       {
407          return 0;
408       }
409 
initSize(uint width,uint height,const Graphics::PixelFormat * format)410       virtual void initSize(uint width, uint height, const Graphics::PixelFormat *format)
411       {
412          _gameScreen.create(width, height, format ? *format : Graphics::PixelFormat::createFormatCLUT8());
413       }
414 
getHeight()415       virtual int16 getHeight()
416       {
417          return _gameScreen.h;
418       }
419 
getWidth()420       virtual int16 getWidth()
421       {
422          return _gameScreen.w;
423       }
424 
getScreenFormat() const425       virtual Graphics::PixelFormat getScreenFormat() const
426       {
427          return _gameScreen.format;
428       }
429 
getSupportedFormats() const430       virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const
431       {
432          Common::List<Graphics::PixelFormat> result;
433 
434          /* RGBA8888 */
435          result.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
436 
437 #ifdef FRONTEND_SUPPORTS_RGB565
438          /* RGB565 - overlay */
439          result.push_back(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
440 #endif
441          /* RGB555 - fmtowns */
442          result.push_back(Graphics::PixelFormat(2, 5, 5, 5, 1, 10, 5, 0, 15));
443 
444          /* Palette - most games */
445          result.push_back(Graphics::PixelFormat::createFormatCLUT8());
446          return result;
447       }
448 
449 
450 
getPaletteManager()451       virtual PaletteManager *getPaletteManager() { return this; }
452    protected:
453       // PaletteManager API
setPalette(const byte * colors,uint start,uint num)454       virtual void setPalette(const byte *colors, uint start, uint num)
455       {
456          _gamePalette.set(colors, start, num);
457       }
458 
grabPalette(byte * colors,uint start,uint num) const459       virtual void grabPalette(byte *colors, uint start, uint num) const
460       {
461          _gamePalette.get(colors, start, num);
462       }
463 
464 
465    public:
copyRectToScreen(const void * buf,int pitch,int x,int y,int w,int h)466       virtual void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h)
467       {
468          const uint8_t *src = (const uint8_t*)buf;
469          uint8_t *pix = (uint8_t*)_gameScreen.pixels;
470          copyRectToSurface(pix, _gameScreen.pitch, src, pitch, x, y, w, h, _gameScreen.format.bytesPerPixel);
471       }
472 
updateScreen()473       virtual void updateScreen()
474       {
475          const Graphics::Surface& srcSurface = (_overlayVisible) ? _overlay : _gameScreen;
476          if(srcSurface.w && srcSurface.h)
477          {
478             switch(srcSurface.format.bytesPerPixel)
479             {
480                case 1:
481                case 3:
482                   blit_uint8_uint16_fast(_screen, srcSurface, _gamePalette);
483                   break;
484                case 2:
485                   blit_uint16_uint16(_screen, srcSurface, _gamePalette);
486                   break;
487                case 4:
488                   blit_uint32_uint16(_screen, srcSurface, _gamePalette);
489                   break;
490             }
491          }
492 
493          // Draw Mouse
494          if(_mouseVisible && _mouseImage.w && _mouseImage.h)
495          {
496             const int x = _mouseX - _mouseHotspotX;
497             const int y = _mouseY - _mouseHotspotY;
498 
499             if(_mouseImage.format.bytesPerPixel == 1)
500                blit_uint8_uint16(_screen, _mouseImage, x, y, _mousePaletteEnabled ? _mousePalette : _gamePalette, _mouseKeyColor);
501             else
502                blit_uint16_uint16(_screen, _mouseImage, x, y, _mousePaletteEnabled ? _mousePalette : _gamePalette, _mouseKeyColor);
503          }
504       }
505 
lockScreen()506       virtual Graphics::Surface *lockScreen()
507       {
508          return &_gameScreen;
509       }
510 
unlockScreen()511       virtual void unlockScreen()
512       {
513          /* EMPTY */
514       }
515 
setShakePos(int shakeXOffset,int shakeYOffset)516       virtual void setShakePos(int shakeXOffset, int shakeYOffset)
517       {
518          // TODO
519       }
520 
showOverlay()521       virtual void showOverlay()
522       {
523          _overlayVisible = true;
524       }
525 
hideOverlay()526       virtual void hideOverlay()
527       {
528          _overlayVisible = false;
529       }
530 
clearOverlay()531       virtual void clearOverlay()
532       {
533          _overlay.fillRect(Common::Rect(_overlay.w, _overlay.h), 0);
534       }
535 
grabOverlay(void * buf,int pitch)536       virtual void grabOverlay(void *buf, int pitch)
537       {
538          const unsigned char *src = (unsigned char*)_overlay.pixels;
539          unsigned char *dst = (byte *)buf;
540          unsigned i = RES_H;
541 
542          do{
543             memcpy(dst, src, RES_W << 1);
544             dst += pitch;
545             src += RES_W << 1;
546          }while(--i);
547       }
548 
copyRectToOverlay(const void * buf,int pitch,int x,int y,int w,int h)549       virtual void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h)
550       {
551          const uint8_t *src = (const uint8_t*)buf;
552          uint8_t *pix = (uint8_t*)_overlay.pixels;
553          copyRectToSurface(pix, _overlay.pitch, src, pitch, x, y, w, h, _overlay.format.bytesPerPixel);
554       }
555 
getOverlayHeight()556       virtual int16 getOverlayHeight()
557       {
558          return _overlay.h;
559       }
560 
getOverlayWidth()561       virtual int16 getOverlayWidth()
562       {
563          return _overlay.w;
564       }
565 
getOverlayFormat() const566       virtual Graphics::PixelFormat getOverlayFormat() const
567       {
568          return _overlay.format;
569       }
570 
571 
572 
showMouse(bool visible)573       virtual bool showMouse(bool visible)
574       {
575          const bool wasVisible = _mouseVisible;
576          _mouseVisible = visible;
577          return wasVisible;
578       }
579 
warpMouse(int x,int y)580       virtual void warpMouse(int x, int y)
581       {
582          _mouseX = x;
583          _mouseY = y;
584       }
585 
setMouseCursor(const void * buf,uint w,uint h,int hotspotX,int hotspotY,uint32 keycolor=255,bool dontScale=false,const Graphics::PixelFormat * format=NULL)586       virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor = 255, bool dontScale = false, const Graphics::PixelFormat *format = NULL)
587       {
588          const Graphics::PixelFormat mformat = format ? *format : Graphics::PixelFormat::createFormatCLUT8();
589 
590          if(_mouseImage.w != w || _mouseImage.h != h || _mouseImage.format != mformat)
591          {
592             _mouseImage.create(w, h, mformat);
593          }
594 
595          memcpy(_mouseImage.pixels, buf, h * _mouseImage.pitch);
596 
597          _mouseHotspotX = hotspotX;
598          _mouseHotspotY = hotspotY;
599          _mouseKeyColor = keycolor;
600          _mouseDontScale = dontScale;
601       }
602 
setCursorPalette(const byte * colors,uint start,uint num)603       virtual void setCursorPalette(const byte *colors, uint start, uint num)
604       {
605          _mousePalette.set(colors, start, num);
606          _mousePaletteEnabled = true;
607       }
608 
retroCheckThread(uint32 offset=0)609 		void retroCheckThread(uint32 offset = 0)
610       {
611          if(_threadExitTime <= (getMillis() + offset))
612          {
613             extern void retro_leave_thread();
614             retro_leave_thread();
615 
616             _threadExitTime = getMillis() + 10;
617          }
618       }
619 
pollEvent(Common::Event & event)620       virtual bool pollEvent(Common::Event &event)
621       {
622          retroCheckThread();
623 
624          ((DefaultTimerManager*)_timerManager)->handler();
625 
626 
627          if(!_events.empty())
628          {
629             event = _events.front();
630             _events.pop_front();
631             return true;
632          }
633 
634          return false;
635       }
636 
getMillis(bool skipRecord=false)637       virtual uint32 getMillis(bool skipRecord = false)
638       {
639 #if (defined(GEKKO) && !defined(WIIU))
640          return (ticks_to_microsecs(gettime()) / 1000.0) - _startTime;
641 #elif defined(WIIU)
642          return ((cpu_features_get_time_usec())/1000) - _startTime;
643 #elif defined(__CELLOS_LV2__)
644          return (sys_time_get_system_time() / 1000.0) - _startTime;
645 #else
646          struct timeval t;
647          gettimeofday(&t, 0);
648 
649          return ((t.tv_sec * 1000) + (t.tv_usec / 1000)) - _startTime;
650 #endif
651       }
652 
delayMillis(uint msecs)653       virtual void delayMillis(uint msecs)
654       {
655 			// Implement 'non-blocking' sleep...
656 			uint32 start_time = getMillis();
657 			if (_speed_hack_enabled)
658 			{
659 				// Use janky inaccurate method...
660 				uint32 elapsed_time = 0;
661 				uint32 time_remaining = msecs;
662 				while(time_remaining > 0)
663 				{
664 					// If delay would take us past the next
665 					// thread exit time, exit the thread immediately
666 					// (i.e. start burning delay time in the main RetroArch
667 					// thread as soon as possible...)
668 					retroCheckThread(time_remaining);
669 					// Check how much delay time remains...
670 					elapsed_time = getMillis() - start_time;
671 					if (time_remaining > elapsed_time)
672 					{
673 						time_remaining = time_remaining - elapsed_time;
674 						retro_sleep(1);
675 					}
676 					else
677 					{
678 						time_remaining = 0;
679 					}
680 					// Have to handle the timer manager here, since some engines
681 					// (e.g. dreamweb) sit in a delayMillis() loop waiting for a
682 					// timer callback...
683 					((DefaultTimerManager*)_timerManager)->handler();
684 				}
685 			}
686 			else
687 			{
688 				// Use accurate method...
689 				while(getMillis() < start_time + msecs)
690 				{
691 					retro_sleep(1);
692 					retroCheckThread();
693 					// Have to handle the timer manager here, since some engines
694 					// (e.g. dreamweb) sit in a delayMillis() loop waiting for a
695 					// timer callback...
696 					((DefaultTimerManager*)_timerManager)->handler();
697 				}
698 			}
699       }
700 
createMutex(void)701       virtual MutexRef createMutex(void)
702       {
703          return MutexRef();
704       }
705 
lockMutex(MutexRef mutex)706       virtual void lockMutex(MutexRef mutex)
707       {
708          /* EMPTY */
709       }
710 
unlockMutex(MutexRef mutex)711       virtual void unlockMutex(MutexRef mutex)
712       {
713          /* EMPTY */
714       }
715 
deleteMutex(MutexRef mutex)716       virtual void deleteMutex(MutexRef mutex)
717       {
718          /* EMPTY */
719       }
720 
quit()721       virtual void quit()
722       {
723          // TODO:
724       }
725 
addSysArchivesToSearchSet(Common::SearchSet & s,int priority=0)726       virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0)
727       {
728          // TODO: NOTHING?
729       }
730 
getTimeAndDate(TimeDate & t) const731       virtual void getTimeAndDate(TimeDate &t) const
732       {
733          time_t curTime = time(NULL);
734 
735 #define YEAR0 1900
736 #define EPOCH_YR 1970
737 #define SECS_DAY (24L * 60L * 60L)
738 #define LEAPYEAR(year) (!((year) % 4) && (((year) % 100) || !((year) % 400)))
739 #define YEARSIZE(year) (LEAPYEAR(year) ? 366 : 365)
740          const int _ytab[2][12] = {
741             {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
742             {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
743          };
744          int year = EPOCH_YR;
745          unsigned long dayclock = (unsigned long)curTime % SECS_DAY;
746          unsigned long dayno = (unsigned long)curTime / SECS_DAY;
747          t.tm_sec = dayclock % 60;
748          t.tm_min = (dayclock % 3600) / 60;
749          t.tm_hour = dayclock / 3600;
750          t.tm_wday = (dayno + 4) % 7; /* day 0 was a thursday */
751          while (dayno >= YEARSIZE(year)) {
752             dayno -= YEARSIZE(year);
753             year++;
754          }
755          t.tm_year = year - YEAR0;
756          t.tm_mon = 0;
757          while (dayno >= _ytab[LEAPYEAR(year)][t.tm_mon]) {
758             dayno -= _ytab[LEAPYEAR(year)][t.tm_mon];
759             t.tm_mon++;
760          }
761          t.tm_mday = dayno + 1;
762       }
763 
getMixer()764       virtual Audio::Mixer *getMixer()
765       {
766          return _mixer;
767       }
768 
getDefaultConfigFileName()769       virtual Common::String getDefaultConfigFileName()
770       {
771          return s_systemDir + "/scummvm.ini";
772       }
773 
logMessage(LogMessageType::Type type,const char * message)774       virtual void logMessage(LogMessageType::Type type, const char *message)
775       {
776          if (log_cb)
777             log_cb(RETRO_LOG_INFO, "%s\n", message);
778       }
779 
780 
781       //
782 
getScreen()783       const Graphics::Surface& getScreen()
784       {
785          const Graphics::Surface& srcSurface = (_overlayVisible) ? _overlay : _gameScreen;
786 
787          if(srcSurface.w != _screen.w || srcSurface.h != _screen.h)
788          {
789 #ifdef FRONTEND_SUPPORTS_RGB565
790             _screen.create(srcSurface.w, srcSurface.h, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
791 #else
792             _screen.create(srcSurface.w, srcSurface.h, Graphics::PixelFormat(2, 5, 5, 5, 1, 10, 5, 0, 15));
793 #endif
794          }
795 
796 
797          return _screen;
798       }
799 
800 #define ANALOG_RANGE 0x8000
801 #define BASE_CURSOR_SPEED 4
802 #define PI 3.141592653589793238
803 
processMouse(retro_input_state_t aCallback,int device,float gampad_cursor_speed,bool analog_response_is_quadratic,int analog_deadzone,float mouse_speed)804       void processMouse(retro_input_state_t aCallback, int device, float gampad_cursor_speed, bool analog_response_is_quadratic, int analog_deadzone, float mouse_speed)
805       {
806          int16_t joy_x, joy_y, joy_rx, joy_ry, x, y;
807          float analog_amplitude_x, analog_amplitude_y;
808          int mouse_acc_int;
809          bool do_joystick, do_mouse, down;
810          float adjusted_cursor_speed = (float)BASE_CURSOR_SPEED * gampad_cursor_speed;
811          int dpad_cursor_offset;
812          double rs_radius, rs_angle;
813          unsigned numpad_index;
814 
815          static const uint32_t retroButtons[2] = {RETRO_DEVICE_ID_MOUSE_LEFT, RETRO_DEVICE_ID_MOUSE_RIGHT};
816          static const Common::EventType eventID[2][2] =
817          {
818             {Common::EVENT_LBUTTONDOWN, Common::EVENT_LBUTTONUP},
819             {Common::EVENT_RBUTTONDOWN, Common::EVENT_RBUTTONUP}
820          };
821 
822 			static const unsigned gampad_key_map[8][3] = {
823 				{ RETRO_DEVICE_ID_JOYPAD_X,      (unsigned)Common::KEYCODE_ESCAPE,    (unsigned)Common::ASCII_ESCAPE    }, // Esc
824 				{ RETRO_DEVICE_ID_JOYPAD_Y,      (unsigned)Common::KEYCODE_PERIOD,    46                                }, // .
825 				{ RETRO_DEVICE_ID_JOYPAD_L,      (unsigned)Common::KEYCODE_RETURN,    (unsigned)Common::ASCII_RETURN    }, // Enter
826 				{ RETRO_DEVICE_ID_JOYPAD_R,      (unsigned)Common::KEYCODE_KP5,       53                                }, // Numpad 5
827 				{ RETRO_DEVICE_ID_JOYPAD_L2,     (unsigned)Common::KEYCODE_BACKSPACE, (unsigned)Common::ASCII_BACKSPACE }, // Backspace
828 				{ RETRO_DEVICE_ID_JOYPAD_L3,     (unsigned)Common::KEYCODE_F10,       (unsigned)Common::ASCII_F10       }, // F10
829 				{ RETRO_DEVICE_ID_JOYPAD_R3,     (unsigned)Common::KEYCODE_KP0,       48                                }, // Numpad 0
830 				{ RETRO_DEVICE_ID_JOYPAD_SELECT, (unsigned)Common::KEYCODE_F1,        (unsigned)Common::ASCII_F1        }, // F1
831 			};
832 
833 			// Right stick circular wrap around: 1 -> 2 -> 3 -> 6 -> 9 -> 8 -> 7 -> 4
834 			static const unsigned gampad_numpad_map[8][2] = {
835 				{ (unsigned)Common::KEYCODE_KP1, 49 },
836 				{ (unsigned)Common::KEYCODE_KP2, 50 },
837 				{ (unsigned)Common::KEYCODE_KP3, 51 },
838 				{ (unsigned)Common::KEYCODE_KP6, 54 },
839 				{ (unsigned)Common::KEYCODE_KP9, 57 },
840 				{ (unsigned)Common::KEYCODE_KP8, 56 },
841 				{ (unsigned)Common::KEYCODE_KP7, 55 },
842 				{ (unsigned)Common::KEYCODE_KP4, 52 },
843 			};
844 
845 			// Reduce gamepad cursor speed, if required
846 			if (device == RETRO_DEVICE_JOYPAD &&
847 			    aCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2))
848 			{
849 				adjusted_cursor_speed = adjusted_cursor_speed * (1.0f / 3.0f);
850 			}
851 
852          down = false;
853          do_joystick = false;
854          x = aCallback(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_X);
855          y = aCallback(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_Y);
856          joy_x = aCallback(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X);
857          joy_y = aCallback(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y);
858 
859 			// Left Analog X Axis
860 			if (joy_x > analog_deadzone || joy_x < -analog_deadzone)
861 			{
862 				if (joy_x > analog_deadzone)
863 				{
864 					// Reset accumulator when changing direction
865 					_mouseXAcc = (_mouseXAcc < 0.0) ? 0.0 : _mouseXAcc;
866 					joy_x = joy_x - analog_deadzone;
867 				}
868 				if (joy_x < -analog_deadzone)
869 				{
870 					// Reset accumulator when changing direction
871 					_mouseXAcc = (_mouseXAcc > 0.0) ? 0.0 : _mouseXAcc;
872 					joy_x = joy_x + analog_deadzone;
873 				}
874 				// Update accumulator
875 				analog_amplitude_x = (float)joy_x / (float)(ANALOG_RANGE - analog_deadzone);
876 				if (analog_response_is_quadratic)
877 				{
878 					if (analog_amplitude_x < 0.0)
879 						analog_amplitude_x = -(analog_amplitude_x * analog_amplitude_x);
880 					else
881 						analog_amplitude_x = analog_amplitude_x * analog_amplitude_x;
882 				}
883 				//printf("analog_amplitude_x: %f\n", analog_amplitude_x);
884 				_mouseXAcc += analog_amplitude_x * adjusted_cursor_speed;
885 				// Get integer part of accumulator
886 				mouse_acc_int = (int)_mouseXAcc;
887 				if (mouse_acc_int != 0)
888 				{
889 					// Set mouse position
890 					_mouseX += mouse_acc_int;
891 					_mouseX = (_mouseX < 0) ? 0 : _mouseX;
892 					_mouseX = (_mouseX >= _screen.w) ? _screen.w : _mouseX;
893 					do_joystick = true;
894 					// Update accumulator
895 					_mouseXAcc -= (float)mouse_acc_int;
896 				}
897 			}
898 
899 			// Left Analog Y Axis
900 			if (joy_y > analog_deadzone || joy_y < -analog_deadzone)
901 			{
902 				if (joy_y > analog_deadzone)
903 				{
904 					// Reset accumulator when changing direction
905 					_mouseYAcc = (_mouseYAcc < 0.0) ? 0.0 : _mouseYAcc;
906 					joy_y = joy_y - analog_deadzone;
907 				}
908 				if (joy_y < -analog_deadzone)
909 				{
910 					// Reset accumulator when changing direction
911 					_mouseYAcc = (_mouseYAcc > 0.0) ? 0.0 : _mouseYAcc;
912 					joy_y = joy_y + analog_deadzone;
913 				}
914 				// Update accumulator
915 				analog_amplitude_y = (float)joy_y / (float)(ANALOG_RANGE - analog_deadzone);
916 				if (analog_response_is_quadratic)
917 				{
918 					if (analog_amplitude_y < 0.0)
919 						analog_amplitude_y = -(analog_amplitude_y * analog_amplitude_y);
920 					else
921 						analog_amplitude_y = analog_amplitude_y * analog_amplitude_y;
922 				}
923 				//printf("analog_amplitude_y: %f\n", analog_amplitude_y);
924 				_mouseYAcc += analog_amplitude_y * adjusted_cursor_speed;
925 				// Get integer part of accumulator
926 				mouse_acc_int = (int)_mouseYAcc;
927 				if (mouse_acc_int != 0)
928 				{
929 					// Set mouse position
930 					_mouseY += mouse_acc_int;
931 					_mouseY = (_mouseY < 0) ? 0 : _mouseY;
932 					_mouseY = (_mouseY >= _screen.h) ? _screen.h : _mouseY;
933 					do_joystick = true;
934 					// Update accumulator
935 					_mouseYAcc -= (float)mouse_acc_int;
936 				}
937 			}
938 
939          if (device == RETRO_DEVICE_JOYPAD) {
940             if (aCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT))
941             {
942 					dpad_cursor_offset = (int)(adjusted_cursor_speed * 0.5f);
943 					dpad_cursor_offset = (dpad_cursor_offset < 1) ? 1 : dpad_cursor_offset;
944                _mouseX -= dpad_cursor_offset;
945                _mouseX = (_mouseX < 0) ? 0 : _mouseX;
946                _mouseX = (_mouseX >= _screen.w) ? _screen.w : _mouseX;
947                do_joystick = true;
948             }
949 
950             if (aCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT))
951             {
952 					dpad_cursor_offset = (int)(adjusted_cursor_speed * 0.5f);
953 					dpad_cursor_offset = (dpad_cursor_offset < 1) ? 1 : dpad_cursor_offset;
954                _mouseX += dpad_cursor_offset;
955                _mouseX = (_mouseX < 0) ? 0 : _mouseX;
956                _mouseX = (_mouseX >= _screen.w) ? _screen.w : _mouseX;
957                do_joystick = true;
958             }
959 
960             if (aCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP))
961             {
962 					dpad_cursor_offset = (int)(adjusted_cursor_speed * 0.5f);
963 					dpad_cursor_offset = (dpad_cursor_offset < 1) ? 1 : dpad_cursor_offset;
964                _mouseY -= dpad_cursor_offset;
965                _mouseY = (_mouseY < 0) ? 0 : _mouseY;
966                _mouseY = (_mouseY >= _screen.h) ? _screen.h : _mouseY;
967                do_joystick = true;
968             }
969 
970             if (aCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN))
971             {
972 					dpad_cursor_offset = (int)(adjusted_cursor_speed * 0.5f);
973 					dpad_cursor_offset = (dpad_cursor_offset < 1) ? 1 : dpad_cursor_offset;
974                _mouseY += dpad_cursor_offset;
975                _mouseY = (_mouseY < 0) ? 0 : _mouseY;
976                _mouseY = (_mouseY >= _screen.h) ? _screen.h : _mouseY;
977                do_joystick = true;
978             }
979 
980             if (aCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START))
981             {
982                Common::Event ev;
983                ev.type = Common::EVENT_MAINMENU;
984                _events.push_back(ev);
985             }
986          }
987 
988 #if defined(WIIU) || defined(__SWITCH__)
989 	int p_x = aCallback(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X);
990 	int p_y = aCallback(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y);
991 	int p_press  = aCallback(0, RETRO_DEVICE_POINTER, 0,RETRO_DEVICE_ID_POINTER_PRESSED);
992 	int px=(int)((p_x+0x7fff)*_screen.w /0xffff);
993 	int py=(int)((p_y+0x7fff)*_screen.h/0xffff);
994 	//printf("(%d,%d) p:%d\n",px,py,pp);
995 
996 	static int ptrhold=0;
997 
998 	if(p_press)ptrhold++;
999 	else ptrhold=0;
1000 
1001 	if(ptrhold>0){
1002 	   _mouseX = px;
1003 	   _mouseY = py;
1004 
1005             Common::Event ev;
1006             ev.type = Common::EVENT_MOUSEMOVE;
1007             ev.mouse.x = _mouseX;
1008             ev.mouse.y = _mouseY;
1009             _events.push_back(ev);
1010 	}
1011 
1012 	if(ptrhold>10 && _ptrmouseButton==0){
1013 	    _ptrmouseButton=1;
1014             Common::Event ev;
1015             ev.type = eventID[0][_ptrmouseButton ? 0 : 1];
1016             ev.mouse.x = _mouseX;
1017             ev.mouse.y = _mouseY;
1018             _events.push_back(ev);
1019 	}
1020 	else if (ptrhold==0 && _ptrmouseButton==1){
1021 	    _ptrmouseButton=0;
1022             Common::Event ev;
1023             ev.type = eventID[0][_ptrmouseButton ? 0 : 1];
1024             ev.mouse.x = _mouseX;
1025             ev.mouse.y = _mouseY;
1026             _events.push_back(ev);
1027 	}
1028 
1029 #endif
1030 
1031          if (do_joystick)
1032          {
1033             Common::Event ev;
1034             ev.type = Common::EVENT_MOUSEMOVE;
1035             ev.mouse.x = _mouseX;
1036             ev.mouse.y = _mouseY;
1037             _events.push_back(ev);
1038          }
1039 
1040          // Gampad mouse buttons
1041          down = aCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A);
1042          if(down != _joypadmouseButtons[0])
1043          {
1044             _joypadmouseButtons[0] = down;
1045 
1046             Common::Event ev;
1047             ev.type = eventID[0][down ? 0 : 1];
1048             ev.mouse.x = _mouseX;
1049             ev.mouse.y = _mouseY;
1050             _events.push_back(ev);
1051          }
1052 
1053          down = aCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B);
1054          if(down != _joypadmouseButtons[1])
1055          {
1056             _joypadmouseButtons[1] = down;
1057 
1058             Common::Event ev;
1059             ev.type = eventID[1][down ? 0 : 1];
1060             ev.mouse.x = _mouseX;
1061             ev.mouse.y = _mouseY;
1062             _events.push_back(ev);
1063          }
1064 
1065 			// Gamepad keyboard buttons
1066 			for(int i = 0; i < 8; i ++)
1067 			{
1068 				down = aCallback(0, RETRO_DEVICE_JOYPAD, 0, gampad_key_map[i][0]);
1069 				if (down != _joypadkeyboardButtons[i])
1070 				{
1071 					_joypadkeyboardButtons[i] = down;
1072 					bool state = down ? true : false;
1073 					processKeyEvent(state, gampad_key_map[i][1], (uint32_t)gampad_key_map[i][2], 0);
1074 				}
1075 			}
1076 
1077 			// Gamepad right stick numpad emulation
1078 			joy_rx = aCallback(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X);
1079 			joy_ry = aCallback(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y);
1080 
1081 			if (joy_rx > analog_deadzone)
1082 				joy_rx = joy_rx - analog_deadzone;
1083 			else if (joy_rx < -analog_deadzone)
1084 				joy_rx = joy_rx + analog_deadzone;
1085 			else
1086 				joy_rx = 0;
1087 
1088 			if (joy_ry > analog_deadzone)
1089 				joy_ry = joy_ry - analog_deadzone;
1090 			else if (joy_ry < -analog_deadzone)
1091 				joy_ry = joy_ry + analog_deadzone;
1092 			else
1093 				joy_ry = 0;
1094 
1095 			// This is very ugly, but I don't have time to make it nicer...
1096 			if (joy_rx != 0 || joy_ry != 0)
1097 			{
1098 				analog_amplitude_x = (float)joy_rx / (float)(ANALOG_RANGE - analog_deadzone);
1099 				analog_amplitude_y = (float)joy_ry / (float)(ANALOG_RANGE - analog_deadzone);
1100 
1101 				// Convert to polar coordinates: part 1
1102 				rs_radius = sqrt((double)(analog_amplitude_x * analog_amplitude_x) + (double)(analog_amplitude_y * analog_amplitude_y));
1103 
1104 				// Check if radius is above threshold
1105 				if (rs_radius > 0.5)
1106 				{
1107 					// Convert to polar coordinates: part 2
1108 					rs_angle = atan2((double)analog_amplitude_y, (double)analog_amplitude_x);
1109 
1110 					// Adjust rotation offset...
1111 					rs_angle = (2.0 * PI) - (rs_angle + PI);
1112 					rs_angle = fmod(rs_angle - (0.125 * PI), 2.0 * PI);
1113 					if (rs_angle < 0)
1114 						rs_angle += 2.0 * PI;
1115 
1116 					// Convert angle into numpad key index
1117 					numpad_index = (unsigned)((rs_angle / (2.0 * PI)) * 8.0);
1118 					// Unnecessary safety check...
1119 					numpad_index = (numpad_index > 7) ? 7 : numpad_index;
1120 					//printf("numpad_index: %u\n", numpad_index);
1121 
1122 					if (numpad_index != _joypadnumpadLast)
1123 					{
1124 						// Unset last key, if required
1125 						if (_joypadnumpadActive)
1126 							processKeyEvent(false, gampad_numpad_map[_joypadnumpadLast][0], (uint32_t)gampad_numpad_map[_joypadnumpadLast][1], 0);
1127 
1128 						// Set new key
1129 						processKeyEvent(true, gampad_numpad_map[numpad_index][0], (uint32_t)gampad_numpad_map[numpad_index][1], 0);
1130 
1131 						_joypadnumpadLast = numpad_index;
1132 						_joypadnumpadActive = true;
1133 					}
1134 				}
1135 				else if (_joypadnumpadActive)
1136 				{
1137 					processKeyEvent(false, gampad_numpad_map[_joypadnumpadLast][0], (uint32_t)gampad_numpad_map[_joypadnumpadLast][1], 0);
1138 					_joypadnumpadActive = false;
1139 					_joypadnumpadLast = 8;
1140 				}
1141 			}
1142 			else if (_joypadnumpadActive)
1143 			{
1144 				processKeyEvent(false, gampad_numpad_map[_joypadnumpadLast][0], (uint32_t)gampad_numpad_map[_joypadnumpadLast][1], 0);
1145 				_joypadnumpadActive = false;
1146 				_joypadnumpadLast = 8;
1147 			}
1148 
1149          // Process input from physical mouse
1150          do_mouse = false;
1151          // > X Axis
1152          if (x != 0)
1153          {
1154             if (x > 0) {
1155                // Reset accumulator when changing direction
1156                _mouseXAcc = (_mouseXAcc < 0.0) ? 0.0 : _mouseXAcc;
1157             }
1158             if (x < 0) {
1159                // Reset accumulator when changing direction
1160                _mouseXAcc = (_mouseXAcc > 0.0) ? 0.0 : _mouseXAcc;
1161             }
1162             // Update accumulator
1163             _mouseXAcc += (float)x * mouse_speed;
1164             // Get integer part of accumulator
1165             mouse_acc_int = (int)_mouseXAcc;
1166             if (mouse_acc_int != 0)
1167             {
1168                // Set mouse position
1169                _mouseX += mouse_acc_int;
1170                _mouseX = (_mouseX < 0) ? 0 : _mouseX;
1171                _mouseX = (_mouseX >= _screen.w) ? _screen.w : _mouseX;
1172                do_mouse = true;
1173                // Update accumulator
1174                _mouseXAcc -= (float)mouse_acc_int;
1175             }
1176          }
1177          // > Y Axis
1178          if (y != 0)
1179          {
1180             if (y > 0) {
1181                // Reset accumulator when changing direction
1182                _mouseYAcc = (_mouseYAcc < 0.0) ? 0.0 : _mouseYAcc;
1183             }
1184             if (y < 0) {
1185                // Reset accumulator when changing direction
1186                _mouseYAcc = (_mouseYAcc > 0.0) ? 0.0 : _mouseYAcc;
1187             }
1188             // Update accumulator
1189             _mouseYAcc += (float)y * mouse_speed;
1190             // Get integer part of accumulator
1191             mouse_acc_int = (int)_mouseYAcc;
1192             if (mouse_acc_int != 0)
1193             {
1194                // Set mouse position
1195                _mouseY += mouse_acc_int;
1196                _mouseY = (_mouseY < 0) ? 0 : _mouseY;
1197                _mouseY = (_mouseY >= _screen.h) ? _screen.h : _mouseY;
1198                do_mouse = true;
1199                // Update accumulator
1200                _mouseYAcc -= (float)mouse_acc_int;
1201             }
1202          }
1203 
1204          if (do_mouse)
1205          {
1206             Common::Event ev;
1207             ev.type = Common::EVENT_MOUSEMOVE;
1208             ev.mouse.x = _mouseX;
1209             ev.mouse.y = _mouseY;
1210             _events.push_back(ev);
1211          }
1212 
1213          for(int i = 0; i < 2; i ++)
1214          {
1215             Common::Event ev;
1216             bool down = aCallback(0, RETRO_DEVICE_MOUSE, 0, retroButtons[i]);
1217             if(down != _mouseButtons[i])
1218             {
1219                _mouseButtons[i] = down;
1220 
1221                ev.type = eventID[i][down ? 0 : 1];
1222                ev.mouse.x = _mouseX;
1223                ev.mouse.y = _mouseY;
1224                _events.push_back(ev);
1225             }
1226 
1227          }
1228       }
1229 
processKeyEvent(bool down,unsigned keycode,uint32_t character,uint16_t key_modifiers)1230       void processKeyEvent(bool down, unsigned keycode, uint32_t character, uint16_t key_modifiers)
1231       {
1232          int _keyflags = 0;
1233          _keyflags |= (key_modifiers & RETROKMOD_CTRL) ? Common::KBD_CTRL : 0;
1234          _keyflags |= (key_modifiers & RETROKMOD_ALT) ? Common::KBD_ALT : 0;
1235          _keyflags |= (key_modifiers & RETROKMOD_SHIFT) ? Common::KBD_SHIFT : 0;
1236          _keyflags |= (key_modifiers & RETROKMOD_META) ? Common::KBD_META : 0;
1237          _keyflags |= (key_modifiers & RETROKMOD_CAPSLOCK) ? Common::KBD_CAPS : 0;
1238          _keyflags |= (key_modifiers & RETROKMOD_NUMLOCK) ? Common::KBD_NUM : 0;
1239          _keyflags |= (key_modifiers & RETROKMOD_SCROLLOCK) ? Common::KBD_SCRL : 0;
1240 
1241          if (keycode == RETROK_SPACE)
1242             keycode &= ~(RETROK_SPACE);
1243 
1244          Common::Event ev;
1245          ev.type = down ? Common::EVENT_KEYDOWN : Common::EVENT_KEYUP;
1246          ev.kbd.keycode = (Common::KeyCode)keycode;
1247          ev.kbd.flags = _keyflags;
1248          ev.kbd.ascii = character;
1249 
1250          /* If shift was down then send upper case letter to engine */
1251          if(ev.kbd.ascii >= 97 && ev.kbd.ascii <= 122 && (_keyflags & Common::KBD_SHIFT))
1252             ev.kbd.ascii = ev.kbd.ascii & ~0x20;
1253 
1254          _events.push_back(ev);
1255       }
1256 
postQuit()1257       void postQuit()
1258       {
1259          Common::Event ev;
1260          ev.type = Common::EVENT_QUIT;
1261          ((OSystem_RETRO*)g_system)->getEventManager()->pushEvent(ev);
1262       }
1263 };
1264 
retroBuildOS(bool aEnableSpeedHack)1265 OSystem* retroBuildOS(bool aEnableSpeedHack)
1266 {
1267    return new OSystem_RETRO(aEnableSpeedHack);
1268 }
1269 
getScreen()1270 const Graphics::Surface& getScreen()
1271 {
1272    return ((OSystem_RETRO*)g_system)->getScreen();
1273 }
1274 
retroProcessMouse(retro_input_state_t aCallback,int device,float gampad_cursor_speed,bool analog_response_is_quadratic,int analog_deadzone,float mouse_speed)1275 void retroProcessMouse(retro_input_state_t aCallback, int device, float gampad_cursor_speed, bool analog_response_is_quadratic, int analog_deadzone, float mouse_speed)
1276 {
1277    ((OSystem_RETRO*)g_system)->processMouse(aCallback, device, gampad_cursor_speed, analog_response_is_quadratic, analog_deadzone, mouse_speed);
1278 }
1279 
retroPostQuit()1280 void retroPostQuit()
1281 {
1282    ((OSystem_RETRO*)g_system)->postQuit();
1283 }
1284 
retroSetSystemDir(const char * aPath)1285 void retroSetSystemDir(const char* aPath)
1286 {
1287    s_systemDir = Common::String(aPath ? aPath : ".");
1288 }
1289 
retroSetSaveDir(const char * aPath)1290 void retroSetSaveDir(const char* aPath)
1291 {
1292    s_saveDir = Common::String(aPath ? aPath : ".");
1293 }
1294 
retroKeyEvent(bool down,unsigned keycode,uint32_t character,uint16_t key_modifiers)1295 void retroKeyEvent(bool down, unsigned keycode, uint32_t character, uint16_t key_modifiers)
1296 {
1297    ((OSystem_RETRO*)g_system)->processKeyEvent(down, keycode, character, key_modifiers);
1298 }
1299