Compare commits

...
471 Commits
Author SHA1 Message Date
Themaister d109c22b49 Update Windows makefile. 2012-01-16 22:10:31 +01:00
Themaister 98f2f1c23d Updates for 0.9.4. 2012-01-16 22:08:54 +01:00
TwinAphex51224 94bc6ff3a2 (PS3) Some more settings filled in 2012-01-16 17:15:16 +01:00
TwinAphex51224 62dc63542c (PS3) Clean up PS3 GL driver always assume HAVE_FBO and HAVE_CG 2012-01-16 16:46:35 +01:00
TwinAphex51224 dd8acd5872 (PS3) Added SN version number in 'print compiler' function 2012-01-16 16:38:27 +01:00
TwinAphex51224 d1113a5af0 (PS3) Added sysutil screenshot feature 2012-01-16 15:45:55 +01:00
TwinAphex51224 024e10b5a9 (PS3) Implemented some settings 2012-01-16 15:33:18 +01:00
TwinAphex51224 c4b2492872 (PS3) Some cleanups 2012-01-16 04:09:28 +01:00
TwinAphex51224 44bc9fe291 (PS3) Menu refactoring 2012-01-16 04:07:02 +01:00
Themaister ee7bacd2bc Fix critical performance regression. 2012-01-14 23:15:25 +01:00
Themaister 90a2070718 Return 0 from main().
On console targets, main() is overridden to ssnes_main().
2012-01-14 20:45:05 +01:00
Themaister abf34c06c1 Attempt to always return from ssnes_main_init() when errors occur. 2012-01-14 16:08:54 +01:00
Themaister 661836fd77 Deconstruct main() into three separate functions.
Split main() into init/iterate/deinit functions.
2012-01-14 14:08:43 +01:00
Themaister 260f3ac7ce Use a more general SSNES_CONSOLE define. 2012-01-14 13:43:15 +01:00
Themaister f57ab1ccd8 Handle zero sized writes. 2012-01-14 02:03:49 +01:00
Themaister ef206b3a27 Fix directory detection. 2012-01-14 01:42:51 +01:00
TwinAphex51224 2dce493240 (PS3) Sysutil exit callback works in menu too 2012-01-13 01:27:18 +01:00
TwinAphex51224 83c3d7be57 (PS3) Menu fixes 2012-01-13 01:01:08 +01:00
TwinAphex51224 7b0e1e8022 (PS3) Got rid of warnings in main.c 2012-01-13 00:22:43 +01:00
Themaister 86950b4d2a FBO scale are float. 2012-01-13 00:29:01 +01:00
Themaister fe02783fc7 Merge branch 'master' of github.com:Themaister/SSNES 2012-01-13 00:09:27 +01:00
Themaister 072406e3c3 Merge branch 'master' of github.com:Themaister/SSNES 2012-01-13 00:09:13 +01:00
Themaister 751761d99c Add config_get_float. 2012-01-13 00:08:55 +01:00
TwinAphex51224 fe993fafd5 (PS3) Fixed menu speed 2012-01-13 00:01:52 +01:00
TwinAphex51224 057785539b Merge branch 'master' of github.com:Themaister/SSNES 2012-01-12 23:46:10 +01:00
TwinAphex51224 048d2f65e0 (PS3) Fixed controller 2 2012-01-12 23:45:48 +01:00
Themaister c305f4347d Add g_console struct. 2012-01-12 22:53:14 +01:00
TwinAphex51224 3ca62fbbbc (PS3) Pushed PS3 video fix 2012-01-12 22:02:28 +01:00
Themaister 225699f545 No real need to memset(). 2012-01-12 20:41:52 +01:00
Themaister 35ae61fbc7 Use more correct UINT*_C() constants. 2012-01-12 20:16:47 +01:00
Themaister 86dac8c979 Make sure sockets are not closed twice on error. 2012-01-12 09:21:33 +01:00
TwinAphex51224 95431414ae (PS3) Initialize some settings 2012-01-12 00:24:17 +01:00
TwinAphex51224 b3f7224ea1 (PS3) menu works, ROM loads, but screen is black 2012-01-12 00:05:32 +01:00
Themaister e583546778 Add some more needed stuff. 2012-01-11 23:48:48 +01:00
Themaister a39c37e1ee Add some hooks to video init/deinit for PS3. 2012-01-11 23:44:29 +01:00
Themaister 67fb35b645 Merge branch 'master' of github.com:Themaister/SSNES 2012-01-11 23:10:05 +01:00
Themaister 3c1e4c879a Integer scale is bad mmkay. 2012-01-11 23:09:22 +01:00
TwinAphex51224 83a11be669 Merge branch 'master' of github.com:Themaister/SSNES 2012-01-11 22:55:37 +01:00
TwinAphex51224 08e35a62d4 (PS3) Can now compile with SNC as well 2012-01-11 22:55:07 +01:00
Themaister 5461c0d86e Merge branch 'master' of github.com:Themaister/SSNES 2012-01-11 22:52:57 +01:00
Themaister 4eab7c4387 Font scale option. 2012-01-11 22:52:25 +01:00
TwinAphex51224 59aeb77744 (PS3) Some more work on menu 2012-01-11 22:27:07 +01:00
Themaister c6fc8e45ff Log more clearly disconnects. 2012-01-11 21:08:44 +01:00
Themaister 4dde927c12 Add some logging and increase buffer sizes. 2012-01-11 20:50:21 +01:00
Themaister 6325b4cd2e Set larger buffer size to mitigate lags on client connect. 2012-01-11 20:14:59 +01:00
Themaister 4beec3870f Spectator mode. 2012-01-11 19:22:18 +01:00
Themaister 36a2c96cb7 ifdef console oriented binds. 2012-01-11 10:00:24 +01:00
TwinAphex51224 a4a68a2ad5 (PS3) Implemented menu code some more 2012-01-11 02:25:49 +01:00
TwinAphex51224 13a2010ed6 (PS3) Fix 2012-01-11 01:17:04 +01:00
TwinAphex51224 e37fd21424 Merge branch 'master' of github.com:Themaister/SSNES 2012-01-11 01:04:47 +01:00
TwinAphex51224 a2698061a6 (PS3) Loads settings from config file 2012-01-11 01:04:17 +01:00
Themaister d00257382a Always dump 16-bit little endian values for movie record. 2012-01-11 00:55:50 +01:00
TwinAphex51224 51ab2f2509 (PS3) Added initial menu - not yet compiled in 2012-01-10 23:33:44 +01:00
TwinAphex51224 61f9ceccab PATH_MAX gets redefined for PS3/Libxenon 2012-01-10 22:08:24 +01:00
Themaister f836a291a0 Reinstate ssnes.cfg. 2012-01-09 16:05:02 +01:00
Themaister 97725e69eb Add missing license header. 2012-01-08 02:30:32 +01:00
Themaister d186e14eeb VSync one frame earlier. 2012-01-08 02:21:28 +01:00
Themaister 08aaa1021c More aestethically pleasing effect. 2012-01-08 01:32:45 +01:00
Themaister b4248038fb Update license headers. 2012-01-08 01:12:05 +01:00
Themaister ca587ab92e Actually runs. 2012-01-08 01:07:26 +01:00
Themaister 6f5c33848e Begin work on menu for Wii. 2012-01-08 00:57:44 +01:00
Themaister 17d380400e Update AUTHORS. 2012-01-07 17:07:22 +01:00
Themaister 2e456b2570 Rename gl-> to vid-> for consistency. 2012-01-07 15:30:52 +01:00
TwinAphex51224 fe17a42e62 (360) Fixed 2012-01-07 15:28:39 +01:00
Themaister c46866c6e5 Use correct geometries (I hope). 2012-01-07 15:21:23 +01:00
Themaister 3117633adf Actually use a viewport. 2012-01-07 15:11:57 +01:00
Themaister 8a49321648 Rename shader vars again. :D 2012-01-07 15:03:09 +01:00
Themaister 18f027ed41 Rename shader variable names. 2012-01-07 15:00:51 +01:00
TwinAphex51224 79b9c68cb5 (360) Compile fixes 2012-01-07 14:59:11 +01:00
Themaister 2b1344c3cf Clean up and add missing bits to 360 D3D9. 2012-01-07 14:54:55 +01:00
TwinAphex51224 da26925118 (360) Fleshed out video driver some more 2012-01-07 14:13:23 +01:00
Themaister f2a152f7c9 Minor cleanup. 2012-01-07 11:47:53 +01:00
Themaister 1953ea7312 Fix Xenon build. 2012-01-07 11:32:39 +01:00
TwinAphex51224 e55dbe944d (360) changed buf to uint8_t * 2012-01-06 22:55:07 +01:00
Themaister f5ad906e7b Don't need byteswapping on 360. 2012-01-06 22:49:30 +01:00
TwinAphex51224 7cad2bcd6e (360) Some sound fixes 2012-01-06 22:40:40 +01:00
Themaister cc921f25ed Use integer audio on 360. 2012-01-06 22:30:12 +01:00
Themaister 435109ceae Rework SRAM semantics for Sufami. 2012-01-06 20:32:30 +01:00
Themaister ca375f65d5 Call CreateEvent. 2012-01-06 19:45:27 +01:00
Themaister 76212f47bf Fix indentation. 2012-01-06 18:51:45 +01:00
TwinAphex51224 6efb904919 Merge branch 'master' of github.com:Themaister/SSNES 2012-01-06 14:12:38 +01:00
TwinAphex51224 072342cdab (360) Gets to initing audio 2012-01-06 14:12:12 +01:00
Themaister 09761c0786 Merge branch 'master' of github.com:Themaister/SSNES 2012-01-06 00:05:05 +01:00
Themaister c48fab00e8 Remove unneeded header. 2012-01-06 00:04:48 +01:00
TwinAphex51224 d1c562ce4e (360) Small correction to main.c file 2012-01-05 23:19:14 +01:00
Themaister 45cae81d51 Merge branch 'master' of github.com:Themaister/SSNES 2012-01-05 23:10:28 +01:00
Themaister 30e28acfb3 Workaround GetFullPathName not existing on XDK. 2012-01-05 23:09:52 +01:00
TwinAphex51224 00459365c4 Merge branch 'master' of github.com:Themaister/SSNES 2012-01-05 22:47:54 +01:00
TwinAphex51224 649884bc05 (360) Added main files 2012-01-05 22:47:34 +01:00
TwinAphex51224 e1af420b2d (360) More work on 360 2012-01-05 22:46:11 +01:00
Themaister 613f50dd14 Merge branch 'master' of github.com:Themaister/SSNES 2012-01-05 21:45:32 +01:00
Themaister a18c0b2b14 Use const. 2012-01-05 21:43:55 +01:00
TwinAphex51224 d7f8500b3a Merge branch 'master' of github.com:Themaister/SSNES 2012-01-05 20:54:26 +01:00
TwinAphex51224 7ecf9681c5 (360) Updated vcxproj file 2012-01-05 20:54:04 +01:00
Themaister e9ca7acce9 Merge branch 'master' of github.com:Themaister/SSNES 2012-01-05 19:44:39 +01:00
Themaister ea68de8070 Don't use *A() version. 2012-01-05 19:44:11 +01:00
TwinAphex51224 0fa0bfeb74 (360) Compiles in dynamic.c 2012-01-05 19:42:29 +01:00
TwinAphex51224 4a5d0d8dfb (360) Updated solution 2012-01-05 19:35:56 +01:00
Themaister af35a18515 :v 2012-01-05 19:34:15 +01:00
Themaister 5560babc11 Some build fixups. 2012-01-05 19:33:38 +01:00
Themaister 3e76201d80 Rename to C++. 2012-01-05 19:28:19 +01:00
Themaister 5b15d8626c Restructure XAudio2 360 driver. 2012-01-05 19:27:58 +01:00
TwinAphex51224 f8a03a7d5d Merge branch 'master' of github.com:Themaister/SSNES 2012-01-05 18:38:49 +01:00
TwinAphex51224 b7b9acb336 (360) compiles now 2012-01-05 18:38:29 +01:00
Themaister 44e2d66cf5 Mainstub clean. 2012-01-05 17:53:30 +01:00
Themaister 9747767474 Use GetFileAttributes. 2012-01-05 17:41:04 +01:00
Themaister cee33327f8 Ugh 2012-01-05 17:28:11 +01:00
Themaister f70b52a0df Don't use unicode. 2012-01-05 17:27:48 +01:00
Themaister 0b62771b54 Don't use getenv on XBOX. 2012-01-05 17:27:18 +01:00
Themaister b168109672 Fix missing stuff. 2012-01-05 17:23:22 +01:00
Themaister d8b6aebe9a Use plain ASCII for directories. 2012-01-05 17:22:03 +01:00
TwinAphex51224 4812b632c3 (360) Fixed most compile errors for 360 2012-01-05 15:11:55 +01:00
TwinAphex51224 8320d0a0e9 (360) Xaudio2 driver compiles now 2012-01-05 14:48:54 +01:00
TwinAphex51224 a287ebe736 (360) New Xaudio2 driver 2012-01-05 14:17:35 +01:00
TwinAphex51224 ebea0220cd (360) Added 360 solution and added some defines 2012-01-05 13:30:13 +01:00
TwinAphex51224 2b01f36fc0 (360) Added preliminary xdk 360 drivers 2012-01-05 12:37:27 +01:00
Themaister 7e3092dc93 Build in freetype. Will be used later. 2012-01-03 13:04:23 +01:00
Themaister 114c723d59 Only init input once. 2012-01-03 12:22:07 +01:00
Themaister da39f8d3d6 Support classic controller. 2012-01-03 12:11:02 +01:00
Themaister 33b76628aa Far better vsync handling. 2012-01-03 11:32:07 +01:00
Themaister 94162f452d Use RGB5A3 for Wii. 2012-01-03 10:32:51 +01:00
Themaister 318d875981 Small cleanups. 2012-01-03 02:50:45 +01:00
Themaister 520878272c Checks if swapinterval succeeds. 2012-01-02 22:09:55 +01:00
Themaister fc87336c45 MSVC doesn't have PATH_MAX. 2012-01-02 16:03:39 +01:00
Themaister d66e039536 Fix 15->16 bit conversions. 2012-01-02 15:43:46 +01:00
Themaister eeebc2d06b Optimize a bit. 2012-01-02 14:50:03 +01:00
Themaister 7d1ebdf94a Pick linear/nearest filtering correctly. 2012-01-02 13:45:31 +01:00
Themaister 3d1b0ef35b Merge branch 'fix' 2012-01-02 13:33:27 +01:00
Themaister c2ba0d474c Use limits.h and PATH_MAX. 2012-01-02 13:33:03 +01:00
Themaister 793c00e614 Attempt on tiled textures for Wii. 2012-01-02 12:56:09 +01:00
Themaister d4093dc31c Fix build for gekko. 2012-01-02 12:12:30 +01:00
Themaister bc66841a29 More correct save state and rewind handling. 2011-12-27 18:30:14 +01:00
Themaister f4cc8a4bca Update filters. 2011-12-27 03:33:18 +01:00
Themaister 539563f0f4 Add filters to project. 2011-12-27 03:27:28 +01:00
Themaister 8c5d86a6eb Add logging to SDL_Init(). 2011-12-27 01:04:50 +01:00
Themaister 884c113645 Cleanup stupid code. 2011-12-27 00:54:31 +01:00
Themaister 70587bc0df More verbosely log SDL failure. 2011-12-27 00:37:29 +01:00
Themaister df4e0bb1e4 Don't use x64libs. 2011-12-27 00:15:58 +01:00
Themaister cdc92af959 Cleanups. 2011-12-26 16:43:47 +01:00
Themaister 763a5bf2c0 Style nit. 2011-12-26 16:22:34 +01:00
Themaister 8301cf8a2f Style nit. 2011-12-26 16:14:33 +01:00
Themaister 44da8a6749 :v 2011-12-26 01:32:19 +01:00
Themaister 06309ba1e0 Build some more stuff. 2011-12-26 00:06:41 +01:00
Themaister 004ca0fe89 Better formatting. 2011-12-25 21:43:00 +01:00
Themaister 40cce7c9d6 Also log compiler version normally. 2011-12-25 21:39:58 +01:00
Themaister 1c29d31859 Better formatting. 2011-12-25 21:20:07 +01:00
Themaister d3af29fa1f Compiler logging macros. 2011-12-25 21:16:48 +01:00
Themaister c5d1fd32d5 Deinit audio before video. 2011-12-25 19:31:05 +01:00
Themaister a4767d3d43 Add python build. Fix ssize_t define. 2011-12-25 18:25:37 +01:00
Themaister c26f527c20 Enable SSE for 64-bit builds. 2011-12-25 16:50:13 +01:00
Themaister 0c8d85d589 Minor fixes. 2011-12-25 16:47:03 +01:00
Themaister 0c16e1a134 x64 build. 2011-12-25 16:36:56 +01:00
Themaister 0a887395eb Remove useless global. 2011-12-25 16:11:48 +01:00
Themaister 9118976c49 Don't include general.h 2011-12-25 12:56:21 +01:00
Themaister 7f1e599186 Use modern FFmpeg defines. 2011-12-25 12:50:34 +01:00
Themaister 672102d377 Change asserts to ssnes_assert(). 2011-12-25 12:47:47 +01:00
Themaister fe7f05e717 Style nit. 2011-12-25 12:14:26 +01:00
Themaister 0724ab2ca1 Fix assertion bugs. 2011-12-25 12:13:19 +01:00
Themaister c272ba56ad Fix build for Release mode. 2011-12-25 11:45:27 +01:00
Themaister 381498e945 Print feature for DirectSound. 2011-12-25 01:59:30 +01:00
Themaister 70f07196ea gettimeofday() should return int. 2011-12-25 01:54:29 +01:00
Themaister c8dee57278 Set constant macros with define. 2011-12-25 01:45:09 +01:00
Themaister 0ab305156b Fixup header. 2011-12-25 01:41:12 +01:00
Themaister eac468ba19 MSVC compat. 2011-12-25 01:38:59 +01:00
Themaister 18f407110b Fixup compatibility. 2011-12-24 20:43:58 +01:00
Themaister ceee10b56c Fix types. 2011-12-24 15:57:43 +01:00
Themaister 9805bcc5f9 Merge branch 'master' of github.com:Themaister/SSNES 2011-12-24 15:47:47 +01:00
Themaister d5fca50a2f Can build for C++. 2011-12-24 15:26:01 +01:00
Themaister 4ca72bd7e6 Fix endian issues and strict aliasing. 2011-12-24 14:41:19 +01:00
Themaister 62ead00f0f Some additions, but still broken. 2011-12-24 14:41:19 +01:00
TwinAphex51224 5dc573ed38 (Libxenon) Changed texture size to 512x512 - stop libxenon development
for now - no double buffering/triple buffering available - return to
it when it's more mature
2011-12-24 14:41:19 +01:00
TwinAphex51224 fa053ffc2b (Libxenon) Fixed colors 2011-12-24 14:41:18 +01:00
TwinAphex51224 be6c7bad24 (Libxenon) Revert to Xenos driver that works - current issues - colors
are wrong (doing | XE_FMT_ARGB produces 'distorted' graphics but right colors) - no vsync (doing while Xe_IsVBlank(device) Xe_Sync(device) makes everything too
slow
2011-12-24 14:41:18 +01:00
Themaister 2680971bb3 Try some stuff. 2011-12-24 14:41:18 +01:00
Themaister 630f19f248 ... 2011-12-24 14:41:18 +01:00
Themaister ef4bee2e4e Minor fix. 2011-12-24 14:41:18 +01:00
Themaister f182a2ad24 Debork party. Untested. 2011-12-24 14:41:18 +01:00
Themaister 3eb98951f7 :v 2011-12-24 14:41:18 +01:00
Themaister f9d4bbf4d3 Fix endian issues and strict aliasing. 2011-12-19 01:27:04 +01:00
Themaister eff4fcecae Some additions, but still broken. 2011-12-18 13:27:06 +01:00
TwinAphex51224 cbfdc9cf97 (Libxenon) Changed texture size to 512x512 - stop libxenon development
for now - no double buffering/triple buffering available - return to
it when it's more mature
2011-12-16 18:54:12 +01:00
TwinAphex51224 034c7c70fb (Libxenon) Fixed colors 2011-12-16 17:22:37 +01:00
TwinAphex51224 44ad016b91 (Libxenon) Revert to Xenos driver that works - current issues - colors
are wrong (doing | XE_FMT_ARGB produces 'distorted' graphics but right colors) - no vsync (doing while Xe_IsVBlank(device) Xe_Sync(device) makes everything too
slow
2011-12-16 17:09:33 +01:00
Themaister 5ed0d00249 Try some stuff. 2011-12-16 16:38:25 +01:00
Themaister 6336fb4a1b ... 2011-12-16 16:26:44 +01:00
Themaister 99497e21cf Minor fix. 2011-12-16 16:21:58 +01:00
Themaister 0181d97cae Debork party. Untested. 2011-12-16 16:02:30 +01:00
TwinAphex51224 968c73a748 Merge branch 'master' of github.com:Themaister/SSNES 2011-12-16 15:22:56 +01:00
TwinAphex51224 13f9e94f61 (Libxenon 360) Shows video for one/two frames, then crashes 2011-12-16 15:22:25 +01:00
Themaister 8c1018d573 Merge branch 'master' of github.com:Themaister/SSNES 2011-12-16 15:09:46 +01:00
Themaister d4d00a35d7 :v 2011-12-16 15:09:15 +01:00
TwinAphex51224 e3177fd489 (Libxenon) Xenos gfx commit - still broken 2011-12-16 14:43:09 +01:00
Themaister dd1300f1cc Fix rewind granularity setting when not playing movies. 2011-12-16 10:19:45 +01:00
TwinAphex51224 7f03af2b2b (Libxenon) starts up now - borked graphics though :) 2011-12-15 15:32:47 +01:00
TwinAphex51224 f431f77834 (Libxenon) fix (still crashes during init) 2011-12-15 15:19:03 +01:00
TwinAphex51224 7c28a62b40 (Libxenon) No more SDL 2011-12-15 13:54:22 +01:00
TwinAphex51224 a360042f77 Merge branch 'master' of github.com:Themaister/SSNES 2011-12-15 13:38:55 +01:00
TwinAphex51224 82af27cf33 (Libxenon) Initial xenos graphics driver 2011-12-15 13:38:28 +01:00
Themaister 0b78abb31d hrr drr. 2011-12-15 00:28:47 +01:00
Themaister 2fd8ffbf22 Some progress at least. 2011-12-14 23:56:07 +01:00
Themaister 83f7be0cbb Some more stuff. 2011-12-14 22:29:12 +01:00
Themaister 7f5db4d70f Boots up, but broken graphics. 2011-12-14 21:44:03 +01:00
Themaister 4f04c1288b Use fatInit default. 2011-12-14 19:11:46 +01:00
Themaister 8a2c5bf9e1 Some cleanups. 2011-12-14 17:05:23 +01:00
Themaister 5c05e309c1 Xenon input takes prio. 2011-12-14 16:53:13 +01:00
Themaister bd147270eb Use built-in getopt. 2011-12-14 16:40:25 +01:00
Themaister 528cf8d472 Don't use SDL input on xenon. 2011-12-14 16:37:31 +01:00
Themaister 0fce2f409f Add a warning. :3 2011-12-14 16:29:38 +01:00
Themaister fd7b0b05b8 Hurr. 2011-12-14 16:01:16 +01:00
Themaister 9abc7c00c9 It links :o 2011-12-14 14:52:58 +01:00
Themaister ebc5f433cd It links :o 2011-12-14 14:36:23 +01:00
Themaister aa4f79f236 Start working on video. 2011-12-14 14:26:40 +01:00
Themaister 62f5c53b72 Start on Wii input. 2011-12-14 13:20:22 +01:00
Themaister 534163a57f Start adding stuff for Wii. 2011-12-14 12:49:13 +01:00
TwinAphex51224 325a9fb48e (Libxenon) D-pad works now in ROM browser menu 2011-12-14 08:36:04 +01:00
TwinAphex51224 ee43531a99 Merge branch 'master' of github.com:Themaister/SSNES 2011-12-14 01:35:46 +01:00
TwinAphex51224 757fa71469 (Libxenon) Added (non-working) input driver 2011-12-14 01:35:17 +01:00
Themaister bfee7986bd Fix missing break; 2011-12-14 00:58:17 +01:00
Themaister 9aaad17c1a Update Makefile. 2011-12-14 00:44:38 +01:00
Themaister 93874bba83 Fixup makefile. 2011-12-14 00:41:06 +01:00
Themaister 9c67452f10 <________________________< 2011-12-14 00:36:28 +01:00
Themaister 0416a2ae61 Don't use float <_< 2011-12-14 00:30:03 +01:00
Themaister 8bbde14019 Merge branch 'master' of github.com:Themaister/SSNES 2011-12-14 00:25:26 +01:00
Themaister 0e8f2339d8 Might work better ... 2011-12-14 00:25:04 +01:00
TwinAphex51224 9f37427d7a (Libxenon) Compile with -O3 2011-12-13 23:50:56 +01:00
Themaister 6ad4b1f15a Little endian DAC on 360 (lolwut?) 2011-12-13 23:44:55 +01:00
Themaister a39c0f01f9 Should fix up audio driver a bit. 2011-12-13 23:38:05 +01:00
TwinAphex51224 1136820124 (Libxenon) Terribly borked libxenon audio driver :) 2011-12-13 23:17:37 +01:00
TwinAphex51224 2a3f3bad23 (360 Libxenon) Initial xenon 360 audio driver 2011-12-13 22:57:49 +01:00
Themaister 74def91a53 Debork main a bit. 2011-12-13 21:48:17 +01:00
TwinAphex51224 bc62e1be08 (Libxenon) Added slimjim Libxenon filebrowser - from examples 2011-12-13 21:12:50 +01:00
Themaister 25aea134ef Add temporary hack for SDL cond in Xenon. 2011-12-13 19:34:45 +01:00
Themaister e488c3081d Small nit. 2011-12-11 13:14:44 +01:00
Themaister 331f46fb24 Missing stuff. 2011-12-11 12:51:32 +01:00
Themaister e88662cab0 Updates for 0.9.3. 2011-12-11 12:50:16 +01:00
Themaister 395f6d1d3c Build fixups. 2011-12-10 18:02:50 +01:00
Themaister 94bd78b3e1 Merge branch 'master' of github.com:Themaister/SSNES
Conflicts:
	Makefile.xenon
2011-12-10 17:42:07 +01:00
Themaister dc373fb7d0 Gets to link, but fails there. 2011-12-10 17:41:16 +01:00
Themaister 140812d64a Fixup xenon makefile a bit. 2011-12-10 16:26:26 +01:00
TwinAphex51224 a91c4e556f (360 Libxenon) change to makefile - use built-in getopt 2011-12-10 16:22:37 +01:00
Themaister 372c622166 Nits. 2011-12-10 15:23:20 +01:00
TwinAphex51224 d961d68e9c (360 / Libxenon) Added Libxenon Makefile 2011-12-07 03:19:12 +01:00
Themaister 33a325a730 Nit. 2011-12-07 01:13:06 +01:00
Themaister 909b25c7ac Remove XML stuff. 2011-12-04 18:44:50 +01:00
Themaister 77f110c23e Nits. 2011-12-04 18:26:17 +01:00
Themaister 9dc9416ef9 Merge branch 'ssnes-ps3' 2011-12-04 18:13:31 +01:00
Themaister 0b20f11617 Nits. 2011-12-04 18:06:50 +01:00
Themaister c9594776f8 Style nits. 2011-12-04 18:06:50 +01:00
Themaister 8f55b9904d Update license. 2011-12-04 18:06:50 +01:00
Themaister 093ba1c33d Dynamic fix. 2011-12-04 18:06:50 +01:00
Themaister 67a434d563 Clean. 2011-12-04 18:06:50 +01:00
Themaister ff0c3f047a Some cleanups. 2011-12-04 18:06:50 +01:00
Themaister 2934ba301b Nit. 2011-12-04 18:06:50 +01:00
Themaister f3627aaf59 Nits. 2011-12-04 18:03:08 +01:00
Themaister dc8a2dea72 Style nits. 2011-12-04 18:00:55 +01:00
Themaister 329969eb05 Update license. 2011-12-04 17:57:25 +01:00
Themaister 71923af675 Dynamic fix. 2011-12-04 17:54:00 +01:00
Themaister 18e58ca5f4 Clean. 2011-12-04 17:30:44 +01:00
Themaister 8c3aebbbc8 Some cleanups. 2011-12-04 17:29:59 +01:00
Themaister 7f40c11eb7 Merge branch 'master' of github.com:Themaister/SSNES into ssnes-ps3 2011-12-04 17:24:28 +01:00
Themaister 0ed668d1b5 Minor cleanups. 2011-12-04 17:19:21 +01:00
Themaister 1c8632cac9 Nit. 2011-12-04 17:17:49 +01:00
TwinAphex51224 e7324989fc (PS3) Better extra button bindings 2011-12-04 04:11:02 +01:00
TwinAphex51224 a7fc3807b9 (PS3) Cleaned up indenting in ps3_input.c 2011-12-04 04:00:17 +01:00
TwinAphex51224 99ad7bcc51 Merge branch 'master' of github.com:Themaister/SSNES into ssnes-consoles 2011-12-04 03:43:52 +01:00
Themaister 5b88e338df Nits. 2011-12-04 01:42:00 +01:00
Themaister 425af71450 GET_CAN_REWIND. 2011-12-04 01:40:25 +01:00
Themaister 19c5eab07a Minor clean. 2011-12-04 01:30:16 +01:00
Themaister e5286cbe39 Update XAudio for pure C. 2011-12-04 01:10:16 +01:00
Themaister 02d40aa212 Drop shadows for fonts. 2011-12-03 19:48:13 +01:00
Themaister 8a5c537e15 Fix warning. 2011-12-03 04:09:40 +01:00
TwinAphex51224 c6c4f2f4d1 (PS3) Debug fonts hooked up 2011-12-03 03:52:53 +01:00
TwinAphex51224 5bc7ea4045 (PS3) Properly exits now with shader loaded 2011-12-03 03:10:23 +01:00
TwinAphex51224 077acf7894 (PS3) Savestates hooked up (R2 + R3 - save state - L2 + R3 - load state -
R2 + Right stick right - save state plus - R2 + Right stick left - save state minus)
2011-12-03 02:40:20 +01:00
TwinAphex51224 c5f86f12c0 Revert "(PS3) Would not cleanly exit on PS3 without this - perhaps something"
This reverts commit 243e941d81.
2011-12-03 01:56:41 +01:00
TwinAphex51224 243e941d81 (PS3) Would not cleanly exit on PS3 without this - perhaps something
Cg-related needs deiniting prior to exit(0)
2011-12-03 01:54:57 +01:00
TwinAphex51224 d67e6b7c15 (PS3) Cg shader support fixed 2011-12-03 01:26:56 +01:00
Themaister f76bf59fed Merge branch 'master' of github.com:Themaister/SSNES into ssnes-consoles 2011-12-03 00:49:26 +01:00
Themaister 1c4d88eb04 Compiles ... properly. 2011-12-03 00:49:09 +01:00
Themaister ad04db8365 Fix includes. 2011-12-03 00:48:42 +01:00
TwinAphex51224 a63ccbbdab (PS3) Implemented rewind/fast forward hooks 2011-12-03 00:07:01 +01:00
Themaister 278f314c03 Merge branch 'master' of github.com:Themaister/SSNES into ssnes-consoles 2011-12-02 22:57:13 +01:00
Themaister a3abda7e7b Refactor. 2011-12-02 22:56:11 +01:00
Themaister c0a9db111d Fix bug with reordering. 2011-12-02 22:23:19 +01:00
TwinAphex51224 676ce10119 (PS3) Now reads from config file 2011-12-02 22:22:44 +01:00
Themaister c18dce4783 Merge branch 'master' of github.com:Themaister/SSNES into ssnes-consoles 2011-12-02 22:25:37 +01:00
Themaister 088b01b52e More logial ordering. 2011-12-02 21:37:35 +01:00
Themaister c0f436b8ab Minor nit. 2011-12-02 21:25:25 +01:00
Themaister 3377020242 Fixup build. 2011-12-02 21:24:33 +01:00
Themaister 6db58fe1dd Merge branch 'ssnes-consoles' of github.com:Themaister/SSNES into ssnes-consoles 2011-12-02 21:22:36 +01:00
Themaister 67c7cd8de9 No default config path on ps3. 2011-12-02 21:22:14 +01:00
Themaister 457a3d458a Merge branch 'master' of github.com:Themaister/SSNES into ssnes-consoles
Conflicts:
	general.h
2011-12-02 21:18:09 +01:00
Themaister 6538312d86 Fix some includes. 2011-12-02 21:16:51 +01:00
TwinAphex51224 7f1a5075b1 Updated Makefile 2011-12-02 21:14:25 +01:00
Themaister e412ecdefe Do not exit() prematurely. 2011-12-02 19:28:39 +01:00
Themaister 67b89d6f42 Kill off useless font rendering code. 2011-12-02 19:19:48 +01:00
Themaister c8d3278dbc Merge branch 'master' of github.com:Themaister/SSNES into ssnes-consoles 2011-12-02 19:15:21 +01:00
Themaister 3556445660 Add new extension support. 2011-12-02 19:12:47 +01:00
Themaister f28fc0cabb Merge branch 'ssnes-consoles' of github.com:Themaister/SSNES into ssnes-consoles 2011-12-02 16:22:05 +01:00
Themaister e0bc548400 sys_lw synchro. 2011-12-02 16:21:01 +01:00
TwinAphex51224 011a4c8a89 Merge branch 'ssnes-consoles' of github.com:Themaister/SSNES into ssnes-consoles 2011-12-02 15:59:40 +01:00
TwinAphex51224 87bc5220eb (PS3) Takes care of audio pop 2011-12-02 15:59:07 +01:00
Themaister 673d0ed1a2 Minor fix. 2011-12-02 15:55:49 +01:00
Themaister a5079bdda1 Should improve the state of audio. 2011-12-02 15:50:51 +01:00
Themaister fc43e7155e Should fixup input. 2011-12-02 15:33:14 +01:00
TwinAphex51224 4935333b63 (PS3) Updated icon + PARAM.SFO title 2011-12-02 04:52:29 +01:00
TwinAphex51224 5a3232adff (PS3) SSNES PS3 lives :) - audio, video works - controls don't
seem to work
2011-12-02 03:46:31 +01:00
TwinAphex51224 d03f351f33 (PS3) Crashes in find_audio_driver (driver.c) 2011-12-02 03:32:04 +01:00
TwinAphex51224 8d5bf997a9 Made global g_quitting variable in PSGL driver 2011-12-02 02:51:21 +01:00
Themaister 0738480439 Make sure set_defaults is called. 2011-12-02 02:48:04 +01:00
TwinAphex51224 9a5e1a31ad Merge branch 'ssnes-consoles' of github.com:Themaister/SSNES into ssnes-consoles 2011-12-02 02:47:28 +01:00
Themaister 5ab7664f49 Merge branch 'master' of github.com:Themaister/SSNES into ssnes-consoles 2011-12-02 02:48:26 +01:00
TwinAphex51224 1cb2c60ccc Calblack put in video_psgl.c - not sure how to use it there 2011-12-02 02:46:47 +01:00
Themaister 1356d0ab4c .___. 2011-12-02 02:41:32 +01:00
Themaister b4c4a65f2d Clear up input. 2011-12-02 02:34:06 +01:00
Themaister ab3cf8daca Merge branch 'ssnes-consoles' of github.com:Themaister/SSNES into ssnes-consoles 2011-12-02 02:25:40 +01:00
Themaister 2b6c252747 Minor fixes. 2011-12-02 02:22:29 +01:00
TwinAphex51224 ec9a6ac90a Can make a PKG now 2011-12-02 02:07:46 +01:00
Themaister a207549f18 fixup stub. 2011-12-02 01:59:44 +01:00
Themaister efbf9354f9 It ... links! 2011-12-02 01:59:07 +01:00
Themaister 216ddc9fd6 Merge branch 'ssnes-consoles' of github.com:Themaister/SSNES into ssnes-consoles 2011-12-02 01:38:24 +01:00
Themaister 3b668cccd3 Add audio/utils.o. 2011-12-02 01:38:04 +01:00
Themaister 30a86a2845 Merge branch 'master' of github.com:Themaister/SSNES into ssnes-consoles 2011-12-02 01:35:15 +01:00
Themaister a7870aa888 Altivec sample conversion. 2011-12-02 01:34:02 +01:00
TwinAphex51224 271b99981c Won't link right now 2011-12-02 01:28:47 +01:00
Themaister 08ef01bb13 Merge branch 'master' of github.com:Themaister/SSNES into ssnes-consoles
Conflicts:
	dynamic.c
2011-12-02 00:07:54 +01:00
Themaister e778af462a Stub main. 2011-12-02 00:01:48 +01:00
Themaister 9d124b2380 Do not use anything dylib related if not compiled in. 2011-12-01 22:36:26 +01:00
Themaister f24e7cd665 Texrefs (untested). 2011-12-01 22:21:15 +01:00
Themaister e7f1526942 Fix compilation errors. 2011-12-01 21:54:42 +01:00
TwinAphex51224 647b1ba53c (PS3) Comiles now, doesn't link 2011-12-01 21:23:49 +01:00
TwinAphex51224 eac8d9f191 Update to PSGL driver 2011-12-01 11:25:08 +01:00
TwinAphex51224 50babe8432 More commits to PSGL driver 2011-11-30 23:50:31 +01:00
TwinAphex51224 8171977ed7 Preliminary version of PSGL video driver 2011-11-30 21:54:25 +01:00
TwinAphex51224 f8aaf1df1e (PS3) Some more commits 2011-11-30 18:32:45 +01:00
Themaister 04d0d84d01 Fix up more paths. 2011-11-30 18:31:09 +01:00
TwinAphex51224 f4aa9fa865 Merge branch 'master' of github.com:Themaister/SSNES into ssnes-consoles 2011-11-30 18:27:11 +01:00
TwinAphex51224 40ef7d6f00 Improved Makefile a bit 2011-11-30 18:26:42 +01:00
TwinAphex51224 66b7b1691c (PS3) Removed thread.o from Makefile 2011-11-30 18:19:34 +01:00
Themaister 43972d4c35 Fix build. 2011-11-30 18:18:50 +01:00
TwinAphex51224 632545c409 Merge branch 'master' of github.com:Themaister/SSNES into ssnes-consoles 2011-11-30 18:13:27 +01:00
TwinAphex51224 3a47e2cd63 Merge branch 'master' of github.com:Themaister/SSNES into ssnes-consoles 2011-11-30 18:11:06 +01:00
Themaister a221e3e4cd Enable/disable threading support. 2011-11-30 17:46:58 +01:00
Themaister b87f50dc9d Fix include path. 2011-11-30 17:34:18 +01:00
Themaister a5b3f421d1 Fix include paths for libsnes header. 2011-11-30 17:32:30 +01:00
TwinAphex51224 182525afa9 Merge branch 'master' of github.com:Themaister/SSNES into ssnes-consoles 2011-11-30 17:28:11 +01:00
TwinAphex51224 419afbcb83 Progresses to thread.c now 2011-11-30 17:27:47 +01:00
Themaister 12ca70a308 Refactor binds. 2011-11-30 17:25:44 +01:00
TwinAphex51224 1fa7663d3b Put in old input driver too - progresses to dynamic.c now 2011-11-30 17:24:18 +01:00
TwinAphex51224 2e34c6fc5c Moved in old PS3 audio driver 2011-11-30 17:11:42 +01:00
Themaister cb7002559d Put defines in makefile. 2011-11-30 17:01:15 +01:00
TwinAphex51224 36ec92793f Put PACKAGE_VERSION define in Makefile 2011-11-30 16:58:20 +01:00
TwinAphex51224 4187d70b30 Merge branch 'master' of github.com:Themaister/SSNES into ssnes-consoles 2011-11-30 16:56:38 +01:00
Themaister 5969655c3c Do not allow netplay args if not compiled in. 2011-11-30 16:43:09 +01:00
Themaister 09d2ec7d3a Do not build in anything netplay related if not included. 2011-11-30 16:41:00 +01:00
TwinAphex51224 27b975d0fc Add in PS3 define for ssnes_sleep 2011-11-30 16:40:52 +01:00
TwinAphex51224 6da64013fa Merge branch 'master' of github.com:Themaister/SSNES into ssnes-consoles 2011-11-30 16:38:53 +01:00
Themaister d8eb5de380 Do not include netplay header needlessly. 2011-11-30 16:27:16 +01:00
Themaister 23aa8bbe7a Actually use sleep param. 2011-11-30 16:26:23 +01:00
TwinAphex51224 3b5472dbac Merge branch 'master' of github.com:Themaister/SSNES into ssnes-consoles 2011-11-30 16:22:16 +01:00
TwinAphex51224 3b4e60aada Header guards for netplay.c not necessary 2011-11-30 16:21:21 +01:00
TwinAphex51224 8d8fb44c18 Use getopt replacement 2011-11-30 16:19:12 +01:00
TwinAphex51224 b46fb60a6e Merge branch 'master' of github.com:Themaister/SSNES into ssnes-consoles 2011-11-30 16:02:49 +01:00
Themaister f7399bbc8b Fix docs. 2011-11-30 12:09:22 +01:00
Themaister 7f7d47b120 Custom getopt for portability. 2011-11-30 11:48:53 +01:00
TwinAphex51224 e7aa3ed0cc Compile in OpenGL and Cg 2011-11-30 01:41:50 +01:00
TwinAphex51224 0ece8b1319 Added static Makefile for PS3 2011-11-30 01:33:14 +01:00
TwinAphex51224 557e05dd12 initial new branch 2011-11-30 01:07:38 +01:00
Themaister 08a1496501 Use big-endian BSV1 magic.
Keep compatibility with old implementation.
Documentation was suggesting little-endian, but this was not correct.
2011-11-28 02:11:33 +01:00
Themaister 5a24037c61 Update joyconfig. 2011-11-26 16:02:49 +01:00
Themaister 5dbd1ea35c Add mute toggle. 2011-11-26 15:54:58 +01:00
Themaister 2476e3dee3 Updates for 0.9.2. 2011-11-24 13:13:55 +01:00
Themaister c05a5c9fdd Only init Video if it isn't already. 2011-11-23 03:26:56 +01:00
Themaister 503c51d633 Check for additional fonts. 2011-11-22 18:52:20 +01:00
Themaister 46054de4f8 Fix possible segfault. 2011-11-22 17:32:38 +01:00
Themaister 604eb9b973 Can dupe extension. 2011-11-22 17:27:02 +01:00
Themaister 0e72120bdc Updates for 0.9.2-rc2. 2011-11-21 16:30:35 +01:00
Themaister b8064f5d42 New semantics for BSV movie recording. 2011-11-20 20:19:05 +01:00
Themaister 379b14a0f3 Flush more sanely. 2011-11-20 03:19:17 +01:00
Themaister 2a598c0b97 Do not quit SSNES on movie playback end. 2011-11-20 03:00:21 +01:00
Themaister aa124b4c40 Should fix occasional horrible noise on end of recordings. 2011-11-20 02:44:21 +01:00
Themaister bb5e31df0d Still record audio even if audio is not enabled. 2011-11-20 02:06:25 +01:00
Themaister e49d216884 Check for large skews in timing. 2011-11-19 14:16:55 +01:00
Themaister 598d06fcb5 More explicitly log paths. 2011-11-19 01:33:21 +01:00
Themaister 7f13ec88e6 Simplify things a bit. 2011-11-18 18:43:02 +01:00
Themaister c5c60c6f53 Add --bsvrecord. 2011-11-18 18:03:24 +01:00
Themaister 81b0e6d0a3 Use display refresh rates rather than input rate directly. 2011-11-18 15:14:56 +01:00
Themaister da97b29d0b Update FFmpeg to use new define in Win32. 2011-11-18 13:07:24 +01:00
Themaister 69b7f92285 Updates for 0.9.2-rc1. 2011-11-18 12:17:25 +01:00
Themaister 3a9dbbc8b7 Pause while inactive disabled by default. 2011-11-17 21:17:29 +01:00
Themaister bf5db10459 Change timeout message to be less misleading. 2011-11-16 22:30:57 +01:00
Themaister 4fa27a5f0f Binaries link in README. 2011-11-16 21:28:30 +01:00
Themaister 3e7c412738 Custom timing support for FFmpeg recording. 2011-11-16 18:56:42 +01:00
Themaister 88c870dcfa Allow -L/--libsnes from command line. 2011-11-15 21:15:12 +01:00
Themaister 66e1179503 Do not remove -s. 2011-11-15 16:44:40 +01:00
Themaister 4ecea5d0a4 Expose python to external drivers. 2011-11-15 15:41:49 +01:00
Themaister 57816edfd3 Fix some hardcoding. 2011-11-13 17:44:20 +01:00
Themaister 17cf0985c5 Typo. 2011-11-13 17:10:21 +01:00
Themaister 776b0a1e2d Add a helper define for input scale. 2011-11-13 17:09:49 +01:00
Themaister 4a6392aefa Fix wrong placement of line in print_help(). 2011-11-13 01:12:32 +01:00
Themaister 29dd4727b8 Disable used attribs in Cg as well. 2011-11-12 18:31:22 +01:00
Themaister face42a888 Disable used attributes on shader change. 2011-11-12 18:20:54 +01:00
Themaister 45fa6795c3 Fixups. 2011-11-12 16:43:59 +01:00
Themaister a9d339efb4 Use glColorPointer(). 2011-11-12 15:51:37 +01:00
Themaister 60841b01a5 Use custom "stock" program. 2011-11-12 15:26:24 +01:00
Themaister ad67511483 Cleanups. PREV{1-6} for GLSL as well. 2011-11-12 14:18:10 +01:00
Themaister 104fb4fb16 nits. 2011-11-12 13:00:37 +01:00
Themaister 816ef095ed Lots of PREV frames in Cg. 2011-11-12 12:55:03 +01:00
Themaister 48e8472f9c Ring buffer of 8 textures :o 2011-11-12 12:28:07 +01:00
Themaister 1755500b19 Source cleanup. 2011-11-12 01:42:37 +01:00
Themaister 4bfc827eb2 Some fixes to Python. 2011-11-11 19:20:56 +01:00
Themaister ddfeacbd83 Minor fixes and cleanups to BSV. 2011-11-11 00:55:35 +01:00
Themaister 79353f861c Do not report dupes. 2011-11-10 00:49:45 +01:00
Themaister f3f4efe304 Improve error reporting in Cg. 2011-11-10 00:46:39 +01:00
Themaister 51721b4cb6 video_font_enable. 2011-11-10 00:15:41 +01:00
Themaister 477091ce8f Do not force crop_overscan with ffmpeg. 2011-11-10 00:03:52 +01:00
Themaister 2707b87767 Should fix overscan overcrop. 2011-11-09 23:58:14 +01:00
Themaister b3d422b5cd rubyFrameDirection / IN.frame_direction. 2011-11-09 23:45:34 +01:00
Themaister d1dc65f202 Cleaner setup of bind-map. 2011-11-09 22:47:12 +01:00
Themaister 7815940a97 SNES_ENVIRONMENT_OVERSCAN. 2011-11-09 22:18:48 +01:00
Themaister 4f841c208d Use --qp 0 rather than --crf 0 for lossless. 2011-11-07 23:16:32 +01:00
Themaister b4f0d9b8f8 Restrict number of lag frames. 2011-11-06 20:38:42 +01:00
Themaister b96ab2982c Should fix minor issues with timeouts when lag frames > 8. 2011-11-06 20:28:02 +01:00
Themaister 825c1de7d1 Nits. 2011-11-05 15:24:29 +01:00
Themaister 6ada4d87d3 Style nit. 2011-11-05 13:34:41 +01:00
Themaister 53abc92322 Add some metadata. Should be a workaround. 2011-11-05 12:25:09 +01:00
Themaister a816082ac3 Style nit. 2011-11-05 11:44:17 +01:00
Themaister 47e63f1c6b Style nit. 2011-11-05 11:37:04 +01:00
Themaister cdf3d05c8e Should fix spurious timeouts for netplay. 2011-11-04 00:18:17 +01:00
Themaister 389e9ba0dc Style nit. 2011-11-04 00:07:53 +01:00
Themaister a6f7a2311f Minor cleanups for hermite. 2011-11-03 23:48:36 +01:00
Themaister f19d99d523 Log error when netplay init fails. 2011-11-03 21:05:12 +01:00
Themaister e7082fd6ea Warning nit. 2011-11-02 20:33:37 +01:00
Themaister 4806d2fe88 Clear up inconsistencies, and avoid breaking standard compliance. 2011-11-02 20:04:31 +01:00
Themaister f85ff7124b More nits. 2011-11-02 19:34:08 +01:00
Themaister 0f010cf3d2 Fix style nits. 2011-11-02 19:31:36 +01:00
Themaister 95636d4f04 Refactor XVideo driver. Also, attempts harder to find suitable formats. 2011-11-02 17:51:15 +01:00
Themaister 43905e410e Fix build ... *grummel* 2011-11-02 17:04:49 +01:00
Themaister d23a7e3ddf HAVE_OPENGL=1 in Windows. 2011-11-02 17:02:59 +01:00
Themaister 652f4c5856 More explicit checking for inconsistency. 2011-11-02 16:54:45 +01:00
Themaister 90febc4ecf Use dynamic by default.
FFmpeg and Python does not require explicit --enable.
2011-11-02 16:50:34 +01:00
Themaister 34b5994842 Fix minor issue. 2011-11-01 21:28:32 +01:00
Themaister 0c3f6ed66b Cleanup and optimize rewind a bit. Forced POT buffer size. 2011-11-01 21:00:41 +01:00
Themaister f3e487557e Fix some style nits. 2011-11-01 20:27:59 +01:00
Themaister ee12266a2b Fix build for OSX. 2011-11-01 18:45:50 +01:00
Themaister 1981b14de9 Allow OpenGL to be disabled. 2011-11-01 18:24:43 +01:00
Themaister 65665f36cc Fixup netplay. 2011-10-31 22:51:54 +01:00
Themaister a48dc55c41 Fix ugly possible segfault. 2011-10-30 16:58:45 +01:00
Themaister 202a458524 Updates for 0.9.1. 2011-10-30 11:24:16 +01:00
Themaister b4de704a09 Style nit. 2011-10-30 02:12:00 +02:00
Themaister fef5edfac8 Change default aspect handling. 2011-10-30 01:58:08 +02:00
Themaister a6e74775b1 Edge trigger reset. 2011-10-29 13:35:01 +02:00
Themaister ee66a28d05 Style nit. 2011-10-29 13:33:15 +02:00
Themaister 5e28d82af2 Fix compile with HAVE_CONFIGFILE=0. 2011-10-28 17:10:58 +02:00
Themaister c2a06bfa09 Replace some magic numbers. 2011-10-28 09:06:34 +02:00
Themaister 66510e21aa Fixup build for non dynamic builds. 2011-10-28 00:34:42 +02:00
Themaister ec5e3355b9 Add some logging. 2011-10-28 00:23:49 +02:00
Themaister 0522a2d6a0 Start implementing some minor extensions to libsnes. 2011-10-27 23:40:34 +02:00
Themaister fad89f9d2d More gracious error handling for state tracker. 2011-10-26 19:51:10 +02:00
Themaister 97f937ec6d Use floating point values for uniforms from Python. 2011-10-26 10:26:09 +02:00
Themaister 9647006a2b Merge branch 'master' of github.com:Themaister/SSNES 2011-10-25 23:03:20 +02:00
Themaister 418ba455f8 Allow the rest of the buttons in Python.
Fix issue where long type was enforced for return values of uniforms.
2011-10-25 23:02:17 +02:00
Themaister 197d62860b Default screenshot directory. 2011-10-24 21:34:30 +02:00
Themaister 402451626f More accurate colors for screenshot. 2011-10-24 19:23:58 +02:00
Themaister 3739cbfc70 Minor cleanup for rewind. 2011-10-23 17:13:16 +02:00
Themaister 235355ffc7 Check more explicitly for XVideo and Xext. 2011-10-23 12:48:44 +02:00
Themaister 4856d0cac3 Allow screenshots while paused. 2011-10-23 12:38:11 +02:00
Themaister 77a2723bb0 Neat optimizations for SSE. 2011-10-23 02:56:33 +02:00
Themaister 41cd6e21c3 Use _mm* intrinsics. 2011-10-22 23:36:02 +02:00
Themaister 1fc99c7123 Fix deprecation warning. 2011-10-22 22:54:36 +02:00
Themaister fddcc3447c Fix build for Clang. 2011-10-22 22:19:54 +02:00
162 changed files with 14510 additions and 3165 deletions

No files matched your search

View File
Whitespace-only changes.
+9 -1
View File
@@ -1,7 +1,15 @@
*.o
*.bmpobj
*.so
*.dll
ssnes
/ssnes
/config.h
/config.mk
/tools/ssnes-joyconfig
*.sdf
*.opensdf
*.suo
Debug
Release
ipch
*.user
+42
View File
@@ -0,0 +1,42 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
* Copyright (C) 2011-2012 - Daniel De Matteis
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <xtl.h>
#include <stddef.h>
#include <xbdm.h>
int ssnes_main(int argc, char *argv[]);
#undef main
// Temporary, a more sane implementation should go here.
int main(int argc, char *argv[])
{
//for devits only, we will need to mount all partitions for retail
//in a different way
DmMapDevkitDrive();
char arg1[] = "ssnes";
char arg2[] = "e:\\roms\\mario.sfc";
char arg3[] = "-v";
char arg4[] = "-c";
char arg5[] = "e:\\roms\\ssnes.cfg";
char *argv_[] = { arg1, arg2, arg3, arg4, arg5, NULL };
return ssnes_main(sizeof(argv_) / sizeof(argv_[0]) - 1, argv_);
}
+49
View File
@@ -0,0 +1,49 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __SSNES_MSVC_COMPAT_H
#define __SSNES_MSVC_COMPAT_H
#ifdef _MSC_VER
#undef UNICODE // Do not bother with UNICODE at this time.
#include <stddef.h>
#include <math.h>
// Python headers defines ssize_t and sets HAVE_SSIZE_T. Cannot duplicate these efforts.
#ifndef HAVE_SSIZE_T
typedef int ssize_t;
#endif
#define snprintf _snprintf
#define strcasecmp _stricmp
// Disable some of the annoying warnings.
#pragma warning(disable : 4800)
#pragma warning(disable : 4244)
#pragma warning(disable : 4305)
#pragma warning(disable : 4146)
#pragma warning(disable : 4267)
static inline float roundf(float in)
{
return in >= 0.0f ? floorf(in + 0.5f) : ceilf(in - 0.5f);
}
#endif
#endif
+222
View File
@@ -0,0 +1,222 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "../driver.h"
#include <stdlib.h>
#include <xtl.h>
#include <xaudio2.h>
#include "../general.h"
#define MAX_BUFFERS 16
#define MAX_BUFFERS_MASK 15
struct XAudio : public IXAudio2VoiceCallback
{
XAudio() :
buf(0), pXAudio2(0), pMasteringVoice(0),
pSourceVoice(0), nonblock(false), bufsize(0),
bufptr(0), write_buffer(0), buffers(0), hEvent(0)
{}
~XAudio()
{
if (pSourceVoice)
{
pSourceVoice->Stop(0, XAUDIO2_COMMIT_NOW);
pSourceVoice->DestroyVoice();
}
if (pMasteringVoice)
pMasteringVoice->DestroyVoice();
if (pXAudio2)
pXAudio2->Release();
if (hEvent)
CloseHandle(hEvent);
delete[] buf;
}
bool init(unsigned rate, unsigned latency)
{
size_t bufsize_ = latency * rate / 1000;
size_t size = bufsize_ * 2 * sizeof(int16_t);
SSNES_LOG("XAudio2: Requesting %d ms latency, using %d ms latency.\n", latency, (int)bufsize_ * 1000 / rate);
if (FAILED(XAudio2Create(&pXAudio2, 0)))
return false;
if (FAILED(pXAudio2->CreateMasteringVoice(&pMasteringVoice, 2, rate, 0, 0, NULL)))
return false;
WAVEFORMATEX wfx = {0};
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 2;
wfx.nSamplesPerSec = rate;
wfx.nBlockAlign = 2 * sizeof(int16_t);
wfx.wBitsPerSample = sizeof(int16_t) * 8;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
wfx.cbSize = 0;
if (FAILED(pXAudio2->CreateSourceVoice(&pSourceVoice, &wfx,
XAUDIO2_VOICE_NOSRC, XAUDIO2_DEFAULT_FREQ_RATIO, this, 0, 0)))
return false;
hEvent = CreateEvent(0, FALSE, FALSE, 0);
bufsize = size / MAX_BUFFERS;
buf = new uint8_t[bufsize * MAX_BUFFERS];
memset(buf, 0, bufsize * MAX_BUFFERS);
if (FAILED(pSourceVoice->Start(0)))
return false;
return true;
}
// It's really 16-bit, but we have to byteswap.
size_t write(const uint8_t *buffer, size_t size)
{
if (nonblock)
{
size_t avail = bufsize * (MAX_BUFFERS - buffers - 1);
if (avail == 0)
return 0;
if (avail < size)
size = avail;
}
unsigned bytes = size;
while (bytes)
{
unsigned need = min(bytes, bufsize - bufptr);
uint8_t *base_write = buf + write_buffer * bufsize + bufptr;
memcpy(base_write, buffer, need);
bufptr += need;
buffer += need;
bytes -= need;
if (bufptr == bufsize)
{
while (buffers == MAX_BUFFERS - 1)
WaitForSingleObject(hEvent, INFINITE);
XAUDIO2_BUFFER xa2buffer = {0};
xa2buffer.AudioBytes = bufsize;
xa2buffer.pAudioData = buf + write_buffer * bufsize;
if (FAILED(pSourceVoice->SubmitSourceBuffer(&xa2buffer)))
return 0;
InterlockedIncrement(&buffers);
bufptr = 0;
write_buffer = (write_buffer + 1) & MAX_BUFFERS_MASK;
}
}
return size;
}
STDMETHOD_(void, OnBufferStart) (void *) {}
STDMETHOD_(void, OnBufferEnd) (void *)
{
InterlockedDecrement(&buffers);
SetEvent(hEvent);
}
STDMETHOD_(void, OnLoopEnd) (void *) {}
STDMETHOD_(void, OnStreamEnd) () {}
STDMETHOD_(void, OnVoiceError) (void *, HRESULT) {}
STDMETHOD_(void, OnVoiceProcessingPassEnd) () {}
STDMETHOD_(void, OnVoiceProcessingPassStart) (UINT32) {}
uint8_t *buf;
IXAudio2 *pXAudio2;
IXAudio2MasteringVoice *pMasteringVoice;
IXAudio2SourceVoice *pSourceVoice;
bool nonblock;
unsigned bufsize;
unsigned bufptr;
unsigned write_buffer;
volatile long buffers;
HANDLE hEvent;
};
static void *xa_init(const char *device, unsigned rate, unsigned latency)
{
if (latency < 8)
latency = 8; // Do not allow shenanigans.
XAudio *xa = new XAudio;
if (!xa->init(rate, latency))
goto error;
return xa;
error:
SSNES_ERR("Failed to init XAudio2.\n");
delete xa;
return NULL;
}
static ssize_t xa_write(void *data, const void *buf, size_t size)
{
XAudio *xa = (XAudio*)data;
size_t ret = xa->write((const uint8_t*)buf, size);
if (ret == 0)
return -1;
return ret;
}
static bool xa_stop(void *data)
{
(void)data;
return true;
}
static void xa_set_nonblock_state(void *data, bool state)
{
XAudio *xa = (XAudio*)data;
xa->nonblock = state;
}
static bool xa_start(void *data)
{
(void)data;
return true;
}
static void xa_free(void *data)
{
XAudio *xa = (XAudio*)data;
if (xa)
delete xa;
}
const audio_driver_t audio_xdk360 = {
xa_init,
xa_write,
xa_stop,
xa_start,
xa_set_nonblock_state,
xa_free,
NULL,
"xdk360"
};
+124
View File
@@ -0,0 +1,124 @@
/* SSNES - A Super Ninteno Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
* Copyright (C) 2011-2012 - Daniel De Matteis
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <stdlib.h>
#include <xtl.h>
#include "../driver.h"
#include "../libsnes.hpp"
static XINPUT_STATE state[5];
static void xdk360_input_poll(void *data)
{
(void)data;
ZeroMemory(&state, sizeof(XINPUT_STATE));
for (unsigned i = 0; i < 5; i++)
XInputGetState(i, &state[i]);
}
static int16_t xdk360_input_state(void *data, const struct snes_keybind **binds,
bool port, unsigned device,
unsigned index, unsigned id)
{
(void)data;
(void)binds;
(void)index;
if (device != SNES_DEVICE_JOYPAD)
return 0;
unsigned player = 0;
if (port == SNES_PORT_2 && device == SNES_DEVICE_MULTITAP)
player = index + 1;
else if (port == SNES_PORT_2)
player = 1;
// Hardcoded binds.
uint64_t button;
switch (id)
{
case SNES_DEVICE_ID_JOYPAD_A:
button = XINPUT_GAMEPAD_B;
break;
case SNES_DEVICE_ID_JOYPAD_B:
button = XINPUT_GAMEPAD_A;
break;
case SNES_DEVICE_ID_JOYPAD_X:
button = XINPUT_GAMEPAD_Y;
break;
case SNES_DEVICE_ID_JOYPAD_Y:
button = XINPUT_GAMEPAD_X;
break;
case SNES_DEVICE_ID_JOYPAD_LEFT:
button = XINPUT_GAMEPAD_DPAD_LEFT;
break;
case SNES_DEVICE_ID_JOYPAD_RIGHT:
button = XINPUT_GAMEPAD_DPAD_RIGHT;
break;
case SNES_DEVICE_ID_JOYPAD_UP:
button = XINPUT_GAMEPAD_DPAD_UP;
break;
case SNES_DEVICE_ID_JOYPAD_DOWN:
button = XINPUT_GAMEPAD_DPAD_DOWN;
break;
case SNES_DEVICE_ID_JOYPAD_START:
button = XINPUT_GAMEPAD_START;
break;
case SNES_DEVICE_ID_JOYPAD_SELECT:
button = XINPUT_GAMEPAD_BACK;
break;
case SNES_DEVICE_ID_JOYPAD_L:
button = XINPUT_GAMEPAD_LEFT_SHOULDER;
break;
case SNES_DEVICE_ID_JOYPAD_R:
button = XINPUT_GAMEPAD_RIGHT_SHOULDER;
break;
default:
button = 0;
}
return (state[player].Gamepad.wButtons & button) ? 1 : 0;
}
static void xdk360_free_input(void *data)
{
(void)data;
}
static void* xdk360_input_init(void)
{
return (void*)-1;
}
static bool xdk360_key_pressed(void *data, int key)
{
(void)data;
(void)key;
return false;
}
const input_driver_t input_xdk360 = {
xdk360_input_init,
xdk360_input_poll,
xdk360_input_state,
xdk360_key_pressed,
xdk360_free_input,
"xdk360"};
+304
View File
@@ -0,0 +1,304 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <xtl.h>
#include "../driver.h"
#include "../general.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
static const char* g_strPixelShaderProgram =
" sampler2D tex : register(s0); "
" struct PS_IN "
" { "
" float2 coord : TEXCOORD0; "
" }; "
" "
" float4 main(PS_IN input) : COLOR "
" { "
" return tex2D(tex, input.coord); "
" } ";
static const char* g_strVertexShaderProgram =
" struct VS_IN "
" "
" { "
" float2 pos : POSITION; "
" float2 coord : TEXCOORD0; "
" }; "
" "
" struct VS_OUT "
" { "
" float4 pos : POSITION; "
" float2 coord : TEXCOORD0; "
" }; "
" "
" VS_OUT main(VS_IN input) "
" { "
" VS_OUT output; "
" output.pos = float4(input.pos, 0.0, 1.0); "
" output.coord = input.coord; "
" return output; "
" } ";
typedef struct DrawVerticeFormats
{
float x, y;
float u, v;
} DrawVerticeFormats;
static bool g_quitting;
typedef struct xdk360_video
{
IDirect3D9* xdk360_device;
IDirect3DDevice9* xdk360_render_device;
IDirect3DVertexShader9 *pVertexShader;
IDirect3DPixelShader9* pPixelShader;
IDirect3DVertexDeclaration9* pVertexDecl;
IDirect3DVertexBuffer9* vertex_buf;
IDirect3DTexture9* lpTexture;
unsigned frame_count;
unsigned last_width, last_height;
} xdk360_video_t;
static void xdk360_gfx_free(void *data)
{
xdk360_video_t *vid = (xdk360_video_t*)data;
if (!vid)
return;
vid->lpTexture->Release();
vid->vertex_buf->Release();
vid->pVertexDecl->Release();
vid->pPixelShader->Release();
vid->pVertexShader->Release();
vid->xdk360_render_device->Release();
vid->xdk360_device->Release();
free(vid);
}
static void *xdk360_gfx_init(const video_info_t *video, const input_driver_t **input, void **input_data)
{
xdk360_video_t *vid = (xdk360_video_t*)calloc(1, sizeof(xdk360_video_t));
if (!vid)
return NULL;
vid->xdk360_device = Direct3DCreate9(D3D_SDK_VERSION);
if (!vid->xdk360_device)
{
free(vid);
return NULL;
}
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.BackBufferWidth = 1280;
d3dpp.BackBufferHeight = 720;
d3dpp.BackBufferFormat = (D3DFORMAT)MAKESRGBFMT(D3DFMT_A8R8G8B8);
d3dpp.FrontBufferFormat = (D3DFORMAT)MAKESRGBFMT(D3DFMT_LE_X8R8G8B8);
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.MultiSampleQuality = 0;
d3dpp.BackBufferCount = 2;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
vid->xdk360_device->CreateDevice(0, D3DDEVTYPE_HAL, NULL, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp,
&vid->xdk360_render_device);
ID3DXBuffer* pShaderCodeV = NULL;
ID3DXBuffer* pShaderCodeP = NULL;
ID3DXBuffer* pErrorMsg = NULL;
HRESULT hr = D3DXCompileShader(g_strVertexShaderProgram, (UINT)strlen(g_strVertexShaderProgram),
NULL, NULL, "main", "vs_2_0", 0, &pShaderCodeV, &pErrorMsg, NULL);
if (SUCCEEDED(hr))
{
hr = D3DXCompileShader(g_strPixelShaderProgram, (UINT)strlen(g_strPixelShaderProgram),
NULL, NULL, "main", "ps_2_0", 0, &pShaderCodeP, &pErrorMsg, NULL);
}
if (FAILED(hr))
{
OutputDebugString(pErrorMsg ? (char*)pErrorMsg->GetBufferPointer() : "");
vid->xdk360_render_device->Release();
vid->xdk360_device->Release();
free(vid);
return NULL;
}
vid->xdk360_render_device->CreateVertexShader((const DWORD*)pShaderCodeV->GetBufferPointer(), &vid->pVertexShader);
vid->xdk360_render_device->CreatePixelShader((const DWORD*)pShaderCodeP->GetBufferPointer(), &vid->pPixelShader);
pShaderCodeV->Release();
pShaderCodeP->Release();
vid->xdk360_render_device->CreateTexture(512, 512, 1, 0, D3DFMT_LIN_X1R5G5B5,
0, &vid->lpTexture, NULL);
D3DLOCKED_RECT d3dlr;
if (SUCCEEDED(vid->lpTexture->LockRect(0, &d3dlr, NULL, D3DLOCK_NOSYSLOCK)))
{
memset(d3dlr.pBits, 0, 512 * d3dlr.Pitch);
vid->lpTexture->UnlockRect(0);
}
vid->last_width = 512;
vid->last_height = 512;
vid->xdk360_render_device->CreateVertexBuffer(4 * sizeof(DrawVerticeFormats), 0,
0, 0, &vid->vertex_buf, NULL);
static const DrawVerticeFormats init_verts[] = {
{ -1.0f, -1.0f, 0.0f, 1.0f },
{ 1.0f, -1.0f, 1.0f, 1.0f },
{ -1.0f, 1.0f, 0.0f, 0.0f },
{ 1.0f, 1.0f, 1.0f, 0.0f },
};
void *verts_ptr;
vid->vertex_buf->Lock(0, 0, &verts_ptr, 0);
memcpy(verts_ptr, init_verts, sizeof(init_verts));
vid->vertex_buf->Unlock();
static const D3DVERTEXELEMENT9 VertexElements[] =
{
{ 0, 0 * sizeof(float), D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
{ 0, 2 * sizeof(float), D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
D3DDECL_END()
};
vid->xdk360_render_device->CreateVertexDeclaration(VertexElements, &vid->pVertexDecl);
vid->xdk360_render_device->Clear(0, NULL, D3DCLEAR_TARGET,
0xff000000, 1.0f, 0);
vid->xdk360_render_device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
vid->xdk360_render_device->SetRenderState(D3DRS_ZENABLE, FALSE);
D3DVIEWPORT9 vp = {0};
vp.Width = 1280;
vp.Height = 720;
vp.MinZ = 0.0f;
vp.MaxZ = 1.0f;
vid->xdk360_render_device->SetViewport(&vp);
return vid;
}
static bool xdk360_gfx_frame(void *data, const void *frame,
unsigned width, unsigned height, unsigned pitch, const char *msg)
{
xdk360_video_t *vid = (xdk360_video_t*)data;
vid->frame_count++;
vid->xdk360_render_device->Clear(0, NULL, D3DCLEAR_TARGET,
0xff000000, 1.0f, 0);
if (vid->last_width != width || vid->last_height != height)
{
D3DLOCKED_RECT d3dlr;
if (SUCCEEDED(vid->lpTexture->LockRect(0, &d3dlr, NULL, D3DLOCK_NOSYSLOCK)))
{
memset(d3dlr.pBits, 0, 512 * d3dlr.Pitch);
vid->lpTexture->UnlockRect(0);
}
float tex_w = width / 512.0f;
float tex_h = height / 512.0f;
const DrawVerticeFormats verts[] = {
{ -1.0f, -1.0f, 0.0f, tex_h },
{ 1.0f, -1.0f, tex_w, tex_h },
{ -1.0f, 1.0f, 0.0f, 0.0f },
{ 1.0f, 1.0f, tex_w, 0.0f },
};
void *verts_ptr;
vid->vertex_buf->Lock(0, 0, &verts_ptr, 0);
memcpy(verts_ptr, verts, sizeof(verts));
vid->vertex_buf->Unlock();
vid->last_width = width;
vid->last_height = height;
}
D3DLOCKED_RECT d3dlr;
if (SUCCEEDED(vid->lpTexture->LockRect(0, &d3dlr, NULL, D3DLOCK_NOSYSLOCK)))
{
for (unsigned y = 0; y < height; y++)
{
const uint8_t *in = (const uint8_t*)frame + y * pitch;
uint8_t *out = (uint8_t*)d3dlr.pBits + y * d3dlr.Pitch;
memcpy(out, in, width * sizeof(uint16_t));
}
vid->lpTexture->UnlockRect(0);
}
vid->xdk360_render_device->SetTexture(0, vid->lpTexture);
vid->xdk360_render_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
vid->xdk360_render_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
vid->xdk360_render_device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER);
vid->xdk360_render_device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER);
vid->xdk360_render_device->SetVertexShader(vid->pVertexShader);
vid->xdk360_render_device->SetPixelShader(vid->pPixelShader);
vid->xdk360_render_device->SetVertexDeclaration(vid->pVertexDecl);
vid->xdk360_render_device->SetStreamSource(0, vid->vertex_buf, 0, sizeof(DrawVerticeFormats));
vid->xdk360_render_device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
vid->xdk360_render_device->Present(NULL, NULL, NULL, NULL);
return true;
}
static void xdk360_gfx_set_nonblock_state(void *data, bool state)
{
(void)data;
(void)state;
}
static bool xdk360_gfx_alive(void *data)
{
(void)data;
return !g_quitting;
}
static bool xdk360_gfx_focus(void *data)
{
(void)data;
return true;
}
const video_driver_t video_xdk360 = {
xdk360_gfx_init,
xdk360_gfx_frame,
xdk360_gfx_set_nonblock_state,
xdk360_gfx_alive,
xdk360_gfx_focus,
NULL,
xdk360_gfx_free,
"xdk360"
};
+5
View File
@@ -6,3 +6,8 @@ Devin J. Pohly - <[email protected]>
Chris Moeller - <[email protected]>
- CoreAudio audio driver
Daniel De Matteis - <[email protected]>
- PlayStation 3 port
- XBox 360 XDK port
+30 -13
View File
@@ -2,11 +2,11 @@ include config.mk
TARGET = ssnes tools/ssnes-joyconfig
OBJ = ssnes.o file.o driver.o settings.o dynamic.o message.o rewind.o movie.o autosave.o gfx/gfx_common.o ups.o bps.o strl.o screenshot.o thread.o audio/hermite.o
OBJ = ssnes.o file.o driver.o settings.o dynamic.o message.o rewind.o movie.o gfx/gfx_common.o ups.o bps.o strl.o getopt.o screenshot.o audio/hermite.o audio/utils.o
JOYCONFIG_OBJ = tools/ssnes-joyconfig.o conf/config_file.o strl.o
HEADERS = $(wildcard */*.h) $(wildcard *.h)
LIBS = -lm -lpthread
LIBS = -lm
DEFINES = -DHAVE_CONFIG_H
ifneq ($(findstring Darwin,$(OS)),)
@@ -27,6 +27,11 @@ ifneq ($(findstring Linux,$(OS)),)
LIBS += -lrt
endif
ifeq ($(HAVE_THREADS), 1)
OBJ += autosave.o thread.o
LIBS += -lpthread
endif
ifeq ($(HAVE_CONFIGFILE), 1)
OBJ += conf/config_file.o
endif
@@ -86,20 +91,24 @@ ifeq ($(HAVE_COREAUDIO), 1)
endif
ifeq ($(HAVE_SDL), 1)
OBJ += gfx/sdl.o gfx/gl.o gfx/sdlwrap.o input/sdl.o audio/sdl.o fifo_buffer.o
OBJ += gfx/sdl_gfx.o gfx/sdlwrap.o input/sdl_input.o audio/sdl_audio.o fifo_buffer.o
DEFINES += $(SDL_CFLAGS) $(BSD_LOCAL_INC)
LIBS += $(SDL_LIBS)
ifeq ($(HAVE_OPENGL), 1)
OBJ += gfx/gl.o
ifeq ($(OSX),1)
LIBS += -framework OpenGL
LIBS += -framework OpenGL
else
LIBS += -lGL
LIBS += -lGL
endif
endif
endif
ifeq ($(HAVE_XVIDEO), 1)
OBJ += gfx/xvideo.o input/x11_input.o
LIBS += $(XVIDEO_LIBS)
DEFINES += $(XVIDEO_CFLAGS)
LIBS += $(XVIDEO_LIBS) $(X11_LIBS) $(XEXT_LIBS)
DEFINES += $(XVIDEO_CFLAGS) $(X11_CFLAGS) $(XEXT_CFLAGS)
endif
ifeq ($(HAVE_CG), 1)
@@ -108,9 +117,13 @@ ifeq ($(HAVE_CG), 1)
endif
ifeq ($(HAVE_XML), 1)
OBJ += gfx/shader_glsl.o sha256.o cheats.o
OBJ += sha256.o cheats.o
LIBS += $(XML_LIBS)
DEFINES += $(XML_CFLAGS)
ifeq ($(HAVE_OPENGL), 1)
OBJ += gfx/shader_glsl.o
endif
endif
ifeq ($(HAVE_XML), 1)
@@ -120,7 +133,7 @@ else ifeq ($(HAVE_CG), 1)
endif
ifeq ($(HAVE_DYLIB), 1)
OBJ += gfx/ext.o audio/ext.o
OBJ += gfx/ext_gfx.o audio/ext_audio.o
LIBS += $(DYLIB_LIB)
endif
@@ -147,10 +160,6 @@ else
LIBS += $(libsnes)
endif
ifeq ($(HAVE_STRL), 1)
DEFINES += -DHAVE_STRL
endif
ifeq ($(HAVE_PYTHON), 1)
DEFINES += $(PYTHON_CFLAGS) -Wno-unused-parameter
LIBS += $(PYTHON_LIBS)
@@ -167,11 +176,15 @@ ifeq ($(DEBUG), 1)
endif
CFLAGS += -Wall $(OPTIMIZE_FLAG) -g -I. -pedantic
ifeq ($(CXX_BUILD), 1)
CFLAGS += -std=c++0x -xc++ -D__STDC_CONSTANT_MACROS
else
ifneq ($(findstring icc,$(CC)),)
CFLAGS += -std=c99 -D_GNU_SOURCE
else
CFLAGS += -std=gnu99
endif
endif
all: $(TARGET) config.mk
@@ -184,7 +197,11 @@ ssnes: $(OBJ)
@$(if $(Q), $(shell echo echo LD $@),)
tools/ssnes-joyconfig: $(JOYCONFIG_OBJ)
ifeq ($(CXX_BUILD), 1)
$(Q)$(CXX) -o $@ $(JOYCONFIG_OBJ) $(SDL_LIBS) $(LDFLAGS) $(LIBRARY_DIRS)
else
$(Q)$(CC) -o $@ $(JOYCONFIG_OBJ) $(SDL_LIBS) $(LDFLAGS) $(LIBRARY_DIRS)
endif
@$(if $(Q), $(shell echo echo LD $@),)
%.o: %.c config.h config.mk $(HEADERS)
+85
View File
@@ -0,0 +1,85 @@
###
##
# Makefile for SSNES PS3. Somewhat generic and avoids using the odd SDK examples.
##
###
##
DEBUG = 0
CELL_BUILD_TOOLS = GCC
## Platform detection from nall/Makefile. Only two applicable hosts for PS3 SDK.
ifeq ($(platform),)
uname := $(shell uname -a)
ifeq ($(uname),)
platform := win
else
platform := linux
endif
endif
CELL_SDK := /usr/local/cell
ifeq ($(platform),win)
HOST_DIR := host-win32
else
HOST_DIR := host-linux
endif
ifeq ($(CELL_BUILD_TOOLS),SNC)
CC = $(CELL_SDK)/$(HOST_DIR)/sn/bin/ps3ppusnc
CXX = $(CC)
LD = $(CELL_SDK)/$(HOST_DIR)/sn/bin/ps3ppuld
else
CC = $(CELL_SDK)/$(HOST_DIR)/ppu/bin/ppu-lv2-gcc
CXX = $(CELL_SDK)/$(HOST_DIR)/ppu/bin/ppu-lv2-g++
LD = $(CELL_SDK)/$(HOST_DIR)/ppu/bin/ppu-lv2-g++
endif
STRIP = $(CELL_SDK)/$(HOST_DIR)/ppu/bin/ppu-lv2-strip
PPU_TARGET := ssnes.elf
LDDIRS = -L. -L$(CELL_SDK)/target/ppu/lib/PSGL/RSX/ultra-opt
INCDIRS = -I. -Icommon
MAKE_FSELF_NPDRM = $(CELL_SDK)/$(HOST_DIR)/bin/make_fself_npdrm
MAKE_PACKAGE_NPDRM = $(CELL_SDK)/$(HOST_DIR)/bin/make_package_npdrm
OBJ = fifo_buffer.o ps3/cellframework2/fileio/file_browser.o ps3/ps3_audio.o ps3/menu.o ps3/ps3_input.o ps3/cellframework2/input/pad_input.o getopt.o ssnes.o driver.o file.o settings.o message.o rewind.o movie.o gfx/gfx_common.o ps3/ps3_video_psgl.o gfx/shader_cg.o gfx/snes_state.o ups.o bps.o strl.o screenshot.o audio/hermite.o dynamic.o ps3/main.o audio/utils.o conf/config_file.o gfx/image.o
LIBS = -ldbgfont -lPSGL -lPSGLcgc -lcgc -lgcm_cmd -lgcm_sys_stub -lsnes -lresc_stub -lm -lio_stub -lfs_stub -lsysutil_stub -lsysutil_game_stub -lsysutil_screenshot_stub -lsysmodule_stub -laudio_stub -lnet_stub -lpthread
DEFINES = -DSSNES_CONSOLE -DHAVE_OPENGL=1 -DHAVE_CG=1 -DHAVE_FBO=1 -D__CELLOS_LV2__ -DHAVE_CONFIGFILE=1 -DPACKAGE_VERSION=\"0.9.4\" -Dmain=ssnes_main
ifeq ($(DEBUG), 1)
PPU_OPTIMIZE_LV := -O0 -g
else
PPU_OPTIMIZE_LV := -O3 -g
endif
## Use this for new SDK!
CFLAGS = $(PPU_OPTIMIZE_LV) $(DEFINES)
CXXFLAGS = $(PPU_OPTIMIZE_LV) $(DEFINES)
all: pkg
$(PPU_TARGET): $(OBJ)
$(LD) -o $@ $(OBJ) $(LDFLAGS) $(LDDIRS) $(LIBS)
$(STRIP) $(PPU_TARGET)
%.o: %.c config.h
$(CC) $(INCDIRS) $(CFLAGS) -c -o $@ $<
%.o: %.cpp config.h
$(CXX) $(INCDIRS) $(CXXFLAGS) -c -o $@ $<
pkg: $(PPU_TARGET)
cp ssnes.cfg ps3/pkg/USRDIR/
$(MAKE_FSELF_NPDRM) $(PPU_TARGET) ps3/pkg/USRDIR/EBOOT.BIN
$(MAKE_PACKAGE_NPDRM) ps3/pkg/package.conf ps3/pkg
clean:
rm -f $(PPU_TARGET)
rm -f $(OBJ)
rm -f *.pkg
.PHONY: all clean pkg
+58
View File
@@ -0,0 +1,58 @@
###
##
# Makefile for SSNES Wii.
## Doesn't really work yet, beware :V
###
##
DEBUG = 0
CC = powerpc-eabi-gcc
CXX = powerpc-eabi-g++
LD = powerpc-eabi-ld
DOL_TARGET := ssnes.dol
ELF_TARGET := ssnes.elf
INCLUDE := -I. -I$(DEVKITPRO)/libogc/include
LIBDIRS := -L$(DEVKITPRO)/libogc/lib/wii -L.
MACHDEP := -DGEKKO -mrvl -mcpu=750 -meabi -mhard-float
CFLAGS += -Wall -std=gnu99 $(MACHDEP) $(INCLUDE)
CXXFLAGS += -Wall -std=gnu99 $(MACHDEP) $(INCLUDE)
LDFLAGS := $(MACHDEP)
LIBS := -lfat -lsnes -lwiiuse -logc -lbte -lfreetype
OBJ = wii/main.o fifo_buffer.o ssnes.o driver.o gfx/fonts.o file.o settings.o message.o rewind.o movie.o ups.o bps.o strl.o screenshot.o audio/hermite.o dynamic.o audio/utils.o conf/config_file.o wii/audio.o wii/input.o wii/video.o console/sgui.o console/list.o console/font.bmpobj
CFLAGS += -std=gnu99 -DSSNES_CONSOLE -DHAVE_CONFIGFILE=1 -DHAVE_GETOPT_LONG -DHAVE_FREETYPE -DPACKAGE_VERSION=\"0.9.4\" -Dmain=ssnes_main -Wno-char-subscripts
ifeq ($(DEBUG), 1)
CFLAGS += -O0 -g
CXXFLAGS += -O0 -g
else
CLFAGS += -O3
CXXFLAGS += -O3
endif
all: $(DOL_TARGET)
%.dol: %.elf
elf2dol $< $@
$(ELF_TARGET): $(OBJ)
$(CXX) -o $@ $(LDFLAGS) $(LIBDIRS) $(OBJ) $(LIBS)
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
%.bmpobj: %.bmp
$(LD) -r -b binary -o $@ $<
clean:
rm -f $(DOL_TARGET)
rm -f $(ELF_TARGET)
rm -f $(OBJ)
.PHONY: clean
+35 -19
View File
@@ -1,7 +1,7 @@
TARGET = ssnes.exe
JTARGET = ssnes-joyconfig.exe
OBJ = ssnes.o file.o driver.o conf/config_file.o settings.o dynamic.o message.o rewind.o movie.o autosave.o gfx/gfx_common.o bps.o ups.o strl.o screenshot.o audio/hermite.o thread.o
JOBJ = conf/config_file.o tools/main-stub.o tools/ssnes-joyconfig.o strl.o
OBJ = ssnes.o file.o driver.o conf/config_file.o settings.o dynamic.o message.o rewind.o movie.o gfx/gfx_common.o bps.o ups.o strl.o screenshot.o audio/hermite.o getopt.o audio/utils.o posix_string.o
JOBJ = conf/config_file.o tools/ssnes-joyconfig.o strl.o posix_string.o
CC = gcc
CXX = g++
@@ -10,8 +10,10 @@ HAVE_DINPUT = 1
HAVE_XAUDIO = 1
HAVE_DSOUND = 1
HAVE_SDL = 1
HAVE_OPENGL = 1
HAVE_DYLIB = 1
HAVE_NETPLAY = 1
HAVE_THREADS = 1
DYNAMIC = 1
ifeq ($(SLIM),)
@@ -27,17 +29,27 @@ endif
libsnes ?= -lsnes
LIBS = -lm -lshlwapi
DEFINES = -I. -DHAVE_CONFIGFILE
LDFLAGS = -L. -static-libgcc -s
LDCXXFLAGS = -static-libstdc++
LIBS = -lm
DEFINES = -I. -DHAVE_CONFIGFILE -DPACKAGE_VERSION=\"0.9.4\"
LDFLAGS = -L. -static-libgcc
LDCXXFLAGS = -static-libstdc++ -s
ifeq ($(HAVE_SDL), 1)
OBJ += gfx/sdl.o gfx/gl.o gfx/sdlwrap.o input/sdl.o audio/sdl.o fifo_buffer.o
LIBS += -lSDL -lopengl32
OBJ += gfx/sdl_gfx.o gfx/gl.o gfx/sdlwrap.o input/sdl_input.o audio/sdl_audio.o fifo_buffer.o
LIBS += -lSDL
DEFINES += -ISDL -DHAVE_SDL
endif
ifeq ($(HAVE_THREADS), 1)
OBJ += autosave.o thread.o
DEFINES += -DHAVE_THREADS
endif
ifeq ($(HAVE_OPENGL), 1)
DEFINES += -DHAVE_OPENGL
LIBS += -lopengl32
endif
ifeq ($(HAVE_SDL_IMAGE), 1)
LIBS += -lSDL_image
DEFINES += -DHAVE_SDL_IMAGE
@@ -100,7 +112,7 @@ ifeq ($(HAVE_FBO), 1)
endif
ifeq ($(HAVE_DYLIB), 1)
OBJ += gfx/ext.o audio/ext.o
OBJ += gfx/ext_gfx.o audio/ext_audio.o
endif
ifeq ($(HAVE_PYTHON), 1)
@@ -122,16 +134,21 @@ ifeq ($(HAVE_FFMPEG), 1)
DEFINES += -DHAVE_FFMPEG_AVCODEC_OPEN2
DEFINES += -DHAVE_FFMPEG_AVIO_OPEN
DEFINES += -DHAVE_FFMPEG_AVFORMAT_WRITE_HEADER
DEFINES += -DHAVE_FFMPEG_AVFORMAT_NEW_STREAM
DEFINES += -DHAVE_X264RGB
OBJ += record/ffemu.o
endif
ifneq ($(V),1)
ifneq ($(V), 1)
Q := @
endif
CFLAGS += -Wall -O3 -std=gnu99 -I.
CXXFLAGS += -Wall -O3 -pedantic -I.
CFLAGS += -Wall -O3 -I.
ifeq ($(CXX_BUILD), 1)
CFLAGS += -std=c++0x -xc++ -D__STDC_CONSTANT_MACROS
else
CFLAGS += -std=gnu99
endif
all: $(TARGET) $(JTARGET)
@@ -143,13 +160,12 @@ $(TARGET): $(OBJ)
$(Q)$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
@$(if $(Q), $(shell echo echo CC $<),)
%.o: %.cpp
$(Q)$(CXX) $(CXXFLAGS) $(DEFINES) -c -o $@ $<
@$(if $(Q), $(shell echo echo CXX $<),)
$(JTARGET): $(JOBJ)
ifeq ($(CXX_BUILD), 1)
$(Q)$(CXX) -o $@ $(JOBJ) -lSDL $(LDFLAGS)
else
$(Q)$(CC) -o $@ $(JOBJ) -lSDL $(LDFLAGS)
endif
@$(if $(Q), $(shell echo echo LD $@),)
clean:
@@ -166,10 +182,10 @@ clean:
rm -f tools/*.o
dist_x86: all
zip -r ssnes-win32-0.9.zip $(TARGET) $(JTARGET) ssnes.cfg snes.dll SDL.dll
zip -r ssnes-win32-0.9.4.zip $(TARGET) $(JTARGET) ssnes.cfg snes.dll SDL.dll
dist_x86_64: all
zip -r ssnes-win64-0.9.zip $(TARGET) $(JTARGET) ssnes.cfg snes.dll SDL.dll
zip -r ssnes-win64-0.9.4.zip $(TARGET) $(JTARGET) ssnes.cfg snes.dll SDL.dll
libs_x86:
wget https://github.com/downloads/Themaister/SSNES/SSNES-win32-libs.zip --no-check-certificate
+55
View File
@@ -0,0 +1,55 @@
###
##
# Makefile for SSNES libxenon.
##
###
##
DEBUG = 0
CC = xenon-gcc
CXX = xenon-g++
OBJCOPY = xenon-objcopy
STRIP = xenon-strip
PPU_TARGET := ssnes-libxenon.elf
PPU_TARGET_ADJUSTED := ssnes-libxenon.elf32
LDDIRS = -L. -L$(DEVKITXENON)/usr/lib -L$(DEVKITXENON)/xenon/lib/32
INCDIRS = -I. -I$(DEVKITXENON)/usr/include
OBJ = fifo_buffer.o ssnes.o driver.o file.o settings.o message.o rewind.o movie.o gfx/gfx_common.o ups.o bps.o strl.o screenshot.o audio/hermite.o dynamic.o audio/utils.o conf/config_file.o xenon/main.o xenon/xenon360_audio.o xenon/xenon360_input.o xenon/xenon360_video.o
LIBS = -lsnes -lxenon -lm -lc
DEFINES = -std=gnu99 -DHAVE_CONFIGFILE=1 -DPACKAGE_VERSION=\"0.9.4\" -DSSNES_CONSOLE -DHAVE_GETOPT_LONG=1 -Dmain=ssnes_main
DEFINES += -maltivec -mhard-float -m32 -mpowerpc64 -mcpu=cell -mtune=cell -fno-pic -g -Wall -DXENON $(INCDIRS)
DEFINES += -u read -u _start -u exc_base
ifeq ($(DEBUG), 1)
OPTIMIZE_LV := -O0 -g
else
OPTIMIZE_LV := -O3
endif
all: $(PPU_TARGET_ADJUSTED)
CFLAGS := $(OPTIMIZE_LV) $(DEFINES)
LDFLAGS := -m32 -n -T $(DEVKITXENON)/app.lds
$(PPU_TARGET_ADJUSTED): $(PPU_TARGET)
$(OBJCOPY) -O elf32-powerpc --adjust-vma 0x80000000 $< $@
$(STRIP) $@
$(PPU_TARGET): $(OBJ)
$(CXX) -o $@ $(OBJ) $(LDFLAGS) $(LDDIRS) $(LIBS)
%.o: %.c config.h
$(CC) $(CFLAGS) -c -o $@ $<
clean:
rm -f $(PPU_TARGET)
rm -f $(OBJ)
.PHONY: clean
+4
View File
@@ -7,6 +7,10 @@ SSNES is a simple frontend for the libsnes library.
libsnes is the emulator core of [bSNES](http://www.byuu.org), the most accurate SNES emulator to date, in library form. The libsnes API has been implemented by SNES9x as well, allowing multiple different cores to be used for an emulator that supports libsnes.
This enables the possibility of custom front-ends for the emulator.
# Binaries
Latest Windows binaries are currently hosted on my [homepage](http://themaister.net/ssnes.html).
# Philosophy
SSNES attempts to be very small and lean, while still having all the useful core features expected from an emulator.
+31 -30
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -16,10 +16,10 @@
*/
#include "driver.h"
#include "../driver.h"
#include <stdlib.h>
#include <asoundlib.h>
#include "general.h"
#include "../general.h"
#define TRY_ALSA(x) if (x < 0) { \
goto error; \
@@ -32,9 +32,9 @@ typedef struct alsa
bool has_float;
} alsa_t;
static bool __alsa_use_float(void *data)
static bool alsa_use_float(void *data)
{
alsa_t *alsa = data;
alsa_t *alsa = (alsa_t*)data;
return alsa->has_float;
}
@@ -49,9 +49,9 @@ static bool find_float_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
return false;
}
static void* __alsa_init(const char* device, unsigned rate, unsigned latency)
static void *alsa_init(const char *device, unsigned rate, unsigned latency)
{
alsa_t *alsa = calloc(1, sizeof(alsa_t));
alsa_t *alsa = (alsa_t*)calloc(1, sizeof(alsa_t));
if (!alsa)
return NULL;
@@ -62,14 +62,17 @@ static void* __alsa_init(const char* device, unsigned rate, unsigned latency)
if (device)
alsa_dev = device;
TRY_ALSA(snd_pcm_open(&alsa->pcm, alsa_dev, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK));
unsigned int latency_usec = latency * 1000;
unsigned int channels = 2;
unsigned periods = 4;
snd_pcm_uframes_t buffer_size;
snd_pcm_format_t format;
TRY_ALSA(snd_pcm_open(&alsa->pcm, alsa_dev, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK));
TRY_ALSA(snd_pcm_hw_params_malloc(&params));
alsa->has_float = find_float_format(alsa->pcm, params);
snd_pcm_format_t format = alsa->has_float ? SND_PCM_FORMAT_FLOAT : SND_PCM_FORMAT_S16;
unsigned int channels = 2;
format = alsa->has_float ? SND_PCM_FORMAT_FLOAT : SND_PCM_FORMAT_S16;
TRY_ALSA(snd_pcm_hw_params_any(alsa->pcm, params));
TRY_ALSA(snd_pcm_hw_params_set_access(alsa->pcm, params, SND_PCM_ACCESS_RW_INTERLEAVED));
@@ -78,12 +81,10 @@ static void* __alsa_init(const char* device, unsigned rate, unsigned latency)
TRY_ALSA(snd_pcm_hw_params_set_rate(alsa->pcm, params, rate, 0));
TRY_ALSA(snd_pcm_hw_params_set_buffer_time_near(alsa->pcm, params, &latency_usec, NULL));
unsigned periods = 4;
TRY_ALSA(snd_pcm_hw_params_set_periods_near(alsa->pcm, params, &periods, NULL));
TRY_ALSA(snd_pcm_hw_params(alsa->pcm, params));
snd_pcm_uframes_t buffer_size;
snd_pcm_hw_params_get_period_size(params, &buffer_size, NULL);
SSNES_LOG("ALSA: Period size: %d frames\n", (int)buffer_size);
snd_pcm_hw_params_get_buffer_size(params, &buffer_size);
@@ -117,16 +118,16 @@ error:
return NULL;
}
static ssize_t __alsa_write(void *data, const void *buf, size_t size)
static ssize_t alsa_write(void *data, const void *buf, size_t size)
{
alsa_t *alsa = data;
alsa_t *alsa = (alsa_t*)data;
snd_pcm_sframes_t frames;
snd_pcm_sframes_t written = 0;
int rc;
size = snd_pcm_bytes_to_frames(alsa->pcm, size); // Frames to write
while (written < size)
while (written < (snd_pcm_sframes_t)size)
{
if (!alsa->nonblock)
{
@@ -159,25 +160,25 @@ static ssize_t __alsa_write(void *data, const void *buf, size_t size)
return snd_pcm_frames_to_bytes(alsa->pcm, size);
}
static bool __alsa_stop(void *data)
static bool alsa_stop(void *data)
{
return true;
}
static void __alsa_set_nonblock_state(void *data, bool state)
static void alsa_set_nonblock_state(void *data, bool state)
{
alsa_t *alsa = data;
alsa_t *alsa = (alsa_t*)data;
alsa->nonblock = state;
}
static bool __alsa_start(void *data)
static bool alsa_start(void *data)
{
return true;
}
static void __alsa_free(void *data)
static void alsa_free(void *data)
{
alsa_t *alsa = data;
alsa_t *alsa = (alsa_t*)data;
if (alsa)
{
if (alsa->pcm)
@@ -190,13 +191,13 @@ static void __alsa_free(void *data)
}
const audio_driver_t audio_alsa = {
.init = __alsa_init,
.write = __alsa_write,
.stop = __alsa_stop,
.start = __alsa_start,
.use_float = __alsa_use_float,
.set_nonblock_state = __alsa_set_nonblock_state,
.free = __alsa_free,
.ident = "alsa"
alsa_init,
alsa_write,
alsa_stop,
alsa_start,
alsa_set_nonblock_state,
alsa_free,
alsa_use_float,
"alsa"
};
+52 -50
View File
@@ -1,6 +1,6 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2011 - Chris Moeller
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
* Copyright (C) 2011-2012 - Chris Moeller
*
* Some code herein may be based on code found in BSNES.
*
@@ -21,7 +21,7 @@
#include "general.h"
#include "fifo_buffer.h"
#include <stdlib.h>
#include <stdbool.h>
#include "../boolean.h"
#include <pthread.h>
#include <CoreAudio/CoreAudio.h>
@@ -43,7 +43,7 @@ typedef struct coreaudio
static void coreaudio_free(void *data)
{
coreaudio_t *dev = data;
coreaudio_t *dev = (coreaudio_t*)data;
if (!dev)
return;
@@ -66,7 +66,7 @@ static OSStatus audio_cb(void *userdata, AudioUnitRenderActionFlags *action_flag
const AudioTimeStamp *time_stamp, UInt32 bus_number,
UInt32 number_frames, AudioBufferList *io_data)
{
coreaudio_t *dev = userdata;
coreaudio_t *dev = (coreaudio_t*)userdata;
(void)time_stamp;
(void)bus_number;
(void)number_frames;
@@ -95,11 +95,11 @@ static OSStatus audio_cb(void *userdata, AudioUnitRenderActionFlags *action_flag
return noErr;
}
static void* coreaudio_init(const char* device, unsigned rate, unsigned latency)
static void *coreaudio_init(const char *device, unsigned rate, unsigned latency)
{
(void)device;
coreaudio_t *dev = calloc(1, sizeof(*dev));
coreaudio_t *dev = (coreaudio_t*)calloc(1, sizeof(*dev));
if (!dev)
return NULL;
@@ -115,40 +115,46 @@ static void* coreaudio_init(const char* device, unsigned rate, unsigned latency)
AudioObjectSetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL,
sizeof(CFRunLoopRef), &run_loop);
ComponentDescription desc = {
.componentType = kAudioUnitType_Output,
.componentSubType = kAudioUnitSubType_HALOutput,
.componentManufacturer = kAudioUnitManufacturer_Apple,
};
ComponentDescription desc = {0};
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_HALOutput;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
Component comp = FindNextComponent(NULL, &desc);
AudioStreamBasicDescription stream_desc = {0};
AudioStreamBasicDescription real_desc;
AudioChannelLayout layout = {0};
AURenderCallbackStruct cb = {0};
Component comp = NULL;
OSStatus res = noErr;
UInt32 i_size = 0;
size_t fifo_size;
comp = FindNextComponent(NULL, &desc);
if (comp == NULL)
goto error;
OSStatus res = OpenAComponent(comp, &dev->dev);
res = OpenAComponent(comp, &dev->dev);
if (res != noErr)
goto error;
dev->dev_alive = true;
AudioStreamBasicDescription stream_desc = {
.mSampleRate = rate,
.mBitsPerChannel = sizeof(float) * CHAR_BIT,
.mChannelsPerFrame = 2,
.mBytesPerPacket = 2 * sizeof(float),
.mBytesPerFrame = 2 * sizeof(float),
.mFramesPerPacket = 1,
.mFormatID = kAudioFormatLinearPCM,
.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked | (is_little_endian() ? 0 : kAudioFormatFlagIsBigEndian),
};
stream_desc.mSampleRate = rate;
stream_desc.mBitsPerChannel = sizeof(float) * CHAR_BIT;
stream_desc.mChannelsPerFrame = 2;
stream_desc.mBytesPerPacket = 2 * sizeof(float);
stream_desc.mBytesPerFrame = 2 * sizeof(float);
stream_desc.mFramesPerPacket = 1;
stream_desc.mFormatID = kAudioFormatLinearPCM;
stream_desc.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked | (is_little_endian() ? 0 : kAudioFormatFlagIsBigEndian);
res = AudioUnitSetProperty(dev->dev, kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input, 0, &stream_desc, sizeof(stream_desc));
if (res != noErr)
goto error;
AudioStreamBasicDescription real_desc;
UInt32 i_size = sizeof(real_desc);
i_size = sizeof(real_desc);
res = AudioUnitGetProperty(dev->dev, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &real_desc, &i_size);
if (res != noErr)
goto error;
@@ -165,20 +171,16 @@ static void* coreaudio_init(const char* device, unsigned rate, unsigned latency)
if (real_desc.mFormatID != stream_desc.mFormatID)
goto error;
AudioChannelLayout layout = {
.mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelBitmap,
.mChannelBitmap = (1 << 2) - 1,
};
layout.mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelBitmap;
layout.mChannelBitmap = 0x03;
res = AudioUnitSetProperty(dev->dev, kAudioUnitProperty_AudioChannelLayout,
kAudioUnitScope_Input, 0, &layout, sizeof(layout));
if (res != noErr)
goto error;
AURenderCallbackStruct cb = {
.inputProc = audio_cb,
.inputProcRefCon = dev,
};
cb.inputProc = audio_cb;
cb.inputProcRefCon = dev;
res = AudioUnitSetProperty(dev->dev, kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input, 0, &cb, sizeof(cb));
@@ -189,7 +191,7 @@ static void* coreaudio_init(const char* device, unsigned rate, unsigned latency)
if (res != noErr)
goto error;
size_t fifo_size = (latency * g_settings.audio.out_rate) / 1000;
fifo_size = (latency * g_settings.audio.out_rate) / 1000;
fifo_size *= 2 * sizeof(float);
dev->buffer = fifo_new(fifo_size);
@@ -210,11 +212,11 @@ error:
return NULL;
}
static ssize_t coreaudio_write(void* data, const void* buf_, size_t size)
static ssize_t coreaudio_write(void *data, const void *buf_, size_t size)
{
coreaudio_t *dev = data;
coreaudio_t *dev = (coreaudio_t*)data;
const uint8_t *buf = buf_;
const uint8_t *buf = (const uint8_t*)buf_;
size_t written = 0;
while (size > 0)
@@ -246,19 +248,19 @@ static ssize_t coreaudio_write(void* data, const void* buf_, size_t size)
static bool coreaudio_stop(void *data)
{
coreaudio_t *dev = data;
coreaudio_t *dev = (coreaudio_t*)data;
return AudioOutputUnitStop(dev->dev) == noErr;
}
static void coreaudio_set_nonblock_state(void *data, bool state)
{
coreaudio_t *dev = data;
coreaudio_t *dev = (coreaudio_t*)data;
dev->nonblock = state;
}
static bool coreaudio_start(void *data)
{
coreaudio_t *dev = data;
coreaudio_t *dev = (coreaudio_t*)data;
return AudioOutputUnitStart(dev->dev) == noErr;
}
@@ -269,13 +271,13 @@ static bool coreaudio_use_float(void *data)
}
const audio_driver_t audio_coreaudio = {
.init = coreaudio_init,
.write = coreaudio_write,
.stop = coreaudio_stop,
.start = coreaudio_start,
.set_nonblock_state = coreaudio_set_nonblock_state,
.free = coreaudio_free,
.use_float = coreaudio_use_float,
.ident = "coreaudio"
coreaudio_init,
coreaudio_write,
coreaudio_stop,
coreaudio_start,
coreaudio_set_nonblock_state,
coreaudio_free,
coreaudio_use_float,
"coreaudio"
};
+35 -36
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -15,16 +15,16 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "driver.h"
#include "../driver.h"
#include <stdlib.h>
#include <stdbool.h>
#include "../boolean.h"
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <dsound.h>
#include "fifo_buffer.h"
#include "general.h"
#include "../fifo_buffer.h"
#include "../general.h"
typedef struct dsound
{
@@ -111,7 +111,7 @@ static inline void release_region(dsound_t *ds, const struct audio_lock *region)
static DWORD CALLBACK dsound_thread(PVOID data)
{
dsound_t *ds = data;
dsound_t *ds = (dsound_t*)data;
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
DWORD write_ptr;
@@ -218,7 +218,7 @@ static void dsound_clear_buffer(dsound_t *ds)
static void dsound_free(void *data)
{
dsound_t *ds = data;
dsound_t *ds = (dsound_t*)data;
if (ds)
{
if (ds->thread)
@@ -249,9 +249,12 @@ static void dsound_free(void *data)
}
}
static void* dsound_init(const char *device, unsigned rate, unsigned latency)
static void *dsound_init(const char *device, unsigned rate, unsigned latency)
{
dsound_t *ds = calloc(1, sizeof(*ds));
WAVEFORMATEX wfx = {0};
DSBUFFERDESC bufdesc = {0};
dsound_t *ds = (dsound_t*)calloc(1, sizeof(*ds));
if (!ds)
goto error;
@@ -263,14 +266,12 @@ static void* dsound_init(const char *device, unsigned rate, unsigned latency)
if (IDirectSound_SetCooperativeLevel(ds->ds, GetDesktopWindow(), DSSCL_PRIORITY) != DS_OK)
goto error;
WAVEFORMATEX wfx = {
.wFormatTag = WAVE_FORMAT_PCM,
.nChannels = 2,
.nSamplesPerSec = rate,
.wBitsPerSample = 16,
.nBlockAlign = 2 * sizeof(int16_t),
.nAvgBytesPerSec = rate * 2 * sizeof(int16_t),
};
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 2;
wfx.nSamplesPerSec = rate;
wfx.wBitsPerSample = 16;
wfx.nBlockAlign = 2 * sizeof(int16_t);
wfx.nAvgBytesPerSec = rate * 2 * sizeof(int16_t);
ds->buffer_size = (latency * wfx.nAvgBytesPerSec) / 1000;
ds->buffer_size /= CHUNK_SIZE;
@@ -281,12 +282,10 @@ static void* dsound_init(const char *device, unsigned rate, unsigned latency)
SSNES_LOG("[DirectSound]: Setting buffer size of %u bytes\n", ds->buffer_size);
SSNES_LOG("[DirectSound]: Latency = %u ms\n", (unsigned)((1000 * ds->buffer_size) / wfx.nAvgBytesPerSec));
DSBUFFERDESC bufdesc = {
.dwSize = sizeof(DSBUFFERDESC),
.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS,
.dwBufferBytes = ds->buffer_size,
.lpwfxFormat = &wfx,
};
bufdesc.dwSize = sizeof(DSBUFFERDESC);
bufdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS;
bufdesc.dwBufferBytes = ds->buffer_size;
bufdesc.lpwfxFormat = &wfx;
ds->event = CreateEvent(NULL, false, false, NULL);
if (!ds->event)
@@ -319,14 +318,14 @@ error:
static bool dsound_stop(void *data)
{
dsound_t *ds = data;
dsound_t *ds = (dsound_t*)data;
dsound_stop_thread(ds);
return IDirectSoundBuffer_Stop(ds->dsb) == DS_OK;
}
static bool dsound_start(void *data)
{
dsound_t *ds = data;
dsound_t *ds = (dsound_t*)data;
dsound_clear_buffer(ds);
if (!dsound_start_thread(ds))
@@ -337,14 +336,14 @@ static bool dsound_start(void *data)
static void dsound_set_nonblock_state(void *data, bool state)
{
dsound_t *ds = data;
dsound_t *ds = (dsound_t*)data;
ds->nonblock = state;
}
static ssize_t dsound_write(void *data, const void *buf_, size_t size)
{
dsound_t *ds = data;
const uint8_t *buf = buf_;
dsound_t *ds = (dsound_t*)data;
const uint8_t *buf = (const uint8_t*)buf_;
if (!ds->thread_alive)
return -1;
@@ -374,14 +373,14 @@ static ssize_t dsound_write(void *data, const void *buf_, size_t size)
return written;
}
const audio_driver_t audio_dsound = {
.init = dsound_init,
.write = dsound_write,
.stop = dsound_stop,
.start = dsound_start,
.set_nonblock_state = dsound_set_nonblock_state,
.free = dsound_free,
.ident = "dsound"
dsound_init,
dsound_write,
dsound_stop,
dsound_start,
dsound_set_nonblock_state,
dsound_free,
NULL,
"dsound"
};
+1 -1
View File
@@ -61,7 +61,7 @@ typedef struct ssnes_audio_driver_info
typedef struct ssnes_audio_driver
{
// Initializes the device.
void* (*init)(const ssnes_audio_driver_info_t *info);
void *(*init)(const ssnes_audio_driver_info_t *info);
// Write data in buffer to audio driver.
// A frame here is defined as one combined sample of left and right
+1 -1
View File
@@ -87,7 +87,7 @@ typedef struct ssnes_dsp_input
typedef struct ssnes_dsp_plugin
{
// Creates a handle of the plugin. Returns NULL if failed.
void* (*init)(const ssnes_dsp_info_t *info);
void *(*init)(const ssnes_dsp_info_t *info);
// Processes input data.
// The plugin is allowed to return variable sizes for output data.
+1 -1
View File
@@ -207,7 +207,7 @@ static void generate_filter_coeffs(float * restrict fir_out, float * restrict ii
}
static void* dsp_init(const ssnes_dsp_info_t *info)
static void *dsp_init(const ssnes_dsp_info_t *info)
{
(void)info;
dsp_state *state = calloc(1, sizeof(*state));
+29 -28
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -16,12 +16,12 @@
*/
#include "ext/ssnes_audio.h"
#include <stdbool.h>
#include "../boolean.h"
#include <stdlib.h>
#include <stdint.h>
#include "driver.h"
#include "dynamic.h"
#include "general.h"
#include "../driver.h"
#include "../dynamic.h"
#include "../general.h"
#include <sys/types.h>
typedef struct audio_ext
@@ -34,7 +34,7 @@ typedef struct audio_ext
static void audio_ext_free(void *data)
{
audio_ext_t *ext = data;
audio_ext_t *ext = (audio_ext_t*)data;
if (ext)
{
if (ext->driver && ext->handle)
@@ -45,7 +45,7 @@ static void audio_ext_free(void *data)
}
}
static void* audio_ext_init(const char *device, unsigned rate, unsigned latency)
static void *audio_ext_init(const char *device, unsigned rate, unsigned latency)
{
if (!(*g_settings.audio.external_driver))
{
@@ -53,10 +53,13 @@ static void* audio_ext_init(const char *device, unsigned rate, unsigned latency)
return NULL;
}
audio_ext_t *ext = calloc(1, sizeof(*ext));
audio_ext_t *ext = (audio_ext_t*)calloc(1, sizeof(*ext));
if (!ext)
return NULL;
ssnes_audio_driver_info_t info = {0};
const ssnes_audio_driver_t *(*plugin_load)(void) = NULL;
ext->lib = dylib_load(g_settings.audio.external_driver);
if (!ext->lib)
{
@@ -64,7 +67,7 @@ static void* audio_ext_init(const char *device, unsigned rate, unsigned latency)
goto error;
}
const ssnes_audio_driver_t* (*plugin_load)(void) = (const ssnes_audio_driver_t* (*)(void))dylib_proc(ext->lib, "ssnes_audio_driver_init");
plugin_load = (const ssnes_audio_driver_t *(*)(void))dylib_proc(ext->lib, "ssnes_audio_driver_init");
if (!plugin_load)
{
@@ -87,11 +90,9 @@ static void* audio_ext_init(const char *device, unsigned rate, unsigned latency)
goto error;
}
ssnes_audio_driver_info_t info = {
.device = device,
.sample_rate = rate,
.latency = latency
};
info.device = device;
info.sample_rate = rate;
info.latency = latency;
ext->handle = ext->driver->init(&info);
if (!ext->handle)
@@ -115,7 +116,7 @@ error:
static ssize_t audio_ext_write(void *data, const void *buf, size_t size)
{
audio_ext_t *ext = data;
audio_ext_t *ext = (audio_ext_t*)data;
unsigned frame_size = ext->is_float ? (2 * sizeof(float)) : (2 * sizeof(int16_t));
size /= frame_size;
@@ -127,37 +128,37 @@ static ssize_t audio_ext_write(void *data, const void *buf, size_t size)
static bool audio_ext_start(void *data)
{
audio_ext_t *ext = data;
audio_ext_t *ext = (audio_ext_t*)data;
return ext->driver->start(ext->handle);
}
static bool audio_ext_stop(void *data)
{
audio_ext_t *ext = data;
audio_ext_t *ext = (audio_ext_t*)data;
return ext->driver->stop(ext->handle);
}
static void audio_ext_set_nonblock_state(void *data, bool toggle)
{
audio_ext_t *ext = data;
audio_ext_t *ext = (audio_ext_t*)data;
ext->driver->set_nonblock_state(ext->handle, toggle);
}
static bool audio_ext_use_float(void *data)
{
audio_ext_t *ext = data;
audio_ext_t *ext = (audio_ext_t*)data;
ext->is_float = ext->driver->use_float(ext->handle);
return ext->is_float;
}
const audio_driver_t audio_ext = {
.init = audio_ext_init,
.write = audio_ext_write,
.stop = audio_ext_stop,
.start = audio_ext_start,
.set_nonblock_state = audio_ext_set_nonblock_state,
.use_float = audio_ext_use_float,
.free = audio_ext_free,
.ident = "ext"
audio_ext_init,
audio_ext_write,
audio_ext_stop,
audio_ext_start,
audio_ext_set_nonblock_state,
audio_ext_free,
audio_ext_use_float,
"ext"
};
+15 -25
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -35,8 +35,8 @@ static inline float hermite_kernel(float mu1, float a, float b, float c, float d
mu2 = mu1 * mu1;
mu3 = mu2 * mu1;
m0 = (c - a) * 0.5;
m1 = (d - b) * 0.5;
m0 = (c - a) * 0.5f;
m1 = (d - b) * 0.5f;
a0 = +2 * mu3 - 3 * mu2 + 1;
a1 = mu3 - 2 * mu2 + mu1;
@@ -48,54 +48,44 @@ static inline float hermite_kernel(float mu1, float a, float b, float c, float d
hermite_resampler_t *hermite_new(void)
{
hermite_resampler_t *re = calloc(1, sizeof(*re));
if (!re)
return NULL;
return re;
return (hermite_resampler_t*)calloc(1, sizeof(hermite_resampler_t));
}
// We make sure to allocate enough output data beforehand ... ;)
void hermite_process(hermite_resampler_t *re, struct hermite_data *data)
{
double r_step = 1.0 / data->ratio;
size_t processed_out = 0;
size_t processed_in = 0;
size_t in_frames = data->input_frames;
size_t out_frames = data->output_frames;
const float *in_data = data->data_in;
float *out_data = data->data_out;
while (processed_in < in_frames && processed_out < out_frames)
for (size_t i = 0; i < in_frames; i++)
{
while (re->r_frac <= 1.0 && processed_out < out_frames)
while (re->r_frac <= 1.0)
{
re->r_frac += r_step;
for (unsigned i = 0; i < CHANNELS; i++)
{
float res = hermite_kernel(re->r_frac,
float res = hermite_kernel((float)re->r_frac,
re->chan_data[i][0], re->chan_data[i][1], re->chan_data[i][2], re->chan_data[i][3]);
*out_data++ = res;
}
processed_out++;
}
if (re->r_frac >= 1.0)
re->r_frac -= 1.0;
for (unsigned i = 0; i < CHANNELS; i++)
{
re->r_frac -= 1.0;
for (unsigned i = 0; i < CHANNELS; i++)
{
re->chan_data[i][0] = re->chan_data[i][1];
re->chan_data[i][1] = re->chan_data[i][2];
re->chan_data[i][2] = re->chan_data[i][3];
re->chan_data[i][3] = *in_data++;
}
processed_in++;
re->chan_data[i][0] = re->chan_data[i][1];
re->chan_data[i][1] = re->chan_data[i][2];
re->chan_data[i][2] = re->chan_data[i][3];
re->chan_data[i][3] = *in_data++;
}
}
data->input_frames_used = processed_in;
data->output_frames_gen = processed_out;
data->output_frames = processed_out;
}
void hermite_free(hermite_resampler_t *re)
+2 -5
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -22,7 +22,7 @@
#define __SSNES_HERMITE_H
#include <stddef.h>
#include <stdbool.h>
#include "../boolean.h"
typedef struct hermite_resampler hermite_resampler_t;
@@ -36,9 +36,6 @@ struct hermite_data
size_t input_frames;
size_t output_frames;
size_t input_frames_used;
size_t output_frames_gen;
double ratio;
};
+43 -42
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -16,16 +16,16 @@
*/
#include "driver.h"
#include "../driver.h"
#include <stdlib.h>
#include "general.h"
#include "../general.h"
#include <jack/jack.h>
#include <jack/types.h>
#include <jack/ringbuffer.h>
#include <pthread.h>
#include <stdint.h>
#include <stdbool.h>
#include "../boolean.h"
#include <string.h>
#include <assert.h>
@@ -45,7 +45,7 @@ typedef struct jack
static int process_cb(jack_nframes_t nframes, void *data)
{
jack_t *jd = data;
jack_t *jd = (jack_t*)data;
if (nframes <= 0)
{
pthread_cond_signal(&jd->cond);
@@ -62,7 +62,7 @@ static int process_cb(jack_nframes_t nframes, void *data)
for (int i = 0; i < 2; i++)
{
jack_default_audio_sample_t *out = jack_port_get_buffer(jd->ports[i], nframes);
jack_default_audio_sample_t *out = (jack_default_audio_sample_t*)jack_port_get_buffer(jd->ports[i], nframes);
assert(out);
jack_ringbuffer_read(jd->buffer[i], (char*)out, min_avail * sizeof(jack_default_audio_sample_t));
@@ -77,7 +77,7 @@ static int process_cb(jack_nframes_t nframes, void *data)
static void shutdown_cb(void *data)
{
jack_t *jd = data;
jack_t *jd = (jack_t*)data;
jd->shutdown = true;
pthread_cond_signal(&jd->cond);
}
@@ -108,7 +108,7 @@ static size_t find_buffersize(jack_t *jd, int latency)
for (int i = 0; i < 2; i++)
{
jack_port_get_latency_range(jd->ports[i], JackPlaybackLatency, &range);
if (range.max > jack_latency)
if ((int)range.max > jack_latency)
jack_latency = range.max;
}
@@ -124,9 +124,9 @@ static size_t find_buffersize(jack_t *jd, int latency)
return buffer_frames * sizeof(jack_default_audio_sample_t);
}
static void* __jack_init(const char* device, unsigned rate, unsigned latency)
static void *ja_init(const char *device, unsigned rate, unsigned latency)
{
jack_t *jd = calloc(1, sizeof(jack_t));
jack_t *jd = (jack_t*)calloc(1, sizeof(jack_t));
if (!jd)
return NULL;
@@ -134,6 +134,9 @@ static void* __jack_init(const char* device, unsigned rate, unsigned latency)
pthread_mutex_init(&jd->cond_lock, NULL);
const char **jports = NULL;
char *dest_ports[2];
size_t bufsize = 0;
int parsed = 0;
jd->client = jack_client_open("SSNES", JackNullOption, NULL);
if (jd->client == NULL)
@@ -152,7 +155,6 @@ static void* __jack_init(const char* device, unsigned rate, unsigned latency)
goto error;
}
char *dest_ports[2];
jports = jack_get_ports(jd->client, NULL, NULL, JackPortIsPhysical | JackPortIsInput);
if (jports == NULL)
{
@@ -160,7 +162,7 @@ static void* __jack_init(const char* device, unsigned rate, unsigned latency)
goto error;
}
size_t bufsize = find_buffersize(jd, latency);
bufsize = find_buffersize(jd, latency);
SSNES_LOG("JACK: Internal buffer size: %d frames.\n", (int)(bufsize / sizeof(jack_default_audio_sample_t)));
for (int i = 0; i < 2; i++)
{
@@ -172,7 +174,7 @@ static void* __jack_init(const char* device, unsigned rate, unsigned latency)
}
}
int parsed = parse_ports(dest_ports, jports);
parsed = parse_ports(dest_ports, jports);
if (jack_activate(jd->client) < 0)
{
@@ -191,7 +193,6 @@ static void* __jack_init(const char* device, unsigned rate, unsigned latency)
for (int i = 0; i < parsed; i++)
free(dest_ports[i]);
jack_free(jports);
return jd;
@@ -204,7 +205,7 @@ error:
static size_t write_buffer(jack_t *jd, const float *buf, size_t size)
{
jack_default_audio_sample_t out_deinterleaved_buffer[2][FRAMES(size)];
jack_default_audio_sample_t out_deinterleaved_buffer[2][AUDIO_CHUNK_SIZE_NONBLOCKING];
for (int i = 0; i < 2; i++)
for (size_t j = 0; j < FRAMES(size); j++)
@@ -218,9 +219,11 @@ static size_t write_buffer(jack_t *jd, const float *buf, size_t size)
if (jd->shutdown)
return 0;
size_t avail[2];
avail[0] = jack_ringbuffer_write_space(jd->buffer[0]);
avail[1] = jack_ringbuffer_write_space(jd->buffer[1]);
size_t avail[2] = {
jack_ringbuffer_write_space(jd->buffer[0]),
jack_ringbuffer_write_space(jd->buffer[1]),
};
size_t min_avail = avail[0] < avail[1] ? avail[0] : avail[1];
min_avail /= sizeof(float);
@@ -229,7 +232,10 @@ static size_t write_buffer(jack_t *jd, const float *buf, size_t size)
if (write_frames > 0)
{
for (int i = 0; i < 2; i++)
jack_ringbuffer_write(jd->buffer[i], (const char*)&out_deinterleaved_buffer[i][written], write_frames * sizeof(jack_default_audio_sample_t));
{
jack_ringbuffer_write(jd->buffer[i], (const char*)&out_deinterleaved_buffer[i][written],
write_frames * sizeof(jack_default_audio_sample_t));
}
written += write_frames;
}
else
@@ -246,34 +252,34 @@ static size_t write_buffer(jack_t *jd, const float *buf, size_t size)
return written * sizeof(float) * 2;
}
static ssize_t __jack_write(void* data, const void* buf, size_t size)
static ssize_t ja_write(void *data, const void *buf, size_t size)
{
jack_t *jd = data;
jack_t *jd = (jack_t*)data;
return write_buffer(jd, buf, size);
return write_buffer(jd, (const float*)buf, size);
}
static bool __jack_stop(void *data)
static bool ja_stop(void *data)
{
(void)data;
return true;
}
static void __jack_set_nonblock_state(void *data, bool state)
static void ja_set_nonblock_state(void *data, bool state)
{
jack_t *jd = data;
jack_t *jd = (jack_t*)data;
jd->nonblock = state;
}
static bool __jack_start(void *data)
static bool ja_start(void *data)
{
(void)data;
return true;
}
static void __jack_free(void *data)
static void ja_free(void *data)
{
jack_t *jd = data;
jack_t *jd = (jack_t*)data;
jd->shutdown = true;
@@ -292,25 +298,20 @@ static void __jack_free(void *data)
free(jd);
}
static bool __jack_use_float(void *data)
static bool ja_use_float(void *data)
{
(void)data;
return true;
}
const audio_driver_t audio_jack = {
.init = __jack_init,
.write = __jack_write,
.stop = __jack_stop,
.start = __jack_start,
.set_nonblock_state = __jack_set_nonblock_state,
.free = __jack_free,
.use_float = __jack_use_float,
.ident = "jack"
ja_init,
ja_write,
ja_stop,
ja_start,
ja_set_nonblock_state,
ja_free,
ja_use_float,
"jack"
};
+27 -28
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -15,8 +15,7 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "driver.h"
#include "../driver.h"
#ifdef __APPLE__
#include <OpenAL/al.h>
@@ -56,10 +55,10 @@ typedef struct al
} al_t;
static void* __al_init(const char* device, unsigned rate, unsigned latency)
static void *al_init(const char *device, unsigned rate, unsigned latency)
{
(void)device;
al_t *al = calloc(1, sizeof(al_t));
al_t *al = (al_t*)calloc(1, sizeof(al_t));
if (!al)
return NULL;
@@ -76,8 +75,8 @@ static void* __al_init(const char* device, unsigned rate, unsigned latency)
al->rate = rate;
al->num_buffers = (latency * rate * 2 * 2) / (1000 * BUFSIZE);
al->buffers = calloc(al->num_buffers, sizeof(ALuint));
al->res_buf = calloc(al->num_buffers, sizeof(ALuint));
al->buffers = (ALuint*)calloc(al->num_buffers, sizeof(ALuint));
al->res_buf = (ALuint*)calloc(al->num_buffers, sizeof(ALuint));
if (al->buffers == NULL || al->res_buf == NULL)
goto error;
@@ -127,10 +126,9 @@ static bool al_get_buffer(al_t *al, ALuint *buffer)
if (al->res_ptr == 0)
{
#ifndef _WIN32
struct timespec tv = {
.tv_sec = 0,
.tv_nsec = 1000000
};
struct timespec tv = {0};
tv.tv_sec = 0;
tv.tv_nsec = 1000000;
#endif
for (;;)
@@ -153,17 +151,17 @@ static bool al_get_buffer(al_t *al, ALuint *buffer)
return true;
}
static size_t al_fill_internal_buf(al_t *al, const void* buf, size_t size)
static size_t al_fill_internal_buf(al_t *al, const void *buf, size_t size)
{
size_t read_size = (BUFSIZE - al->tmpbuf_ptr > size) ? size : (BUFSIZE - al->tmpbuf_ptr);
size_t read_size = (BUFSIZE - al->tmpbuf_ptr > (ssize_t)size) ? size : (BUFSIZE - al->tmpbuf_ptr);
memcpy(al->tmpbuf + al->tmpbuf_ptr, buf, read_size);
al->tmpbuf_ptr += read_size;
return read_size;
}
static ssize_t __al_write(void* data, const void* buf, size_t size)
static ssize_t al_write(void *data, const void *buf, size_t size)
{
al_t *al = data;
al_t *al = (al_t*)data;
size_t written = 0;
while (written < size)
@@ -196,27 +194,27 @@ static ssize_t __al_write(void* data, const void* buf, size_t size)
return size;
}
static bool __al_stop(void *data)
static bool al_stop(void *data)
{
(void)data;
return true;
}
static void __al_set_nonblock_state(void *data, bool state)
static void al_set_nonblock_state(void *data, bool state)
{
al_t *al = data;
al_t *al = (al_t*)data;
al->nonblock = state;
}
static bool __al_start(void *data)
static bool al_start(void *data)
{
(void)data;
return true;
}
static void __al_free(void *data)
static void al_free(void *data)
{
al_t *al= data;
al_t *al = (al_t*)data;
if (al)
{
alSourceStop(al->source);
@@ -235,12 +233,13 @@ static void __al_free(void *data)
}
const audio_driver_t audio_openal = {
.init = __al_init,
.write = __al_write,
.stop = __al_stop,
.start = __al_start,
.set_nonblock_state = __al_set_nonblock_state,
.free = __al_free,
.ident = "openal"
al_init,
al_write,
al_stop,
al_start,
al_set_nonblock_state,
al_free,
NULL,
"openal"
};
+21 -20
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -41,9 +41,9 @@
#define DEFAULT_OSS_DEV "/dev/dsp"
#endif
static void* __oss_init(const char* device, unsigned rate, unsigned latency)
static void *oss_init(const char *device, unsigned rate, unsigned latency)
{
int *fd = calloc(1, sizeof(int));
int *fd = (int*)calloc(1, sizeof(int));
if (fd == NULL)
return NULL;
@@ -96,9 +96,9 @@ static void* __oss_init(const char* device, unsigned rate, unsigned latency)
return fd;
}
static ssize_t __oss_write(void* data, const void* buf, size_t size)
static ssize_t oss_write(void *data, const void *buf, size_t size)
{
int *fd = data;
int *fd = (int*)data;
if (size == 0)
return 0;
@@ -114,21 +114,21 @@ static ssize_t __oss_write(void* data, const void* buf, size_t size)
return ret;
}
static bool __oss_stop(void *data)
static bool oss_stop(void *data)
{
int *fd = data;
int *fd = (int*)data;
ioctl(*fd, SNDCTL_DSP_RESET, 0);
return true;
}
static bool __oss_start(void *data)
static bool oss_start(void *data)
{
return true;
}
static void __oss_set_nonblock_state(void *data, bool state)
static void oss_set_nonblock_state(void *data, bool state)
{
int *fd = data;
int *fd = (int*)data;
int rc;
if (state)
rc = fcntl(*fd, F_SETFL, fcntl(*fd, F_GETFL) | O_NONBLOCK);
@@ -138,9 +138,9 @@ static void __oss_set_nonblock_state(void *data, bool state)
fprintf(stderr, "SSNES [ERROR]: Could not set nonblocking on OSS file descriptor. Will not be able to fast-forward.\n");
}
static void __oss_free(void *data)
static void oss_free(void *data)
{
int *fd = data;
int *fd = (int*)data;
ioctl(*fd, SNDCTL_DSP_RESET, 0);
close(*fd);
@@ -148,12 +148,13 @@ static void __oss_free(void *data)
}
const audio_driver_t audio_oss = {
.init = __oss_init,
.write = __oss_write,
.stop = __oss_stop,
.start = __oss_start,
.set_nonblock_state = __oss_set_nonblock_state,
.free = __oss_free,
.ident = "oss"
oss_init,
oss_write,
oss_stop,
oss_start,
oss_set_nonblock_state,
oss_free,
NULL,
"oss"
};
+38 -43
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -19,7 +19,7 @@
#include "driver.h"
#include "general.h"
#include <pulse/pulseaudio.h>
#include <stdbool.h>
#include "../boolean.h"
#include <string.h>
#include <stdio.h>
@@ -32,9 +32,9 @@ typedef struct
bool nonblock;
} pa_t;
static void __pulse_free(void *data)
static void pulse_free(void *data)
{
pa_t *pa = data;
pa_t *pa = (pa_t*)data;
if (pa)
{
if (pa->mainloop)
@@ -61,7 +61,7 @@ static void __pulse_free(void *data)
static void context_state_cb(pa_context *c, void *data)
{
pa_t *pa = data;
pa_t *pa = (pa_t*)data;
switch (pa_context_get_state(c))
{
case PA_CONTEXT_READY:
@@ -76,7 +76,7 @@ static void context_state_cb(pa_context *c, void *data)
static void stream_state_cb(pa_stream *s, void *data)
{
pa_t *pa = data;
pa_t *pa = (pa_t*)data;
switch (pa_stream_get_state(s)) {
case PA_STREAM_READY:
case PA_STREAM_FAILED:
@@ -92,20 +92,24 @@ static void stream_request_cb(pa_stream *s, size_t length, void *data)
{
(void)length;
(void)s;
pa_t *pa = data;
pa_t *pa = (pa_t*)data;
pa_threaded_mainloop_signal(pa->mainloop, 0);
}
static void stream_latency_update_cb(pa_stream *s, void *data)
{
(void)s;
pa_t *pa = data;
pa_t *pa = (pa_t*)data;
pa_threaded_mainloop_signal(pa->mainloop, 0);
}
static void* __pulse_init(const char* device, unsigned rate, unsigned latency)
static void *pulse_init(const char *device, unsigned rate, unsigned latency)
{
pa_t *pa = calloc(1, sizeof(*pa));
pa_sample_spec spec;
memset(&spec, 0, sizeof(spec));
pa_buffer_attr buffer_attr = {0};
pa_t *pa = (pa_t*)calloc(1, sizeof(*pa));
if (!pa)
goto error;
@@ -131,11 +135,9 @@ static void* __pulse_init(const char* device, unsigned rate, unsigned latency)
if (pa_context_get_state(pa->context) != PA_CONTEXT_READY)
goto unlock_error;
pa_sample_spec spec = {
.format = is_little_endian() ? PA_SAMPLE_FLOAT32LE : PA_SAMPLE_FLOAT32BE,
.channels = 2,
.rate = rate
};
spec.format = is_little_endian() ? PA_SAMPLE_FLOAT32LE : PA_SAMPLE_FLOAT32BE;
spec.channels = 2;
spec.rate = rate;
pa->stream = pa_stream_new(pa->context, "audio", &spec, NULL);
if (!pa->stream)
@@ -145,13 +147,11 @@ static void* __pulse_init(const char* device, unsigned rate, unsigned latency)
pa_stream_set_write_callback(pa->stream, stream_request_cb, pa);
pa_stream_set_latency_update_callback(pa->stream, stream_latency_update_cb, pa);
pa_buffer_attr buffer_attr = {
.maxlength = -1,
.tlength = pa_usec_to_bytes(latency * PA_USEC_PER_MSEC, &spec),
.prebuf = -1,
.minreq = -1,
.fragsize = -1
};
buffer_attr.maxlength = -1;
buffer_attr.tlength = pa_usec_to_bytes(latency * PA_USEC_PER_MSEC, &spec);
buffer_attr.prebuf = -1;
buffer_attr.minreq = -1;
buffer_attr.fragsize = -1;
if (pa_stream_connect_playback(pa->stream, NULL, &buffer_attr, PA_STREAM_ADJUST_LATENCY, NULL, NULL) < 0)
goto error;
@@ -168,13 +168,13 @@ static void* __pulse_init(const char* device, unsigned rate, unsigned latency)
unlock_error:
pa_threaded_mainloop_unlock(pa->mainloop);
error:
__pulse_free(pa);
pulse_free(pa);
return NULL;
}
static ssize_t __pulse_write(void* data, const void* buf, size_t size)
static ssize_t pulse_write(void *data, const void *buf, size_t size)
{
pa_t *pa = data;
pa_t *pa = (pa_t*)data;
pa_threaded_mainloop_lock(pa->mainloop);
unsigned length = pa_stream_writable_size(pa->stream);
@@ -198,43 +198,38 @@ static ssize_t __pulse_write(void* data, const void* buf, size_t size)
return write_size;
}
static bool __pulse_stop(void *data)
static bool pulse_stop(void *data)
{
(void)data;
return true;
}
static bool __pulse_start(void *data)
static bool pulse_start(void *data)
{
(void)data;
return true;
}
static void __pulse_set_nonblock_state(void *data, bool state)
static void pulse_set_nonblock_state(void *data, bool state)
{
pa_t *pa = data;
pa_t *pa = (pa_t*)data;
pa->nonblock = state;
}
static bool __pulse_use_float(void *data)
static bool pulse_use_float(void *data)
{
(void)data;
return true;
}
const audio_driver_t audio_pulse = {
.init = __pulse_init,
.write = __pulse_write,
.stop = __pulse_stop,
.start = __pulse_start,
.set_nonblock_state = __pulse_set_nonblock_state,
.use_float = __pulse_use_float,
.free = __pulse_free,
.ident = "pulse"
pulse_init,
pulse_write,
pulse_stop,
pulse_start,
pulse_set_nonblock_state,
pulse_free,
pulse_use_float,
"pulse"
};
+21 -24
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -21,7 +21,7 @@
#include <roaraudio.h>
#include <errno.h>
#include <stdio.h>
#include <stdbool.h>
#include "../boolean.h"
#include "general.h"
typedef struct
@@ -30,10 +30,11 @@ typedef struct
bool nonblocking;
} roar_t;
static void* __roar_init(const char* device, unsigned rate, unsigned latency)
static void *ra_init(const char *device, unsigned rate, unsigned latency)
{
(void)latency;
int err;
roar_t *roar = calloc(1, sizeof(roar_t));
roar_t *roar = (roar_t*)calloc(1, sizeof(roar_t));
if (roar == NULL)
return NULL;
@@ -51,9 +52,9 @@ static void* __roar_init(const char* device, unsigned rate, unsigned latency)
return roar;
}
static ssize_t __roar_write(void* data, const void* buf, size_t size)
static ssize_t ra_write(void *data, const void *buf, size_t size)
{
roar_t *roar = data;
roar_t *roar = (roar_t*)data;
ssize_t rc;
if (size == 0)
@@ -77,45 +78,41 @@ static ssize_t __roar_write(void* data, const void* buf, size_t size)
return size;
}
static bool __roar_stop(void *data)
static bool ra_stop(void *data)
{
(void)data;
return true;
}
static void __roar_set_nonblock_state(void *data, bool state)
static void ra_set_nonblock_state(void *data, bool state)
{
roar_t *roar = data;
roar_t *roar = (roar_t*)data;
if (roar_vs_blocking(roar->vss, (state) ? ROAR_VS_FALSE : ROAR_VS_TRUE, NULL) < 0)
fprintf(stderr, "SSNES [ERROR]: Can't set nonblocking. Will not be able to fast-forward.\n");
roar->nonblocking = state;
}
static bool __roar_start(void *data)
static bool ra_start(void *data)
{
(void)data;
return true;
}
static void __roar_free(void *data)
static void ra_free(void *data)
{
roar_t *roar = data;
roar_t *roar = (roar_t*)data;
roar_vs_close(roar->vss, ROAR_VS_TRUE, NULL);
free(data);
}
const audio_driver_t audio_roar = {
.init = __roar_init,
.write = __roar_write,
.stop = __roar_stop,
.start = __roar_start,
.set_nonblock_state = __roar_set_nonblock_state,
.free = __roar_free,
.ident = "roar"
ra_init,
ra_write,
ra_stop,
ra_start,
ra_set_nonblock_state,
ra_free,
NULL,
"roar"
};
+24 -23
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -20,7 +20,7 @@
#include <stdlib.h>
#include <rsound.h>
#include "fifo_buffer.h"
#include <stdbool.h>
#include "../boolean.h"
#include "SDL.h"
typedef struct rsd
@@ -37,7 +37,7 @@ typedef struct rsd
static ssize_t audio_cb(void *data, size_t bytes, void *userdata)
{
rsd_t *rsd = userdata;
rsd_t *rsd = (rsd_t*)userdata;
size_t avail = fifo_read_avail(rsd->buffer);
size_t write_size = bytes > avail ? avail : bytes;
@@ -49,14 +49,14 @@ static ssize_t audio_cb(void *data, size_t bytes, void *userdata)
static void err_cb(void *userdata)
{
rsd_t *rsd = userdata;
rsd_t *rsd = (rsd_t*)userdata;
rsd->has_error = true;
SDL_CondSignal(rsd->cond);
}
static void* __rsd_init(const char* device, unsigned rate, unsigned latency)
static void *rs_init(const char *device, unsigned rate, unsigned latency)
{
rsd_t *rsd = calloc(1, sizeof(rsd_t));
rsd_t *rsd = (rsd_t*)calloc(1, sizeof(rsd_t));
if (!rsd)
return NULL;
@@ -98,9 +98,9 @@ static void* __rsd_init(const char* device, unsigned rate, unsigned latency)
return rsd;
}
static ssize_t __rsd_write(void* data, const void* buf, size_t size)
static ssize_t rs_write(void *data, const void *buf, size_t size)
{
rsd_t *rsd = data;
rsd_t *rsd = (rsd_t*)data;
if (rsd->has_error)
return -1;
@@ -144,32 +144,32 @@ static ssize_t __rsd_write(void* data, const void* buf, size_t size)
}
}
static bool __rsd_stop(void *data)
static bool rs_stop(void *data)
{
rsd_t *rsd = data;
rsd_t *rsd = (rsd_t*)data;
rsd_stop(rsd->rd);
return true;
}
static void __rsd_set_nonblock_state(void *data, bool state)
static void rs_set_nonblock_state(void *data, bool state)
{
rsd_t *rsd = data;
rsd_t *rsd = (rsd_t*)data;
rsd->nonblock = state;
}
static bool __rsd_start(void *data)
static bool rs_start(void *data)
{
rsd_t *rsd = data;
rsd_t *rsd = (rsd_t*)data;
if (rsd_start(rsd->rd) < 0)
return false;
return true;
}
static void __rsd_free(void *data)
static void rs_free(void *data)
{
rsd_t *rsd = data;
rsd_t *rsd = (rsd_t*)data;
rsd_stop(rsd->rd);
rsd_free(rsd->rd);
@@ -182,12 +182,13 @@ static void __rsd_free(void *data)
}
const audio_driver_t audio_rsound = {
.init = __rsd_init,
.write = __rsd_write,
.stop = __rsd_stop,
.start = __rsd_start,
.set_nonblock_state = __rsd_set_nonblock_state,
.free = __rsd_free,
.ident = "rsound"
rs_init,
rs_write,
rs_stop,
rs_start,
rs_set_nonblock_state,
rs_free,
NULL,
"rsound"
};
+40 -39
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -16,36 +16,37 @@
*/
#include "driver.h"
#include "../driver.h"
#include <stdlib.h>
#include <stdbool.h>
#include "../boolean.h"
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "SDL.h"
#include "SDL_audio.h"
#include "SDL_thread.h"
#include "general.h"
#include "fifo_buffer.h"
#include "../thread.h"
#include "../general.h"
#include "../fifo_buffer.h"
typedef struct sdl_audio
{
bool nonblock;
SDL_mutex *lock;
SDL_cond *cond;
slock_t *lock;
scond_t *cond;
fifo_buffer_t *buffer;
} sdl_audio_t;
static void sdl_audio_cb(void *data, Uint8 *stream, int len)
{
sdl_audio_t *sdl = data;
sdl_audio_t *sdl = (sdl_audio_t*)data;
size_t avail = fifo_read_avail(sdl->buffer);
size_t write_size = len > avail ? avail : len;
size_t write_size = len > (int)avail ? avail : len;
fifo_read(sdl->buffer, stream, write_size);
SDL_CondSignal(sdl->cond);
scond_signal(sdl->cond);
// If underrun, fill rest with silence.
memset(stream + write_size, 0, len - write_size);
@@ -58,27 +59,26 @@ static inline int find_num_frames(int rate, int latency)
return next_pow2(frames);
}
static void* sdl_audio_init(const char* device, unsigned rate, unsigned latency)
static void *sdl_audio_init(const char *device, unsigned rate, unsigned latency)
{
(void)device;
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
return NULL;
sdl_audio_t *sdl = calloc(1, sizeof(*sdl));
sdl_audio_t *sdl = (sdl_audio_t*)calloc(1, sizeof(*sdl));
if (!sdl)
return NULL;
// We have to buffer up some data ourselves, so we let SDL carry approx half of the latency. SDL double buffers audio and we do as well.
int frames = find_num_frames(rate, latency / 4);
SDL_AudioSpec spec = {
.freq = rate,
.format = AUDIO_S16SYS,
.channels = 2,
.samples = frames, // This is in audio frames, not samples ... :(
.callback = sdl_audio_cb,
.userdata = sdl
};
SDL_AudioSpec spec = {0};
spec.freq = rate;
spec.format = AUDIO_S16SYS;
spec.channels = 2;
spec.samples = frames; // This is in audio frames, not samples ... :(
spec.callback = sdl_audio_cb;
spec.userdata = sdl;
SDL_AudioSpec out;
@@ -90,8 +90,8 @@ static void* sdl_audio_init(const char* device, unsigned rate, unsigned latency)
}
g_settings.audio.out_rate = out.freq;
sdl->lock = SDL_CreateMutex();
sdl->cond = SDL_CreateCond();
sdl->lock = slock_new();
sdl->cond = scond_new();
SSNES_LOG("SDL audio: Requested %d ms latency, got %d ms\n", latency, (int)(out.samples * 4 * 1000 / g_settings.audio.out_rate));
@@ -109,9 +109,9 @@ static void* sdl_audio_init(const char* device, unsigned rate, unsigned latency)
return sdl;
}
static ssize_t sdl_audio_write(void* data, const void* buf, size_t size)
static ssize_t sdl_audio_write(void *data, const void *buf, size_t size)
{
sdl_audio_t *sdl = data;
sdl_audio_t *sdl = (sdl_audio_t*)data;
ssize_t ret = 0;
if (sdl->nonblock)
@@ -134,9 +134,9 @@ static ssize_t sdl_audio_write(void* data, const void* buf, size_t size)
if (avail == 0)
{
SDL_UnlockAudio();
SDL_mutexP(sdl->lock);
SDL_CondWait(sdl->cond, sdl->lock);
SDL_mutexV(sdl->lock);
slock_lock(sdl->lock);
scond_wait(sdl->cond, sdl->lock);
slock_unlock(sdl->lock);
}
else
{
@@ -168,7 +168,7 @@ static bool sdl_audio_start(void *data)
static void sdl_audio_set_nonblock_state(void *data, bool state)
{
sdl_audio_t *sdl = data;
sdl_audio_t *sdl = (sdl_audio_t*)data;
sdl->nonblock = state;
}
@@ -177,23 +177,24 @@ static void sdl_audio_free(void *data)
SDL_CloseAudio();
SDL_QuitSubSystem(SDL_INIT_AUDIO);
sdl_audio_t *sdl = data;
sdl_audio_t *sdl = (sdl_audio_t*)data;
if (sdl)
{
fifo_free(sdl->buffer);
SDL_DestroyMutex(sdl->lock);
SDL_DestroyCond(sdl->cond);
slock_free(sdl->lock);
scond_free(sdl->cond);
}
free(sdl);
}
const audio_driver_t audio_sdl = {
.init = sdl_audio_init,
.write = sdl_audio_write,
.stop = sdl_audio_stop,
.start = sdl_audio_start,
.set_nonblock_state = sdl_audio_set_nonblock_state,
.free = sdl_audio_free,
.ident = "sdl"
sdl_audio_init,
sdl_audio_write,
sdl_audio_stop,
sdl_audio_start,
sdl_audio_set_nonblock_state,
sdl_audio_free,
NULL,
"sdl"
};
+119
View File
@@ -0,0 +1,119 @@
#include "utils.h"
#if __SSE2__
#include <emmintrin.h>
#elif __ALTIVEC__
#include <altivec.h>
#endif
void audio_convert_s16_to_float_C(float *out,
const int16_t *in, size_t samples)
{
for (size_t i = 0; i < samples; i++)
out[i] = (float)in[i] / 0x8000;
}
void audio_convert_float_to_s16_C(int16_t *out,
const float *in, size_t samples)
{
for (size_t i = 0; i < samples; i++)
{
int32_t val = (int32_t)(in[i] * 0x8000);
out[i] = (val > 0x7FFF) ? 0x7FFF : (val < -0x8000 ? -0x8000 : (int16_t)val);
}
}
#if __SSE2__
void audio_convert_s16_to_float_SSE2(float *out,
const int16_t *in, size_t samples)
{
__m128 factor = _mm_set1_ps(1.0f / (0x7fff * 0x10000));
size_t i;
for (i = 0; i + 8 <= samples; i += 8, in += 8, out += 8)
{
__m128i input = _mm_loadu_si128((const __m128i *)in);
__m128i regs[2] = {
_mm_unpacklo_epi16(_mm_setzero_si128(), input),
_mm_unpackhi_epi16(_mm_setzero_si128(), input),
};
__m128 output[2] = {
_mm_mul_ps(_mm_cvtepi32_ps(regs[0]), factor),
_mm_mul_ps(_mm_cvtepi32_ps(regs[1]), factor),
};
_mm_storeu_ps(out + 0, output[0]);
_mm_storeu_ps(out + 4, output[1]);
}
audio_convert_s16_to_float_C(out, in, samples - i);
}
void audio_convert_float_to_s16_SSE2(int16_t *out,
const float *in, size_t samples)
{
__m128 factor = _mm_set1_ps((float)0x7fff);
size_t i;
for (i = 0; i + 8 <= samples; i += 8, in += 8, out += 8)
{
__m128 input[2] = { _mm_loadu_ps(in + 0), _mm_loadu_ps(in + 4) };
__m128 res[2] = { _mm_mul_ps(input[0], factor), _mm_mul_ps(input[1], factor) };
__m128i ints[2] = { _mm_cvtps_epi32(res[0]), _mm_cvtps_epi32(res[1]) };
__m128i packed = _mm_packs_epi32(ints[0], ints[1]);
_mm_storeu_si128((__m128i *)out, packed);
}
audio_convert_float_to_s16_C(out, in, samples - i);
}
#elif __ALTIVEC__
void audio_convert_s16_to_float_altivec(float *out,
const int16_t *in, size_t samples)
{
// Unaligned loads/store is a bit expensive, so we optimize for the good path (very likely).
if (((uintptr_t)out & 15) + ((uintptr_t)in & 15) == 0)
{
size_t i;
for (i = 0; i + 8 <= samples; i += 8, in += 8, out += 8)
{
vector signed short input = vec_ld(0, in);
vector signed int hi = vec_unpackh(input);
vector signed int lo = vec_unpackl(input);
vector float out_hi = vec_ctf(hi, 15);
vector float out_lo = vec_ctf(lo, 15);
vec_st(out_hi, 0, out);
vec_st(out_lo, 16, out);
}
audio_convert_s16_to_float_C(out, in, samples - i);
}
else
audio_convert_s16_to_float_C(out, in, samples);
}
void audio_convert_float_to_s16_altivec(int16_t *out,
const float *in, size_t samples)
{
// Unaligned loads/store is a bit expensive, so we optimize for the good path (very likely).
if (((uintptr_t)out & 15) + ((uintptr_t)in & 15) == 0)
{
size_t i;
for (i = 0; i + 8 <= samples; i += 8, in += 8, out += 8)
{
vector float input0 = vec_ld( 0, in);
vector float input1 = vec_ld(16, in);
vector signed int result0 = vec_cts(input0, 15);
vector signed int result1 = vec_cts(input1, 15);
vec_st(vec_packs(result0, result1), 0, out);
}
audio_convert_float_to_s16_C(out, in, samples - i);
}
else
audio_convert_float_to_s16_C(out, in, samples);
}
#endif
+23 -68
View File
@@ -2,82 +2,37 @@
#define AUDIO_UTILS_H
#include <stdint.h>
#include <stddef.h>
#ifdef __SSE2__
#include <emmintrin.h>
#if __SSE2__
#define audio_convert_s16_to_float audio_convert_s16_to_float_SSE2
#define audio_convert_float_to_s16 audio_convert_float_to_s16_SSE2
void audio_convert_s16_to_float_SSE2(float *out,
const int16_t *in, size_t samples);
void audio_convert_float_to_s16_SSE2(int16_t *out,
const float *in, size_t samples);
#elif __ALTIVEC__
#define audio_convert_s16_to_float audio_convert_s16_to_float_altivec
#define audio_convert_float_to_s16 audio_convert_float_to_s16_altivec
void audio_convert_s16_to_float_altivec(float *out,
const int16_t *in, size_t samples);
void audio_convert_float_to_s16_altivec(int16_t *out,
const float *in, size_t samples);
#else
#define audio_convert_s16_to_float audio_convert_s16_to_float_C
#define audio_convert_float_to_s16 audio_convert_float_to_s16_C
#endif
static inline void audio_convert_s16_to_float_C(float *out,
const int16_t *in, unsigned samples)
{
for (unsigned i = 0; i < samples; i++)
out[i] = (float)in[i] / 0x8000;
}
static inline void audio_convert_float_to_s16_C(int16_t *out,
const float *in, unsigned samples)
{
for (unsigned i = 0; i < samples; i++)
{
int32_t val = in[i] * 0x8000;
out[i] = (val > 0x7FFF) ? 0x7FFF : (val < -0x8000 ? -0x8000 : (int16_t)val);
}
}
#ifdef __SSE2__
static inline void audio_convert_s16_to_float_SSE2(float *out,
const int16_t *in, unsigned samples)
{
// Not aligned? FML :(
if (((uintptr_t)in & 7) || ((uintptr_t)out & 15))
{
audio_convert_s16_to_float_C(out, in, samples);
return;
}
__m128 factor = _mm_set1_ps(1.0f / 0x7fff);
unsigned i;
for (i = 0; i + 4 <= samples; i += 4, in += 4, out += 4)
{
__m64 input = *(const __m64*)in;
__m128 reg = _mm_cvtpi16_ps(input);
__m128 res = _mm_mul_ps(reg, factor);
*(__m128*)out = res;
}
audio_convert_s16_to_float_C(out, in, samples - i);
}
static inline void audio_convert_float_to_s16_SSE2(int16_t *out,
const float *in, unsigned samples)
{
// Not aligned? FML :(
if (((uintptr_t)in & 7) || ((uintptr_t)out & 15))
{
audio_convert_float_to_s16_C(out, in, samples);
return;
}
__m128 factor = _mm_set1_ps(0x7fff);
unsigned i;
for (i = 0; i + 4 <= samples; i += 4, in += 4, out += 4)
{
__m128 input = *(const __m128*)in;
__m128 res = _mm_mul_ps(input, factor);
__m64 output = _mm_cvtps_pi16(res);
*(__m64*)out = output;
}
audio_convert_float_to_s16_C(out, in, samples - i);
}
#endif
void audio_convert_s16_to_float_C(float *out,
const int16_t *in, size_t samples);
void audio_convert_float_to_s16_C(int16_t *out,
const float *in, size_t samples);
#endif
+172
View File
@@ -0,0 +1,172 @@
/*
Simple C interface for XAudio2
Author: Hans-Kristian Arntzen
License: Public Domain
*/
#include "xaudio.h"
#include "xaudio-c.h"
#include <stdint.h>
#include "../../msvc/msvc_compat.h"
#define MAX_BUFFERS 16
#define MAX_BUFFERS_MASK (MAX_BUFFERS - 1)
#undef min
#undef max
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
struct xaudio2
{
const IXAudio2VoiceCallbackVtbl *lpVtbl;
uint8_t *buf;
IXAudio2 *pXAudio2;
IXAudio2MasteringVoice *pMasterVoice;
IXAudio2SourceVoice *pSourceVoice;
HANDLE hEvent;
volatile long buffers;
unsigned bufsize;
unsigned bufptr;
unsigned write_buffer;
};
static void WINAPI voice_on_buffer_end(void *handle_, void *data)
{
(void)data;
xaudio2_t *handle = (xaudio2_t*)handle_;
InterlockedDecrement(&handle->buffers);
SetEvent(handle->hEvent);
}
static void WINAPI dummy_voidp(void *handle, void *data) { (void)handle; (void)data; }
static void WINAPI dummy_nil(void *handle) { (void)handle; }
static void WINAPI dummy_uint32(void *handle, UINT32 dummy) { (void)handle; (void)dummy; }
static void WINAPI dummy_voidp_hresult(void *handle, void *data, HRESULT dummy) { (void)handle; (void)data; (void)dummy; }
const struct IXAudio2VoiceCallbackVtbl voice_vtable = {
dummy_uint32,
dummy_nil,
dummy_nil,
dummy_voidp,
voice_on_buffer_end,
dummy_voidp,
dummy_voidp_hresult,
};
xaudio2_t *xaudio2_new(unsigned samplerate, unsigned channels, size_t size)
{
xaudio2_t *handle = (xaudio2_t*)calloc(1, sizeof(*handle));
if (!handle)
return NULL;
handle->lpVtbl = &voice_vtable;
CoInitializeEx(0, COINIT_MULTITHREADED);
WAVEFORMATEX wfx = {0};
if (FAILED(XAudio2Create(&handle->pXAudio2)))
goto error;
if (FAILED(IXAudio2_CreateMasteringVoice(handle->pXAudio2,
&handle->pMasterVoice, channels, samplerate, 0, 0, 0)))
goto error;
wfx.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
wfx.nChannels = channels;
wfx.nSamplesPerSec = samplerate;
wfx.nBlockAlign = channels * sizeof(float);
wfx.wBitsPerSample = sizeof(float) * 8;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
wfx.cbSize = 0;
if (FAILED(IXAudio2_CreateSourceVoice(handle->pXAudio2,
&handle->pSourceVoice, &wfx,
XAUDIO2_VOICE_NOSRC, XAUDIO2_DEFAULT_FREQ_RATIO,
(IXAudio2VoiceCallback*)handle, 0, 0)))
goto error;
handle->hEvent = CreateEvent(0, FALSE, FALSE, 0);
if (!handle->hEvent)
goto error;
handle->bufsize = size / MAX_BUFFERS;
handle->buf = (uint8_t*)calloc(1, handle->bufsize * MAX_BUFFERS);
if (!handle->buf)
goto error;
if (FAILED(IXAudio2SourceVoice_Start(handle->pSourceVoice, 0, XAUDIO2_COMMIT_NOW)))
goto error;
return handle;
error:
xaudio2_free(handle);
return NULL;
}
size_t xaudio2_write_avail(xaudio2_t *handle)
{
return handle->bufsize * (MAX_BUFFERS - handle->buffers - 1);
}
size_t xaudio2_write(xaudio2_t *handle, const void *buf, size_t bytes_)
{
unsigned bytes = bytes_;
const uint8_t *buffer = (const uint8_t*)buf;
while (bytes)
{
unsigned need = min(bytes, handle->bufsize - handle->bufptr);
memcpy(handle->buf + handle->write_buffer * handle->bufsize + handle->bufptr,
buffer, need);
handle->bufptr += need;
buffer += need;
bytes -= need;
if (handle->bufptr == handle->bufsize)
{
while (handle->buffers == MAX_BUFFERS - 1)
WaitForSingleObject(handle->hEvent, INFINITE);
XAUDIO2_BUFFER xa2buffer = {0};
xa2buffer.AudioBytes = handle->bufsize;
xa2buffer.pAudioData = handle->buf + handle->write_buffer * handle->bufsize;
if (FAILED(IXAudio2SourceVoice_SubmitSourceBuffer(handle->pSourceVoice, &xa2buffer, NULL)))
return 0;
InterlockedIncrement(&handle->buffers);
handle->bufptr = 0;
handle->write_buffer = (handle->write_buffer + 1) & MAX_BUFFERS_MASK;
}
}
return bytes_;
}
void xaudio2_free(xaudio2_t *handle)
{
if (handle)
{
if (handle->pSourceVoice)
{
IXAudio2SourceVoice_Stop(handle->pSourceVoice, 0, XAUDIO2_COMMIT_NOW);
IXAudio2SourceVoice_DestroyVoice(handle->pSourceVoice);
}
if (handle->pMasterVoice)
IXAudio2MasteringVoice_DestroyVoice(handle->pMasterVoice);
if (handle->pXAudio2)
IXAudio2_Release(handle->pXAudio2);
if (handle->hEvent)
CloseHandle(handle->hEvent);
free(handle->buf);
free(handle);
}
}
-164
View File
@@ -1,164 +0,0 @@
/*
Simple C interface for XAudio2
Author: Hans-Kristian Arntzen
License: Public Domain
*/
#include "xaudio-c.h"
#include "xaudio2.hpp"
#include <stdint.h>
#include <algorithm>
struct xaudio2 : public IXAudio2VoiceCallback
{
xaudio2(unsigned samplerate, unsigned channels, unsigned size) :
buf(0), pXAudio2(0), pMasterVoice(0), pSourceVoice(0),
buffers(0), bufptr(0)
{
CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(XAudio2Create(&pXAudio2, 0)))
throw -1;
if (FAILED(pXAudio2->CreateMasteringVoice(
&pMasterVoice, channels, samplerate, 0, 0, 0)))
throw -1;
WAVEFORMATEX wfx;
wfx.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
wfx.nChannels = channels;
wfx.nSamplesPerSec = samplerate;
wfx.nBlockAlign = channels * sizeof(float);
wfx.wBitsPerSample = sizeof(float) * 8;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
wfx.cbSize = 0;
if (FAILED(pXAudio2->CreateSourceVoice(
&pSourceVoice, &wfx, XAUDIO2_VOICE_NOSRC, XAUDIO2_DEFAULT_FREQ_RATIO, this, 0, 0)))
throw -1;
hEvent = CreateEvent(0, FALSE, FALSE, 0);
if (!hEvent)
throw -1;
pSourceVoice->Start(0);
bufsize = size / max_buffers;
buf = new uint8_t[bufsize * max_buffers];
write_buffer = 0;
}
virtual ~xaudio2()
{
if (pSourceVoice)
{
pSourceVoice->Stop(0);
pSourceVoice->DestroyVoice();
}
if (pMasterVoice)
pMasterVoice->DestroyVoice();
if (pXAudio2)
pXAudio2->Release();
if (hEvent)
CloseHandle(hEvent);
if (buf)
delete[] buf;
}
size_t write_avail() const
{
return bufsize * (max_buffers - buffers - 1);
}
size_t write(const void *buffer_, size_t bytes_)
{
unsigned bytes = bytes_;
const uint8_t *buffer = reinterpret_cast<const uint8_t*>(buffer_);
while (bytes > 0)
{
unsigned need = std::min(bytes, bufsize - bufptr);
memcpy(buf + write_buffer * bufsize + bufptr,
buffer, need);
bufptr += need;
buffer += need;
bytes -= need;
if (bufptr == bufsize)
{
WaitForSingleObject(hEvent, 0); // Clear out ready state.
while (buffers == max_buffers - 1)
WaitForSingleObject(hEvent, INFINITE);
XAUDIO2_BUFFER xa2buffer = {0};
xa2buffer.AudioBytes = bufsize;
xa2buffer.pAudioData = buf + write_buffer * bufsize;
xa2buffer.pContext = 0;
if (FAILED(pSourceVoice->SubmitSourceBuffer(&xa2buffer)))
return 0;
InterlockedIncrement(&buffers);
bufptr = 0;
write_buffer = (write_buffer + 1) & (max_buffers_mask);
}
}
return bytes_;
}
enum { max_buffers = 16, max_buffers_mask = max_buffers - 1 };
STDMETHOD_(void, OnBufferStart) (void *) {}
STDMETHOD_(void, OnBufferEnd) (void *)
{
InterlockedDecrement(&buffers);
SetEvent(hEvent);
}
STDMETHOD_(void, OnLoopEnd) (void *) {}
STDMETHOD_(void, OnStreamEnd) () {}
STDMETHOD_(void, OnVoiceError) (void *, HRESULT) {}
STDMETHOD_(void, OnVoiceProcessingPassEnd) () {}
STDMETHOD_(void, OnVoiceProcessingPassStart) (UINT32) {}
uint8_t *buf;
IXAudio2 *pXAudio2;
IXAudio2MasteringVoice *pMasterVoice;
IXAudio2SourceVoice *pSourceVoice;
HANDLE hEvent;
volatile long buffers;
unsigned bufsize;
unsigned bufptr;
unsigned write_buffer;
};
xaudio2_t *xaudio2_new(unsigned samplerate, unsigned channels, size_t size)
{
xaudio2 *handle = 0;
try {
handle = new xaudio2(samplerate, channels, size);
} catch(...) { delete handle; return 0; }
return handle;
}
size_t xaudio2_write_avail(xaudio2_t *handle)
{
try {
return handle->write_avail();
} catch(...) { return 0; }
}
size_t xaudio2_write(xaudio2_t *handle, const void *buf, size_t bytes)
{
try {
return handle->write(buf, bytes);
} catch(...) { return 0; }
}
void xaudio2_free(xaudio2_t *handle)
{
delete handle;
}
+61 -159
View File
@@ -1,35 +1,37 @@
/*
xaudio2.hpp (2010-08-14)
author: OV2
xaudio.h (2010-08-14) / (2012-12-04)
authors: OV2, Themaister
*/
// Kinda stripped down. Only contains the bare essentials used in SSNES.
#ifndef XAUDIO2_MINGW_H
#define XAUDIO2_MINGW_H
#ifdef __cplusplus
#define CINTERFACE
#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef min
#undef max
#include <basetyps.h>
#include <objbase.h>
#include <mmreg.h>
// 64-bit GCC fix
#define GUID_EXT EXTERN_C
#define GUID_SECT
#define DEFINE_GUID_X(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) GUID_EXT const GUID n GUID_SECT = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
#define DEFINE_GUID_X(n, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
static const GUID n = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
#define DEFINE_CLSID_X(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
DEFINE_GUID_X(CLSID_##className, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)
#define DEFINE_IID_X(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
DEFINE_GUID_X(IID_##interfaceName, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)
#define X2DEFAULT(x) =x
#define X2DEFAULT(x)
DEFINE_CLSID_X(XAudio2, e21a7345, eb21, 468e, be, 50, 80, 4d, b9, 7c, f7, 08);
DEFINE_CLSID_X(XAudio2_Debug, f7a76c21, 53d4, 46bb, ac, 53, 8b, 45, 9c, ae, 46, bd);
DEFINE_IID_X(IXAudio2, 8bcf1f58, 9fe7, 4583, 8a, c6, e2, ad, c4, 65, c8, bb);
DECLARE_INTERFACE(IXAudio2Voice);
#ifndef INTERFACE
#define INTERFACE void
#endif
#define XAUDIO2_COMMIT_NOW 0
#define XAUDIO2_DEFAULT_CHANNELS 0
@@ -46,95 +48,33 @@ typedef enum XAUDIO2_DEVICE_ROLE
DefaultCommunicationsDevice = 0x4,
DefaultGameDevice = 0x8,
GlobalDefaultDevice = 0xf,
InvalidDeviceRole = ~GlobalDefaultDevice
InvalidDeviceRole = ~GlobalDefaultDevice
} XAUDIO2_DEVICE_ROLE;
typedef struct XAUDIO2_DEVICE_DETAILS
{
WCHAR DeviceID[256];
WCHAR DisplayName[256];
XAUDIO2_DEVICE_ROLE Role;
WAVEFORMATEXTENSIBLE OutputFormat;
} XAUDIO2_DEVICE_DETAILS;
typedef struct XAUDIO2_VOICE_DETAILS
{
UINT32 CreationFlags;
UINT32 InputChannels;
UINT32 InputSampleRate;
} XAUDIO2_VOICE_DETAILS;
typedef enum XAUDIO2_WINDOWS_PROCESSOR_SPECIFIER
{
Processor1 = 0x00000001,
Processor2 = 0x00000002,
Processor3 = 0x00000004,
Processor4 = 0x00000008,
Processor5 = 0x00000010,
Processor6 = 0x00000020,
Processor7 = 0x00000040,
Processor8 = 0x00000080,
Processor9 = 0x00000100,
Processor10 = 0x00000200,
Processor11 = 0x00000400,
Processor12 = 0x00000800,
Processor13 = 0x00001000,
Processor14 = 0x00002000,
Processor15 = 0x00004000,
Processor16 = 0x00008000,
Processor17 = 0x00010000,
Processor18 = 0x00020000,
Processor19 = 0x00040000,
Processor20 = 0x00080000,
Processor21 = 0x00100000,
Processor22 = 0x00200000,
Processor23 = 0x00400000,
Processor24 = 0x00800000,
Processor25 = 0x01000000,
Processor26 = 0x02000000,
Processor27 = 0x04000000,
Processor28 = 0x08000000,
Processor29 = 0x10000000,
Processor30 = 0x20000000,
Processor31 = 0x40000000,
Processor32 = 0x80000000,
XAUDIO2_ANY_PROCESSOR = 0xffffffff,
XAUDIO2_DEFAULT_PROCESSOR = XAUDIO2_ANY_PROCESSOR
XAUDIO2_ANY_PROCESSOR = 0xffffffff,
XAUDIO2_DEFAULT_PROCESSOR = XAUDIO2_ANY_PROCESSOR
} XAUDIO2_WINDOWS_PROCESSOR_SPECIFIER, XAUDIO2_PROCESSOR;
typedef struct XAUDIO2_VOICE_SENDS
{
UINT32 OutputCount;
IXAudio2Voice** pOutputVoices;
} XAUDIO2_VOICE_SENDS;
typedef struct XAUDIO2_EFFECT_DESCRIPTOR
{
IUnknown* pEffect;
BOOL InitialState;
UINT32 OutputChannels;
} XAUDIO2_EFFECT_DESCRIPTOR;
typedef struct XAUDIO2_EFFECT_CHAIN
{
UINT32 EffectCount;
const XAUDIO2_EFFECT_DESCRIPTOR* pEffectDescriptors;
} XAUDIO2_EFFECT_CHAIN;
typedef enum XAUDIO2_FILTER_TYPE
{
typedef enum XAUDIO2_FILTER_TYPE {
LowPassFilter,
BandPassFilter,
HighPassFilter
HighPassFilter
} XAUDIO2_FILTER_TYPE;
typedef struct XAUDIO2_FILTER_PARAMETERS
{
XAUDIO2_FILTER_TYPE Type;
float Frequency;
float OneOverQ;
} XAUDIO2_FILTER_PARAMETERS;
typedef struct XAUDIO2_DEVICE_DETAILS XAUDIO2_DEVICE_DETAILS;
typedef struct XAUDIO2_VOICE_DETAILS XAUDIO2_VOICE_DETAILS;
typedef struct XAUDIO2_VOICE_SENDS XAUDIO2_VOICE_SENDS;
typedef struct XAUDIO2_EFFECT_DESCRIPTOR XAUDIO2_EFFECT_DESCRIPTOR;
typedef struct XAUDIO2_EFFECT_CHAIN XAUDIO2_EFFECT_CHAIN;
typedef struct XAUDIO2_FILTER_PARAMETERS XAUDIO2_FILTER_PARAMETERS;
typedef struct XAUDIO2_BUFFER_WMA XAUDIO2_BUFFER_WMA;
typedef struct XAUDIO2_VOICE_STATE XAUDIO2_VOICE_STATE;
typedef struct XAUDIO2_PERFORMANCE_DATA XAUDIO2_PERFORMANCE_DATA;
typedef struct XAUDIO2_DEBUG_CONFIGURATION XAUDIO2_DEBUG_CONFIGURATION;
typedef struct IXAudio2EngineCallback IXAudio2EngineCallback;
typedef struct IXAudio2SubmixVoice IXAudio2SubmixVoice;
typedef struct XAUDIO2_BUFFER
{
@@ -146,65 +86,18 @@ typedef struct XAUDIO2_BUFFER
UINT32 LoopBegin;
UINT32 LoopLength;
UINT32 LoopCount;
void* pContext;
void *pContext;
} XAUDIO2_BUFFER;
typedef struct XAUDIO2_BUFFER_WMA
{
const UINT32* pDecodedPacketCumulativeBytes;
UINT32 PacketCount;
} XAUDIO2_BUFFER_WMA;
typedef struct XAUDIO2_VOICE_STATE
{
void* pCurrentBufferContext;
UINT32 BuffersQueued;
UINT64 SamplesPlayed;
} XAUDIO2_VOICE_STATE;
typedef struct XAUDIO2_PERFORMANCE_DATA
{
UINT64 AudioCyclesSinceLastQuery;
UINT64 TotalCyclesSinceLastQuery;
UINT32 MinimumCyclesPerQuantum;
UINT32 MaximumCyclesPerQuantum;
UINT32 MemoryUsageInBytes;
UINT32 CurrentLatencyInSamples;
UINT32 GlitchesSinceEngineStarted;
UINT32 ActiveSourceVoiceCount;
UINT32 TotalSourceVoiceCount;
UINT32 ActiveSubmixVoiceCount;
UINT32 TotalSubmixVoiceCount;
UINT32 ActiveXmaSourceVoices;
UINT32 ActiveXmaStreams;
} XAUDIO2_PERFORMANCE_DATA;
typedef struct XAUDIO2_DEBUG_CONFIGURATION
{
UINT32 TraceMask;
UINT32 BreakMask;
BOOL LogThreadID;
BOOL LogFileline;
BOOL LogFunctionName;
BOOL LogTiming;
} XAUDIO2_DEBUG_CONFIGURATION;
DECLARE_INTERFACE(IXAudio2EngineCallback)
{
STDMETHOD_(void, OnProcessingPassStart) (THIS) PURE;
STDMETHOD_(void, OnProcessingPassEnd) (THIS) PURE;
STDMETHOD_(void, OnCriticalError) (THIS_ HRESULT Error) PURE;
};
DECLARE_INTERFACE(IXAudio2VoiceCallback)
{
STDMETHOD_(void, OnVoiceProcessingPassStart) (THIS_ UINT32 BytesRequired) PURE;
STDMETHOD_(void, OnVoiceProcessingPassEnd) (THIS) PURE;
STDMETHOD_(void, OnStreamEnd) (THIS) PURE;
STDMETHOD_(void, OnBufferStart) (THIS_ void* pBufferContext) PURE;
STDMETHOD_(void, OnBufferEnd) (THIS_ void* pBufferContext) PURE;
STDMETHOD_(void, OnLoopEnd) (THIS_ void* pBufferContext) PURE;
STDMETHOD_(void, OnVoiceError) (THIS_ void* pBufferContext, HRESULT Error) PURE;
STDMETHOD_(void, OnBufferStart) (THIS_ void *pBufferContext) PURE;
STDMETHOD_(void, OnBufferEnd) (THIS_ void *pBufferContext) PURE;
STDMETHOD_(void, OnLoopEnd) (THIS_ void *pBufferContext) PURE;
STDMETHOD_(void, OnVoiceError) (THIS_ void *pBufferContext, HRESULT Error) PURE;
};
DECLARE_INTERFACE(IXAudio2Voice)
@@ -219,10 +112,10 @@ DECLARE_INTERFACE(IXAudio2Voice)
UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \
STDMETHOD_(void, GetEffectState) (THIS_ UINT32 EffectIndex, BOOL* pEnabled) PURE; \
STDMETHOD(SetEffectParameters) (THIS_ UINT32 EffectIndex, \
const void* pParameters, \
const void *pParameters, \
UINT32 ParametersByteSize, \
UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \
STDMETHOD(GetEffectParameters) (THIS_ UINT32 EffectIndex, void* pParameters, \
STDMETHOD(GetEffectParameters) (THIS_ UINT32 EffectIndex, void *pParameters, \
UINT32 ParametersByteSize) PURE; \
STDMETHOD(SetFilterParameters) (THIS_ const XAUDIO2_FILTER_PARAMETERS* pParameters, \
UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \
@@ -245,17 +138,11 @@ DECLARE_INTERFACE(IXAudio2Voice)
Declare_IXAudio2Voice_Methods();
};
DECLARE_INTERFACE_(IXAudio2MasteringVoice, IXAudio2Voice)
{
Declare_IXAudio2Voice_Methods();
};
DECLARE_INTERFACE_(IXAudio2SubmixVoice, IXAudio2Voice)
{
Declare_IXAudio2Voice_Methods();
};
DECLARE_INTERFACE_(IXAudio2SourceVoice, IXAudio2Voice)
{
Declare_IXAudio2Voice_Methods();
@@ -304,23 +191,38 @@ DECLARE_INTERFACE_(IXAudio2, IUnknown)
STDMETHOD(CommitChanges) (THIS_ UINT32 OperationSet) PURE;
STDMETHOD_(void, GetPerformanceData) (THIS_ XAUDIO2_PERFORMANCE_DATA* pPerfData) PURE;
STDMETHOD_(void, SetDebugConfiguration) (THIS_ const XAUDIO2_DEBUG_CONFIGURATION* pDebugConfiguration,
void* pReserved X2DEFAULT(NULL)) PURE;
void *pReserved X2DEFAULT(NULL)) PURE;
};
static inline HRESULT XAudio2Create(IXAudio2** ppXAudio2, UINT32 Flags X2DEFAULT(0),
XAUDIO2_PROCESSOR XAudio2Processor X2DEFAULT(XAUDIO2_DEFAULT_PROCESSOR))
// C hooks.
#define IXAudio2_Initialize(THIS, a, b) (THIS)->lpVtbl->Initialize(THIS, a, b)
#define IXAudio2_Release(THIS) (THIS)->lpVtbl->Release(THIS)
#define IXAudio2_CreateSourceVoice(THIS, a, b, c, d, e, f, g) (THIS)->lpVtbl->CreateSourceVoice(THIS, a, b, c, d, e, f, g)
#define IXAudio2_CreateMasteringVoice(THIS, a, b, c, d, e, f) (THIS)->lpVtbl->CreateMasteringVoice(THIS, a, b, c, d, e, f)
#define IXAudio2SourceVoice_Start(THIS, a, b) (THIS)->lpVtbl->Start(THIS, a, b)
#define IXAudio2SourceVoice_Stop(THIS, a, b) (THIS)->lpVtbl->Stop(THIS, a, b)
#define IXAudio2SourceVoice_SubmitSourceBuffer(THIS, a, b) (THIS)->lpVtbl->SubmitSourceBuffer(THIS, a, b)
#define IXAudio2SourceVoice_DestroyVoice(THIS) (THIS)->lpVtbl->DestroyVoice(THIS)
#define IXAudio2MasteringVoice_DestroyVoice(THIS) (THIS)->lpVtbl->DestroyVoice(THIS)
static inline HRESULT XAudio2Create(IXAudio2 **ppXAudio2)
{
IXAudio2* pXAudio2;
HRESULT hr = CoCreateInstance((Flags & XAUDIO2_DEBUG_ENGINE) ? CLSID_XAudio2_Debug : CLSID_XAudio2,
NULL, CLSCTX_INPROC_SERVER, IID_IXAudio2, reinterpret_cast<void**>(&pXAudio2));
IXAudio2 *pXAudio2;
#ifdef __cplusplus
HRESULT hr = CoCreateInstance(CLSID_XAudio2, NULL, CLSCTX_INPROC_SERVER, IID_IXAudio2, (void**)&pXAudio2);
#else
HRESULT hr = CoCreateInstance(&CLSID_XAudio2, NULL, CLSCTX_INPROC_SERVER, &IID_IXAudio2, (void**)&pXAudio2);
#endif
if (SUCCEEDED(hr))
{
hr = pXAudio2->Initialize(Flags, XAudio2Processor);
hr = IXAudio2_Initialize(pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR);
if (SUCCEEDED(hr))
*ppXAudio2 = pXAudio2;
else
pXAudio2->Release();
IXAudio2_Release(pXAudio2);
}
return hr;
}
+26 -25
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -15,10 +15,10 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "driver.h"
#include "../driver.h"
#include <stdlib.h>
#include "xaudio-c/xaudio-c.h"
#include "general.h"
#include "../general.h"
typedef struct
{
@@ -26,13 +26,13 @@ typedef struct
bool nonblock;
} xa_t;
static void* __xa_init(const char* device, unsigned rate, unsigned latency)
static void *xa_init(const char *device, unsigned rate, unsigned latency)
{
if (latency < 8)
latency = 8; // Do not allow shenanigans.
xa_t *xa = calloc(1, sizeof(xa_t));
if (xa == NULL)
xa_t *xa = (xa_t*)calloc(1, sizeof(*xa));
if (!xa)
return NULL;
size_t bufsize = latency * rate / 1000;
@@ -46,12 +46,13 @@ static void* __xa_init(const char* device, unsigned rate, unsigned latency)
free(xa);
return NULL;
}
return xa;
}
static ssize_t __xa_write(void* data, const void* buf, size_t size)
static ssize_t xa_write(void *data, const void *buf, size_t size)
{
xa_t *xa = data;
xa_t *xa = (xa_t*)data;
if (xa->nonblock)
{
size_t avail = xaudio2_write_avail(xa->xa);
@@ -60,39 +61,40 @@ static ssize_t __xa_write(void* data, const void* buf, size_t size)
if (avail < size)
size = avail;
}
size_t ret = xaudio2_write(xa->xa, buf, size);
if (ret == 0)
if (ret == 0 && size > 0)
return -1;
return ret;
}
static bool __xa_stop(void *data)
static bool xa_stop(void *data)
{
(void)data;
return true;
}
static void __xa_set_nonblock_state(void *data, bool state)
static void xa_set_nonblock_state(void *data, bool state)
{
xa_t *xa = data;
xa_t *xa = (xa_t*)data;
xa->nonblock = state;
}
static bool __xa_start(void *data)
static bool xa_start(void *data)
{
(void)data;
return true;
}
static bool __xa_use_float(void *data)
static bool xa_use_float(void *data)
{
(void)data;
return true;
}
static void __xa_free(void *data)
static void xa_free(void *data)
{
xa_t *xa = data;
xa_t *xa = (xa_t*)data;
if (xa)
{
if (xa->xa)
@@ -102,13 +104,12 @@ static void __xa_free(void *data)
}
const audio_driver_t audio_xa = {
.init = __xa_init,
.write = __xa_write,
.stop = __xa_stop,
.start = __xa_start,
.set_nonblock_state = __xa_set_nonblock_state,
.use_float = __xa_use_float,
.free = __xa_free,
.ident = "xaudio"
xa_init,
xa_write,
xa_stop,
xa_start,
xa_set_nonblock_state,
xa_free,
xa_use_float,
"xaudio"
};
+4 -4
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -18,7 +18,7 @@
#include "autosave.h"
#include "thread.h"
#include <stdlib.h>
#include <stdbool.h>
#include "boolean.h"
#include <string.h>
#include <stdio.h>
#include "general.h"
@@ -41,7 +41,7 @@ struct autosave
static void autosave_thread(void *data)
{
autosave_t *save = data;
autosave_t *save = (autosave_t*)data;
bool first_log = true;
@@ -86,7 +86,7 @@ static void autosave_thread(void *data)
autosave_t *autosave_new(const char *path, const void *data, size_t size, unsigned interval)
{
autosave_t *handle = calloc(1, sizeof(*handle));
autosave_t *handle = (autosave_t*)calloc(1, sizeof(*handle));
if (!handle)
return NULL;
+1 -1
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
+26
View File
@@ -0,0 +1,26 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __SSNES_BOOLEAN_H
#define __SSNES_BOOLEAN_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#endif
+12 -13
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -18,7 +18,8 @@
#include "bps.h"
#include "movie.h"
#include <stdint.h>
#include <stdbool.h>
#include "boolean.h"
#include "msvc/msvc_compat.h"
enum bps_mode
{
@@ -77,17 +78,15 @@ bps_error_t bps_apply_patch(
if (modify_length < 19)
return BPS_PATCH_TOO_SMALL;
struct bps_data bps = {
.modify_data = modify_data,
.modify_length = modify_length,
.target_data = target_data,
.target_length = *target_length,
.source_data = source_data,
.source_length = source_length,
.modify_checksum = ~0,
.target_checksum = ~0,
};
struct bps_data bps = {0};
bps.modify_data = modify_data;
bps.modify_length = modify_length;
bps.target_data = target_data;
bps.target_length = *target_length;
bps.source_data = source_data;
bps.source_length = source_length;
bps.modify_checksum = ~0;
bps.target_checksum = ~0;
if ((bps_read(&bps) != 'B') || (bps_read(&bps) != 'P') || (bps_read(&bps) != 'S') || (bps_read(&bps) != '1'))
return BPS_PATCH_INVALID_HEADER;
+1 -1
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
+10 -8
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -51,13 +51,13 @@ struct cheat_manager
unsigned buf_size;
};
static char* strcat_alloc(char *dest, const char *input)
static char *strcat_alloc(char *dest, const char *input)
{
size_t dest_len = dest ? strlen(dest) : 0;
size_t input_len = strlen(input);
size_t required_len = dest_len + input_len + 1;
char *output = realloc(dest, required_len);
char *output = (char*)realloc(dest, required_len);
if (!output)
return NULL;
@@ -126,7 +126,7 @@ static bool xml_grab_cheats(cheat_manager_t *handle, xmlNodePtr ptr)
if (handle->size == handle->buf_size)
{
handle->buf_size *= 2;
handle->cheats = realloc(handle->cheats, handle->buf_size * sizeof(struct cheat));
handle->cheats = (struct cheat*)realloc(handle->cheats, handle->buf_size * sizeof(struct cheat));
if (!handle->cheats)
return false;
}
@@ -242,12 +242,15 @@ cheat_manager_t* cheat_manager_new(const char *path)
xmlParserCtxtPtr ctx = NULL;
xmlDocPtr doc = NULL;
cheat_manager_t *handle = calloc(1, sizeof(struct cheat_manager));
cheat_manager_t *handle = (cheat_manager_t*)calloc(1, sizeof(struct cheat_manager));
if (!handle)
return NULL;
xmlNodePtr head = NULL;
xmlNodePtr cur = NULL;
handle->buf_size = 1;
handle->cheats = calloc(handle->buf_size, sizeof(struct cheat));
handle->cheats = (struct cheat*)calloc(handle->buf_size, sizeof(struct cheat));
if (!handle->cheats)
{
handle->buf_size = 0;
@@ -271,8 +274,7 @@ cheat_manager_t* cheat_manager_new(const char *path)
goto error;
}
xmlNodePtr head = xmlDocGetRootElement(doc);
xmlNodePtr cur = NULL;
head = xmlDocGetRootElement(doc);
for (cur = head; cur; cur = cur->next)
{
if (cur->type == XML_ELEMENT_NODE && strcmp((const char*)cur->name, "database") == 0)
+1 -1
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
+87 -42
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -22,20 +22,24 @@
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include "strl.h"
#include "../strl.h"
#include "../posix_string.h"
#include "../msvc/msvc_compat.h"
#ifndef _WIN32
#include <sys/param.h> // MAXPATHLEN
#else
#if !defined(_WIN32) && !defined(__CELLOS_LV2__) && !defined(_XBOX)
#include <sys/param.h> // PATH_MAX
#elif defined(_WIN32) && !defined(_XBOX)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#elif defined(_XBOX)
#include <xtl.h>
#endif
#ifndef MAXPATHLEN
#ifndef PATH_MAX
#ifdef PATH_MAX
#define MAXPATHLEN PATH_MAX
#define PATH_MAX PATH_MAX
#else
#define MAXPATHLEN 512
#define PATH_MAX 512
#endif
#endif
@@ -69,7 +73,7 @@ static config_file_t *config_file_new_internal(const char *path, unsigned depth)
static char *getaline(FILE *file)
{
char *newline = malloc(9);
char *newline = (char*)malloc(9);
size_t cur_size = 8;
size_t index = 0;
@@ -79,7 +83,7 @@ static char *getaline(FILE *file)
if (index == cur_size)
{
cur_size *= 2;
newline = realloc(newline, cur_size + 1);
newline = (char*)realloc(newline, cur_size + 1);
}
newline[index++] = in;
@@ -89,7 +93,7 @@ static char *getaline(FILE *file)
return newline;
}
static char* extract_value(char *line, bool is_value)
static char *extract_value(char *line, bool is_value)
{
if (is_value)
{
@@ -98,7 +102,7 @@ static char* extract_value(char *line, bool is_value)
// If we don't have an equal sign here, we've got an invalid string...
if (*line != '=')
return false;
return NULL;
line++;
}
@@ -112,7 +116,7 @@ static char* extract_value(char *line, bool is_value)
line++;
char *tok = strtok(line, "\"");
if (!tok)
return false;
return NULL;
return strdup(tok);
}
else if (*line == '\0') // Nothing :(
@@ -171,7 +175,7 @@ static void add_child_list(config_file_t *parent, config_file_t *child)
static void add_include_list(config_file_t *conf, const char *path)
{
struct include_list *head = conf->includes;
struct include_list *node = calloc(1, sizeof(*node));
struct include_list *node = (struct include_list*)calloc(1, sizeof(*node));
node->path = strdup(path);
if (head)
@@ -193,19 +197,42 @@ static void add_sub_conf(config_file_t *conf, char *line)
add_include_list(conf, path);
char real_path[MAXPATHLEN];
char real_path[PATH_MAX];
#ifndef _WIN32
if (*path == '/')
{
#ifdef _WIN32
// Accomodate POSIX systems on Win32.
bool is_full_path = *path == '/';
if (is_full_path)
strlcpy(real_path, path, sizeof(real_path));
else
{
// Workaround GetFullPathName not existing on XDK.
// : is not a valid element in a path name. (NTFS streams?)
if (strchr(path, ':') == NULL)
{
strlcpy(real_path, conf->path, sizeof(real_path));
char *split = strrchr(real_path, '/');
if (!split)
split = strrchr(real_path, '\\');
split[1] = '\0';
strlcat(real_path, path, sizeof(real_path));
}
else
strlcpy(real_path, path, sizeof(real_path));
}
#else
if (*path == '/')
strlcpy(real_path, path, sizeof(real_path));
#ifndef __CELLOS_LV2__
else if (*path == '~')
{
const char *home = getenv("HOME");
strlcpy(real_path, home ? home : "/", sizeof(real_path));
strlcat(real_path, path + 1, sizeof(real_path));
}
#endif
else
{
strlcpy(real_path, conf->path, sizeof(real_path));
@@ -218,25 +245,6 @@ static void add_sub_conf(config_file_t *conf, char *line)
else
strlcpy(real_path, path, sizeof(real_path));
}
#else
// Accomodate POSIX systems on Win32.
bool is_full_path = *path == '/';
if (is_full_path)
strlcpy(real_path, path, sizeof(real_path));
else
GetFullPathNameA(path, sizeof(real_path), real_path, NULL);
if (strcmp(path, real_path) != 0)
{
strlcpy(real_path, conf->path, sizeof(real_path));
char *split = strrchr(real_path, '/');
if (!split)
split = strrchr(real_path, '\\');
split[1] = '\0';
strlcat(real_path, path, sizeof(real_path));
}
#endif
config_file_t *sub_conf = config_file_new_internal(real_path, conf->include_depth + 1);
@@ -276,7 +284,7 @@ static bool parse_line(config_file_t *conf, struct entry_list *list, char *line)
while (isspace(*line))
line++;
char *key = malloc(9);
char *key = (char*)malloc(9);
size_t cur_size = 8;
size_t index = 0;
@@ -285,7 +293,7 @@ static bool parse_line(config_file_t *conf, struct entry_list *list, char *line)
if (index == cur_size)
{
cur_size *= 2;
key = realloc(key, cur_size + 1);
key = (char*)realloc(key, cur_size + 1);
}
key[index++] = *line++;
@@ -306,7 +314,7 @@ static bool parse_line(config_file_t *conf, struct entry_list *list, char *line)
static config_file_t *config_file_new_internal(const char *path, unsigned depth)
{
struct config_file *conf = calloc(1, sizeof(*conf));
struct config_file *conf = (struct config_file*)calloc(1, sizeof(*conf));
if (!conf)
return NULL;
@@ -332,7 +340,7 @@ static config_file_t *config_file_new_internal(const char *path, unsigned depth)
while (!feof(file))
{
struct entry_list *list = calloc(1, sizeof(*list));
struct entry_list *list = (struct entry_list*)calloc(1, sizeof(*list));
char *line = getaline(file);
if (line)
@@ -411,6 +419,22 @@ bool config_get_double(config_file_t *conf, const char *key, double *in)
return false;
}
bool config_get_float(config_file_t *conf, const char *key, float *in)
{
struct entry_list *list = conf->entries;
while (list)
{
if (strcmp(key, list->key) == 0)
{
*in = (float)strtod(list->value, NULL);
return true;
}
list = list->next;
}
return false;
}
bool config_get_int(config_file_t *conf, const char *key, int *in)
{
struct entry_list *list = conf->entries;
@@ -434,6 +458,23 @@ bool config_get_int(config_file_t *conf, const char *key, int *in)
return false;
}
bool config_get_uint(config_file_t *conf, const char *key, unsigned *in)
{
struct entry_list *list = conf->entries;
while (list != NULL)
{
if (strcmp(key, list->key) == 0)
{
*in = strtol(list->value, NULL, 0);
return true;
}
list = list->next;
}
return false;
}
bool config_get_hex(config_file_t *conf, const char *key, unsigned *in)
{
struct entry_list *list = conf->entries;
@@ -550,7 +591,7 @@ void config_set_string(config_file_t *conf, const char *key, const char *val)
list = list->next;
}
struct entry_list *elem = calloc(1, sizeof(*elem));
struct entry_list *elem = (struct entry_list*)calloc(1, sizeof(*elem));
elem->key = strdup(key);
elem->value = strdup(val);
@@ -563,7 +604,11 @@ void config_set_string(config_file_t *conf, const char *key, const char *val)
void config_set_double(config_file_t *conf, const char *key, double val)
{
char buf[128];
#ifdef __cplusplus
snprintf(buf, sizeof(buf), "%f", (float)val);
#else
snprintf(buf, sizeof(buf), "%lf", val);
#endif
config_set_string(conf, key, buf);
}
+6 -2
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -20,7 +20,7 @@
#define __CONFIG_FILE_H
#include <stdint.h>
#include <stdbool.h>
#include "../boolean.h"
#include <stdio.h>
#include <stddef.h>
@@ -49,8 +49,12 @@ bool config_entry_exists(config_file_t *conf, const char *entry);
// Extracts a double from config file.
bool config_get_double(config_file_t *conf, const char *entry, double *in);
// Extracts a float from config file.
bool config_get_float(config_file_t *conf, const char *entry, float *in);
// Extracts an int from config file.
bool config_get_int(config_file_t *conf, const char *entry, int *in);
// Extracts an uint from config file.
bool config_get_uint(config_file_t *conf, const char *entry, unsigned *in);
// Extracts an int from config file. (Hexadecimal)
bool config_get_hex(config_file_t *conf, const char *entry, unsigned *in);
// Extracts a single char. If value consists of several chars, this is an error.
+61 -14
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -22,7 +22,7 @@
#ifndef __CONFIG_DEF_H
#define __CONFIG_DEF_H
#include <stdbool.h>
#include "boolean.h"
#include "libsnes.hpp"
#include "driver.h"
@@ -37,6 +37,9 @@
#define VIDEO_XVIDEO 11
#define VIDEO_SDL 13
#define VIDEO_EXT 14
#define VIDEO_WII 24
#define VIDEO_XENON360 25
#define VIDEO_XDK360 28
////////////////////////
#define AUDIO_RSOUND 1
#define AUDIO_OSS 2
@@ -50,13 +53,27 @@
#define AUDIO_EXT 15
#define AUDIO_DSOUND 16
#define AUDIO_COREAUDIO 17
#define AUDIO_PS3 18
#define AUDIO_XENON360 20
#define AUDIO_WII 22
#define AUDIO_XDK360 27
////////////////////////
#define INPUT_SDL 7
#define INPUT_X 12
#define INPUT_PS3 19
#define INPUT_XENON360 21
#define INPUT_WII 23
#define INPUT_XDK360 26
////////////////////////
#if defined(HAVE_SDL)
#if defined(HAVE_OPENGL) || defined(__CELLOS_LV2__)
#define VIDEO_DEFAULT_DRIVER VIDEO_GL
#elif defined(GEKKO)
#define VIDEO_DEFAULT_DRIVER VIDEO_WII
#elif defined(XENON)
#define VIDEO_DEFAULT_DRIVER VIDEO_XENON360
#elif defined(_XBOX)
#define VIDEO_DEFAULT_DRIVER VIDEO_XDK360
#elif defined(HAVE_XVIDEO)
#define VIDEO_DEFAULT_DRIVER VIDEO_XVIDEO
#elif defined(HAVE_SDL)
@@ -67,7 +84,15 @@
#error "Need at least one video driver!"
#endif
#if defined(HAVE_ALSA)
#if defined(__CELLOS_LV2__)
#define AUDIO_DEFAULT_DRIVER AUDIO_PS3
#elif defined(XENON)
#define AUDIO_DEFAULT_DRIVER AUDIO_XENON360
#elif defined(_XBOX)
#define AUDIO_DEFAULT_DRIVER AUDIO_XDK360
#elif defined(GEKKO)
#define AUDIO_DEFAULT_DRIVER AUDIO_WII
#elif defined(HAVE_ALSA)
#define AUDIO_DEFAULT_DRIVER AUDIO_ALSA
#elif defined(HAVE_PULSE)
#define AUDIO_DEFAULT_DRIVER AUDIO_PULSE
@@ -95,8 +120,16 @@
#error "Need at least one audio driver!"
#endif
#if defined(HAVE_SDL)
#if defined(XENON)
#define INPUT_DEFAULT_DRIVER INPUT_XENON360
#elif defined(_XBOX)
#define INPUT_DEFAULT_DRIVER INPUT_XDK360
#elif defined(HAVE_SDL)
#define INPUT_DEFAULT_DRIVER INPUT_SDL
#elif defined(__CELLOS_LV2__)
#define INPUT_DEFAULT_DRIVER INPUT_PS3
#elif defined(GEKKO)
#define INPUT_DEFAULT_DRIVER INPUT_WII
#elif defined(HAVE_XVIDEO)
#define INPUT_DEFAULT_DRIVER INPUT_X
#else
@@ -111,7 +144,6 @@
// Windowed
static const float xscale = 3.0; // Real x res = aspect * base_size * xscale
static const float yscale = 3.0; // Real y res = base_size * yscale
static const unsigned base_size = 224; // Base size for windowed mode.
// Fullscreen
static const bool fullscreen = false; // To start in Fullscreen or not
@@ -134,10 +166,13 @@ static const bool video_smooth = true;
static const bool force_aspect = true;
// Crop overscanned frames (7/8 or 15/15 for interlaced frames).
static const bool crop_overscan = false;
static const bool crop_overscan = true;
// Font size for on-screen messages.
static const unsigned font_size = 48;
// Attempt to scale the font size.
// The scale factor will be window_size / desktop_size.
static const bool font_scale = true;
// Offset for where messages will be placed on-screen. Values are in range [0.0, 1.0].
static const float message_pos_offset_x = 0.05;
@@ -157,7 +192,22 @@ static const bool hires_record = false;
// Record post-filtered (CPU filter) video rather than raw SNES output.
static const bool post_filter_record = false;
#define SNES_ASPECT_RATIO (4.0/3)
// OSD-messages
static const bool font_enable = true;
// The accurate refresh rate of your monitor (Hz).
// This is used to calculate audio input rate with the formula:
// audio_input_rate = game_input_rate * display_refresh_rate / game_refresh_rate.
// If the implementation does not report any values,
// SNES NTSC defaults will be assumed for compatibility.
// This value should stay close to 60Hz to avoid large pitch changes.
// If your monitor does not run at 60Hz, or something close to it, disable VSync,
// and leave this at its default.
#if defined(__CELLOS_LV2__) || defined(XENON) || defined(GEKKO)
static const float refresh_rate = 59.92;
#else
static const float refresh_rate = 59.95;
#endif
////////////////
// Audio
@@ -169,15 +219,11 @@ static const bool audio_enable = true;
// Output samplerate
static const unsigned out_rate = 48000;
// Input samplerate from libSNES.
// Lower this (slightly) if you are experiencing frequent audio dropouts while vsync is enabled.
static const float in_rate = 31980.0;
// When changing input rate on-the-fly
static const float audio_rate_step = 0.25;
// Audio device (e.g. hw:0,0 or /dev/audio). If NULL, will use defaults.
static const char* audio_device = NULL;
static const char *audio_device = NULL;
// Desired audio latency in milliseconds. Might not be honored if driver can't provide given latency.
static const int out_latency = 64;
@@ -196,7 +242,7 @@ static const unsigned rewind_buffer_size = 20 << 20; // 20MiB
static const unsigned rewind_granularity = 1;
// Pause gameplay when gameplay loses focus.
static const bool pause_nonactive = true;
static const bool pause_nonactive = false;
// Saves non-volatile SRAM at a regular interval. It is measured in seconds. A value of 0 disables autosave.
static const unsigned autosave_interval = 0;
@@ -261,6 +307,7 @@ static const struct snes_keybind snes_keybinds_1[] = {
{ SSNES_CHEAT_TOGGLE, SK_u, NO_BTN, AXIS_NONE },
{ SSNES_SCREENSHOT, SK_PRINT, NO_BTN, AXIS_NONE },
{ SSNES_DSP_CONFIG, SK_c, NO_BTN, AXIS_NONE },
{ SSNES_MUTE, SK_F9, NO_BTN, AXIS_NONE },
{ -1 }
};
+19 -1
View File
@@ -2,7 +2,7 @@
#define __SSNES_FEATURES_H
#include <stddef.h>
#include <stdbool.h>
#include "boolean.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -14,6 +14,18 @@ static const bool _sdl_supp = true;
static const bool _sdl_supp = false;
#endif
#ifdef HAVE_THREADS
static const bool _thread_supp = true;
#else
static const bool _thread_supp = false;
#endif
#ifdef HAVE_OPENGL
static const bool _opengl_supp = true;
#else
static const bool _opengl_supp = false;
#endif
#ifdef HAVE_XVIDEO
static const bool _xvideo_supp = true;
#else
@@ -62,6 +74,12 @@ static const bool _pulse_supp = true;
static const bool _pulse_supp = false;
#endif
#ifdef HAVE_DSOUND
static const bool _dsound_supp = true;
#else
static const bool _dsound_supp = false;
#endif
#ifdef HAVE_XAUDIO
static const bool _xaudio_supp = true;
#else
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

+118
View File
@@ -0,0 +1,118 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "list.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
struct sgui_file
{
char *path;
sgui_file_type_t type;
};
struct sgui_list
{
struct sgui_file *list;
size_t capacity;
size_t ptr;
};
sgui_list_t *sgui_list_new(void)
{
return (sgui_list_t*)calloc(1, sizeof(sgui_list_t));
}
bool sgui_list_empty(const sgui_list_t *list)
{
return list->ptr == 0;
}
void sgui_list_push(sgui_list_t *list, const char *path, sgui_file_type_t type)
{
if (list->ptr >= list->capacity)
{
list->capacity++;
list->capacity *= 2;
list->list = (struct sgui_file*)realloc(list->list, list->capacity * sizeof(struct sgui_file));
}
list->list[list->ptr].path = strdup(path);
list->list[list->ptr].type = type;
list->ptr++;
}
void sgui_list_pop(sgui_list_t *list)
{
if (!sgui_list_empty(list))
free(list->list[--list->ptr].path);
}
void sgui_list_free(sgui_list_t *list)
{
for (size_t i = 0; i < list->ptr; i++)
free(list->list[i].path);
free(list->list);
free(list);
}
void sgui_list_clear(sgui_list_t *list)
{
for (size_t i = 0; i < list->ptr; i++)
free(list->list[i].path);
list->ptr = 0;
}
void sgui_list_back(const sgui_list_t *list,
const char **path, sgui_file_type_t *file_type)
{
if (sgui_list_size(list) > 0)
sgui_list_at(list, sgui_list_size(list) - 1, path, file_type);
}
size_t sgui_list_size(const sgui_list_t *list)
{
return list->ptr;
}
void sgui_list_at(const sgui_list_t *list, size_t index,
const char **path, sgui_file_type_t *file_type)
{
if (path)
*path = list->list[index].path;
if (file_type)
*file_type = list->list[index].type;
}
static int list_comp(const void *a_, const void *b_)
{
const struct sgui_file *a = (const struct sgui_file*)a_;
const struct sgui_file *b = (const struct sgui_file*)b_;
if (a->type != b->type)
return a->type == SGUI_FILE_DIRECTORY ? -1 : 1;
return strcmp(a->path, b->path);
}
void sgui_list_sort(sgui_list_t *list)
{
qsort(list->list, list->ptr, sizeof(struct sgui_file), list_comp);
}
+51
View File
@@ -0,0 +1,51 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SGUI_LIST_H__
#define SGUI_LIST_H__
#include "sgui.h"
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct sgui_list sgui_list_t;
sgui_list_t *sgui_list_new(void);
void sgui_list_free(sgui_list_t *list);
void sgui_list_push(sgui_list_t *list, const char *path, sgui_file_type_t type);
void sgui_list_pop(sgui_list_t *list);
void sgui_list_clear(sgui_list_t *list);
bool sgui_list_empty(const sgui_list_t *list);
void sgui_list_back(const sgui_list_t *list,
const char **path, sgui_file_type_t *type);
size_t sgui_list_size(const sgui_list_t *list);
void sgui_list_at(const sgui_list_t *list, size_t index,
const char **path, sgui_file_type_t *type);
void sgui_list_sort(sgui_list_t *list);
#ifdef __cplusplus
}
#endif
#endif
+314
View File
@@ -0,0 +1,314 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "sgui.h"
#include "list.h"
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#define FONT_WIDTH 5
#define FONT_HEIGHT 10
#define FONT_WIDTH_STRIDE (FONT_WIDTH + 1)
#define FONT_HEIGHT_STRIDE (FONT_HEIGHT + 1)
#define TERM_WIDTH (((SGUI_WIDTH - 30) / (FONT_WIDTH_STRIDE)))
#define TERM_HEIGHT (((SGUI_HEIGHT - 30) / (FONT_HEIGHT_STRIDE)))
#define TERM_START_X 15
#define TERM_START_Y 15
struct sgui_handle
{
uint16_t *frame_buf;
size_t frame_buf_pitch;
const uint8_t *font_buf;
sgui_folder_enum_cb_t folder_cb;
void *userdata;
sgui_list_t *path_stack;
sgui_list_t *folder_buf;
size_t directory_ptr;
bool need_refresh;
char path_buf[PATH_MAX];
uint16_t font_white[256][FONT_HEIGHT][FONT_WIDTH];
uint16_t font_green[256][FONT_HEIGHT][FONT_WIDTH];
};
static void copy_glyph(uint16_t glyph_white[FONT_HEIGHT][FONT_WIDTH],
uint16_t glyph_green[FONT_HEIGHT][FONT_WIDTH],
const uint8_t *buf)
{
for (int y = 0; y < FONT_HEIGHT; y++)
{
for (int x = 0; x < FONT_WIDTH; x++)
{
uint32_t col =
((uint32_t)buf[3 * (-y * 256 + x) + 0] << 0) |
((uint32_t)buf[3 * (-y * 256 + x) + 1] << 8) |
((uint32_t)buf[3 * (-y * 256 + x) + 2] << 16);
glyph_white[y][x] = col == 0xff ? 0 : 0x7fff;
glyph_green[y][x] = col == 0xff ? 0 : (5 << 10) | (20 << 5) | (5 << 0);
}
}
}
static void init_font(sgui_handle_t *sgui, const char *path)
{
for (unsigned i = 0; i < 256; i++)
{
unsigned y = i / 16;
unsigned x = i % 16;
copy_glyph(sgui->font_white[i],
sgui->font_green[i],
sgui->font_buf + 54 + 3 * (256 * (255 - 16 * y) + 16 * x));
}
}
sgui_handle_t *sgui_init(const char *base_path,
uint16_t *buf, size_t buf_pitch,
const uint8_t *font_buf,
sgui_folder_enum_cb_t folder_cb, void *userdata)
{
sgui_handle_t *sgui = (sgui_handle_t*)calloc(1, sizeof(*sgui));
sgui->frame_buf = buf;
sgui->frame_buf_pitch = buf_pitch;
sgui->font_buf = font_buf;
sgui->folder_cb = folder_cb;
sgui->userdata = userdata;
sgui->path_stack = sgui_list_new();
sgui->folder_buf = sgui_list_new();
sgui_list_push(sgui->path_stack, base_path, SGUI_FILE_DIRECTORY);
init_font(sgui, "font.bmp");
return sgui;
}
void sgui_free(sgui_handle_t *sgui)
{
sgui_list_free(sgui->path_stack);
sgui_list_free(sgui->folder_buf);
free(sgui);
}
static uint16_t gray_filler(unsigned x, unsigned y)
{
x >>= 1;
y >>= 1;
uint16_t col = ((x + y) & 1) + 1;
col <<= 1;
return (col << 0) | (col << 5) | (col << 10);
}
static uint16_t green_filler(unsigned x, unsigned y)
{
x >>= 1;
y >>= 1;
uint16_t col = ((x + y) & 1) + 1;
col <<= 1;
return (col << 0) | (col << 6) | (col << 10);
}
static void fill_rect(uint16_t *buf, unsigned pitch,
unsigned x, unsigned y,
unsigned width, unsigned height,
uint16_t (*col)(unsigned x, unsigned y))
{
for (unsigned j = y; j < y + height; j++)
for (unsigned i = x; i < x + width; i++)
buf[j * (pitch >> 1) + i] = col(i, j);
}
static void blit_line(sgui_handle_t *sgui,
unsigned x, unsigned y, const char *message, bool green)
{
while (*message)
{
for (unsigned j = 0; j < FONT_HEIGHT; j++)
{
for (unsigned i = 0; i < FONT_WIDTH; i++)
{
uint16_t col = green ?
sgui->font_green[(unsigned char)*message][j][i] :
sgui->font_white[(unsigned char)*message][j][i];
if (col)
sgui->frame_buf[(y + j) * (sgui->frame_buf_pitch >> 1) + (x + i)] = col;
}
}
x += FONT_WIDTH_STRIDE;
message++;
}
}
static void render_text(sgui_handle_t *sgui, size_t begin, size_t end)
{
fill_rect(sgui->frame_buf, sgui->frame_buf_pitch,
0, 0, SGUI_WIDTH, SGUI_HEIGHT, gray_filler);
fill_rect(sgui->frame_buf, sgui->frame_buf_pitch,
5, 5, SGUI_WIDTH - 10, 5, green_filler);
fill_rect(sgui->frame_buf, sgui->frame_buf_pitch,
5, SGUI_HEIGHT - 10, SGUI_WIDTH - 10, 5, green_filler);
fill_rect(sgui->frame_buf, sgui->frame_buf_pitch,
5, 5, 5, SGUI_HEIGHT - 10, green_filler);
fill_rect(sgui->frame_buf, sgui->frame_buf_pitch,
SGUI_WIDTH - 10, 5, 5, SGUI_HEIGHT - 10, green_filler);
unsigned x = TERM_START_X;
unsigned y = TERM_START_Y;
for (size_t i = begin; i < end; i++, y += FONT_HEIGHT_STRIDE)
{
const char *path;
sgui_file_type_t type;
sgui_list_at(sgui->folder_buf, i, &path, &type);
char message[TERM_WIDTH + 1];
snprintf(message, sizeof(message), "%c %-*s %6s\n",
i == sgui->directory_ptr ? '>' : ' ',
TERM_WIDTH - (6 + 1 + 2),
path,
type == SGUI_FILE_PLAIN ? "(FILE)" : "(DIR)");
blit_line(sgui, x, y, message, i == sgui->directory_ptr);
}
}
const char *sgui_iterate(sgui_handle_t *sgui, sgui_action_t action)
{
switch (action)
{
case SGUI_ACTION_UP:
if (sgui->directory_ptr > 0)
sgui->directory_ptr--;
break;
case SGUI_ACTION_DOWN:
if (sgui->directory_ptr + 1 < sgui_list_size(sgui->folder_buf))
sgui->directory_ptr++;
break;
case SGUI_ACTION_LEFT:
case SGUI_ACTION_CANCEL:
if (sgui_list_size(sgui->path_stack) > 1)
{
sgui_list_pop(sgui->path_stack);
sgui->need_refresh = true;
}
break;
case SGUI_ACTION_RIGHT:
case SGUI_ACTION_OK:
{
if (sgui_list_size(sgui->folder_buf) == 0)
return NULL;
const char *path = NULL;
sgui_file_type_t type = SGUI_FILE_PLAIN;
sgui_list_at(sgui->folder_buf, sgui->directory_ptr,
&path, &type);
const char *dir;
sgui_list_back(sgui->path_stack, &dir, NULL);
if (type == SGUI_FILE_DIRECTORY)
{
char cat_path[PATH_MAX];
snprintf(cat_path, sizeof(cat_path), "%s/%s",
strcmp(dir, "/") == 0 ? "" : dir, path);
sgui_list_push(sgui->path_stack, cat_path, SGUI_FILE_DIRECTORY);
sgui->need_refresh = true;
}
else
{
snprintf(sgui->path_buf, sizeof(sgui->path_buf), "%s/%s",
strcmp(dir, "/") == 0 ? "" : dir, path);
return sgui->path_buf;
}
break;
}
case SGUI_ACTION_REFRESH:
sgui->need_refresh = true;
break;
default:
return NULL;
}
if (sgui->need_refresh)
{
sgui->directory_ptr = 0;
sgui_list_clear(sgui->folder_buf);
const char *path = NULL;
sgui_list_back(sgui->path_stack, &path, NULL);
if (!sgui->folder_cb(path,
(sgui_file_enum_cb_t)sgui_list_push,
sgui->userdata, sgui->folder_buf))
return NULL;
sgui_list_sort(sgui->folder_buf);
sgui->need_refresh = false;
}
size_t begin = sgui->directory_ptr >= TERM_HEIGHT / 2 ?
sgui->directory_ptr - TERM_HEIGHT / 2 : 0;
size_t end = sgui->directory_ptr + TERM_HEIGHT <= sgui_list_size(sgui->folder_buf) ?
sgui->directory_ptr + TERM_HEIGHT : sgui_list_size(sgui->folder_buf);
if (end - begin > TERM_HEIGHT)
end = begin + TERM_HEIGHT;
#if 0
printf("========================================\n");
for (size_t i = begin; i < end; i++)
{
const char *path;
sgui_file_type_t type;
sgui_list_at(sgui->folder_buf, i, &path, &type);
printf("%c %-50s %s\n",
i == sgui->directory_ptr ? '>' : ' ',
path,
type == SGUI_FILE_PLAIN ? "(FILE)" : "(DIR)");
}
printf("========================================\n");
#endif
render_text(sgui, begin, end);
return NULL;
}
+71
View File
@@ -0,0 +1,71 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SGUI_H__
#define SGUI_H__
#include <stdint.h>
#include <stddef.h>
#ifndef __cplusplus
#include <stdbool.h>
#else
extern "C" {
#endif
typedef enum
{
SGUI_FILE_PLAIN,
SGUI_FILE_DIRECTORY
} sgui_file_type_t;
typedef enum
{
SGUI_ACTION_UP,
SGUI_ACTION_DOWN,
SGUI_ACTION_LEFT,
SGUI_ACTION_RIGHT,
SGUI_ACTION_OK,
SGUI_ACTION_CANCEL,
SGUI_ACTION_REFRESH,
SGUI_ACTION_NOOP
} sgui_action_t;
typedef struct sgui_handle sgui_handle_t;
typedef void (*sgui_file_enum_cb_t)(void *ctx, const char *path,
sgui_file_type_t file_type);
typedef bool (*sgui_folder_enum_cb_t)(const char *directory,
sgui_file_enum_cb_t file_cb, void *userdata, void *ctx);
#define SGUI_WIDTH 320
#define SGUI_HEIGHT 240
sgui_handle_t *sgui_init(const char *base_path,
uint16_t *framebuf, size_t framebuf_pitch,
const uint8_t *font_buf,
sgui_folder_enum_cb_t folder_cb, void *userdata);
const char *sgui_iterate(sgui_handle_t *sgui, sgui_action_t action);
void sgui_free(sgui_handle_t *sgui);
#ifdef __cplusplus
}
#endif
#endif
+30 -2
View File
@@ -1,6 +1,6 @@
.\" ssnes.1:
.TH "SSNES" "1" "October 2011" "SSNES" "System Manager's Manual: ssnes"
.TH "SSNES" "1" "November 2011" "SSNES" "System Manager's Manual: ssnes"
.SH NAME
@@ -27,9 +27,16 @@ If no rom file path is defined on the command line, \fBssnes\fR will try to load
\fB--help, -h\fR
Prints help text.
.TP
\fB--features\fR
Prints available features compiled into SSNES, then exits.
.TP
\fB-L PATH, --libsnes PATH\fR
Path to a libsnes implementation which is to be used.
This option will override any setting in a config file.
This option is only available if SSNES is compiled with dynamic libsnes loading.
.TP
\fB--save PATH, -s PATH\fR
Overrides the path used for save ram (*.srm).
@@ -94,6 +101,7 @@ When using Sufami, save ram paths will be inferred from the Sufami BIOS path, no
\fB--mouse PORT, -m PORT\fR
Connects a Super Nintendo Mouse into port number PORT of the emulated SNES. Possible values for PORT are 1 and 2.
.TP
\fB--nodevice PORT, -N PORT\fR
Disconnects an input device from port number PORT of the emulated SNES. Possible values for PORT are 1 and 2. This may be needed for some odd games to run properly.
@@ -116,7 +124,7 @@ Connects a four-way multitap into port 2 of the SNES. This allows for up to 5 pl
.TP
\fB--record PATH, -r PATH\fR
Activates video recording of gameplay into PATH. Using .mkv extension is recommended.
Codecs used are FFV1/FLAC, suitable for processing the material further.
Codecs used are (FFV1 or H264 RGB lossless (x264))/FLAC, suitable for processing the material further.
.TP
\fB--size WIDTHxHEIGHT\fR
@@ -128,6 +136,17 @@ The video input is scaled with point filtering before being encoded at the corre
Play back a movie recorded in the .bsv format (bSNES). Cart ROM and movie file need to correspond.
It also requires to play back with the same libsnes backend that was used for recording.
.TP
\fB--bsvrecord PATH, -R PATH\fR
Start recording a .bsv video to PATH immediately after startup.
.TP
\fB--sram-mode MODE, -M MODE\fR
MODE designates how to handle SRAM.
The format of the second parameter is {no,}load-{no,}save.
These two boolean values tell if SRAM loading and SRAM saving should take place.
Note that noload-save implies that the SRAM will be overwritten with new data.
.TP
\fB--verbose, -v\fR
Activates verbose logging.
@@ -149,6 +168,15 @@ Set FRAMES to 0 to have perfect sync. 0 frames is only suitable for LAN. Default
\fB--port PORT\fR
Network port used for netplay. This defaults to 55435. This option affects both TCP and UDP.
.TP
\fB--spectate\fR
If netplay is used, it will go into a spectator mode.
Spectator mode allows one host to live stream game playback to multiple clients.
Essentially, clients receive a live streamed BSV movie file.
Clients can connect and disconnect at any time.
Clients thus cannot interact as player 2.
For spectating mode to work, both host and clients will need to use this flag.
.TP
\fB--ups PATCH, -U PATCH\fR
Attempts to apply an UPS patch to the current ROM image. No files are altered.
+165 -73
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -21,8 +21,8 @@
#include "file.h"
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#include "posix_string.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -65,11 +65,31 @@ static const audio_driver_t *audio_drivers[] = {
#ifdef HAVE_DYLIB
&audio_ext,
#endif
#ifdef __CELLOS_LV2__
&audio_ps3,
#endif
#ifdef XENON
&audio_xenon360,
#endif
#ifdef _XBOX
&audio_xdk360,
#endif
#ifdef GEKKO
&audio_wii,
#endif
};
static const video_driver_t *video_drivers[] = {
#ifdef HAVE_SDL
#ifdef HAVE_OPENGL
&video_gl,
#endif
#ifdef XENON
&video_xenon360,
#endif
#ifdef _XBOX
&video_xdk360,
#endif
#ifdef HAVE_SDL
&video_sdl,
#endif
#ifdef HAVE_XVIDEO
@@ -78,20 +98,35 @@ static const video_driver_t *video_drivers[] = {
#ifdef HAVE_DYLIB
&video_ext,
#endif
#ifdef GEKKO
&video_wii,
#endif
};
static const input_driver_t *input_drivers[] = {
#ifdef __CELLOS_LV2__
&input_ps3,
#endif
#ifdef HAVE_SDL
&input_sdl,
#endif
#ifdef HAVE_XVIDEO
&input_x,
#endif
#ifdef XENON
&input_xenon360,
#endif
#ifdef _XBOX
&input_xdk360,
#endif
#ifdef GEKKO
&input_wii,
#endif
};
static void find_audio_driver(void)
{
for (int i = 0; i < sizeof(audio_drivers) / sizeof(audio_driver_t*); i++)
for (unsigned i = 0; i < sizeof(audio_drivers) / sizeof(audio_driver_t*); i++)
{
if (strcasecmp(g_settings.audio.driver, audio_drivers[i]->ident) == 0)
{
@@ -101,15 +136,15 @@ static void find_audio_driver(void)
}
SSNES_ERR("Couldn't find any audio driver named \"%s\"\n", g_settings.audio.driver);
fprintf(stderr, "Available audio drivers are:\n");
for (int i = 0; i < sizeof(audio_drivers) / sizeof(audio_driver_t*); i++)
for (size_t i = 0; i < sizeof(audio_drivers) / sizeof(audio_driver_t*); i++)
fprintf(stderr, "\t%s\n", audio_drivers[i]->ident);
exit(1);
ssnes_fail(1, "find_audio_driver()");
}
static void find_video_driver(void)
{
for (int i = 0; i < sizeof(video_drivers) / sizeof(video_driver_t*); i++)
for (unsigned i = 0; i < sizeof(video_drivers) / sizeof(video_driver_t*); i++)
{
if (strcasecmp(g_settings.video.driver, video_drivers[i]->ident) == 0)
{
@@ -119,15 +154,15 @@ static void find_video_driver(void)
}
SSNES_ERR("Couldn't find any video driver named \"%s\"\n", g_settings.video.driver);
fprintf(stderr, "Available video drivers are:\n");
for (int i = 0; i < sizeof(video_drivers) / sizeof(video_driver_t*); i++)
for (size_t i = 0; i < sizeof(video_drivers) / sizeof(video_driver_t*); i++)
fprintf(stderr, "\t%s\n", video_drivers[i]->ident);
exit(1);
ssnes_fail(1, "find_video_driver()");
}
static void find_input_driver(void)
{
for (int i = 0; i < sizeof(input_drivers) / sizeof(input_driver_t*); i++)
for (unsigned i = 0; i < sizeof(input_drivers) / sizeof(input_driver_t*); i++)
{
if (strcasecmp(g_settings.input.driver, input_drivers[i]->ident) == 0)
{
@@ -137,10 +172,10 @@ static void find_input_driver(void)
}
SSNES_ERR("Couldn't find any input driver named \"%s\"\n", g_settings.input.driver);
fprintf(stderr, "Available input drivers are:\n");
for (int i = 0; i < sizeof(input_drivers) / sizeof(input_driver_t*); i++)
for (size_t i = 0; i < sizeof(input_drivers) / sizeof(input_driver_t*); i++)
fprintf(stderr, "\t%s\n", input_drivers[i]->ident);
exit(1);
ssnes_fail(1, "find_input_driver()");
}
void init_drivers(void)
@@ -151,14 +186,16 @@ void init_drivers(void)
void uninit_drivers(void)
{
uninit_video_input();
uninit_audio();
uninit_video_input();
}
#ifdef HAVE_DYLIB
static void init_dsp_plugin(void)
{
if (!(*g_settings.audio.dsp_plugin))
return;
ssnes_dsp_info_t info = {0};
g_extern.audio_data.dsp_lib = dylib_load(g_settings.audio.dsp_plugin);
if (!g_extern.audio_data.dsp_lib)
@@ -167,7 +204,7 @@ static void init_dsp_plugin(void)
return;
}
const ssnes_dsp_plugin_t* (*SSNES_API_CALLTYPE plugin_init)(void) =
const ssnes_dsp_plugin_t* (SSNES_API_CALLTYPE *plugin_init)(void) =
(const ssnes_dsp_plugin_t *(SSNES_API_CALLTYPE*)(void))dylib_proc(g_extern.audio_data.dsp_lib, "ssnes_dsp_plugin_init");
if (!plugin_init)
{
@@ -190,10 +227,8 @@ static void init_dsp_plugin(void)
SSNES_LOG("Loaded DSP plugin: \"%s\"\n", g_extern.audio_data.dsp_plugin->ident ? g_extern.audio_data.dsp_plugin->ident : "Unknown");
const ssnes_dsp_info_t info = {
.input_rate = g_settings.audio.in_rate,
.output_rate = g_settings.audio.out_rate
};
info.input_rate = g_settings.audio.in_rate;
info.output_rate = g_settings.audio.out_rate;
g_extern.audio_data.dsp_handle = g_extern.audio_data.dsp_plugin->init(&info);
if (!g_extern.audio_data.dsp_handle)
@@ -219,24 +254,70 @@ static void deinit_dsp_plugin(void)
dylib_close(g_extern.audio_data.dsp_lib);
}
}
#endif
static void adjust_audio_input_rate(void)
{
static bool first = true;
if (!first)
return;
if (g_extern.system.timing_set)
{
float timing_skew = fabs(1.0f - g_extern.system.timing.fps / g_settings.video.refresh_rate);
if (timing_skew > 0.05f) // We don't want to adjust pitch too much. If we have extreme cases, just don't readjust at all.
{
SSNES_LOG("Timings deviate too much. Will not adjust. (Display = %.2f Hz, Game = %.2f Hz)\n",
g_settings.video.refresh_rate,
(float)g_extern.system.timing.fps);
g_settings.video.refresh_rate = g_extern.system.timing.fps;
}
}
if (g_extern.system.timing_set)
{
g_settings.audio.in_rate = g_extern.system.timing.sample_rate *
(g_settings.video.refresh_rate / g_extern.system.timing.fps);
}
else
{
g_settings.audio.in_rate = 32040.5 *
(g_settings.video.refresh_rate / (21477272.0 / 357366.0)); // SNES metrics.
}
SSNES_LOG("Set audio input rate to: %.2f Hz.\n", g_settings.audio.in_rate);
first = false;
}
#define AUDIO_CHUNK_SIZE_BLOCKING 64
#define AUDIO_CHUNK_SIZE_NONBLOCKING 2048 // So we don't get complete line-noise when fast-forwarding audio.
#define AUDIO_MAX_RATIO 16
void init_audio(void)
{
// Accomodate rewind since at some point we might have two full buffers.
size_t max_bufsamples = AUDIO_CHUNK_SIZE_NONBLOCKING * 2;
// Used for recording even if audio isn't enabled.
ssnes_assert(g_extern.audio_data.conv_outsamples = (int16_t*)malloc(max_bufsamples * sizeof(int16_t) * AUDIO_MAX_RATIO));
g_extern.audio_data.block_chunk_size = AUDIO_CHUNK_SIZE_BLOCKING;
g_extern.audio_data.nonblock_chunk_size = AUDIO_CHUNK_SIZE_NONBLOCKING;
g_extern.audio_data.chunk_size = g_extern.audio_data.block_chunk_size;
// Needs to be able to hold full content of a full max_bufsamples in addition to its own.
ssnes_assert(g_extern.audio_data.rewind_buf = (int16_t*)malloc(max_bufsamples * sizeof(int16_t)));
g_extern.audio_data.rewind_size = max_bufsamples;
if (!g_settings.audio.enable)
{
g_extern.audio_active = false;
return;
}
adjust_audio_input_rate();
find_audio_driver();
g_extern.audio_data.block_chunk_size = AUDIO_CHUNK_SIZE_BLOCKING;
g_extern.audio_data.nonblock_chunk_size = AUDIO_CHUNK_SIZE_NONBLOCKING;
driver.audio_data = driver.audio->init(*g_settings.audio.device ? g_settings.audio.device : NULL,
g_settings.audio.out_rate, g_settings.audio.latency);
driver.audio_data = driver.audio->init(strlen(g_settings.audio.device) ? g_settings.audio.device : NULL, g_settings.audio.out_rate, g_settings.audio.latency);
if (!driver.audio_data)
g_extern.audio_active = false;
@@ -248,36 +329,34 @@ void init_audio(void)
driver.audio->set_nonblock_state(driver.audio_data, true);
g_extern.audio_data.chunk_size = g_extern.audio_data.nonblock_chunk_size;
}
else
g_extern.audio_data.chunk_size = g_extern.audio_data.block_chunk_size;
g_extern.audio_data.source = hermite_new();
if (!g_extern.audio_data.source)
g_extern.audio_active = false;
size_t max_bufsamples = g_extern.audio_data.block_chunk_size > g_extern.audio_data.nonblock_chunk_size ?
g_extern.audio_data.block_chunk_size : g_extern.audio_data.nonblock_chunk_size;
max_bufsamples *= 2; // Accomodate rewind since at some point we might have two full buffers.
assert((g_extern.audio_data.data = malloc(max_bufsamples * sizeof(float))));
ssnes_assert(g_extern.audio_data.data = (float*)malloc(max_bufsamples * sizeof(float)));
g_extern.audio_data.data_ptr = 0;
assert(g_settings.audio.out_rate < g_settings.audio.in_rate * AUDIO_MAX_RATIO);
assert((g_extern.audio_data.outsamples = malloc(max_bufsamples * sizeof(float) * AUDIO_MAX_RATIO)));
assert((g_extern.audio_data.conv_outsamples = malloc(max_bufsamples * sizeof(int16_t) * AUDIO_MAX_RATIO)));
// Needs to be able to hold full content of a full max_bufsamples in addition to its own.
assert((g_extern.audio_data.rewind_buf = malloc(max_bufsamples * sizeof(int16_t))));
g_extern.audio_data.rewind_size = max_bufsamples;
ssnes_assert(g_settings.audio.out_rate < g_settings.audio.in_rate * AUDIO_MAX_RATIO);
ssnes_assert(g_extern.audio_data.outsamples = (float*)malloc(max_bufsamples * sizeof(float) * AUDIO_MAX_RATIO));
g_extern.audio_data.src_ratio =
(double)g_settings.audio.out_rate / g_settings.audio.in_rate;
#ifdef HAVE_DYLIB
init_dsp_plugin();
#endif
}
void uninit_audio(void)
{
free(g_extern.audio_data.conv_outsamples);
g_extern.audio_data.conv_outsamples = NULL;
g_extern.audio_data.data_ptr = 0;
free(g_extern.audio_data.rewind_buf);
g_extern.audio_data.rewind_buf = NULL;
if (!g_settings.audio.enable)
{
g_extern.audio_active = false;
@@ -290,12 +369,15 @@ void uninit_audio(void)
if (g_extern.audio_data.source)
hermite_free(g_extern.audio_data.source);
free(g_extern.audio_data.data); g_extern.audio_data.data = NULL;
free(g_extern.audio_data.outsamples); g_extern.audio_data.outsamples = NULL;
free(g_extern.audio_data.conv_outsamples); g_extern.audio_data.conv_outsamples = NULL;
free(g_extern.audio_data.rewind_buf); g_extern.audio_data.rewind_buf = NULL;
free(g_extern.audio_data.data);
g_extern.audio_data.data = NULL;
free(g_extern.audio_data.outsamples);
g_extern.audio_data.outsamples = NULL;
#ifdef HAVE_DYLIB
deinit_dsp_plugin();
#endif
}
#ifdef HAVE_DYLIB
@@ -330,21 +412,21 @@ static void init_filter(void)
g_extern.filter.active = true;
unsigned width = 512;
unsigned height = 512;
unsigned width = g_extern.system.geom.max_width;
unsigned height = g_extern.system.geom.max_height;
g_extern.filter.psize(&width, &height);
unsigned pow2_x = next_pow2(ceil(width));
unsigned pow2_y = next_pow2(ceil(height));
unsigned pow2_x = next_pow2(width);
unsigned pow2_y = next_pow2(height);
unsigned maxsize = pow2_x > pow2_y ? pow2_x : pow2_y;
g_extern.filter.scale = maxsize / 256;
g_extern.filter.scale = maxsize / SSNES_SCALE_BASE;
g_extern.filter.buffer = malloc(256 * 256 * g_extern.filter.scale * g_extern.filter.scale * sizeof(uint32_t));
g_extern.filter.pitch = 256 * g_extern.filter.scale * sizeof(uint32_t);
assert(g_extern.filter.buffer);
g_extern.filter.buffer = (uint32_t*)malloc(SSNES_SCALE_BASE * SSNES_SCALE_BASE * g_extern.filter.scale * g_extern.filter.scale * sizeof(uint32_t));
g_extern.filter.pitch = SSNES_SCALE_BASE * g_extern.filter.scale * sizeof(uint32_t);
ssnes_assert(g_extern.filter.buffer);
g_extern.filter.colormap = malloc(32768 * sizeof(uint32_t));
assert(g_extern.filter.colormap);
g_extern.filter.colormap = (uint32_t*)malloc(32768 * sizeof(uint32_t));
ssnes_assert(g_extern.filter.colormap);
// Set up conversion map from 16-bit XRGB1555 to 32-bit ARGB.
for (int i = 0; i < 32768; i++)
@@ -359,7 +441,6 @@ static void init_filter(void)
g_extern.filter.colormap[i] = (r << 16) | (g << 8) | (b << 0);
}
}
#endif
static void deinit_filter(void)
{
@@ -372,6 +453,7 @@ static void deinit_filter(void)
free(g_extern.filter.colormap);
}
}
#endif
#ifdef HAVE_XML
static void init_shader_dir(void)
@@ -412,8 +494,9 @@ void init_video_input(void)
init_shader_dir();
#endif
// We use at least 512x512 textures to accomodate for hi-res games.
unsigned scale = 2;
unsigned max_dim = max(g_extern.system.geom.max_width, g_extern.system.geom.max_height);
unsigned scale = max_dim / SSNES_SCALE_BASE;
scale = max(scale, 1);
find_video_driver();
find_input_driver();
@@ -430,28 +513,35 @@ void init_video_input(void)
}
else
{
if (g_settings.video.force_aspect)
if (g_settings.video.force_aspect && (g_settings.video.aspect_ratio > 0.0f))
{
width = roundf(g_settings.video.base_size * g_settings.video.xscale * g_settings.video.aspect_ratio);
height = roundf(g_settings.video.base_size * g_settings.video.yscale);
width = roundf(g_extern.system.geom.base_height * g_settings.video.xscale * g_settings.video.aspect_ratio);
height = roundf(g_extern.system.geom.base_height * g_settings.video.yscale);
}
else
{
width = roundf(8.0f / 7.0f * g_settings.video.base_size * g_settings.video.xscale); // Assume 8:7 aspect.
height = roundf(g_settings.video.base_size * g_settings.video.yscale);
width = roundf(g_extern.system.geom.base_width * g_settings.video.xscale);
height = roundf(g_extern.system.geom.base_height * g_settings.video.yscale);
}
}
video_info_t video = {
.width = width,
.height = height,
.fullscreen = g_settings.video.fullscreen,
.vsync = g_settings.video.vsync,
.force_aspect = g_settings.video.force_aspect,
.smooth = g_settings.video.smooth,
.input_scale = scale,
.rgb32 = g_extern.filter.active
};
if (g_settings.video.aspect_ratio < 0.0f)
{
g_settings.video.aspect_ratio = (float)g_extern.system.geom.base_width / g_extern.system.geom.base_height;
SSNES_LOG("Adjusting aspect ratio to %.2f\n", g_settings.video.aspect_ratio);
}
SSNES_LOG("Video @ %ux%u\n", width, height);
video_info_t video = {0};
video.width = width;
video.height = height;
video.fullscreen = g_settings.video.fullscreen;
video.vsync = g_settings.video.vsync;
video.force_aspect = g_settings.video.force_aspect;
video.smooth = g_settings.video.smooth;
video.input_scale = scale;
video.rgb32 = g_extern.filter.active;
const input_driver_t *tmp = driver.input;
driver.video_data = driver.video->init(&video, &driver.input, &driver.input_data);
@@ -459,7 +549,7 @@ void init_video_input(void)
if (driver.video_data == NULL)
{
SSNES_ERR("Cannot open video driver ... Exiting ...\n");
exit(1);
ssnes_fail(1, "init_video_input()");
}
// Video driver didn't provide an input driver so we use configured one.
@@ -472,13 +562,13 @@ void init_video_input(void)
if (driver.input_data == NULL)
{
SSNES_ERR("Cannot init input driver. Exiting ...\n");
exit(1);
ssnes_fail(1, "init_video_input()");
}
}
else
{
SSNES_ERR("Cannot find input driver. Exiting ...\n");
exit(1);
ssnes_fail(1, "init_video_input()");
}
}
}
@@ -491,7 +581,9 @@ void uninit_video_input(void)
if (driver.video_data && driver.video)
driver.video->free(driver.video_data);
#ifdef HAVE_DYLIB
deinit_filter();
#endif
#ifdef HAVE_XML
deinit_shader_dir();
+50 -27
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -20,15 +20,21 @@
#define __DRIVER__H
#include <sys/types.h>
#include <stdbool.h>
#include "boolean.h"
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include "msvc/msvc_compat.h"
#include "input/keysym.h"
#define AUDIO_CHUNK_SIZE_BLOCKING 64
#define AUDIO_CHUNK_SIZE_NONBLOCKING 2048 // So we don't get complete line-noise when fast-forwarding audio.
#define AUDIO_MAX_RATIO 16
// SNES has 12 buttons from 0-11 (libsnes.hpp)
#define SSNES_FIRST_META_KEY 12
enum
{
SSNES_FAST_FORWARD_KEY = 12, // SNES has 12 buttons from 0-11 (libsnes.hpp)
SSNES_FAST_FORWARD_KEY = SSNES_FIRST_META_KEY,
SSNES_FAST_FORWARD_HOLD_KEY,
SSNES_LOAD_STATE_KEY,
SSNES_SAVE_STATE_KEY,
@@ -50,11 +56,18 @@ enum
SSNES_CHEAT_TOGGLE,
SSNES_SCREENSHOT,
SSNES_DSP_CONFIG,
SSNES_MUTE,
#if defined(__CELLOS_LV2__) || defined(XENON) || defined(_XBOX)
SSNES_CHEAT_INPUT,
SSNES_INGAME_MENU,
SSNES_EXIT_TO_MENU,
SSNES_SRAM_WRITE_PROTECT,
#endif
SSNES_BIND_LIST_END
};
struct snes_keybind
{
int id;
@@ -77,24 +90,24 @@ typedef struct video_info
typedef struct audio_driver
{
void* (*init)(const char* device, unsigned rate, unsigned latency);
ssize_t (*write)(void* data, const void* buf, size_t size);
bool (*stop)(void* data);
bool (*start)(void* data);
void (*set_nonblock_state)(void* data, bool toggle); // Should we care about blocking in audio thread? Fast forwarding.
void (*free)(void* data);
void *(*init)(const char *device, unsigned rate, unsigned latency);
ssize_t (*write)(void *data, const void *buf, size_t size);
bool (*stop)(void *data);
bool (*start)(void *data);
void (*set_nonblock_state)(void *data, bool toggle); // Should we care about blocking in audio thread? Fast forwarding.
void (*free)(void *data);
bool (*use_float)(void *data); // Defines if driver will take standard floating point samples, or int16_t samples.
const char *ident;
} audio_driver_t;
#define AXIS_NEG(x) (((uint32_t)(x) << 16) | 0xFFFFU)
#define AXIS_POS(x) ((uint32_t)(x) | 0xFFFF0000U)
#define AXIS_NONE (0xFFFFFFFFU)
#define AXIS_NEG(x) (((uint32_t)(x) << 16) | UINT16_C(0xFFFF))
#define AXIS_POS(x) ((uint32_t)(x) | UINT32_C(0xFFFF0000))
#define AXIS_NONE UINT32_C(0xFFFFFFFF)
#define AXIS_NEG_GET(x) (((uint32_t)(x) >> 16) & 0xFFFFU)
#define AXIS_POS_GET(x) ((uint32_t)(x) & 0xFFFFU)
#define AXIS_NEG_GET(x) (((uint32_t)(x) >> 16) & UINT16_C(0xFFFF))
#define AXIS_POS_GET(x) ((uint32_t)(x) & UINT16_C(0xFFFF))
#define NO_BTN ((uint16_t)0xFFFFU) // I hope no joypad will ever have this many buttons ... ;)
#define NO_BTN UINT16_C(0xFFFF) // I hope no joypad will ever have this many buttons ... ;)
#define HAT_UP_MASK (1 << 15)
#define HAT_DOWN_MASK (1 << 14)
@@ -108,29 +121,28 @@ typedef struct audio_driver
typedef struct input_driver
{
void* (*init)(void);
void (*poll)(void* data);
int16_t (*input_state)(void* data, const struct snes_keybind **snes_keybinds, bool port, unsigned device, unsigned index, unsigned id);
bool (*key_pressed)(void* data, int key);
void (*free)(void* data);
void *(*init)(void);
void (*poll)(void *data);
int16_t (*input_state)(void *data, const struct snes_keybind **snes_keybinds, bool port, unsigned device, unsigned index, unsigned id);
bool (*key_pressed)(void *data, int key);
void (*free)(void *data);
const char *ident;
} input_driver_t;
typedef struct video_driver
{
void* (*init)(const video_info_t *video, const input_driver_t **input, void **input_data);
void *(*init)(const video_info_t *video, const input_driver_t **input, void **input_data);
// Should the video driver act as an input driver as well? :) The video init might preinitialize an input driver to override the settings in case the video driver relies on input driver for event handling, e.g.
bool (*frame)(void* data, const void* frame, unsigned width, unsigned height, unsigned pitch, const char *msg); // msg is for showing a message on the screen along with the video frame.
void (*set_nonblock_state)(void* data, bool toggle); // Should we care about syncing to vblank? Fast forwarding.
bool (*frame)(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch, const char *msg); // msg is for showing a message on the screen along with the video frame.
void (*set_nonblock_state)(void *data, bool toggle); // Should we care about syncing to vblank? Fast forwarding.
// Is the window still active?
bool (*alive)(void *data);
bool (*focus)(void *data); // Does the window have focus?
bool (*xml_shader)(void *data, const char *path); // Sets XML-shader. Might not be implemented.
void (*free)(void* data);
void (*free)(void *data);
const char *ident;
} video_driver_t;
typedef struct driver
{
const audio_driver_t *audio;
@@ -164,12 +176,23 @@ extern const audio_driver_t audio_pulse;
extern const audio_driver_t audio_ext;
extern const audio_driver_t audio_dsound;
extern const audio_driver_t audio_coreaudio;
extern const audio_driver_t audio_xenon360;
extern const audio_driver_t audio_xdk360;
extern const audio_driver_t audio_ps3;
extern const audio_driver_t audio_wii;
extern const video_driver_t video_gl;
extern const video_driver_t video_wii;
extern const video_driver_t video_xenon360;
extern const video_driver_t video_xvideo;
extern const video_driver_t video_xdk360;
extern const video_driver_t video_sdl;
extern const video_driver_t video_ext;
extern const input_driver_t input_sdl;
extern const input_driver_t input_x;
extern const input_driver_t input_ps3;
extern const input_driver_t input_xenon360;
extern const input_driver_t input_wii;
extern const input_driver_t input_xdk360;
////////////////////////////////////////////////
#endif
+150 -36
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -19,32 +19,37 @@
#include "general.h"
#include "strl.h"
#include <string.h>
#include <assert.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <libsnes.hpp>
#include "boolean.h"
#include "libsnes.hpp"
#ifdef NEED_DYNAMIC
#ifdef _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#endif
#endif
#ifdef HAVE_DYNAMIC
#ifdef NEED_DYNAMIC
#define DLSYM(lib, x) dylib_proc(lib, #x)
#define SYM(type, x) do { \
p##x = (type)DLSYM(lib_handle, x); \
if (p##x == NULL) { SSNES_ERR("Failed to load symbol: \"%s\"\n", #x); exit(1); } \
if (p##x == NULL) { SSNES_ERR("Failed to load symbol: \"%s\"\n", #x); ssnes_fail(1, "init_libsnes_sym()"); } \
} while (0)
#define OPT_SYM(type, x) do { \
p##x = (type)DLSYM(lib_handle, x); \
} while (0)
#endif
#ifdef HAVE_DYNAMIC
static dylib_t lib_handle = NULL;
#endif
@@ -96,6 +101,11 @@ unsigned (*psnes_get_memory_size)(unsigned);
void (*psnes_unload_cartridge)(void);
void (*psnes_term)(void);
#if defined(NEED_DYNAMIC) || defined(GEKKO) || defined(__CELLOS_LV2__) || defined(XENON)
static void set_environment(void);
#endif
static void set_environment_defaults(void);
#ifdef HAVE_DYNAMIC
static void load_dynamic(void)
{
@@ -104,7 +114,7 @@ static void load_dynamic(void)
if (!lib_handle)
{
SSNES_ERR("Failed to open dynamic library: \"%s\"\n", g_settings.libsnes);
exit(1);
ssnes_fail(1, "load_dynamic()");
}
SYM(void (*)(void), snes_init);
@@ -140,13 +150,11 @@ static void load_dynamic(void)
SYM(void (*)(void), snes_unload_cartridge);
SYM(void (*)(void), snes_term);
}
#endif
#else
#define SSYM(x) do { \
p##x = x; \
} while (0)
#ifndef HAVE_DYNAMIC
static void set_statics(void)
{
SSYM(snes_init);
@@ -179,31 +187,23 @@ static void set_statics(void)
}
#endif
void init_dlsym(void)
void init_libsnes_sym(void)
{
// Guarantee that we can do "dirty" casting. Every OS that this program supports should pass this ...
assert(sizeof(void*) == sizeof(void (*)(void)));
// Guarantee that we can do "dirty" casting.
// Every OS that this program supports should pass this ...
ssnes_assert(sizeof(void*) == sizeof(void (*)(void)));
#ifdef HAVE_DYNAMIC
#ifndef _WIN32 // Try to verify that -lsnes was not linked in from other modules
// since loading it dynamically and with -l will fail hard.
void *lib = dlopen(NULL, RTLD_LAZY);
if (lib)
// Try to verify that -lsnes was not linked in from other modules
// since loading it dynamically and with -l will fail hard.
function_t sym = dylib_proc(NULL, "snes_init");
if (sym)
{
void *sym = dlsym(lib, "snes_init");
if (sym)
{
SSNES_ERR("Serious problem! SSNES wants to load libsnes dyamically, but it is already linked!\n");
SSNES_ERR("This could happen if other modules SSNES depends on link against libsnes directly.\n");
SSNES_ERR("Proceeding could cause a crash! Aborting ...\n");
dlclose(lib);
exit(1);
}
dlclose(lib);
SSNES_ERR("Serious problem! SSNES wants to load libsnes dyamically, but it is already linked!\n");
SSNES_ERR("This could happen if other modules SSNES depends on link against libsnes directly.\n");
SSNES_ERR("Proceeding could cause a crash! Aborting ...\n");
ssnes_fail(1, "init_libsnes_sym()");
}
#endif
if (!*g_settings.libsnes)
{
@@ -220,9 +220,14 @@ void init_dlsym(void)
#else
set_statics();
#endif
set_environment_defaults();
#if defined(NEED_DYNAMIC) || defined(GEKKO) || defined(__CELLOS_LV2__) || defined(XENON)
set_environment();
#endif
}
void uninit_dlsym(void)
void uninit_libsnes_sym(void)
{
#ifdef HAVE_DYNAMIC
if (lib_handle)
@@ -230,6 +235,7 @@ void uninit_dlsym(void)
#endif
}
#ifdef NEED_DYNAMIC
// Platform independent dylib loading.
dylib_t dylib_load(const char *path)
{
@@ -243,25 +249,133 @@ dylib_t dylib_load(const char *path)
function_t dylib_proc(dylib_t lib, const char *proc)
{
#ifdef _WIN32
function_t sym = (function_t)GetProcAddress(lib, proc);
function_t sym = (function_t)GetProcAddress(lib ? (HMODULE)lib : GetModuleHandle(NULL), proc);
#else
// Dirty hack to workaround the non-legality of void* -> fn-pointer casts.
void *ptr_sym = dlsym(lib, proc);
void *ptr_sym = NULL;
if (lib)
ptr_sym = dlsym(lib, proc);
else
{
void *handle = dlopen(NULL, RTLD_LAZY);
if (handle)
{
ptr_sym = dlsym(handle, proc);
dlclose(handle);
}
}
// Dirty hack to workaround the non-legality of (void*) -> fn-pointer casts.
function_t sym;
memcpy(&sym, &ptr_sym, sizeof(void*));
#endif
if (!sym)
SSNES_WARN("Failed to load symbol \"%s\"\n", proc);
return sym;
}
void dylib_close(dylib_t lib)
{
#ifdef _WIN32
FreeLibrary(lib);
FreeLibrary((HMODULE)lib);
#else
dlclose(lib);
#endif
}
#endif
#if defined(NEED_DYNAMIC) || defined(GEKKO) || defined(__CELLOS_LV2__) || defined(XENON)
static bool environment_cb(unsigned cmd, void *data)
{
switch (cmd)
{
case SNES_ENVIRONMENT_GET_FULLPATH:
*(const char**)data = g_extern.system.fullpath;
SSNES_LOG("Environ FULLPATH: \"%s\"\n", g_extern.system.fullpath);
break;
case SNES_ENVIRONMENT_SET_GEOMETRY:
g_extern.system.geom = *(const struct snes_geometry*)data;
g_extern.system.geom.max_width = next_pow2(g_extern.system.geom.max_width);
g_extern.system.geom.max_height = next_pow2(g_extern.system.geom.max_height);
SSNES_LOG("Environ SET_GEOMETRY: (%ux%u) / (%ux%u)\n",
g_extern.system.geom.base_width,
g_extern.system.geom.base_height,
g_extern.system.geom.max_width,
g_extern.system.geom.max_height);
break;
case SNES_ENVIRONMENT_SET_PITCH:
g_extern.system.pitch = *(const unsigned*)data;
SSNES_LOG("Environ SET_PITCH: %u\n", g_extern.system.pitch);
break;
case SNES_ENVIRONMENT_GET_OVERSCAN:
*(bool*)data = !g_settings.video.crop_overscan;
SSNES_LOG("Environ GET_OVERSCAN: %u\n", (unsigned)!g_settings.video.crop_overscan);
break;
case SNES_ENVIRONMENT_SET_TIMING:
g_extern.system.timing = *(const struct snes_system_timing*)data;
g_extern.system.timing_set = true;
SSNES_LOG("Environ SET_TIMING: %.3f Hz/ %.3f Hz\n",
(float)g_extern.system.timing.fps, (float)g_extern.system.timing.sample_rate);
break;
case SNES_ENVIRONMENT_GET_CAN_DUPE:
*(bool*)data = true;
SSNES_LOG("Environ GET_CAN_DUPE: true\n");
break;
case SNES_ENVIRONMENT_SET_NEED_FULLPATH:
g_extern.system.need_fullpath = *(const bool*)data;
SSNES_LOG("Environ SET_NEED_FULLPATH: %s\n", g_extern.system.need_fullpath ? "true" : "false");
break;
case SNES_ENVIRONMENT_GET_CAN_REWIND:
*(bool*)data = g_settings.rewind_enable;
SSNES_LOG("Environ GET_CAN_REWIND: %s\n", g_settings.rewind_enable ? "true" : "false");
break;
default:
SSNES_LOG("Environ UNSUPPORTED (#%u)!\n", cmd);
return false;
}
return true;
}
#endif
#ifdef NEED_DYNAMIC
// SSNES extension hooks. Totally optional 'n shizz :)
static void set_environment(void)
{
#ifdef HAVE_DYNAMIC
dylib_t lib = lib_handle;
#else
dylib_t lib = NULL;
#endif
void (*psnes_set_environment)(snes_environment_t) =
(void (*)(snes_environment_t))dylib_proc(lib, "snes_set_environment");
if (psnes_set_environment)
psnes_set_environment(environment_cb);
}
#elif defined(GEKKO) || defined(__CELLOS_LV2__) || defined(XENON)
// Not very optional when we're running on a console without dynamic loading support.
static void set_environment(void)
{
snes_set_environment(environment_cb);
}
#endif
// Assume SNES as defaults.
static void set_environment_defaults(void)
{
SSNES_LOG("Setting environment defaults (SNES)\n");
g_extern.system.pitch = 0; // 0 is classic libsnes semantics.
g_extern.system.geom.base_width = 256;
g_extern.system.geom.base_height = 224;
g_extern.system.geom.max_width = 512;
g_extern.system.geom.max_height = 512;
}
+18 -6
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -18,18 +18,30 @@
#ifndef __DYNAMIC_H
#define __DYNAMIC_H
#include <stdbool.h>
#include <libsnes.hpp>
#include "boolean.h"
#include "libsnes.hpp"
void init_dlsym(void);
void uninit_dlsym(void);
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#if defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB)
#define NEED_DYNAMIC
#else
#undef NEED_DYNAMIC
#endif
void init_libsnes_sym(void);
void uninit_libsnes_sym(void);
typedef void *dylib_t;
#ifdef NEED_DYNAMIC
typedef void (*function_t)(void);
dylib_t dylib_load(const char *path);
void dylib_close(dylib_t lib);
function_t dylib_proc(dylib_t lib, const char *proc);
#endif
extern void (*psnes_init)(void);
@@ -41,7 +53,7 @@ extern void (*psnes_set_input_state)(snes_input_state_t);
extern void (*psnes_cheat_reset)(void);
extern void (*psnes_cheat_set)(unsigned, bool, const char*);
extern const char* (*psnes_library_id)(void);
extern const char *(*psnes_library_id)(void);
extern unsigned (*psnes_library_revision_minor)(void);
extern unsigned (*psnes_library_revision_major)(void);
+14 -13
View File
@@ -1,5 +1,5 @@
/* RSound - A PCM audio client/server
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* RSound is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
@@ -14,22 +14,23 @@
*/
#include "fifo_buffer.h"
#include <stdint.h>
struct fifo_buffer
{
char *buffer;
uint8_t *buffer;
size_t bufsize;
size_t first;
size_t end;
};
fifo_buffer_t* fifo_new(size_t size)
fifo_buffer_t *fifo_new(size_t size)
{
fifo_buffer_t *buf = calloc(1, sizeof(*buf));
fifo_buffer_t *buf = (fifo_buffer_t*)calloc(1, sizeof(*buf));
if (buf == NULL)
return NULL;
buf->buffer = calloc(1, size + 1);
buf->buffer = (uint8_t*)calloc(1, size + 1);
if (buf->buffer == NULL)
{
free(buf);
@@ -40,13 +41,13 @@ fifo_buffer_t* fifo_new(size_t size)
return buf;
}
void fifo_free(fifo_buffer_t* buffer)
void fifo_free(fifo_buffer_t *buffer)
{
free(buffer->buffer);
free(buffer);
}
size_t fifo_read_avail(fifo_buffer_t* buffer)
size_t fifo_read_avail(fifo_buffer_t *buffer)
{
size_t first = buffer->first;
size_t end = buffer->end;
@@ -55,7 +56,7 @@ size_t fifo_read_avail(fifo_buffer_t* buffer)
return end - first;
}
size_t fifo_write_avail(fifo_buffer_t* buffer)
size_t fifo_write_avail(fifo_buffer_t *buffer)
{
size_t first = buffer->first;
size_t end = buffer->end;
@@ -65,7 +66,7 @@ size_t fifo_write_avail(fifo_buffer_t* buffer)
return (buffer->bufsize - 1) - (end - first);
}
void fifo_write(fifo_buffer_t* buffer, const void* in_buf, size_t size)
void fifo_write(fifo_buffer_t *buffer, const void *in_buf, size_t size)
{
size_t first_write = size;
size_t rest_write = 0;
@@ -77,13 +78,13 @@ void fifo_write(fifo_buffer_t* buffer, const void* in_buf, size_t size)
memcpy(buffer->buffer + buffer->end, in_buf, first_write);
if (rest_write > 0)
memcpy(buffer->buffer, (const char*)in_buf + first_write, rest_write);
memcpy(buffer->buffer, (const uint8_t*)in_buf + first_write, rest_write);
buffer->end = (buffer->end + size) % buffer->bufsize;
}
void fifo_read(fifo_buffer_t* buffer, void* in_buf, size_t size)
void fifo_read(fifo_buffer_t *buffer, void *in_buf, size_t size)
{
size_t first_read = size;
size_t rest_read = 0;
@@ -93,9 +94,9 @@ void fifo_read(fifo_buffer_t* buffer, void* in_buf, size_t size)
rest_read = size - first_read;
}
memcpy(in_buf, (const char*)buffer->buffer + buffer->first, first_read);
memcpy(in_buf, (const uint8_t*)buffer->buffer + buffer->first, first_read);
if (rest_read > 0)
memcpy((char*)in_buf + first_read, buffer->buffer, rest_read);
memcpy((uint8_t*)in_buf + first_read, buffer->buffer, rest_read);
buffer->first = (buffer->first + size) % buffer->bufsize;
}
+7 -8
View File
@@ -1,5 +1,5 @@
/* RSound - A PCM audio client/server
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* RSound is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
@@ -17,7 +17,6 @@
#define __BUFFER_H
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
@@ -26,11 +25,11 @@
typedef struct fifo_buffer fifo_buffer_t;
#endif
fifo_buffer_t* fifo_new(size_t size);
void fifo_write(fifo_buffer_t* buffer, const void* in_buf, size_t size);
void fifo_read(fifo_buffer_t* buffer, void* in_buf, size_t size);
void fifo_free(fifo_buffer_t* buffer);
size_t fifo_read_avail(fifo_buffer_t* buffer);
size_t fifo_write_avail(fifo_buffer_t* buffer);
fifo_buffer_t *fifo_new(size_t size);
void fifo_write(fifo_buffer_t *buffer, const void *in_buf, size_t size);
void fifo_read(fifo_buffer_t *buffer, void *in_buf, size_t size);
void fifo_free(fifo_buffer_t *buffer);
size_t fifo_read_avail(fifo_buffer_t *buffer);
size_t fifo_write_avail(fifo_buffer_t *buffer);
#endif
+222 -208
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -18,10 +18,9 @@
#include "file.h"
#include "general.h"
#include <stdlib.h>
#include <stdbool.h>
#include <libsnes.hpp>
#include "boolean.h"
#include "libsnes.hpp"
#include <string.h>
#include <assert.h>
#include <time.h>
#include "dynamic.h"
#include "movie.h"
@@ -33,11 +32,16 @@
#include "sha256.h"
#endif
#ifdef _WIN32
#if defined(_WIN32) && !defined(_XBOX)
#include <io.h>
#include <fcntl.h>
#include <windows.h>
#include <shlwapi.h>
#ifdef _MSC_VER
#define setmode _setmode
#endif
#elif defined(_XBOX)
#include <xtl.h>
#define setmode _setmode
#else
#include <sys/types.h>
#include <sys/stat.h>
@@ -49,12 +53,13 @@ ssize_t read_file(const char *path, void **buf)
{
void *rom_buf = NULL;
FILE *file = fopen(path, "rb");
ssize_t rc = 0;
size_t len = 0;
if (!file)
goto error;
fseek(file, 0, SEEK_END);
long len = ftell(file);
ssize_t rc = 0;
len = ftell(file);
rewind(file);
rom_buf = malloc(len + 1);
if (!rom_buf)
@@ -63,7 +68,7 @@ ssize_t read_file(const char *path, void **buf)
goto error;
}
if ((rc = fread(rom_buf, 1, len, file)) < len)
if ((rc = fread(rom_buf, 1, len, file)) < (ssize_t)len)
SSNES_WARN("Didn't read whole file.\n");
*buf = rom_buf;
@@ -86,29 +91,33 @@ bool read_file_string(const char *path, char **buf)
{
*buf = NULL;
FILE *file = fopen(path, "r");
size_t len = 0;
char *ptr = NULL;
if (!file)
goto error;
fseek(file, 0, SEEK_END);
long len = ftell(file) + 2; // Takes account of being able to read in EOF and '\0' at end.
len = ftell(file) + 2; // Takes account of being able to read in EOF and '\0' at end.
rewind(file);
*buf = calloc(len, sizeof(char));
*buf = (char*)calloc(len, sizeof(char));
if (!*buf)
goto error;
char *ptr = *buf;
ptr = *buf;
while (ptr && !feof(file))
{
size_t bufsize = (size_t)(((ptrdiff_t)*buf + (ptrdiff_t)len) - (ptrdiff_t)ptr);
fgets(ptr, bufsize, file);
ptr = strchr(ptr, '\0');
ptr += strlen(ptr);
}
ptr = strchr(ptr, EOF);
if (ptr) *ptr = '\0';
if (ptr)
*ptr = '\0';
fclose(file);
return true;
@@ -136,6 +145,7 @@ static void patch_rom(uint8_t **buf, ssize_t *size)
ssize_t patch_size = 0;
void *patch_data = NULL;
enum patch_type type = PATCH_NONE;
bool success = false;
if (g_extern.ups_pref && g_extern.bps_pref)
{
@@ -168,19 +178,18 @@ static void patch_rom(uint8_t **buf, ssize_t *size)
}
size_t target_size = ret_size * 4; // Just to be sure ...
uint8_t *patched_rom = malloc(target_size);
uint8_t *patched_rom = (uint8_t*)malloc(target_size);
if (!patched_rom)
{
SSNES_ERR("Failed to allocate memory for patched ROM ...\n");
goto error;
}
bool success = false;
switch (type)
{
case PATCH_UPS:
{
ups_error_t err = ups_apply_patch(patch_data, patch_size, ret_buf, ret_size, patched_rom, &target_size);
ups_error_t err = ups_apply_patch((const uint8_t*)patch_data, patch_size, ret_buf, ret_size, patched_rom, &target_size);
if (err == UPS_SUCCESS)
{
SSNES_LOG("ROM patched successfully (UPS)!\n");
@@ -194,7 +203,7 @@ static void patch_rom(uint8_t **buf, ssize_t *size)
case PATCH_BPS:
{
bps_error_t err = bps_apply_patch(patch_data, patch_size, ret_buf, ret_size, patched_rom, &target_size);
bps_error_t err = bps_apply_patch((const uint8_t*)patch_data, patch_size, ret_buf, ret_size, patched_rom, &target_size);
if (err == BPS_SUCCESS)
{
SSNES_LOG("ROM patched successfully (BPS)!\n");
@@ -237,14 +246,14 @@ static ssize_t read_rom_file(FILE* file, void** buf)
if (file == NULL) // stdin
{
#ifdef _WIN32
#if defined(_WIN32) && !defined(_XBOX)
setmode(0, O_BINARY);
#endif
SSNES_LOG("Reading ROM from stdin ...\n");
size_t buf_size = 0xFFFFF; // Some initial guesstimate.
size_t buf_ptr = 0;
uint8_t *rom_buf = malloc(buf_size);
uint8_t *rom_buf = (uint8_t*)malloc(buf_size);
if (rom_buf == NULL)
{
SSNES_ERR("Couldn't allocate memory!\n");
@@ -260,7 +269,7 @@ static ssize_t read_rom_file(FILE* file, void** buf)
if (buf_ptr < buf_size)
break;
rom_buf = realloc(rom_buf, buf_size * 2);
rom_buf = (uint8_t*)realloc(rom_buf, buf_size * 2);
if (rom_buf == NULL)
{
SSNES_ERR("Couldn't allocate memory!\n");
@@ -286,14 +295,14 @@ static ssize_t read_rom_file(FILE* file, void** buf)
return -1;
}
if (fread(rom_buf, 1, ret, file) < ret)
if (fread(rom_buf, 1, ret, file) < (size_t)ret)
{
SSNES_ERR("Didn't read whole file.\n");
free(rom_buf);
return -1;
}
ret_buf = rom_buf;
ret_buf = (uint8_t*)rom_buf;
}
// Remove copier header if present (512 first bytes).
@@ -359,8 +368,10 @@ static const char *ramtype2str(int type)
// Attempt to save valuable RAM data somewhere ...
static void dump_to_file_desperate(const void *data, size_t size, int type)
{
#ifdef _WIN32
#if defined(_WIN32) && !defined(_XBOX)
const char *base = getenv("APPDATA");
#elif defined(__CELLOS_LV2__) || defined(_XBOX)
const char *base = NULL;
#else
const char *base = getenv("HOME");
#endif
@@ -368,9 +379,9 @@ static void dump_to_file_desperate(const void *data, size_t size, int type)
if (!base)
goto error;
char path[MAXPATHLEN];
char path[PATH_MAX];
snprintf(path, sizeof(path), "%s/SSNES-recovery-", base);
char timebuf[MAXPATHLEN];
char timebuf[PATH_MAX];
time_t time_;
time(&time_);
@@ -404,11 +415,14 @@ bool save_state(const char *path)
}
SSNES_LOG("State size: %d bytes.\n", (int)size);
psnes_serialize(data, size);
bool ret = dump_to_file(path, data, size);
free(data);
bool ret = psnes_serialize((uint8_t*)data, size);
if (ret)
ret = dump_to_file(path, data, size);
if (!ret)
SSNES_ERR("Failed to save state to \"%s\".\n", path);
free(data);
return ret;
}
@@ -417,86 +431,86 @@ bool load_state(const char *path)
SSNES_LOG("Loading state: \"%s\".\n", path);
void *buf = NULL;
ssize_t size = read_file(path, &buf);
if (size < 0)
{
SSNES_ERR("Failed to load state from \"%s\".\n", path);
return false;
}
else
bool ret = true;
SSNES_LOG("State size: %d bytes.\n", (int)size);
uint8_t *block_buf[2] = {NULL, NULL};
int block_type[2] = {-1, -1};
unsigned block_size[2] = {0};
if (g_settings.block_sram_overwrite)
{
SSNES_LOG("State size: %d bytes.\n", (int)size);
uint8_t *block_buf[2] = {NULL, NULL};
int block_type[2] = {-1, -1};
unsigned block_size[2] = {0};
if (g_settings.block_sram_overwrite)
SSNES_LOG("Blocking SRAM overwrite!\n");
switch (g_extern.game_type)
{
SSNES_LOG("Blocking SRAM overwrite!\n");
switch (g_extern.game_type)
{
case SSNES_CART_NORMAL:
block_type[0] = SNES_MEMORY_CARTRIDGE_RAM;
block_type[1] = SNES_MEMORY_CARTRIDGE_RTC;
break;
case SSNES_CART_NORMAL:
block_type[0] = SNES_MEMORY_CARTRIDGE_RAM;
block_type[1] = SNES_MEMORY_CARTRIDGE_RTC;
break;
case SSNES_CART_BSX:
case SSNES_CART_BSX_SLOTTED:
block_type[0] = SNES_MEMORY_BSX_RAM;
block_type[1] = SNES_MEMORY_BSX_PRAM;
break;
case SSNES_CART_BSX:
case SSNES_CART_BSX_SLOTTED:
block_type[0] = SNES_MEMORY_BSX_RAM;
block_type[1] = SNES_MEMORY_BSX_PRAM;
break;
case SSNES_CART_SUFAMI:
block_type[0] = SNES_MEMORY_SUFAMI_TURBO_A_RAM;
block_type[1] = SNES_MEMORY_SUFAMI_TURBO_B_RAM;
break;
case SSNES_CART_SUFAMI:
block_type[0] = SNES_MEMORY_SUFAMI_TURBO_A_RAM;
block_type[1] = SNES_MEMORY_SUFAMI_TURBO_B_RAM;
break;
case SSNES_CART_SGB:
block_type[0] = SNES_MEMORY_GAME_BOY_RAM;
block_type[1] = SNES_MEMORY_GAME_BOY_RTC;
break;
}
case SSNES_CART_SGB:
block_type[0] = SNES_MEMORY_GAME_BOY_RAM;
block_type[1] = SNES_MEMORY_GAME_BOY_RTC;
break;
}
for (unsigned i = 0; i < 2; i++)
if (block_type[i] != -1)
block_size[i] = psnes_get_memory_size(block_type[i]);
for (unsigned i = 0; i < 2; i++)
if (block_size[i])
block_buf[i] = malloc(block_size[i]);
// Backup current SRAM which is overwritten by unserialize.
for (unsigned i = 0; i < 2; i++)
{
if (block_buf[i])
{
const uint8_t *ptr = psnes_get_memory_data(block_type[i]);
if (ptr)
memcpy(block_buf[i], ptr, block_size[i]);
}
}
psnes_unserialize(buf, size);
// Flush back :D
for (unsigned i = 0; i < 2; i++)
{
if (block_buf[i])
{
uint8_t *ptr = psnes_get_memory_data(block_type[i]);
if (ptr)
memcpy(ptr, block_buf[i], block_size[i]);
}
}
for (unsigned i = 0; i < 2; i++)
if (block_buf[i])
free(block_buf[i]);
}
for (unsigned i = 0; i < 2; i++)
if (block_type[i] != -1)
block_size[i] = psnes_get_memory_size(block_type[i]);
for (unsigned i = 0; i < 2; i++)
if (block_size[i])
block_buf[i] = (uint8_t*)malloc(block_size[i]);
// Backup current SRAM which is overwritten by unserialize.
for (unsigned i = 0; i < 2; i++)
{
if (block_buf[i])
{
const uint8_t *ptr = psnes_get_memory_data(block_type[i]);
if (ptr)
memcpy(block_buf[i], ptr, block_size[i]);
}
}
ret = psnes_unserialize((uint8_t*)buf, size);
// Flush back :D
for (unsigned i = 0; i < 2 && ret; i++)
{
if (block_buf[i])
{
uint8_t *ptr = psnes_get_memory_data(block_type[i]);
if (ptr)
memcpy(ptr, block_buf[i], block_size[i]);
}
}
for (unsigned i = 0; i < 2; i++)
if (block_buf[i])
free(block_buf[i]);
free(buf);
return true;
return ret;
}
void load_ram_file(const char *path, int type)
@@ -509,8 +523,8 @@ void load_ram_file(const char *path, int type)
void *buf = NULL;
ssize_t rc = read_file(path, &buf);
if (rc <= size)
memcpy(data, buf, size);
if (rc > 0 && rc <= (ssize_t)size)
memcpy(data, buf, rc);
free(buf);
}
@@ -531,7 +545,7 @@ void save_ram_file(const char *path, int type)
}
}
static char* load_xml_map(const char *path)
static char *load_xml_map(const char *path)
{
char *xml_buf = NULL;
if (*path)
@@ -553,48 +567,45 @@ static bool load_sgb_rom(void)
FILE *extra_rom = NULL;
void *extra_rom_buf = NULL;
ssize_t extra_rom_len = 0;
char *xml_buf = 0;
bool ret = true;
if ((rom_len = read_rom_file(g_extern.rom_file, &rom_buf)) == -1)
{
SSNES_ERR("Could not read ROM file.\n");
goto error;
ret = false;
goto end;
}
if ((extra_rom_len = read_file(g_extern.gb_rom_path, &extra_rom_buf)) == -1)
{
SSNES_ERR("Cannot read GameBoy rom.\n");
goto error;
ret = false;
goto end;
}
char *xml_buf = load_xml_map(g_extern.xml_name);
xml_buf = load_xml_map(g_extern.xml_name);
if (!psnes_load_cartridge_super_game_boy(
xml_buf, rom_buf, rom_len,
NULL, extra_rom_buf, extra_rom_len))
xml_buf, (const uint8_t*)rom_buf, rom_len,
NULL, (const uint8_t*)extra_rom_buf, extra_rom_len))
{
SSNES_ERR("Cannot load SGB/GameBoy rom.\n");
goto error;
ret = false;
goto end;
}
if (xml_buf)
free(xml_buf);
end:
if (g_extern.rom_file)
fclose(g_extern.rom_file);
if (extra_rom)
fclose(extra_rom);
free(rom_buf);
free(extra_rom_buf);
return true;
error:
if (g_extern.rom_file)
fclose(g_extern.rom_file);
if (extra_rom)
fclose(extra_rom);
free(rom_buf);
free(extra_rom_buf);
return false;
return ret;
}
static bool load_bsx_rom(bool slotted)
@@ -605,62 +616,60 @@ static bool load_bsx_rom(bool slotted)
FILE *extra_rom = NULL;
void *extra_rom_buf = NULL;
ssize_t extra_rom_len = 0;
char *xml_buf = 0;
bool ret = true;
if ((rom_len = read_rom_file(g_extern.rom_file, &rom_buf)) == -1)
{
SSNES_ERR("Could not read ROM file.\n");
goto error;
ret = false;
goto end;
}
if ((extra_rom_len = read_file(g_extern.bsx_rom_path, &extra_rom_buf)) == -1)
{
SSNES_ERR("Cannot read BSX game rom.\n");
goto error;
ret = false;
goto end;
}
char *xml_buf = load_xml_map(g_extern.xml_name);
xml_buf = load_xml_map(g_extern.xml_name);
if (slotted)
{
if (!psnes_load_cartridge_bsx_slotted(
xml_buf, rom_buf, rom_len,
NULL, extra_rom_buf, extra_rom_len))
xml_buf, (const uint8_t*)rom_buf, rom_len,
NULL, (const uint8_t*)extra_rom_buf, extra_rom_len))
{
SSNES_ERR("Cannot load BSX slotted rom.\n");
goto error;
ret = false;
goto end;
}
}
else
{
if (!psnes_load_cartridge_bsx(
NULL, rom_buf, rom_len,
NULL, extra_rom_buf, extra_rom_len))
NULL, (const uint8_t*)rom_buf, rom_len,
NULL, (const uint8_t*)extra_rom_buf, extra_rom_len))
{
SSNES_ERR("Cannot load BSX rom.\n");
goto error;
ret = false;
goto end;
}
}
if (xml_buf)
free(xml_buf);
end:
if (g_extern.rom_file)
fclose(g_extern.rom_file);
if (extra_rom)
fclose(extra_rom);
free(rom_buf);
free(extra_rom_buf);
return true;
error:
if (g_extern.rom_file)
fclose(g_extern.rom_file);
if (extra_rom)
fclose(extra_rom);
free(rom_buf);
free(extra_rom_buf);
return false;
return ret;
}
static bool load_sufami_rom(void)
@@ -671,63 +680,59 @@ static bool load_sufami_rom(void)
FILE *extra_rom[2] = {NULL};
void *extra_rom_buf[2] = {NULL};
ssize_t extra_rom_len[2] = {0};
char *xml_buf = 0;
const char *roms[2] = {0};
bool ret = true;
if ((rom_len = read_rom_file(g_extern.rom_file, &rom_buf)) == -1)
{
SSNES_ERR("Could not read ROM file.\n");
goto error;
ret = false;
goto end;
}
const char *roms[2] = { g_extern.sufami_rom_path[0], g_extern.sufami_rom_path[1] };
roms[0] = g_extern.sufami_rom_path[0];
roms[1] = g_extern.sufami_rom_path[1];
for (int i = 0; i < 2; i++)
for (unsigned i = 0; i < 2; i++)
{
if (strlen(roms[i]) > 0)
if (*(roms[i]))
{
if ((extra_rom_len[i] = read_file(roms[i], &extra_rom_buf[i])) == -1)
{
SSNES_ERR("Cannot read Sufami game rom.\n");
goto error;
ret = false;
goto end;
}
}
}
char *xml_buf = load_xml_map(g_extern.xml_name);
xml_buf = load_xml_map(g_extern.xml_name);
if (!psnes_load_cartridge_sufami_turbo(
xml_buf, rom_buf, rom_len,
NULL, extra_rom_buf[0], extra_rom_len[0],
NULL, extra_rom_buf[1], extra_rom_len[1]))
xml_buf, (const uint8_t*)rom_buf, rom_len,
NULL, (const uint8_t*)extra_rom_buf[0], extra_rom_len[0],
NULL, (const uint8_t*)extra_rom_buf[1], extra_rom_len[1]))
{
SSNES_ERR("Cannot load Sufami Turbo rom.\n");
goto error;
ret = false;
goto end;
}
if (xml_buf)
free(xml_buf);
end:
if (g_extern.rom_file)
fclose(g_extern.rom_file);
for (int i = 0; i < 2; i++)
for (unsigned i = 0; i < 2; i++)
{
if (extra_rom[i])
fclose(extra_rom[i]);
free(extra_rom_buf[i]);
}
free(rom_buf);
return true;
error:
if (g_extern.rom_file)
fclose(g_extern.rom_file);
for (int i = 0; i < 2; i++)
{
if (extra_rom[i])
fclose(extra_rom[i]);
free(extra_rom_buf[i]);
}
free(rom_buf);
return false;
return ret;
}
static bool load_normal_rom(void)
@@ -735,34 +740,46 @@ static bool load_normal_rom(void)
void *rom_buf = NULL;
ssize_t rom_len = 0;
if ((rom_len = read_rom_file(g_extern.rom_file, &rom_buf)) == -1)
if (!g_extern.system.need_fullpath)
{
SSNES_ERR("Could not read ROM file.\n");
return false;
if ((rom_len = read_rom_file(g_extern.rom_file, &rom_buf)) == -1)
{
SSNES_ERR("Could not read ROM file.\n");
return false;
}
if (g_extern.rom_file)
fclose(g_extern.rom_file);
SSNES_LOG("ROM size: %d bytes\n", (int)rom_len);
}
else
{
if (!g_extern.rom_file)
{
SSNES_ERR("Implementation requires a full path to be set, cannot load ROM from stdin. Aborting ...\n");
return false;
}
if (g_extern.rom_file != NULL)
fclose(g_extern.rom_file);
SSNES_LOG("ROM size: %d bytes\n", (int)rom_len);
char *xml_buf = load_xml_map(g_extern.xml_name);
SSNES_LOG("ROM loading skipped. Implementation will load it on its own.\n");
}
if (!psnes_load_cartridge_normal(xml_buf, rom_buf, rom_len))
char *xml_buf = load_xml_map(g_extern.xml_name);
if (!psnes_load_cartridge_normal(xml_buf, (const uint8_t*)rom_buf, rom_len))
{
SSNES_ERR("ROM file is not valid!\n");
free(rom_buf);
free(xml_buf);
return false;
}
if (xml_buf)
free(xml_buf);
free(xml_buf);
free(rom_buf);
return true;
}
bool init_rom_file(enum ssnes_game_type type)
{
switch (type)
@@ -801,34 +818,30 @@ bool init_rom_file(enum ssnes_game_type type)
}
// Yep, this is C alright ;)
char** dir_list_new(const char *dir, const char *ext)
char **dir_list_new(const char *dir, const char *ext)
{
size_t cur_ptr = 0;
size_t cur_size = 32;
char **dir_list = NULL;
#ifdef _WIN32
WIN32_FIND_DATAW ffd;
WIN32_FIND_DATA ffd;
HANDLE hFind = INVALID_HANDLE_VALUE;
wchar_t wchar_buf[MAXPATHLEN];
char utf8_buf[MAXPATHLEN];
char path_buf[PATH_MAX];
if (strlcpy(utf8_buf, dir, sizeof(utf8_buf)) >= sizeof(utf8_buf))
if (strlcpy(path_buf, dir, sizeof(path_buf)) >= sizeof(path_buf))
goto error;
if (strlcat(utf8_buf, "/*", sizeof(utf8_buf)) >= sizeof(utf8_buf))
if (strlcat(path_buf, "/*", sizeof(path_buf)) >= sizeof(path_buf))
goto error;
if (ext)
{
if (strlcat(utf8_buf, ext, sizeof(utf8_buf)) >= sizeof(utf8_buf))
if (strlcat(path_buf, ext, sizeof(path_buf)) >= sizeof(path_buf))
goto error;
}
if (MultiByteToWideChar(CP_UTF8, 0, utf8_buf, -1, wchar_buf, MAXPATHLEN) == 0)
goto error;
hFind = FindFirstFileW(wchar_buf, &ffd);
hFind = FindFirstFile(path_buf, &ffd);
if (hFind == INVALID_HANDLE_VALUE)
goto error;
#else
@@ -840,7 +853,7 @@ char** dir_list_new(const char *dir, const char *ext)
goto error;
#endif
dir_list = calloc(cur_size, sizeof(char*));
dir_list = (char**)calloc(cur_size, sizeof(char*));
if (!dir_list)
goto error;
@@ -854,32 +867,30 @@ char** dir_list_new(const char *dir, const char *ext)
#ifdef _WIN32
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
continue;
if (WideCharToMultiByte(CP_UTF8, 0, ffd.cFileName, -1, utf8_buf, MAXPATHLEN, NULL, NULL) == 0)
continue;
if (ext && !strstr(utf8_buf, ext))
if (ext && !strstr(ffd.cFileName, ext))
continue;
#else
if (ext && !strstr(entry->d_name, ext))
continue;
#endif
dir_list[cur_ptr] = malloc(MAXPATHLEN);
dir_list[cur_ptr] = (char*)malloc(PATH_MAX);
if (!dir_list[cur_ptr])
goto error;
strlcpy(dir_list[cur_ptr], dir, MAXPATHLEN);
strlcat(dir_list[cur_ptr], "/", MAXPATHLEN);
strlcpy(dir_list[cur_ptr], dir, PATH_MAX);
strlcat(dir_list[cur_ptr], "/", PATH_MAX);
#ifdef _WIN32
strlcat(dir_list[cur_ptr], utf8_buf, MAXPATHLEN);
strlcat(dir_list[cur_ptr], ffd.cFileName, PATH_MAX);
#else
strlcat(dir_list[cur_ptr], entry->d_name, MAXPATHLEN);
strlcat(dir_list[cur_ptr], entry->d_name, PATH_MAX);
#endif
cur_ptr++;
if (cur_ptr + 1 == cur_size) // Need to reserve for NULL.
{
cur_size *= 2;
dir_list = realloc(dir_list, cur_size * sizeof(char*));
dir_list = (char**)realloc(dir_list, cur_size * sizeof(char*));
if (!dir_list)
goto error;
@@ -887,8 +898,8 @@ char** dir_list_new(const char *dir, const char *ext)
memset(dir_list + cur_ptr, 0, (cur_size - cur_ptr) * sizeof(char*));
}
}
#ifdef _WIN32
while (FindNextFileW(hFind, &ffd) != 0);
#if defined(_WIN32)
while (FindNextFile(hFind, &ffd) != 0);
#endif
#ifdef _WIN32
@@ -925,10 +936,11 @@ void dir_list_free(char **dir_list)
bool path_is_directory(const char *path)
{
#ifdef _WIN32
wchar_t buf[MAXPATHLEN];
if (MultiByteToWideChar(CP_UTF8, 0, path, -1, buf, MAXPATHLEN) == 0)
return false;
return PathIsDirectoryW(buf) == FILE_ATTRIBUTE_DIRECTORY;
return GetFileAttributes(path) & FILE_ATTRIBUTE_DIRECTORY;
#elif defined(__CELLOS_LV2__) || defined(XENON)
// Dummy
(void)path;
return false;
#else
struct stat buf;
if (stat(path, &buf) < 0)
@@ -951,25 +963,27 @@ bool path_file_exists(const char *path)
void fill_pathname(char *out_path, const char *in_path, const char *replace, size_t size)
{
char tmp_path[MAXPATHLEN];
assert(strlcpy(tmp_path, in_path, sizeof(tmp_path)) < sizeof(tmp_path));
char tmp_path[PATH_MAX];
ssnes_assert(strlcpy(tmp_path, in_path, sizeof(tmp_path)) < sizeof(tmp_path));
char *tok = strrchr(tmp_path, '.');
if (tok != NULL)
if (tok)
*tok = '\0';
assert(strlcpy(out_path, tmp_path, size) < size);
assert(strlcat(out_path, replace, size) < size);
ssnes_assert(strlcpy(out_path, tmp_path, size) < size);
ssnes_assert(strlcat(out_path, replace, size) < size);
}
void fill_pathname_noext(char *out_path, const char *in_path, const char *replace, size_t size)
{
assert(strlcpy(out_path, in_path, size) < size);
assert(strlcat(out_path, replace, size) < size);
ssnes_assert(strlcpy(out_path, in_path, size) < size);
ssnes_assert(strlcat(out_path, replace, size) < size);
}
void fill_pathname_dir(char *in_dir, const char *in_basename, const char *replace, size_t size)
{
assert(strlcat(in_dir, "/", size) < size);
ssnes_assert(strlcat(in_dir, "/", size) < size);
const char *base = strrchr(in_basename, '/');
if (!base)
base = strrchr(in_basename, '\\');
@@ -979,6 +993,6 @@ void fill_pathname_dir(char *in_dir, const char *in_basename, const char *replac
else
base = in_basename;
assert(strlcat(in_dir, base, size) < size);
assert(strlcat(in_dir, replace, size) < size);
ssnes_assert(strlcat(in_dir, base, size) < size);
ssnes_assert(strlcat(in_dir, replace, size) < size);
}
+3 -4
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -19,7 +19,7 @@
#ifndef __SSNES_FILE_H
#define __SSNES_FILE_H
#include <stdbool.h>
#include "boolean.h"
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
@@ -41,7 +41,7 @@ bool init_rom_file(enum ssnes_game_type type);
// Returns a NULL-terminated list of files in a directory with full paths.
// If ext is NULL, any file will be picked.
// If non-NULL, only files with extension ext are added.
char** dir_list_new(const char *dir, const char *ext);
char **dir_list_new(const char *dir, const char *ext);
void dir_list_free(char **dir_list);
bool path_is_directory(const char *path);
@@ -55,5 +55,4 @@ void fill_pathname_noext(char *out_path, const char *in_path, const char *replac
// Concatenates in_basename and replace to in_dir.
void fill_pathname_dir(char *in_dir, const char *in_basename, const char *replace, size_t size);
#endif
+161 -64
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -19,39 +19,52 @@
#ifndef __SSNES_GENERAL_H
#define __SSNES_GENERAL_H
#include <stdbool.h>
#include "boolean.h"
#include <stdio.h>
#include <time.h>
#include <limits.h>
#include <setjmp.h>
#include "driver.h"
#include "record/ffemu.h"
#include "message.h"
#include "rewind.h"
#include "movie.h"
#include "autosave.h"
#include "netplay.h"
#include "dynamic.h"
#include "cheats.h"
#include "audio/ext/ssnes_dsp.h"
#include "strl.h"
#ifdef __CELLOS_LV2__
#include <sys/timer.h>
#endif
#ifdef XENON
#include <time/time.h>
#endif
#if defined(XENON) || defined(__CELLOS_LV2__)
#undef PATH_MAX
#define PATH_MAX 4096
#endif
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_NETPLAY
#include "netplay.h"
#endif
#include "audio/hermite.h"
#ifndef _WIN32
#include <sys/param.h> // MAXPATHLEN
#else
#if defined(_WIN32) && !defined(_XBOX)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#ifndef MAXPATHLEN
#ifdef PATH_MAX
#define MAXPATHLEN PATH_MAX
#else
#define MAXPATHLEN 512
#endif
#include "msvc/msvc_compat.h"
#elif defined(_XBOX)
#include <xtl.h>
#include "360/msvc_compat.h"
#endif
#define MAX_PLAYERS 5
@@ -74,7 +87,6 @@ struct settings
char driver[32];
float xscale;
float yscale;
unsigned base_size;
bool fullscreen;
unsigned fullscreen_x;
unsigned fullscreen_y;
@@ -83,20 +95,23 @@ struct settings
bool force_aspect;
bool crop_overscan;
float aspect_ratio;
char cg_shader_path[MAXPATHLEN];
char bsnes_shader_path[MAXPATHLEN];
char filter_path[MAXPATHLEN];
char cg_shader_path[PATH_MAX];
char bsnes_shader_path[PATH_MAX];
char filter_path[PATH_MAX];
enum ssnes_shader_type shader_type;
float refresh_rate;
bool render_to_texture;
double fbo_scale_x;
double fbo_scale_y;
char second_pass_shader[MAXPATHLEN];
float fbo_scale_x;
float fbo_scale_y;
char second_pass_shader[PATH_MAX];
bool second_pass_smooth;
char shader_dir[MAXPATHLEN];
char shader_dir[PATH_MAX];
char font_path[MAXPATHLEN];
char font_path[PATH_MAX];
unsigned font_size;
bool font_enable;
bool font_scale;
float msg_pos_x;
float msg_pos_y;
float msg_color_r;
@@ -109,7 +124,7 @@ struct settings
bool hires_record;
bool post_filter_record;
char external_driver[MAXPATHLEN];
char external_driver[PATH_MAX];
} video;
struct
@@ -119,12 +134,12 @@ struct settings
unsigned out_rate;
float in_rate;
float rate_step;
char device[MAXPATHLEN];
char device[PATH_MAX];
unsigned latency;
bool sync;
char dsp_plugin[MAXPATHLEN];
char external_driver[MAXPATHLEN];
char dsp_plugin[PATH_MAX];
char external_driver[PATH_MAX];
} audio;
struct
@@ -136,14 +151,14 @@ struct settings
bool netplay_client_swap_input;
} input;
char libsnes[MAXPATHLEN];
char cheat_database[MAXPATHLEN];
char cheat_settings_path[MAXPATHLEN];
char libsnes[PATH_MAX];
char cheat_database[PATH_MAX];
char cheat_settings_path[PATH_MAX];
char screenshot_directory[MAXPATHLEN];
char screenshot_directory[PATH_MAX];
bool rewind_enable;
unsigned rewind_buffer_size;
size_t rewind_buffer_size;
unsigned rewind_granularity;
bool pause_nonactive;
@@ -153,13 +168,25 @@ struct settings
bool savestate_auto_index;
};
// Settings and/or global state that is specific to a console-style implementation.
#ifdef SSNES_CONSOLE
struct console_settings
{
bool block_config_read;
#ifdef __CELLOS_LV2__
bool return_to_multiman_enable;
#endif
bool screenshots_enable;
};
#endif
enum ssnes_game_type
{
SSNES_CART_NORMAL = 0,
SSNES_CART_SGB,
SSNES_CART_BSX,
SSNES_CART_BSX_SLOTTED,
SSNES_CART_SUFAMI,
SSNES_CART_SUFAMI
};
@@ -182,32 +209,42 @@ struct global
enum ssnes_game_type game_type;
uint32_t cart_crc;
char gb_rom_path[MAXPATHLEN];
char bsx_rom_path[MAXPATHLEN];
char sufami_rom_path[2][MAXPATHLEN];
char gb_rom_path[PATH_MAX];
char bsx_rom_path[PATH_MAX];
char sufami_rom_path[2][PATH_MAX];
bool has_set_save_path;
bool has_set_state_path;
#ifdef HAVE_CONFIGFILE
char config_path[MAXPATHLEN];
char config_path[PATH_MAX];
#endif
char basename[MAXPATHLEN];
char savefile_name_srm[MAXPATHLEN];
char savefile_name_rtc[MAXPATHLEN]; // Make sure that fill_pathname has space.
char savefile_name_psrm[MAXPATHLEN];
char savefile_name_asrm[MAXPATHLEN];
char savefile_name_bsrm[MAXPATHLEN];
char savestate_name[MAXPATHLEN];
char xml_name[MAXPATHLEN];
char basename[PATH_MAX];
char savefile_name_srm[PATH_MAX];
char savefile_name_rtc[PATH_MAX]; // Make sure that fill_pathname has space.
char savefile_name_psrm[PATH_MAX];
char savefile_name_asrm[PATH_MAX];
char savefile_name_bsrm[PATH_MAX];
char savestate_name[PATH_MAX];
char xml_name[PATH_MAX];
bool ups_pref;
bool bps_pref;
char ups_name[MAXPATHLEN];
char bps_name[MAXPATHLEN];
char ups_name[PATH_MAX];
char bps_name[PATH_MAX];
unsigned state_slot;
struct
{
struct snes_geometry geom;
unsigned pitch; // If 0, has classic libsnes semantics.
char fullpath[PATH_MAX];
struct snes_system_timing timing;
bool timing_set;
bool need_fullpath;
} system;
struct
{
hermite_resampler_t *source;
@@ -221,6 +258,7 @@ struct global
double src_ratio;
bool use_float;
bool mute;
float *outsamples;
int16_t *conv_outsamples;
@@ -253,13 +291,26 @@ struct global
// Rewind support.
state_manager_t *state_manager;
void *state_buf;
size_t state_size;
bool frame_is_reverse;
// Movie record support
bsv_movie_t *bsv_movie;
char bsv_movie_path[MAXPATHLEN];
bool bsv_movie_end;
bool bsv_movie_playback;
// Movie playback/recording support.
struct
{
bsv_movie_t *movie;
char movie_path[PATH_MAX];
bool movie_playback;
// Immediate playback/recording.
char movie_start_path[PATH_MAX];
bool movie_start_recording;
bool movie_start_playback;
bool movie_end;
} bsv;
bool sram_load_disable;
bool sram_save_disable;
bool use_sram;
// Pausing support
bool is_paused;
@@ -269,17 +320,20 @@ struct global
autosave_t *autosave[2];
// Netplay.
#ifdef HAVE_NETPLAY
netplay_t *netplay;
char netplay_server[MAXPATHLEN];
char netplay_server[PATH_MAX];
bool netplay_enable;
bool netplay_is_client;
bool netplay_is_spectate;
unsigned netplay_sync_frames;
uint16_t netplay_port;
#endif
// FFmpeg record.
#ifdef HAVE_FFMPEG
ffemu_t *rec;
char record_path[MAXPATHLEN];
char record_path[PATH_MAX];
bool recording;
unsigned record_width;
unsigned record_height;
@@ -296,24 +350,35 @@ struct global
struct
{
char** elems;
char **elems;
size_t size;
size_t ptr;
} shader_dir;
char sha256[64 + 1];
bool do_screenshot;
#ifdef HAVE_XML
cheat_manager_t *cheat;
#endif
bool error_in_init;
char error_string[1024];
jmp_buf error_sjlj_context;
};
void parse_config(void);
void config_set_defaults(void);
void ssnes_main_clear_state(void);
int ssnes_main_init(int argc, char *argv[]);
bool ssnes_main_iterate(void);
void ssnes_main_deinit(void);
extern struct settings g_settings;
extern struct global g_extern;
#ifdef SSNES_CONSOLE
extern struct console_settings g_console;
#endif
#define SSNES_LOG(...) do { \
if (g_extern.verbose) \
@@ -331,6 +396,16 @@ extern struct global g_extern;
fflush(stderr); \
} while (0)
#ifndef max
#define max(a, b) ((a) > (b) ? (a) : (b))
#endif
#ifndef min
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
#define SSNES_SCALE_BASE 256
static inline uint32_t next_pow2(uint32_t v)
{
v--;
@@ -355,19 +430,41 @@ static inline uint8_t is_little_endian(void)
return u.y[0];
}
static inline void ssnes_sleep(unsigned usec)
#ifdef GEKKO
#include <unistd.h>
#endif
static inline void ssnes_sleep(unsigned msec)
{
#ifdef _WIN32
Sleep(10);
#ifdef __CELLOS_LV2__
sys_timer_usleep(1000 * msec);
#elif defined(_WIN32)
Sleep(msec);
#elif defined(XENON)
udelay(1000 * msec);
#elif defined(GEKKO)
usleep(1000 * msec);
#else
struct timespec tv = {
.tv_sec = 0,
.tv_nsec = 10000000
};
struct timespec tv = {0};
tv.tv_sec = msec / 1000;
tv.tv_nsec = (msec % 1000) * 1000000;
nanosleep(&tv, NULL);
#endif
}
#define ssnes_assert(cond) \
if (!(cond)) { SSNES_ERR("Assertion failed at %s:%d!\n", __FILE__, __LINE__); exit(2); }
static inline void ssnes_fail(int error_code, const char *error)
{
// We cannot longjmp unless we're in ssnes_main_init().
// If not, something went very wrong, and we should just exit right away.
ssnes_assert(g_extern.error_in_init);
strlcpy(g_extern.error_string, error, sizeof(g_extern.error_string));
longjmp(g_extern.error_sjlj_context, error_code);
}
#endif
+187
View File
@@ -0,0 +1,187 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "getopt_ssnes.h"
#ifndef HAVE_GETOPT_LONG
#include <string.h>
#include "boolean.h"
#include <stddef.h>
#include <stdlib.h>
#include "msvc/msvc_compat.h"
#include "general.h"
char *optarg;
int optind, opterr, optopt;
static bool is_short_option(const char *str)
{
return str[0] == '-' && str[1] != '-';
}
static bool is_long_option(const char *str)
{
return str[0] == '-' && str[1] == '-';
}
static int find_short_index(char * const *argv)
{
for (int index = 0; argv[index]; index++)
{
if (is_short_option(argv[index]))
return index;
}
return -1;
}
static int find_long_index(char * const *argv)
{
for (int index = 0; argv[index]; index++)
{
if (is_long_option(argv[index]))
return index;
}
return -1;
}
static int parse_short(const char *optstring, char * const *argv)
{
char arg = argv[0][1];
if (arg == ':')
return '?';
const char *opt = strchr(optstring, arg);
if (!opt)
return '?';
bool multiple_opt = argv[0][2];
bool takes_arg = opt[1] == ':';
if (multiple_opt && takes_arg) // Makes little sense to allow.
return '?';
if (takes_arg)
{
optarg = argv[1];
optind += 2;
return optarg ? opt[0] : '?';
}
else if (multiple_opt)
{
memmove(&argv[0][1], &argv[0][2], strlen(&argv[0][2]) + 1);
return opt[0];
}
else
{
optind++;
return opt[0];
}
}
static int parse_long(const struct option *longopts, char * const *argv)
{
const struct option *opt = NULL;
for (size_t indice = 0; longopts[indice].name; indice++)
{
if (strcmp(longopts[indice].name, &argv[0][2]) == 0)
{
opt = &longopts[indice];
break;
}
}
if (!opt)
return '?';
// getopt_long has an "optional" arg, but we don't bother with that.
if (opt->has_arg && !argv[1])
return '?';
if (opt->has_arg)
{
optarg = argv[1];
optind += 2;
}
else
optind++;
if (opt->flag)
{
*opt->flag = opt->val;
return 0;
}
else
return opt->val;
}
static void shuffle_block(char **begin, char **last, char **end)
{
ptrdiff_t len = last - begin;
const char **tmp = (const char**)calloc(len, sizeof(const char*));
ssnes_assert(tmp);
memcpy(tmp, begin, sizeof(tmp));
memmove(begin, last, (end - last) * sizeof(char*));
memcpy(end - len, tmp, sizeof(tmp));
free(tmp);
}
int getopt_long(int argc, char *argv[],
const char *optstring, const struct option *longopts, int *longindex)
{
(void)longindex;
if (argc == 1)
return -1;
if (optind == 0)
optind = 1;
int short_index = find_short_index(&argv[optind]);
int long_index = find_long_index(&argv[optind]);
// We're done here.
if (short_index == -1 && long_index == -1)
return -1;
// Reorder argv so that non-options come last.
// Non-POSIXy, but that's what getopt does by default.
if ((short_index > 0) && ((short_index < long_index) || (long_index == -1)))
{
shuffle_block(&argv[optind], &argv[optind + short_index], &argv[argc]);
short_index = 0;
}
else if ((long_index > 0) && ((long_index < short_index) || (short_index == -1)))
{
shuffle_block(&argv[optind], &argv[optind + long_index], &argv[argc]);
long_index = 0;
}
ssnes_assert(short_index == 0 || long_index == 0);
if (short_index == 0)
return parse_short(optstring, &argv[optind]);
else if (long_index == 0)
return parse_long(longopts, &argv[optind]);
else
return '?';
}
#endif
+52
View File
@@ -0,0 +1,52 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __SSNES_GETOPT_H
#define __SSNES_GETOPT_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
// Custom implementation of the GNU getopt_long for portability.
// Not designed to be fully compatible,
// but compatible with the features SSNES uses.
#ifdef HAVE_GETOPT_LONG
#include <getopt.h>
#else
// Avoid possible naming collitions during link since we prefer to use the actual name.
#define getopt_long(argc, argv, optstring, longopts, longindex) __getopt_long_ssnes(argc, argv, optstring, longopts, longindex)
struct option
{
const char *name;
int has_arg;
int *flag;
int val;
};
// argv[] is declared with char * const argv[] in GNU,
// but this makes no sense, as non-POSIX getopt_long mutates argv (non-opts are moved to the end).
int getopt_long(int argc, char *argv[],
const char *optstring, const struct option *longopts, int *longindex);
extern char *optarg;
extern int optind, opterr, optopt;
#endif
#endif
+37 -14
View File
@@ -6,6 +6,8 @@
#ifndef __SSNES_VIDEO_DRIVER_H
#define __SSNES_VIDEO_DRIVER_H
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
@@ -22,10 +24,10 @@ extern "C" {
#define SSNES_API_CALLTYPE
#endif
#define SSNES_GRAPHICS_API_VERSION 1
#define SSNES_GRAPHICS_API_VERSION 2
// Since we don't want to rely on C++ or C99 for a proper boolean type,
// and make sure return semantics are perfectly clear ... ;)
// make sure return semantics are perfectly clear ... ;)
#ifndef SSNES_OK
#define SSNES_OK 1
@@ -46,6 +48,23 @@ extern "C" {
#define SSNES_COLOR_FORMAT_XRGB1555 0
#define SSNES_COLOR_FORMAT_ARGB8888 1
#define SSNES_INPUT_SCALE_BASE 256
typedef struct py_state py_state_t;
// Create a new runtime for Python.
// py_script: The python script to be loaded. If is_file is true, this will be the full path to a file.
// If false, it will be an UTF-8 encoded string of the script.
// is_file: Tells if py_script is the path to a script, or a script itself.
// py_class: name of the class being instantiated.
typedef py_state_t *(*python_state_new_cb)(const char *py_script, unsigned is_file, const char *py_class);
// Grabs a value from the Python runtime.
// id: The uniform (class method) to be called.
// frame_count: Passes frame_count as an argument to the script.
typedef float (*python_state_get_cb)(py_state_t *handle, const char *id, unsigned frame_count);
// Frees the runtime.
typedef void (*python_state_free_cb)(py_state_t *handle);
typedef struct ssnes_video_info
{
// Width of window.
@@ -79,12 +98,9 @@ typedef struct ssnes_video_info
// input_scale defines the maximum size of the picture that will
// ever be used with the frame callback.
// The maximum resolution is a multiple of 256x256 size,
// The maximum resolution is a multiple of 256x256 size (SSNES_INPUT_SCALE_BASE),
// so an input scale of 2
// means you should allocate a texture or of 512x512.
// It is normally set to 2 due to the possibility of
// pseudo-hires on the SNES.
// CPU filters or otherwise might increase this value.
unsigned input_scale;
// Defines the coloring format used of the input frame.
@@ -112,6 +128,13 @@ typedef struct ssnes_video_info
// A title that should be displayed in the title bar of the window.
const char *title_hint;
// Functions to peek into the python runtime for shaders.
// Check typedefs above for explanation.
// These may be NULL if SSNES is not built with Python support.
python_state_new_cb python_state_new;
python_state_get_cb python_state_get;
python_state_free_cb python_state_free;
} ssnes_video_info_t;
// Some convenience macros.
@@ -181,20 +204,20 @@ typedef struct ssnes_input_driver
// The range of this is [0, 1],
// where 0 means any displacement will register,
// and 1 means the axis has to be pressed all the way to register.
void* (*init)(const int joypad_index[5], float axis_threshold);
void *(*init)(const int joypad_index[5], float axis_threshold);
// Polls input. Called once every frame.
void (*poll)(void* data);
void (*poll)(void *data);
// Queries input state for a certain key on a certain player.
// Players are 1 - 5.
// For digital inputs, pressed key is 1, not pressed key is 0.
// Analog values have same range as a signed 16-bit integer.
int (*input_state)(void* data, const struct ssnes_keybind *bind,
int (*input_state)(void *data, const struct ssnes_keybind *bind,
unsigned player);
// Frees the input struct.
void (*free)(void* data);
void (*free)(void *data);
// Human readable indentification string.
const char *ident;
@@ -208,7 +231,7 @@ typedef struct ssnes_video_driver
// Should the video driver request that a certain input driver is used,
// it is possible to set the driver to *input.
// If no certain driver is desired, set *input to NULL.
void* (*init)(const ssnes_video_info_t *video,
void *(*init)(const ssnes_video_info_t *video,
const ssnes_input_driver_t **input);
// Updates frame on the screen.
@@ -218,13 +241,13 @@ typedef struct ssnes_video_driver
//
// When msg is non-NULL,
// it's a message that should be displayed to the user.
int (*frame)(void* data, const void* frame,
int (*frame)(void *data, const void *frame,
unsigned width, unsigned height, unsigned pitch, const char *msg);
// Requests nonblocking operation.
// True = VSync is turned off.
// False = VSync is turned on.
void (*set_nonblock_state)(void* data, int toggle);
void (*set_nonblock_state)(void *data, int toggle);
// This must return false when the user exits the emulator.
int (*alive)(void *data);
@@ -233,7 +256,7 @@ typedef struct ssnes_video_driver
int (*focus)(void *data);
// Frees the video driver.
void (*free)(void* data);
void (*free)(void *data);
// A human-readable identification of the video driver.
const char *ident;
+80 -68
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -19,11 +19,11 @@
#define SSNES_DLL_IMPORT
#include "ext/ssnes_video.h"
#include <stdbool.h>
#include "../boolean.h"
#include <stdlib.h>
#include <stdint.h>
#include "dynamic.h"
#include "general.h"
#include "../dynamic.h"
#include "../general.h"
#include "sdlwrap.h"
#include "gfx_common.h"
@@ -31,6 +31,11 @@
#include "fonts.h"
#endif
#ifdef HAVE_PYTHON
#define PY_STATE_OMIT_DECLARATION
#include "py_state/py_state.h"
#endif
static bool g_input_dead = true;
static bool g_video_dead = true;
static dylib_t g_lib = NULL;
@@ -43,7 +48,7 @@ typedef struct
void *handle;
} input_ext_t;
static void* input_ext_init(void)
static void *input_ext_init(void)
{
g_input_dead = false;
return calloc(1, sizeof(input_ext_t));
@@ -51,13 +56,13 @@ static void* input_ext_init(void)
static void input_ext_poll(void *data)
{
input_ext_t *ext = data;
input_ext_t *ext = (input_ext_t*)data;
ext->driver->poll(ext->handle);
}
static int16_t input_ext_input_state(void *data, const struct snes_keybind **snes_keybinds, bool port, unsigned device, unsigned index, unsigned id)
{
input_ext_t *ext = data;
input_ext_t *ext = (input_ext_t*)data;
unsigned player = 0;
if (device == SNES_DEVICE_MULTITAP)
@@ -69,7 +74,7 @@ static int16_t input_ext_input_state(void *data, const struct snes_keybind **sne
for (unsigned i = 0; g_settings.input.binds[player - 1][i].id != -1; i++)
{
if (g_settings.input.binds[player - 1][i].id == id)
if (g_settings.input.binds[player - 1][i].id == (int)id)
{
ssnes_bind = &g_settings.input.binds[player - 1][i];
break;
@@ -78,11 +83,10 @@ static int16_t input_ext_input_state(void *data, const struct snes_keybind **sne
if (ssnes_bind)
{
struct ssnes_keybind bind = {
.key = ssnes_bind->key,
.joykey = ssnes_bind->joykey,
.joyaxis = ssnes_bind->joyaxis
};
struct ssnes_keybind bind = {0};
bind.key = ssnes_bind->key;
bind.joykey = ssnes_bind->joykey;
bind.joyaxis = ssnes_bind->joyaxis;
return ext->driver->input_state(ext->handle, &bind, player);
}
@@ -92,7 +96,7 @@ static int16_t input_ext_input_state(void *data, const struct snes_keybind **sne
static bool input_ext_key_pressed(void *data, int key)
{
input_ext_t *ext = data;
input_ext_t *ext = (input_ext_t*)data;
const struct snes_keybind *ssnes_bind = NULL;
for (unsigned i = 0; g_settings.input.binds[0][i].id != -1; i++)
@@ -106,11 +110,10 @@ static bool input_ext_key_pressed(void *data, int key)
if (ssnes_bind)
{
struct ssnes_keybind bind = {
.key = ssnes_bind->key,
.joykey = ssnes_bind->joykey,
.joyaxis = ssnes_bind->joyaxis
};
struct ssnes_keybind bind = {0};
bind.key = ssnes_bind->key;
bind.joykey = ssnes_bind->joykey;
bind.joyaxis = ssnes_bind->joyaxis;
return ext->driver->input_state(ext->handle, &bind, 1);
}
@@ -120,7 +123,7 @@ static bool input_ext_key_pressed(void *data, int key)
static void input_ext_free(void *data)
{
input_ext_t *ext = data;
input_ext_t *ext = (input_ext_t*)data;
if (ext)
{
if (ext->driver && ext->handle)
@@ -139,15 +142,14 @@ static void input_ext_free(void *data)
}
static const input_driver_t input_ext = {
.init = input_ext_init,
.poll = input_ext_poll,
.input_state = input_ext_input_state,
.key_pressed = input_ext_key_pressed,
.free = input_ext_free,
.ident = "ext"
input_ext_init,
input_ext_poll,
input_ext_input_state,
input_ext_key_pressed,
input_ext_free,
"ext"
};
//////////// Video hook
typedef struct
{
@@ -157,7 +159,7 @@ typedef struct
static void video_ext_free(void *data)
{
ext_t *ext = data;
ext_t *ext = (ext_t*)data;
if (ext)
{
if (ext->driver && ext->handle)
@@ -177,29 +179,29 @@ static void video_ext_free(void *data)
static bool video_ext_focus(void *data)
{
ext_t *ext = data;
ext_t *ext = (ext_t*)data;
return ext->driver->focus(ext->handle);
}
static bool video_ext_alive(void *data)
{
ext_t *ext = data;
ext_t *ext = (ext_t*)data;
return ext->driver->alive(ext->handle);
}
static void video_ext_set_nonblock_state(void *data, bool state)
{
ext_t *ext = data;
ext_t *ext = (ext_t*)data;
ext->driver->set_nonblock_state(ext->handle, state);
}
static bool video_ext_frame(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch, const char *msg)
{
ext_t *ext = data;
ext_t *ext = (ext_t*)data;
return ext->driver->frame(ext->handle, frame, width, height, pitch, msg);
}
static void* setup_input(ext_t *ext, const ssnes_input_driver_t *driver)
static void *setup_input(ext_t *ext, const ssnes_input_driver_t *driver)
{
int joypad_index[5];
for (unsigned i = 0; i < 5; i++)
@@ -209,7 +211,7 @@ static void* setup_input(ext_t *ext, const ssnes_input_driver_t *driver)
if (!handle)
return NULL;
input_ext_t *wrap_handle = input_ext.init();
input_ext_t *wrap_handle = (input_ext_t*)input_ext.init();
if (!wrap_handle)
return NULL;
@@ -246,37 +248,45 @@ static bool setup_video(ext_t *ext, const video_info_t *video, const input_drive
font_color_b = font_color_b > 255 ? 255 : (font_color_b < 0 ? 0 : font_color_b);
const char *font = NULL;
if (g_settings.video.font_enable)
{
#ifdef HAVE_FREETYPE
if (*g_settings.video.font_path)
font = g_settings.video.font_path;
else
font = font_renderer_get_default_font();
if (*g_settings.video.font_path)
font = g_settings.video.font_path;
else
font = font_renderer_get_default_font();
#else
font = *g_settings.video.font_path ?
g_settings.video.font_path : NULL;
font = *g_settings.video.font_path ?
g_settings.video.font_path : NULL;
#endif
}
char title_buf[128];
gfx_window_title_reset();
gfx_window_title(title_buf, sizeof(title_buf));
ssnes_video_info_t info = {
.width = video->width,
.height = video->height,
.fullscreen = video->fullscreen,
.vsync = video->vsync,
.force_aspect = video->force_aspect,
.aspect_ratio = g_settings.video.aspect_ratio,
.smooth = video->smooth,
.input_scale = video->input_scale,
.color_format = video->rgb32 ? SSNES_COLOR_FORMAT_ARGB8888 : SSNES_COLOR_FORMAT_XRGB1555,
.xml_shader = xml_shader,
.cg_shader = cg_shader,
.ttf_font = font,
.ttf_font_size = g_settings.video.font_size,
.ttf_font_color = (font_color_r << 16) | (font_color_g << 8) | (font_color_b << 0),
.title_hint = title_buf,
};
ssnes_video_info_t info = {0};
info.width = video->width;
info.height = video->height;
info.fullscreen = video->fullscreen;
info.vsync = video->vsync;
info.force_aspect = video->force_aspect;
info.aspect_ratio = g_settings.video.aspect_ratio;
info.smooth = video->smooth;
info.input_scale = video->input_scale;
info.color_format = video->rgb32 ? SSNES_COLOR_FORMAT_ARGB8888 : SSNES_COLOR_FORMAT_XRGB1555;
info.xml_shader = xml_shader;
info.cg_shader = cg_shader;
info.ttf_font = font;
info.ttf_font_size = g_settings.video.font_size;
info.ttf_font_color = (font_color_r << 16) | (font_color_g << 8) | (font_color_b << 0);
info.title_hint = title_buf;
#ifdef HAVE_PYTHON
info.python_state_new = py_state_new;
info.python_state_get = py_state_get;
info.python_state_free = py_state_free;
#endif
const ssnes_input_driver_t *input_driver = NULL;
ext->handle = ext->driver->init(&info, &input_driver);
@@ -292,12 +302,14 @@ static bool setup_video(ext_t *ext, const video_info_t *video, const input_drive
return true;
}
static void* video_ext_init(const video_info_t *video, const input_driver_t **input, void **input_data)
static void *video_ext_init(const video_info_t *video, const input_driver_t **input, void **input_data)
{
ext_t *ext = calloc(1, sizeof(*ext));
ext_t *ext = (ext_t*)calloc(1, sizeof(*ext));
if (!ext)
return NULL;
const ssnes_video_driver_t *(*video_init)(void) = NULL;
if (!(*g_settings.video.external_driver))
{
SSNES_ERR("External driver needs video_external_driver path to be set!\n");
@@ -311,8 +323,7 @@ static void* video_ext_init(const video_info_t *video, const input_driver_t **in
goto error;
}
const ssnes_video_driver_t* (*video_init)(void) =
(const ssnes_video_driver_t *(*)(void))dylib_proc(g_lib, "ssnes_video_init");
video_init = (const ssnes_video_driver_t *(*)(void))dylib_proc(g_lib, "ssnes_video_init");
if (!video_init)
{
SSNES_ERR("Couldn't find function ssnes_video_init in library ...\n");
@@ -341,12 +352,13 @@ error:
}
const video_driver_t video_ext = {
.init = video_ext_init,
.frame = video_ext_frame,
.alive = video_ext_alive,
.set_nonblock_state = video_ext_set_nonblock_state,
.focus = video_ext_focus,
.free = video_ext_free,
.ident = "ext"
video_ext_init,
video_ext_frame,
video_ext_set_nonblock_state,
video_ext_alive,
video_ext_focus,
NULL,
video_ext_free,
"ext"
};
+10 -7
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -16,7 +16,7 @@
*/
#include "fonts.h"
#include "file.h"
#include "../file.h"
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
@@ -33,11 +33,12 @@ struct font_renderer
font_renderer_t *font_renderer_new(const char *font_path, unsigned font_size)
{
(void)font_size;
font_renderer_t *handle = calloc(1, sizeof(*handle));
FT_Error err;
font_renderer_t *handle = (font_renderer_t*)calloc(1, sizeof(*handle));
if (!handle)
goto error;
FT_Error err = FT_Init_FreeType(&handle->lib);
err = FT_Init_FreeType(&handle->lib);
if (err)
goto error;
@@ -78,11 +79,11 @@ void font_renderer_msg(font_renderer_t *handle, const char *msg, struct font_out
if (!err)
{
struct font_output *tmp = calloc(1, sizeof(*tmp));
struct font_output *tmp = (struct font_output*)calloc(1, sizeof(*tmp));
if (!tmp)
break;
tmp->output = malloc(slot->bitmap.pitch * slot->bitmap.rows);
tmp->output = (uint8_t*)malloc(slot->bitmap.pitch * slot->bitmap.rows);
if (!tmp->output)
{
free(tmp);
@@ -142,6 +143,8 @@ static const char *font_paths[] = {
#elif defined(__APPLE__)
static const char *font_paths[] = {
"/Library/Fonts/Microsoft/Candara.ttf",
"/Library/Fonts/Verdana.ttf",
"/Library/Fonts/Tahoma.ttf",
#else
static const char *font_paths[] = {
"/usr/share/fonts/TTF/DejaVuSansMono.ttf",
@@ -153,7 +156,7 @@ static const char *font_paths[] = {
// Highly OS/platform dependent.
const char *font_renderer_get_default_font(void)
{
for (unsigned i = 0; i < sizeof(font_paths) / sizeof(font_paths[0]); i++)
for (size_t i = 0; i < sizeof(font_paths) / sizeof(font_paths[0]); i++)
{
if (path_file_exists(font_paths[i]))
return font_paths[i];
+1 -1
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
+30 -3
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -16,8 +16,35 @@
*/
#include "gfx_common.h"
#include "general.h"
#include "../general.h"
#ifndef _MSC_VER
#include <sys/time.h>
#else
#include <winsock2.h>
#include <mmsystem.h>
static int gettimeofday(struct timeval *val, void *dummy)
{
(void)dummy;
DWORD msec = timeGetTime();
uint64_t usec = msec * 1000;
val->tv_sec = usec / 1000000;
val->tv_usec = usec % 1000000;
return 0;
}
#endif
#ifdef __CELLOS_LV2__
#include <sys/sys_time.h>
static int gettimeofday(struct timeval *val, void *dummy)
{
(void)dummy;
uint64_t usec = sys_time_get_system_time();
val->tv_sec = usec / 1000000;
val->tv_usec = usec % 1000000;
return 0;
}
#endif
static float tv_to_fps(const struct timeval *tv, const struct timeval *new_tv, int frames)
{
@@ -62,7 +89,7 @@ bool gfx_window_title(char *buf, size_t size)
#ifdef _WIN32
#include <windows.h>
#include "dynamic.h"
#include "../dynamic.h"
// We only load this library once, so we let it be unloaded at application shutdown,
// since unloading it early seems to cause issues on some systems.
+2 -2
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -19,7 +19,7 @@
#define __GFX_COMMON_H
#include <stddef.h>
#include <stdbool.h>
#include "../boolean.h"
bool gfx_window_title(char *buf, size_t size);
void gfx_window_title_reset(void);
+136 -87
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -16,15 +16,13 @@
*/
#include "driver.h"
#include "../driver.h"
#include <stdint.h>
#include "libsnes.hpp"
#include "../libsnes.hpp"
#include <stdio.h>
#include <sys/time.h>
#include <string.h>
#include "general.h"
#include <assert.h>
#include "../general.h"
#include <math.h>
#ifdef HAVE_CONFIG_H
@@ -34,12 +32,12 @@
#include "gl_common.h"
#include "gfx_common.h"
#include "sdlwrap.h"
#include "strl.h"
#include "../strl.h"
#define NO_SDL_GLEXT
#include "SDL.h"
#include "SDL_opengl.h"
#include "input/ssnes_sdl_input.h"
#include "../input/ssnes_sdl_input.h"
#ifdef HAVE_CG
#include "shader_cg.h"
@@ -78,6 +76,14 @@ static const GLfloat tex_coords[] = {
1, 1
};
static const GLfloat white_color[] = {
1, 1, 1, 1,
1, 1, 1, 1,
1, 1, 1, 1,
1, 1, 1, 1,
};
#define LOAD_SYM(sym) if (!p##sym) { SDL_SYM_WRAP(p##sym, #sym) }
#ifdef HAVE_FBO
#ifdef _WIN32
@@ -87,7 +93,6 @@ static PFNGLFRAMEBUFFERTEXTURE2DPROC pglFramebufferTexture2D = NULL;
static PFNGLCHECKFRAMEBUFFERSTATUSPROC pglCheckFramebufferStatus = NULL;
static PFNGLDELETEFRAMEBUFFERSPROC pglDeleteFramebuffers = NULL;
#define LOAD_SYM(sym) if (!p##sym) { SDL_SYM_WRAP(p##sym, #sym) }
static bool load_fbo_proc(void)
{
LOAD_SYM(glGenFramebuffers);
@@ -124,12 +129,19 @@ static inline bool load_gl_proc(void) { return true; }
#define MAX_SHADERS 16
#if defined(HAVE_XML) || defined(HAVE_CG)
#define TEXTURES 8
#else
#define TEXTURES 1
#endif
#define TEXTURES_MASK (TEXTURES - 1)
typedef struct gl
{
bool vsync;
GLuint texture[2];
GLuint texture[TEXTURES];
unsigned tex_index; // For use with PREV.
struct gl_tex_info prev_info;
struct gl_tex_info prev_info[TEXTURES];
GLuint tex_filter;
void *empty_buf;
@@ -158,8 +170,8 @@ typedef struct gl
unsigned win_height;
unsigned vp_width, vp_out_width;
unsigned vp_height, vp_out_height;
unsigned last_width[2];
unsigned last_height[2];
unsigned last_width[TEXTURES];
unsigned last_height[TEXTURES];
unsigned tex_w, tex_h;
GLfloat tex_coords[8];
#ifdef HAVE_FBO
@@ -177,6 +189,8 @@ typedef struct gl
void *font_tex_empty_buf;
char font_last_msg[256];
int font_last_width, font_last_height;
GLfloat font_color[16];
GLfloat font_color_dark[16];
#endif
} gl_t;
@@ -337,6 +351,9 @@ static void gl_shader_scale(unsigned index, struct gl_fbo_scale *scale)
static inline void gl_init_font(gl_t *gl, const char *font_path, unsigned font_size)
{
#ifdef HAVE_FREETYPE
if (!g_settings.video.font_enable)
return;
const char *path = font_path;
if (!*path)
path = font_renderer_get_default_font();
@@ -359,6 +376,22 @@ static inline void gl_init_font(gl_t *gl, const char *font_path, unsigned font_s
}
else
SSNES_LOG("Did not find default font.\n");
for (unsigned i = 0; i < 4; i++)
{
gl->font_color[4 * i + 0] = g_settings.video.msg_color_r;
gl->font_color[4 * i + 1] = g_settings.video.msg_color_g;
gl->font_color[4 * i + 2] = g_settings.video.msg_color_b;
gl->font_color[4 * i + 3] = 1.0;
}
for (unsigned i = 0; i < 4; i++)
{
for (unsigned j = 0; j < 3; j++)
gl->font_color_dark[4 * i + j] = 0.3 * gl->font_color[4 * i + j];
gl->font_color_dark[4 * i + 3] = 1.0;
}
#else
(void)gl;
(void)font_path;
@@ -721,12 +754,16 @@ static void blit_fonts(gl_t *gl, const struct font_output *head, const struct fo
}
static void calculate_font_coords(gl_t *gl,
GLfloat font_vertex[8], GLfloat font_tex_coords[8])
GLfloat font_vertex[8], GLfloat font_vertex_dark[8], GLfloat font_tex_coords[8])
{
GLfloat scale_factor = g_settings.video.font_scale ?
(GLfloat)gl->full_x / (GLfloat)gl->vp_width :
1.0f;
GLfloat lx = g_settings.video.msg_pos_x;
GLfloat hx = (GLfloat)gl->font_last_width / gl->vp_width + lx;
GLfloat hx = (GLfloat)gl->font_last_width / (gl->vp_width * scale_factor) + lx;
GLfloat ly = g_settings.video.msg_pos_y;
GLfloat hy = (GLfloat)gl->font_last_height / gl->vp_height + ly;
GLfloat hy = (GLfloat)gl->font_last_height / (gl->vp_height * scale_factor) + ly;
font_vertex[0] = lx;
font_vertex[1] = ly;
@@ -737,6 +774,14 @@ static void calculate_font_coords(gl_t *gl,
font_vertex[6] = hx;
font_vertex[7] = ly;
GLfloat shift_x = 2.0f / gl->vp_width;
GLfloat shift_y = 2.0f / gl->vp_height;
for (unsigned i = 0; i < 4; i++)
{
font_vertex_dark[2 * i + 0] = font_vertex[2 * i + 0] - shift_x;
font_vertex_dark[2 * i + 1] = font_vertex[2 * i + 1] - shift_y;
}
lx = 0.0f;
hx = (GLfloat)gl->font_last_width / gl->font_tex_w;
ly = 1.0f - (GLfloat)gl->font_last_height / gl->font_tex_h;
@@ -758,20 +803,18 @@ static void gl_render_msg(gl_t *gl, const char *msg)
return;
GLfloat font_vertex[8];
GLfloat font_vertex_dark[8];
GLfloat font_tex_coords[8];
// Deactivate custom shaders. Enable the font texture.
gl_shader_use(0);
set_viewport(gl, gl->win_width, gl->win_height, false);
glBindTexture(GL_TEXTURE_2D, gl->font_tex);
glVertexPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), font_vertex);
glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), font_tex_coords);
glTexCoordPointer(2, GL_FLOAT, 0, font_tex_coords);
// Need blending.
// Using fixed function pipeline here since we cannot guarantee presence of shaders (would be kinda overkill anyways).
glEnable(GL_BLEND);
glColor4f(g_settings.video.msg_color_r, g_settings.video.msg_color_g,
g_settings.video.msg_color_b, 1);
struct font_output_list out;
@@ -792,14 +835,19 @@ static void gl_render_msg(gl_t *gl, const char *msg)
gl->font_last_width = geom.width;
gl->font_last_height = geom.height;
}
calculate_font_coords(gl, font_vertex, font_tex_coords);
calculate_font_coords(gl, font_vertex, font_vertex_dark, font_tex_coords);
glVertexPointer(2, GL_FLOAT, 0, font_vertex_dark);
glColorPointer(4, GL_FLOAT, 0, gl->font_color_dark);
glDrawArrays(GL_QUADS, 0, 4);
glVertexPointer(2, GL_FLOAT, 0, font_vertex);
glColorPointer(4, GL_FLOAT, 0, gl->font_color);
glDrawArrays(GL_QUADS, 0, 4);
// Go back to old rendering path.
glColor4f(1, 1, 1, 1);
glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), gl->tex_coords);
glVertexPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), vertexes_flipped);
glTexCoordPointer(2, GL_FLOAT, 0, gl->tex_coords);
glVertexPointer(2, GL_FLOAT, 0, vertexes_flipped);
glColorPointer(4, GL_FLOAT, 0, white_color);
glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]);
glDisable(GL_BLEND);
@@ -818,7 +866,7 @@ static inline void set_lut_texture_coords(const GLfloat *coords)
// For texture images.
pglClientActiveTexture(GL_TEXTURE1);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), coords);
glTexCoordPointer(2, GL_FLOAT, 0, coords);
pglClientActiveTexture(GL_TEXTURE0);
#else
(void)coords;
@@ -847,9 +895,9 @@ static void check_window(gl_t *gl)
gl->should_resize = true;
}
static bool gl_frame(void *data, const void* frame, unsigned width, unsigned height, unsigned pitch, const char *msg)
static bool gl_frame(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch, const char *msg)
{
gl_t *gl = data;
gl_t *gl = (gl_t*)data;
gl_shader_use(1);
gl->frame_count++;
@@ -987,7 +1035,8 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei
set_texture_coords(gl->tex_coords, xamt, yamt);
}
#if defined(HAVE_XML) || defined(HAVE_CG)
else if (width != gl->last_width[1 - gl->tex_index] || height != gl->last_height[1 - gl->tex_index])
// We might have used different texture coordinates last frame. Edge case if resolution changes very rapidly.
else if (width != gl->last_width[(gl->tex_index - 1) & TEXTURES_MASK] || height != gl->last_height[(gl->tex_index - 1) & TEXTURES_MASK])
{
GLfloat xamt = (GLfloat)width / gl->tex_w;
GLfloat yamt = (GLfloat)height / gl->tex_h;
@@ -999,7 +1048,7 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei
// Need to preserve the "flipped" state when in FBO as well to have
// consistent texture coordinates.
if (gl->render_to_tex)
glVertexPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), vertexes);
glVertexPointer(2, GL_FLOAT, 0, vertexes);
#endif
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / gl->base_size);
@@ -1007,18 +1056,20 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei
0, 0, 0, width, height, gl->texture_type,
gl->texture_fmt, frame);
struct gl_tex_info tex_info = {
.tex = gl->texture[gl->tex_index],
.input_size = {width, height},
.tex_size = {gl->tex_w, gl->tex_h}
};
struct gl_tex_info tex_info = {0};
tex_info.tex = gl->texture[gl->tex_index];
tex_info.input_size[0] = width;
tex_info.input_size[1] = height;
tex_info.tex_size[0] = gl->tex_w;
tex_info.tex_size[1] = gl->tex_h;
struct gl_tex_info fbo_tex_info[MAX_SHADERS];
unsigned fbo_tex_info_cnt = 0;
memcpy(tex_info.coord, gl->tex_coords, sizeof(gl->tex_coords));
glClear(GL_COLOR_BUFFER_BIT);
gl_shader_set_params(width, height, gl->tex_w, gl->tex_h, gl->vp_width, gl->vp_height, gl->frame_count,
&tex_info, &gl->prev_info, fbo_tex_info, fbo_tex_info_cnt);
&tex_info, gl->prev_info, fbo_tex_info, fbo_tex_info_cnt);
glDrawArrays(GL_QUADS, 0, 4);
@@ -1026,7 +1077,7 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei
if (gl->fbo_inited)
{
// Render the rest of our passes.
glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), gl->fbo_tex_coords);
glTexCoordPointer(2, GL_FLOAT, 0, gl->fbo_tex_coords);
// It's kinda handy ... :)
const struct gl_fbo_rect *prev_rect;
@@ -1063,7 +1114,7 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei
gl_shader_set_params(prev_rect->img_width, prev_rect->img_height,
prev_rect->width, prev_rect->height,
gl->vp_width, gl->vp_height, gl->frame_count,
&tex_info, &gl->prev_info, fbo_tex_info, fbo_tex_info_cnt);
&tex_info, gl->prev_info, fbo_tex_info, fbo_tex_info_cnt);
glDrawArrays(GL_QUADS, 0, 4);
@@ -1089,18 +1140,19 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei
gl_shader_set_params(prev_rect->img_width, prev_rect->img_height,
prev_rect->width, prev_rect->height,
gl->vp_width, gl->vp_height, gl->frame_count,
&tex_info, &gl->prev_info, fbo_tex_info, fbo_tex_info_cnt);
&tex_info, gl->prev_info, fbo_tex_info, fbo_tex_info_cnt);
glVertexPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), vertexes_flipped);
glVertexPointer(2, GL_FLOAT, 0, vertexes_flipped);
glDrawArrays(GL_QUADS, 0, 4);
glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), gl->tex_coords);
glTexCoordPointer(2, GL_FLOAT, 0, gl->tex_coords);
}
#endif
#if defined(HAVE_XML) || defined(HAVE_CG)
memcpy(&gl->prev_info, &tex_info, sizeof(tex_info));
gl->tex_index = 1 - gl->tex_index;
memmove(gl->prev_info + 1, gl->prev_info, sizeof(tex_info) * (TEXTURES - 1));
memcpy(&gl->prev_info[0], &tex_info, sizeof(tex_info));
gl->tex_index = (gl->tex_index + 1) & TEXTURES_MASK;
#endif
if (msg)
@@ -1117,13 +1169,14 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei
static void gl_free(void *data)
{
gl_t *gl = data;
gl_t *gl = (gl_t*)data;
gl_deinit_font(gl);
gl_shader_deinit();
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDeleteTextures(2, gl->texture);
glDisableClientState(GL_COLOR_ARRAY);
glDeleteTextures(TEXTURES, gl->texture);
#ifdef HAVE_FBO
if (gl->fbo_inited)
@@ -1142,7 +1195,7 @@ static void gl_free(void *data)
static void gl_set_nonblock_state(void *data, bool state)
{
gl_t *gl = data;
gl_t *gl = (gl_t*)data;
if (gl->vsync)
{
SSNES_LOG("GL VSync => %s\n", state ? "off" : "on");
@@ -1150,7 +1203,7 @@ static void gl_set_nonblock_state(void *data, bool state)
}
}
static void* gl_init(const video_info_t *video, const input_driver_t **input, void **input_data)
static void *gl_init(const video_info_t *video, const input_driver_t **input, void **input_data)
{
#ifdef _WIN32
gfx_set_dwm();
@@ -1160,7 +1213,7 @@ static void* gl_init(const video_info_t *video, const input_driver_t **input, vo
return NULL;
const SDL_VideoInfo *video_info = SDL_GetVideoInfo();
assert(video_info);
ssnes_assert(video_info);
unsigned full_x = video_info->current_w;
unsigned full_y = video_info->current_h;
SSNES_LOG("Detecting desktop resolution %ux%u.\n", full_x, full_y);
@@ -1198,7 +1251,7 @@ static void* gl_init(const video_info_t *video, const input_driver_t **input, vo
}
#endif
gl_t *gl = calloc(1, sizeof(gl_t));
gl_t *gl = (gl_t*)calloc(1, sizeof(gl_t));
if (!gl)
{
sdlwrap_destroy();
@@ -1226,7 +1279,8 @@ static void* gl_init(const video_info_t *video, const input_driver_t **input, vo
SSNES_LOG("GL: Loaded %u program(s).\n", gl_shader_num());
// Set up render to texture.
gl_init_fbo(gl, 256 * video->input_scale, 256 * video->input_scale);
gl_init_fbo(gl, SSNES_SCALE_BASE * video->input_scale,
SSNES_SCALE_BASE * video->input_scale);
gl->keep_aspect = video->force_aspect;
@@ -1249,15 +1303,14 @@ static void* gl_init(const video_info_t *video, const input_driver_t **input, vo
glEnable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glDisable(GL_DITHER);
glColor4f(1, 1, 1, 1);
glClearColor(0, 0, 0, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glGenTextures(2, gl->texture);
glGenTextures(TEXTURES, gl->texture);
for (unsigned i = 0; i < 2; i++)
for (unsigned i = 0; i < TEXTURES; i++)
{
glBindTexture(GL_TEXTURE_2D, gl->texture[i]);
@@ -1270,20 +1323,23 @@ static void* gl_init(const video_info_t *video, const input_driver_t **input, vo
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), vertexes_flipped);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vertexes_flipped);
memcpy(gl->tex_coords, tex_coords, sizeof(tex_coords));
glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), gl->tex_coords);
glTexCoordPointer(2, GL_FLOAT, 0, gl->tex_coords);
glColorPointer(4, GL_FLOAT, 0, white_color);
set_lut_texture_coords(tex_coords);
gl->tex_w = 256 * video->input_scale;
gl->tex_h = 256 * video->input_scale;
gl->tex_w = SSNES_SCALE_BASE * video->input_scale;
gl->tex_h = SSNES_SCALE_BASE * video->input_scale;
// Empty buffer that we use to clear out the texture with on res change.
gl->empty_buf = calloc(gl->tex_w * gl->tex_h, gl->base_size);
for (unsigned i = 0; i < 2; i++)
for (unsigned i = 0; i < TEXTURES; i++)
{
glBindTexture(GL_TEXTURE_2D, gl->texture[i]);
glPixelStorei(GL_UNPACK_ROW_LENGTH, gl->tex_w);
@@ -1293,21 +1349,24 @@ static void* gl_init(const video_info_t *video, const input_driver_t **input, vo
}
glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]);
for (unsigned i = 0; i < 2; i++)
for (unsigned i = 0; i < TEXTURES; i++)
{
gl->last_width[i] = gl->tex_w;
gl->last_height[i] = gl->tex_h;
}
gl->prev_info.tex = gl->texture[1 - gl->tex_index];
gl->prev_info.input_size[0] = gl->tex_w;
gl->prev_info.tex_size[0] = gl->tex_w;
gl->prev_info.input_size[1] = gl->tex_h;
gl->prev_info.tex_size[1] = gl->tex_h;
memcpy(gl->prev_info.coord, tex_coords, sizeof(tex_coords));
for (unsigned i = 0; i < TEXTURES; i++)
{
gl->prev_info[i].tex = gl->texture[(gl->tex_index - (i + 1)) & TEXTURES_MASK];
gl->prev_info[i].input_size[0] = gl->tex_w;
gl->prev_info[i].tex_size[0] = gl->tex_w;
gl->prev_info[i].input_size[1] = gl->tex_h;
gl->prev_info[i].tex_size[1] = gl->tex_h;
memcpy(gl->prev_info[i].coord, tex_coords, sizeof(tex_coords));
}
// Hook up SDL input driver to get SDL_QUIT events and RESIZE.
sdl_input_t *sdl_input = input_sdl.init();
sdl_input_t *sdl_input = (sdl_input_t*)input_sdl.init();
if (sdl_input)
{
*input = &input_sdl;
@@ -1330,7 +1389,7 @@ static void* gl_init(const video_info_t *video, const input_driver_t **input, vo
static bool gl_alive(void *data)
{
gl_t *gl = data;
gl_t *gl = (gl_t*)data;
check_window(gl);
return !gl->quitting;
}
@@ -1344,14 +1403,7 @@ static bool gl_focus(void *data)
#ifdef HAVE_XML
static bool gl_xml_shader(void *data, const char *path)
{
gl_t *gl = data;
//if (!gl_check_error())
// SSNES_WARN("Error happened before deinit!\n");
//if (!gl_check_error())
// SSNES_WARN("Error happened in deinit!\n");
gl_t *gl = (gl_t*)data;
#ifdef HAVE_FBO
if (gl->fbo_inited)
@@ -1370,9 +1422,6 @@ static bool gl_xml_shader(void *data, const char *path)
gl_shader_deinit();
//if (!gl_check_error())
// SSNES_WARN("Failed to deinit rendering path properly!\n");
if (!gl_glsl_init(path))
return false;
@@ -1390,17 +1439,17 @@ static bool gl_xml_shader(void *data, const char *path)
#endif
const video_driver_t video_gl = {
.init = gl_init,
.frame = gl_frame,
.alive = gl_alive,
.set_nonblock_state = gl_set_nonblock_state,
.focus = gl_focus,
.free = gl_free,
gl_init,
gl_frame,
gl_set_nonblock_state,
gl_alive,
gl_focus,
#ifdef HAVE_XML
.xml_shader = gl_xml_shader,
gl_xml_shader,
#else
NULL,
#endif
.ident = "gl"
gl_free,
"gl"
};
+8 -8
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -18,16 +18,19 @@
#ifndef __GL_COMMON_H
#define __GL_COMMON_H
#include "general.h"
#include <assert.h>
#include "../general.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#include "../config.h"
#endif
#ifdef __APPLE__
#if defined(__APPLE__)
#include <OpenGL/gl.h>
#include <OpenGL/glext.h>
#elif defined(__CELLOS_LV2__)
#include <PSGL/psgl.h>
#include <PSGL/psglu.h>
#include <GLES/glext.h>
#else
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
@@ -57,9 +60,6 @@ static inline bool gl_check_error(void)
case GL_OUT_OF_MEMORY:
SSNES_ERR("GL: Out of memory. Harhar.\n");
break;
case GL_TABLE_TOO_LARGE:
SSNES_ERR("GL: Table too large. Big tables scare you! :(\n");
break;
case GL_NO_ERROR:
return true;
break;
+11 -11
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -16,16 +16,16 @@
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#include "../config.h"
#endif
#include "image.h"
#include "file.h"
#include "../file.h"
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include "general.h"
#include "../general.h"
#ifdef HAVE_SDL_IMAGE
@@ -40,7 +40,7 @@ bool texture_image_load(const char *path, struct texture_image *out_img)
out_img->height = img->h;
size_t size = out_img->width * out_img->height * sizeof(uint32_t);
out_img->pixels = malloc(size);
out_img->pixels = (uint32_t*)malloc(size);
if (!out_img->pixels)
{
SDL_FreeSurface(img);
@@ -52,12 +52,12 @@ bool texture_image_load(const char *path, struct texture_image *out_img)
SSNES_LOG("SDL_image: %dx%d @ %d bpp\n", img->w, img->h, img->format->BitsPerPixel);
if (img->format->BitsPerPixel == 32)
{
for (unsigned y = 0; y < img->h; y++)
for (int y = 0; y < img->h; y++)
{
uint32_t *dst = out_img->pixels + y * img->w;
const uint32_t *src = (const uint32_t*)img->pixels + y * img->pitch / sizeof(uint32_t);
for (unsigned x = 0; x < img->w; x++)
for (int x = 0; x < img->w; x++)
{
uint32_t r = (src[x] & fmt->Rmask) >> fmt->Rshift;
uint32_t g = (src[x] & fmt->Gmask) >> fmt->Gshift;
@@ -69,12 +69,12 @@ bool texture_image_load(const char *path, struct texture_image *out_img)
}
else if (img->format->BitsPerPixel == 24)
{
for (unsigned y = 0; y < img->h; y++)
for (int y = 0; y < img->h; y++)
{
uint32_t *dst = out_img->pixels + y * img->w;
const uint8_t *src = (const uint8_t*)img->pixels + y * img->pitch;
for (unsigned x = 0; x < img->w; x++)
for (int x = 0; x < img->w; x++)
{
// Correct?
uint32_t color = 0;
@@ -113,7 +113,7 @@ bool texture_image_load(const char *path, struct texture_image *out_img)
if (len < 0)
return false;
uint8_t *buf = raw_buf;
uint8_t *buf = (uint8_t*)raw_buf;
if (buf[2] != 2) // Uncompressed RGB
{
@@ -134,7 +134,7 @@ bool texture_image_load(const char *path, struct texture_image *out_img)
SSNES_LOG("Loaded TGA: (%ux%u @ %u bpp)\n", width, height, bits);
unsigned size = width * height * sizeof(uint32_t);
out_img->pixels = malloc(size);
out_img->pixels = (uint32_t*)malloc(size);
out_img->width = width;
out_img->height = height;
if (!out_img->pixels)
+3 -3
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -19,7 +19,7 @@
#define __SSNES_IMAGE_H
#include <stdint.h>
#include <stdbool.h>
#include "../boolean.h"
struct texture_image
{
@@ -30,5 +30,5 @@ struct texture_image
bool texture_image_load(const char *path, struct texture_image* img);
#endif
+120 -55
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -16,16 +16,18 @@
*/
#include <Python.h>
#include <stdbool.h>
#include "../../boolean.h"
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "dynamic.h"
#include "libsnes.hpp"
#include "../../dynamic.h"
#include "../../libsnes.hpp"
#include "py_state.h"
#include "general.h"
#include "strl.h"
#include "../../general.h"
#include "../../strl.h"
#include "../../posix_string.h"
#include "../../file.h"
#define PY_READ_FUNC_DECL(RAMTYPE) py_read_##RAMTYPE
#define PY_READ_FUNC(RAMTYPE) \
@@ -60,7 +62,7 @@ PY_READ_FUNC(APURAM)
PY_READ_FUNC(CGRAM)
PY_READ_FUNC(OAM)
static PyObject* py_read_input(PyObject *self, PyObject *args)
static PyObject *py_read_input(PyObject *self, PyObject *args)
{
(void)self;
@@ -72,12 +74,16 @@ static PyObject* py_read_input(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "II", &player, &key))
return NULL;
if (player > MAX_PLAYERS || player < 1)
if (player > MAX_PLAYERS || player < 1 || key >= SSNES_FIRST_META_KEY)
return NULL;
const struct snes_keybind *binds[MAX_PLAYERS];
for (int i = 0; i < MAX_PLAYERS; i++)
binds[i] = g_settings.input.binds[i];
static const struct snes_keybind *binds[MAX_PLAYERS] = {
g_settings.input.binds[0],
g_settings.input.binds[1],
g_settings.input.binds[2],
g_settings.input.binds[3],
g_settings.input.binds[4],
};
int16_t res = driver.input->input_state(driver.input_data,
binds, player > 1,
@@ -85,7 +91,25 @@ static PyObject* py_read_input(PyObject *self, PyObject *args)
player > 2 ? player - 2 : 0,
key);
return PyBool_FromLong((long)res);
return PyBool_FromLong(res);
}
static PyObject *py_read_input_meta(PyObject *self, PyObject *args)
{
(void)self;
if (!driver.input_data)
return PyBool_FromLong(0);
unsigned key;
if (!PyArg_ParseTuple(args, "I", &key))
return NULL;
if (key < SSNES_FIRST_META_KEY)
return NULL;
bool ret = driver.input->key_pressed(driver.input_data, key);
return PyBool_FromLong(ret);
}
static PyMethodDef SNESMethods[] = {
@@ -95,23 +119,50 @@ static PyMethodDef SNESMethods[] = {
{ "read_cgram", PY_READ_FUNC_DECL(CGRAM), METH_VARARGS, "Read CGRAM from SNES." },
{ "read_oam", PY_READ_FUNC_DECL(OAM), METH_VARARGS, "Read OAM from SNES." },
{ "input", py_read_input, METH_VARARGS, "Read input state from SNES." },
{ "input_meta", py_read_input_meta, METH_VARARGS, "Read SSNES specific input." },
{ NULL, NULL, 0, NULL }
};
#define DECL_ATTR_SNES(attr) PyObject_SetAttrString(mod, #attr, PyLong_FromLong(SNES_DEVICE_ID_JOYPAD_##attr))
#define DECL_ATTR_SSNES(attr) PyObject_SetAttrString(mod, #attr, PyLong_FromLong(SSNES_##attr))
static void py_set_attrs(PyObject *mod)
{
PyObject_SetAttrString(mod, "B", PyLong_FromLong(SNES_DEVICE_ID_JOYPAD_B));
PyObject_SetAttrString(mod, "Y", PyLong_FromLong(SNES_DEVICE_ID_JOYPAD_Y));
PyObject_SetAttrString(mod, "SELECT", PyLong_FromLong(SNES_DEVICE_ID_JOYPAD_SELECT));
PyObject_SetAttrString(mod, "START", PyLong_FromLong(SNES_DEVICE_ID_JOYPAD_START));
PyObject_SetAttrString(mod, "UP", PyLong_FromLong(SNES_DEVICE_ID_JOYPAD_UP));
PyObject_SetAttrString(mod, "DOWN", PyLong_FromLong(SNES_DEVICE_ID_JOYPAD_DOWN));
PyObject_SetAttrString(mod, "LEFT", PyLong_FromLong(SNES_DEVICE_ID_JOYPAD_LEFT));
PyObject_SetAttrString(mod, "RIGHT", PyLong_FromLong(SNES_DEVICE_ID_JOYPAD_RIGHT));
PyObject_SetAttrString(mod, "A", PyLong_FromLong(SNES_DEVICE_ID_JOYPAD_A));
PyObject_SetAttrString(mod, "X", PyLong_FromLong(SNES_DEVICE_ID_JOYPAD_X));
PyObject_SetAttrString(mod, "L", PyLong_FromLong(SNES_DEVICE_ID_JOYPAD_L));
PyObject_SetAttrString(mod, "R", PyLong_FromLong(SNES_DEVICE_ID_JOYPAD_R));
DECL_ATTR_SNES(B);
DECL_ATTR_SNES(Y);
DECL_ATTR_SNES(SELECT);
DECL_ATTR_SNES(START);
DECL_ATTR_SNES(UP);
DECL_ATTR_SNES(DOWN);
DECL_ATTR_SNES(LEFT);
DECL_ATTR_SNES(RIGHT);
DECL_ATTR_SNES(A);
DECL_ATTR_SNES(X);
DECL_ATTR_SNES(L);
DECL_ATTR_SNES(R);
DECL_ATTR_SSNES(FAST_FORWARD_KEY);
DECL_ATTR_SSNES(FAST_FORWARD_HOLD_KEY);
DECL_ATTR_SSNES(LOAD_STATE_KEY);
DECL_ATTR_SSNES(SAVE_STATE_KEY);
DECL_ATTR_SSNES(FULLSCREEN_TOGGLE_KEY);
DECL_ATTR_SSNES(QUIT_KEY);
DECL_ATTR_SSNES(STATE_SLOT_PLUS);
DECL_ATTR_SSNES(STATE_SLOT_MINUS);
DECL_ATTR_SSNES(AUDIO_INPUT_RATE_PLUS);
DECL_ATTR_SSNES(AUDIO_INPUT_RATE_MINUS);
DECL_ATTR_SSNES(REWIND);
DECL_ATTR_SSNES(MOVIE_RECORD_TOGGLE);
DECL_ATTR_SSNES(PAUSE_TOGGLE);
DECL_ATTR_SSNES(FRAMEADVANCE);
DECL_ATTR_SSNES(RESET);
DECL_ATTR_SSNES(SHADER_NEXT);
DECL_ATTR_SSNES(SHADER_PREV);
DECL_ATTR_SSNES(CHEAT_INDEX_PLUS);
DECL_ATTR_SSNES(CHEAT_INDEX_MINUS);
DECL_ATTR_SSNES(CHEAT_TOGGLE);
DECL_ATTR_SSNES(SCREENSHOT);
DECL_ATTR_SSNES(DSP_CONFIG);
DECL_ATTR_SSNES(MUTE);
}
static PyModuleDef SNESModule = {
@@ -145,7 +196,7 @@ static char *dupe_newline(const char *str)
return NULL;
unsigned size = strlen(str) + 2;
char *ret = malloc(size);
char *ret = (char*)malloc(size);
if (!ret)
return NULL;
@@ -156,14 +207,14 @@ static char *dupe_newline(const char *str)
}
// Need to make sure that first-line indentation is 0. :(
static char* align_program(const char *program)
static char *align_program(const char *program)
{
char *prog = strdup(program);
if (!prog)
return NULL;
size_t prog_size = strlen(program) + 1;
char *new_prog = calloc(1, prog_size);
char *new_prog = (char*)calloc(1, prog_size);
if (!new_prog)
return NULL;
@@ -190,28 +241,39 @@ static char* align_program(const char *program)
}
free(prog);
return new_prog;
}
py_state_t *py_state_new(const char *script, bool is_file, const char *pyclass)
py_state_t *py_state_new(const char *script, unsigned is_file, const char *pyclass)
{
SSNES_LOG("Initializing Python runtime ...\n");
PyImport_AppendInittab("snes", &PyInit_SNES);
Py_Initialize();
SSNES_LOG("Initialized Python runtime!\n");
py_state_t *handle = calloc(1, sizeof(*handle));
py_state_t *handle = (py_state_t*)calloc(1, sizeof(*handle));
PyObject *hook = NULL;
handle->main = PyImport_AddModule("__main__");
if (!handle->main)
goto error;
Py_INCREF(handle->main);
if (is_file)
{
FILE *file = fopen(script, "r");
if (!file)
// Have to hack around the fact that the
// FILE struct isn't standardized across environments.
// PyRun_SimpleFile() breaks on Windows.
char *script_ = NULL;
if (read_file(script, (void**)&script_) < 0)
{
SSNES_ERR("Python: Failed to read script\n");
goto error;
PyRun_SimpleFile(file, script);
fclose(file);
}
PyRun_SimpleString(script_);
free(script_);
}
else
{
@@ -223,22 +285,35 @@ py_state_t *py_state_new(const char *script, bool is_file, const char *pyclass)
}
}
SSNES_LOG("Python: Script loaded.\n");
handle->dict = PyModule_GetDict(handle->main);
if (!handle->dict)
{
SSNES_ERR("Python: PyModule_GetDict() failed.\n");
goto error;
}
Py_INCREF(handle->dict);
PyObject *hook = PyDict_GetItemString(handle->dict, pyclass);
hook = PyDict_GetItemString(handle->dict, pyclass);
if (!hook)
{
SSNES_ERR("Python: PyDict_GetItemString() failed.\n");
goto error;
}
handle->inst = PyObject_CallFunction(hook, NULL);
if (!handle->inst)
{
SSNES_ERR("Python: PyObject_CallFunction() failed.\n");
goto error;
}
Py_INCREF(handle->inst);
return handle;
error:
PyErr_Print();
PyErr_Clear();
py_state_free(handle);
return NULL;
}
@@ -247,20 +322,19 @@ void py_state_free(py_state_t *handle)
{
if (handle)
{
if (handle->main)
Py_DECREF(handle->main);
if (handle->dict)
Py_DECREF(handle->dict);
if (handle->inst)
Py_DECREF(handle->inst);
PyErr_Print();
PyErr_Clear();
Py_CLEAR(handle->inst);
Py_CLEAR(handle->dict);
Py_CLEAR(handle->main);
free(handle);
Py_Finalize();
}
Py_Finalize();
}
int py_state_get(py_state_t *handle, const char *id,
float py_state_get(py_state_t *handle, const char *id,
unsigned frame_count)
{
PyObject *ret = PyObject_CallMethod(handle->inst, (char*)id, (char*)"I", frame_count);
@@ -269,19 +343,10 @@ int py_state_get(py_state_t *handle, const char *id,
if (!handle->warned_ret)
SSNES_WARN("Didn't get return value from script! Bug?\n");
handle->warned_ret = true;
return 0;
}
int retval = 0;
if (PyLong_Check(ret))
retval = (int)PyLong_AsLong(ret);
else
{
if (!handle->warned_type)
SSNES_WARN("Didn't get long compatible value from script! Bug?\n");
handle->warned_type = true;
return 0.0f;
}
float retval = (float)PyFloat_AsDouble(ret);
Py_DECREF(ret);
return retval;
}
+6 -4
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -19,14 +19,16 @@
#define __SSNES_PY_STATE_H
#include <stdint.h>
#include <stdbool.h>
#include "../../boolean.h"
#ifndef PY_STATE_OMIT_DECLARATION
typedef struct py_state py_state_t;
#endif
py_state_t *py_state_new(const char *program, bool is_file, const char *pyclass);
py_state_t *py_state_new(const char *program, unsigned is_file, const char *pyclass);
void py_state_free(py_state_t *handle);
int py_state_get(py_state_t *handle,
float py_state_get(py_state_t *handle,
const char *id, unsigned frame_count);
#endif
+54 -56
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -16,12 +16,11 @@
*/
#include "SDL.h"
#include "driver.h"
#include <assert.h>
#include "../driver.h"
#include <stdlib.h>
#include <string.h>
#include "general.h"
#include "input/ssnes_sdl_input.h"
#include "../general.h"
#include "../input/ssnes_sdl_input.h"
#include "gfx_common.h"
#ifdef HAVE_CONFIG_H
@@ -37,8 +36,7 @@ static void convert_32bit_32bit_direct(uint32_t *out, unsigned outpitch, const u
static void convert_15bit_15bit_shift(uint16_t *out, unsigned outpitch, const uint16_t *input, unsigned width, unsigned height, unsigned pitch, const SDL_PixelFormat *fmt);
static void convert_32bit_32bit_shift(uint32_t *out, unsigned outpitch, const uint32_t *input, unsigned width, unsigned height, unsigned pitch, const SDL_PixelFormat *fmt);
typedef struct sdl_video sdl_video_t;
struct sdl_video
typedef struct sdl_video
{
SDL_Surface *screen, *buffer;
bool quitting;
@@ -56,11 +54,11 @@ struct sdl_video
uint8_t font_g;
uint8_t font_b;
#endif
};
} sdl_video_t;
static void sdl_gfx_free(void *data)
{
sdl_video_t *vid = data;
sdl_video_t *vid = (sdl_video_t*)data;
if (!vid)
return;
@@ -80,6 +78,9 @@ static void sdl_gfx_free(void *data)
static void sdl_init_font(sdl_video_t *vid, const char *font_path, unsigned font_size)
{
#ifdef HAVE_FREETYPE
if (!g_settings.video.font_enable)
return;
const char *path = font_path;
if (!*path)
path = font_renderer_get_default_font();
@@ -145,7 +146,7 @@ static void sdl_render_msg_15(sdl_video_t *vid, SDL_Surface *buffer, const char
int rbase_y = base_y - head->off_y;
if (rbase_y >= 0)
{
for (int y = 0; y < head->height && (y + rbase_y) < height; y++)
for (int y = 0; y < (int)head->height && (y + rbase_y) < (int)height; y++)
{
if (rbase_x < 0)
continue;
@@ -153,7 +154,7 @@ static void sdl_render_msg_15(sdl_video_t *vid, SDL_Surface *buffer, const char
const uint8_t *a = head->output + head->pitch * y;
uint16_t *out = (uint16_t*)buffer->pixels + (rbase_y - head->height + y) * (buffer->pitch >> 1) + rbase_x;
for (int x = 0; x < head->width && (x + rbase_x) < width; x++)
for (int x = 0; x < (int)head->width && (x + rbase_x) < (int)width; x++)
{
unsigned blend = a[x];
unsigned out_pix = out[x];
@@ -206,7 +207,7 @@ static void sdl_render_msg_32(sdl_video_t *vid, SDL_Surface *buffer, const char
int rbase_y = base_y - head->off_y;
if (rbase_y >= 0)
{
for (int y = 0; y < head->height && (y + rbase_y) < height; y++)
for (int y = 0; y < (int)head->height && (y + rbase_y) < (int)height; y++)
{
if (rbase_x < 0)
continue;
@@ -214,7 +215,7 @@ static void sdl_render_msg_32(sdl_video_t *vid, SDL_Surface *buffer, const char
const uint8_t *a = head->output + head->pitch * y;
uint32_t *out = (uint32_t*)buffer->pixels + (rbase_y - head->height + y) * (buffer->pitch >> 2) + rbase_x;
for (int x = 0; x < head->width && (x + rbase_x) < width; x++)
for (int x = 0; x < (int)head->width && (x + rbase_x) < (int)width; x++)
{
unsigned blend = a[x];
unsigned out_pix = out[x];
@@ -244,7 +245,7 @@ static void sdl_render_msg_32(sdl_video_t *vid, SDL_Surface *buffer, const char
#endif
}
static void* sdl_gfx_init(const video_info_t *video, const input_driver_t **input, void **input_data)
static void *sdl_gfx_init(const video_info_t *video, const input_driver_t **input, void **input_data)
{
#ifdef _WIN32
gfx_set_dwm();
@@ -252,16 +253,19 @@ static void* sdl_gfx_init(const video_info_t *video, const input_driver_t **inpu
SDL_InitSubSystem(SDL_INIT_VIDEO);
sdl_video_t *vid = calloc(1, sizeof(*vid));
sdl_video_t *vid = (sdl_video_t*)calloc(1, sizeof(*vid));
if (!vid)
return NULL;
const SDL_VideoInfo *video_info = SDL_GetVideoInfo();
assert(video_info);
ssnes_assert(video_info);
unsigned full_x = video_info->current_w;
unsigned full_y = video_info->current_h;
SSNES_LOG("Detecting desktop resolution %ux%u.\n", full_x, full_y);
sdl_input_t *sdl_input = NULL;
const SDL_PixelFormat *fmt = NULL;
if (!video->fullscreen)
SSNES_LOG("Creating window @ %ux%u\n", video->width, video->height);
@@ -284,17 +288,19 @@ static void* sdl_gfx_init(const video_info_t *video, const input_driver_t **inpu
SDL_ShowCursor(SDL_DISABLE);
const SDL_PixelFormat *fmt = vid->screen->format;
fmt = vid->screen->format;
if (vid->render32)
{
SSNES_LOG("SDL: Creating 32-bit buffer.\n");
vid->buffer = SDL_CreateRGBSurface(SDL_SWSURFACE, 256 * video->input_scale, 256 * video->input_scale, 32,
vid->buffer = SDL_CreateRGBSurface(SDL_SWSURFACE, SSNES_SCALE_BASE * video->input_scale,
SSNES_SCALE_BASE * video->input_scale, 32,
fmt->Rmask, fmt->Bmask, fmt->Gmask, fmt->Amask);
}
else
{
SSNES_LOG("SDL: Creating 15-bit buffer.\n");
vid->buffer = SDL_CreateRGBSurface(SDL_SWSURFACE, 256 * video->input_scale, 256 * video->input_scale, 15,
vid->buffer = SDL_CreateRGBSurface(SDL_SWSURFACE, SSNES_SCALE_BASE * video->input_scale,
SSNES_SCALE_BASE * video->input_scale, 15,
fmt->Rmask, fmt->Gmask, fmt->Bmask, fmt->Amask);
}
SSNES_LOG("[Debug]: SDL Pixel format: Rshift = %u, Gshift = %u, Bshift = %u\n",
@@ -306,20 +312,22 @@ static void* sdl_gfx_init(const video_info_t *video, const input_driver_t **inpu
goto error;
}
sdl_input_t *sdl_input = input_sdl.init();
sdl_input = (sdl_input_t*)input_sdl.init();
if (sdl_input)
{
*input = &input_sdl;
*input_data = sdl_input;
}
else
{
*input = NULL;
*input_data = NULL;
}
vid->rgb32 = video->rgb32;
sdl_init_font(vid, g_settings.video.font_path, g_settings.video.font_size);
if (fmt->Rshift == 10 && fmt->Gshift == 5 && fmt->Bshift == 0) // XRGB1555
{
SSNES_LOG("SDL: 15-bit format matches. Fast blit.\n");
@@ -462,9 +470,9 @@ static void check_window(sdl_video_t *vid)
}
}
static bool sdl_gfx_frame(void *data, const void* frame, unsigned width, unsigned height, unsigned pitch, const char *msg)
static bool sdl_gfx_frame(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch, const char *msg)
{
sdl_video_t *vid = data;
sdl_video_t *vid = (sdl_video_t*)data;
if (SDL_MUSTLOCK(vid->buffer))
SDL_LockSurface(vid->buffer);
@@ -472,41 +480,31 @@ static bool sdl_gfx_frame(void *data, const void* frame, unsigned width, unsigne
// :(
// 15-bit -> 32-bit (Sometimes 15-bit won't work on "modern" OSes :\)
if (vid->upsample)
{
convert_15bit_32bit(vid->buffer->pixels, vid->buffer->pitch, frame, width, height, pitch, vid->screen->format);
}
convert_15bit_32bit((uint32_t*)vid->buffer->pixels, vid->buffer->pitch, (const uint16_t*)frame, width, height, pitch, vid->screen->format);
// 15-bit -> 15-bit
else if (!vid->rgb32)
{
vid->convert_15_func(vid->buffer->pixels, vid->buffer->pitch, frame, width, height, pitch, vid->screen->format);
}
vid->convert_15_func((uint16_t*)vid->buffer->pixels, vid->buffer->pitch, (const uint16_t*)frame, width, height, pitch, vid->screen->format);
// 32-bit -> 15-bit
else if (vid->rgb32 && g_settings.video.force_16bit)
{
convert_32bit_15bit(vid->buffer->pixels, vid->buffer->pitch, frame, width, height, pitch, vid->screen->format);
}
convert_32bit_15bit((uint16_t*)vid->buffer->pixels, vid->buffer->pitch, (const uint32_t*)frame, width, height, pitch, vid->screen->format);
// 32-bit -> 32-bit
else
{
vid->convert_32_func(vid->buffer->pixels, vid->buffer->pitch, frame, width, height, pitch, vid->screen->format);
}
vid->convert_32_func((uint32_t*)vid->buffer->pixels, vid->buffer->pitch, (const uint32_t*)frame, width, height, pitch, vid->screen->format);
if (SDL_MUSTLOCK(vid->buffer))
SDL_UnlockSurface(vid->buffer);
SDL_Rect src = {
.x = 0,
.y = 0,
.w = width,
.h = height
};
SDL_Rect src = {0};
src.x = 0;
src.y = 0;
src.w = width;
src.h = height;
SDL_Rect dest = {
.x = 0,
.y = 0,
.w = vid->screen->w,
.h = vid->screen->h
};
SDL_Rect dest = {0};
dest.x = 0;
dest.y = 0;
dest.w = vid->screen->w;
dest.h = vid->screen->h;
SDL_SoftStretch(vid->buffer, &src, vid->screen, &dest);
@@ -535,7 +533,7 @@ static void sdl_gfx_set_nonblock_state(void *data, bool state)
static bool sdl_gfx_alive(void *data)
{
sdl_video_t *vid = data;
sdl_video_t *vid = (sdl_video_t*)data;
check_window(vid);
return !vid->quitting;
}
@@ -546,14 +544,14 @@ static bool sdl_gfx_focus(void *data)
return (SDL_GetAppState() & (SDL_APPINPUTFOCUS | SDL_APPACTIVE)) == (SDL_APPINPUTFOCUS | SDL_APPACTIVE);
}
const video_driver_t video_sdl = {
.init = sdl_gfx_init,
.frame = sdl_gfx_frame,
.alive = sdl_gfx_alive,
.set_nonblock_state = sdl_gfx_set_nonblock_state,
.focus = sdl_gfx_focus,
.free = sdl_gfx_free,
.ident = "sdl"
sdl_gfx_init,
sdl_gfx_frame,
sdl_gfx_set_nonblock_state,
sdl_gfx_alive,
sdl_gfx_focus,
NULL,
sdl_gfx_free,
"sdl"
};
+48 -33
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -17,8 +17,7 @@
#include "sdlwrap.h"
#include "SDL_syswm.h"
#include "general.h"
#include <assert.h>
#include "../general.h"
#ifdef __APPLE__
#include <OpenGL/OpenGL.h>
@@ -42,49 +41,54 @@ void sdlwrap_set_swap_interval(unsigned interval, bool inited)
{
g_interval = interval;
bool success = true;
#if SDL_MODERN
if (g_window)
SDL_GL_SetSwapInterval(g_interval);
success = SDL_GL_SetSwapInterval(g_interval) == 0;
#else
if (inited)
{
#if defined(_WIN32)
static BOOL (APIENTRY *wgl_swap_interval)(int) = NULL;
if (!wgl_swap_interval)
{
SDL_SYM_WRAP(wgl_swap_interval, "wglSwapIntervalEXT");
}
if (wgl_swap_interval) wgl_swap_interval(g_interval);
#elif defined(__APPLE__)
if (wgl_swap_interval)
success = wgl_swap_interval(g_interval);
#elif defined(__APPLE__) && defined(HAVE_OPENGL)
GLint val = g_interval;
CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &val);
success = CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &val) == 0;
#else
static int (*glx_swap_interval)(int) = NULL;
if (!glx_swap_interval)
{
SDL_SYM_WRAP(glx_swap_interval, "glXSwapIntervalSGI");
}
if (!glx_swap_interval)
{
SDL_SYM_WRAP(glx_swap_interval, "glXSwapIntervalMESA");
}
if (glx_swap_interval)
glx_swap_interval(g_interval);
if (glx_swap_interval)
success = glx_swap_interval(g_interval) == 0;
else
SSNES_WARN("Could not find GLX VSync call. :(\n");
SSNES_WARN("Could not find GLX VSync call.\n");
#endif
}
#endif
if (!success)
SSNES_WARN("Failed to set swap interval!\n");
}
bool sdlwrap_init(void)
{
#if SDL_MODERN
return SDL_VideoInit(NULL) == 0;
bool ret = SDL_VideoInit(NULL) == 0;
#else
return SDL_Init(SDL_INIT_VIDEO) == 0;
if (SDL_WasInit(SDL_INIT_VIDEO))
return true;
bool ret = SDL_Init(SDL_INIT_VIDEO) == 0;
#endif
if (!ret)
SSNES_ERR("Failed to init SDL video!\n");
return ret;
}
#if SDL_MODERN
@@ -132,21 +136,29 @@ bool sdlwrap_set_video_mode(
#endif
#if SDL_MODERN
if (bits == 15)
{
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
}
g_window = SDL_CreateWindow("SSNES", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | (fullscreen ? SDL_WINDOW_FULLSCREEN : resizable));
if (!g_window)
return false;
g_ctx = SDL_GL_CreateContext(g_window);
if (bits == 15)
{
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
}
g_window = SDL_CreateWindow("SSNES", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | (fullscreen ? SDL_WINDOW_FULLSCREEN : resizable));
if (!g_window)
{
SSNES_ERR("Failed to create SDL window!\n");
return false;
}
g_ctx = SDL_GL_CreateContext(g_window);
#else
if (!SDL_SetVideoMode(width, height, bits,
SDL_OPENGL | (fullscreen ? SDL_FULLSCREEN : resizable)))
{
SSNES_ERR("Failed to create SDL window!\n");
return false;
}
#endif
int attr = 0;
@@ -227,7 +239,7 @@ bool sdlwrap_key_pressed(int key)
// 1.2 specific workaround for tiling WMs. In 1.3 we call GetSize directly, so we don't need to rely on
// proper event handling (I hope).
#if !defined(__APPLE__) && !defined(_WIN32) && !SDL_MODERN
#if !defined(__APPLE__) && !defined(_WIN32) && !SDL_MODERN && !defined(XENON)
static void sdlwrap_get_window_size(unsigned *width, unsigned *height)
{
SDL_SysWMinfo info;
@@ -305,7 +317,7 @@ void sdlwrap_check_window(bool *quit,
}
}
#if !defined(__APPLE__) && !defined(_WIN32)
#if !defined(__APPLE__) && !defined(_WIN32) && !defined(XENON)
// Hack to workaround limitations in tiling WMs ...
if (!*resize && !g_fullscreen)
{
@@ -325,7 +337,10 @@ void sdlwrap_check_window(bool *quit,
bool sdlwrap_get_wm_info(SDL_SysWMinfo *info)
{
#if SDL_MODERN
#ifdef XENON
(void)info;
return false;
#elif SDL_MODERN
if (g_window)
return SDL_GetWindowWMInfo(g_window, info);
else
+4 -4
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -21,7 +21,7 @@
#ifndef __SDLWRAP_H
#define __SDLWRAP_H
#include <stdbool.h>
#include "../boolean.h"
#include "SDL.h"
#include "SDL_version.h"
@@ -33,9 +33,9 @@
#define SDL_MODERN 0
#endif
// Not legal to cast void* to fn-pointer. Need workaround to be compliant.
// Not legal to cast (void*) to fn-pointer. Need workaround to be compliant.
#define SDL_SYM_WRAP(sym, symbol) { \
assert(sizeof(void*) == sizeof(void (*)(void))); \
ssnes_assert(sizeof(void*) == sizeof(void (*)(void))); \
void *sym__ = SDL_GL_GetProcAddress(symbol); \
memcpy(&(sym), &sym__, sizeof(void*)); \
}
+246 -149
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -18,12 +18,13 @@
#include "shader_cg.h"
#include <Cg/cg.h>
#include <Cg/cgGL.h>
#include "general.h"
#include "../general.h"
#include <string.h>
#include "strl.h"
#include "conf/config_file.h"
#include "../strl.h"
#include "../conf/config_file.h"
#include "image.h"
#include "dynamic.h"
#include "../dynamic.h"
#include "../posix_string.h"
#ifdef HAVE_CONFIGFILE
#include "snes_state.h"
@@ -32,7 +33,7 @@
//#define SSNES_CG_DEBUG
// Used when we call deactivate() since just unbinding the program didn't seem to work... :(
static const char* stock_cg_program =
static const char *stock_cg_program =
"void main_vertex"
"("
" float4 position : POSITION,"
@@ -95,6 +96,7 @@ struct cg_fbo_params
#define MAX_SHADERS 16
#define MAX_TEXTURES 8
#define MAX_VARIABLES 64
#define PREV_TEXTURES 7
struct cg_program
{
@@ -104,15 +106,17 @@ struct cg_program
CGparameter tex_size_f;
CGparameter out_size_f;
CGparameter frame_cnt_f;
CGparameter frame_dir_f;
CGparameter vid_size_v;
CGparameter tex_size_v;
CGparameter out_size_v;
CGparameter frame_cnt_v;
CGparameter frame_dir_v;
CGparameter mvp;
struct cg_fbo_params fbo[MAX_SHADERS];
struct cg_fbo_params orig;
struct cg_fbo_params prev;
struct cg_fbo_params prev[PREV_TEXTURES];
};
#define FILTER_UNSPEC 0
@@ -131,7 +135,19 @@ static unsigned lut_textures[MAX_TEXTURES];
static unsigned lut_textures_num = 0;
static char lut_textures_uniform[MAX_TEXTURES][64];
static CGparameter cg_attribs[PREV_TEXTURES + 1 + MAX_SHADERS];
static unsigned cg_attrib_index;
#ifdef HAVE_CONFIGFILE
static snes_tracker_t *snes_tracker = NULL;
#endif
static void gl_cg_reset_attrib(void)
{
for (unsigned i = 0; i < cg_attrib_index; i++)
cgGLDisableClientState(cg_attribs[i]);
cg_attrib_index = 0;
}
void gl_cg_set_proj_matrix(void)
{
@@ -153,113 +169,124 @@ void gl_cg_set_params(unsigned width, unsigned height,
const struct gl_tex_info *fbo_info,
unsigned fbo_info_cnt)
{
if (cg_active && active_index > 0)
if (!cg_active || (active_index == 0))
return;
// Set frame.
set_param_2f(prg[active_index].vid_size_f, width, height);
set_param_2f(prg[active_index].tex_size_f, tex_width, tex_height);
set_param_2f(prg[active_index].out_size_f, out_width, out_height);
set_param_1f(prg[active_index].frame_cnt_f, (float)frame_count);
set_param_1f(prg[active_index].frame_dir_f, g_extern.frame_is_reverse ? -1.0 : 1.0);
set_param_2f(prg[active_index].vid_size_v, width, height);
set_param_2f(prg[active_index].tex_size_v, tex_width, tex_height);
set_param_2f(prg[active_index].out_size_v, out_width, out_height);
set_param_1f(prg[active_index].frame_cnt_v, (float)frame_count);
set_param_1f(prg[active_index].frame_dir_v, g_extern.frame_is_reverse ? -1.0 : 1.0);
// Set orig texture.
CGparameter param = prg[active_index].orig.tex;
if (param)
{
// Set frame.
set_param_2f(prg[active_index].vid_size_f, width, height);
set_param_2f(prg[active_index].tex_size_f, tex_width, tex_height);
set_param_2f(prg[active_index].out_size_f, out_width, out_height);
set_param_1f(prg[active_index].frame_cnt_f, (float)frame_count);
cgGLSetTextureParameter(param, info->tex);
cgGLEnableTextureParameter(param);
}
set_param_2f(prg[active_index].vid_size_v, width, height);
set_param_2f(prg[active_index].tex_size_v, tex_width, tex_height);
set_param_2f(prg[active_index].out_size_v, out_width, out_height);
set_param_1f(prg[active_index].frame_cnt_v, (float)frame_count);
set_param_2f(prg[active_index].orig.vid_size_v, info->input_size[0], info->input_size[1]);
set_param_2f(prg[active_index].orig.vid_size_f, info->input_size[0], info->input_size[1]);
set_param_2f(prg[active_index].orig.tex_size_v, info->tex_size[0], info->tex_size[1]);
set_param_2f(prg[active_index].orig.tex_size_f, info->tex_size[0], info->tex_size[1]);
if (prg[active_index].orig.coord)
{
cgGLSetParameterPointer(prg[active_index].orig.coord, 2, GL_FLOAT, 0, info->coord);
cgGLEnableClientState(prg[active_index].orig.coord);
cg_attribs[cg_attrib_index++] = prg[active_index].orig.coord;
}
// Set orig texture.
CGparameter param = prg[active_index].orig.tex;
// Set prev textures.
for (unsigned i = 0; i < PREV_TEXTURES; i++)
{
param = prg[active_index].prev[i].tex;
if (param)
{
cgGLSetTextureParameter(param, info->tex);
cgGLSetTextureParameter(param, prev_info[i].tex);
cgGLEnableTextureParameter(param);
}
set_param_2f(prg[active_index].orig.vid_size_v, info->input_size[0], info->input_size[1]);
set_param_2f(prg[active_index].orig.vid_size_f, info->input_size[0], info->input_size[1]);
set_param_2f(prg[active_index].orig.tex_size_v, info->tex_size[0], info->tex_size[1]);
set_param_2f(prg[active_index].orig.tex_size_f, info->tex_size[0], info->tex_size[1]);
if (prg[active_index].orig.coord)
{
cgGLSetParameterPointer(prg[active_index].orig.coord, 2, GL_FLOAT, 0, info->coord);
cgGLEnableClientState(prg[active_index].orig.coord);
}
set_param_2f(prg[active_index].prev[i].vid_size_v, prev_info[i].input_size[0], prev_info[i].input_size[1]);
set_param_2f(prg[active_index].prev[i].vid_size_f, prev_info[i].input_size[0], prev_info[i].input_size[1]);
set_param_2f(prg[active_index].prev[i].tex_size_v, prev_info[i].tex_size[0], prev_info[i].tex_size[1]);
set_param_2f(prg[active_index].prev[i].tex_size_f, prev_info[i].tex_size[0], prev_info[i].tex_size[1]);
// Set prev texture
param = prg[active_index].prev.tex;
if (prg[active_index].prev[i].coord)
{
cgGLSetParameterPointer(prg[active_index].prev[i].coord, 2, GL_FLOAT, 0, prev_info[i].coord);
cgGLEnableClientState(prg[active_index].prev[i].coord);
cg_attribs[cg_attrib_index++] = prg[active_index].prev[i].coord;
}
}
// Set lookup textures.
for (unsigned i = 0; i < lut_textures_num; i++)
{
CGparameter param = cgGetNamedParameter(prg[active_index].fprg, lut_textures_uniform[i]);
if (param)
{
cgGLSetTextureParameter(param, prev_info->tex);
cgGLSetTextureParameter(param, lut_textures[i]);
cgGLEnableTextureParameter(param);
}
}
set_param_2f(prg[active_index].prev.vid_size_v, prev_info->input_size[0], prev_info->input_size[1]);
set_param_2f(prg[active_index].prev.vid_size_f, prev_info->input_size[0], prev_info->input_size[1]);
set_param_2f(prg[active_index].prev.tex_size_v, prev_info->tex_size[0], prev_info->tex_size[1]);
set_param_2f(prg[active_index].prev.tex_size_f, prev_info->tex_size[0], prev_info->tex_size[1]);
if (prg[active_index].prev.coord)
// Set FBO textures.
if (active_index > 2)
{
for (unsigned i = 0; i < fbo_info_cnt; i++)
{
cgGLSetParameterPointer(prg[active_index].prev.coord, 2, GL_FLOAT, 0, prev_info->coord);
cgGLEnableClientState(prg[active_index].prev.coord);
}
// Set lookup textures.
for (unsigned i = 0; i < lut_textures_num; i++)
{
CGparameter param = cgGetNamedParameter(prg[active_index].fprg, lut_textures_uniform[i]);
if (param)
if (prg[active_index].fbo[i].tex)
{
cgGLSetTextureParameter(param, lut_textures[i]);
cgGLEnableTextureParameter(param);
cgGLSetTextureParameter(prg[active_index].fbo[i].tex, fbo_info[i].tex);
cgGLEnableTextureParameter(prg[active_index].fbo[i].tex);
}
}
// Set FBO textures.
if (active_index > 2)
{
for (unsigned i = 0; i < fbo_info_cnt; i++)
set_param_2f(prg[active_index].fbo[i].vid_size_v,
fbo_info[i].input_size[0], fbo_info[i].input_size[1]);
set_param_2f(prg[active_index].fbo[i].vid_size_f,
fbo_info[i].input_size[0], fbo_info[i].input_size[1]);
set_param_2f(prg[active_index].fbo[i].tex_size_v,
fbo_info[i].tex_size[0], fbo_info[i].tex_size[1]);
set_param_2f(prg[active_index].fbo[i].tex_size_f,
fbo_info[i].tex_size[0], fbo_info[i].tex_size[1]);
if (prg[active_index].fbo[i].coord)
{
if (prg[active_index].fbo[i].tex)
{
cgGLSetTextureParameter(prg[active_index].fbo[i].tex, fbo_info[i].tex);
cgGLEnableTextureParameter(prg[active_index].fbo[i].tex);
}
set_param_2f(prg[active_index].fbo[i].vid_size_v,
fbo_info[i].input_size[0], fbo_info[i].input_size[1]);
set_param_2f(prg[active_index].fbo[i].vid_size_f,
fbo_info[i].input_size[0], fbo_info[i].input_size[1]);
set_param_2f(prg[active_index].fbo[i].tex_size_v,
fbo_info[i].tex_size[0], fbo_info[i].tex_size[1]);
set_param_2f(prg[active_index].fbo[i].tex_size_f,
fbo_info[i].tex_size[0], fbo_info[i].tex_size[1]);
if (prg[active_index].fbo[i].coord)
{
cgGLSetParameterPointer(prg[active_index].fbo[i].coord, 2, GL_FLOAT, 0, fbo_info[i].coord);
cgGLEnableClientState(prg[active_index].fbo[i].coord);
}
}
}
// Set state parameters
if (snes_tracker)
{
static struct snes_tracker_uniform info[MAX_VARIABLES];
static unsigned cnt = 0;
if (active_index == 1)
cnt = snes_get_uniform(snes_tracker, info, MAX_VARIABLES, frame_count);
for (unsigned i = 0; i < cnt; i++)
{
CGparameter param_v = cgGetNamedParameter(prg[active_index].vprg, info[i].id);
CGparameter param_f = cgGetNamedParameter(prg[active_index].fprg, info[i].id);
set_param_1f(param_v, info[i].value);
set_param_1f(param_f, info[i].value);
cgGLSetParameterPointer(prg[active_index].fbo[i].coord, 2, GL_FLOAT, 0, fbo_info[i].coord);
cgGLEnableClientState(prg[active_index].fbo[i].coord);
cg_attribs[cg_attrib_index++] = prg[active_index].fbo[i].coord;
}
}
}
#ifdef HAVE_CONFIGFILE
// Set state parameters
if (snes_tracker)
{
static struct snes_tracker_uniform info[MAX_VARIABLES];
static unsigned cnt = 0;
if (active_index == 1)
cnt = snes_get_uniform(snes_tracker, info, MAX_VARIABLES, frame_count);
for (unsigned i = 0; i < cnt; i++)
{
CGparameter param_v = cgGetNamedParameter(prg[active_index].vprg, info[i].id);
CGparameter param_f = cgGetNamedParameter(prg[active_index].fprg, info[i].id);
set_param_1f(param_v, info[i].value);
set_param_1f(param_f, info[i].value);
}
}
#endif
}
void gl_cg_deinit(void)
@@ -267,6 +294,8 @@ void gl_cg_deinit(void)
if (!cg_active)
return;
gl_cg_reset_attrib();
cg_active = false;
cg_shader_num = 0;
memset(prg, 0, sizeof(prg));
@@ -276,45 +305,58 @@ void gl_cg_deinit(void)
glDeleteTextures(lut_textures_num, lut_textures);
lut_textures_num = 0;
#ifdef HAVE_CONFIGFILE
if (snes_tracker)
{
snes_tracker_free(snes_tracker);
snes_tracker = NULL;
}
#endif
#ifndef __CELLOS_LV2__
cgDestroyContext(cgCtx);
#endif
}
#define SET_LISTING_INDEX(type, index) \
{ \
const char *list = cgGetLastListing(cgCtx); \
if (list) \
listing_##type[index] = strdup(list); \
}
#define SET_LISTING(type) \
{ \
const char *list = cgGetLastListing(cgCtx); \
if (list) \
listing_##type = strdup(list); \
}
static bool load_plain(const char *path)
{
SSNES_LOG("Loading Cg file: %s\n", path);
char *listing[3] = {NULL};
const char *list = NULL;
char *listing_v[3] = {NULL};
char *listing_f[3] = {NULL};
prg[0].fprg = cgCreateProgram(cgCtx, CG_SOURCE, stock_cg_program, cgFProf, "main_fragment", 0);
SET_LISTING_INDEX(f, 0);
prg[0].vprg = cgCreateProgram(cgCtx, CG_SOURCE, stock_cg_program, cgVProf, "main_vertex", 0);
list = cgGetLastListing(cgCtx);
if (list)
listing[0] = strdup(list);
SET_LISTING_INDEX(v, 0);
prg[1].fprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, path, cgFProf, "main_fragment", 0);
SET_LISTING_INDEX(f, 1);
prg[1].vprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, path, cgVProf, "main_vertex", 0);
list = cgGetLastListing(cgCtx);
if (list)
listing[1] = strdup(list);
SET_LISTING_INDEX(v, 1);
if (*g_settings.video.second_pass_shader && g_settings.video.render_to_texture)
{
SSNES_LOG("Loading 2nd pass: %s\n", g_settings.video.second_pass_shader);
prg[2].fprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, g_settings.video.second_pass_shader, cgFProf, "main_fragment", 0);
SET_LISTING_INDEX(f, 2);
prg[2].vprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, g_settings.video.second_pass_shader, cgVProf, "main_vertex", 0);
SET_LISTING_INDEX(v, 2);
list = cgGetLastListing(cgCtx);
if (list)
listing[2] = strdup(list);
cg_shader_num = 2;
}
else
@@ -329,8 +371,10 @@ static bool load_plain(const char *path)
{
CGerror err = cgGetError();
SSNES_ERR("CG error: %s\n", cgGetErrorString(err));
if (listing[i])
SSNES_ERR("%s\n", listing[i]);
if (listing_v[i])
SSNES_ERR("Vertex:\n%s\n", listing_v[i]);
else if (listing_f[i])
SSNES_ERR("Fragment:\n%s\n", listing_f[i]);
goto error;
}
@@ -338,13 +382,19 @@ static bool load_plain(const char *path)
cgGLLoadProgram(prg[i].vprg);
}
for (unsigned i = 0; i < 3; i++)
{
free(listing_v[i]);
free(listing_f[i]);
}
return true;
error:
for (unsigned i = 0; i < 3; i++)
{
if (listing[i])
free(listing[i]);
free(listing_v[i]);
free(listing_f[i]);
}
return false;
}
@@ -397,8 +447,10 @@ static bool load_textures(const char *dir_path, config_file_t *conf)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, smooth ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, smooth ? GL_LINEAR : GL_NEAREST);
#ifndef __CELLOS_LV2__
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glPixelStorei(GL_UNPACK_ROW_LENGTH, img.width);
#endif
glTexImage2D(GL_TEXTURE_2D,
0, GL_RGBA, img.width, img.height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, img.pixels);
@@ -432,6 +484,13 @@ static bool load_imports(const char *dir_path, config_file_t *conf)
struct snes_tracker_uniform_info info[MAX_VARIABLES];
unsigned info_cnt = 0;
struct snes_tracker_info tracker_info = {0};
#ifdef HAVE_PYTHON
char script_path[128];
char *script = NULL;
char *script_class = NULL;
#endif
const char *id = strtok(imports, ";");
while (id && info_cnt < MAX_VARIABLES)
@@ -465,7 +524,7 @@ static bool load_imports(const char *dir_path, config_file_t *conf)
}
enum snes_tracker_type tracker_type;
enum snes_ram_type ram_type = SNES_MEMORY_WRAM;
enum snes_ram_type ram_type = SSNES_STATE_NONE;
if (strcmp(semantic, "capture") == 0)
tracker_type = SSNES_STATE_CAPTURE;
@@ -490,8 +549,8 @@ static bool load_imports(const char *dir_path, config_file_t *conf)
unsigned addr = 0;
#ifdef HAVE_PYTHON
if (tracker_type != SSNES_STATE_PYTHON)
{
#endif
{
unsigned input_slot = 0;
if (config_get_hex(conf, input_slot_buf, &input_slot))
{
@@ -525,11 +584,9 @@ static bool load_imports(const char *dir_path, config_file_t *conf)
SSNES_ERR("No address assigned to semantic.\n");
goto error;
}
#ifdef HAVE_PYTHON
}
#endif
int memtype = 0;
unsigned memtype;
switch (ram_type)
{
case SSNES_STATE_WRAM:
@@ -549,10 +606,10 @@ static bool load_imports(const char *dir_path, config_file_t *conf)
break;
default:
memtype = SNES_MEMORY_WRAM;
memtype = -1u;
}
if (addr >= psnes_get_memory_size(memtype))
if ((memtype != -1u) && (addr >= psnes_get_memory_size(memtype)))
{
SSNES_ERR("Address out of bounds.\n");
goto error;
@@ -574,20 +631,15 @@ static bool load_imports(const char *dir_path, config_file_t *conf)
id = strtok(NULL, ";");
}
struct snes_tracker_info tracker_info = {
.wram = psnes_get_memory_data(SNES_MEMORY_WRAM),
.vram = psnes_get_memory_data(SNES_MEMORY_VRAM),
.cgram = psnes_get_memory_data(SNES_MEMORY_CGRAM),
.oam = psnes_get_memory_data(SNES_MEMORY_OAM),
.apuram = psnes_get_memory_data(SNES_MEMORY_APURAM),
.info = info,
.info_elem = info_cnt
};
tracker_info.wram = psnes_get_memory_data(SNES_MEMORY_WRAM);
tracker_info.vram = psnes_get_memory_data(SNES_MEMORY_VRAM);
tracker_info.cgram = psnes_get_memory_data(SNES_MEMORY_CGRAM);
tracker_info.oam = psnes_get_memory_data(SNES_MEMORY_OAM);
tracker_info.apuram = psnes_get_memory_data(SNES_MEMORY_APURAM);
tracker_info.info = info;
tracker_info.info_elem = info_cnt;
#ifdef HAVE_PYTHON
char script_path[128];
char *script = NULL;
char *script_class = NULL;
if (config_get_string(conf, "import_script", &script))
{
strlcpy(script_path, dir_path, sizeof(script_path));
@@ -613,7 +665,6 @@ static bool load_imports(const char *dir_path, config_file_t *conf)
#endif
free(imports);
return true;
error:
@@ -637,6 +688,11 @@ static bool load_preset(const char *path)
cgGLLoadProgram(prg[0].fprg);
cgGLLoadProgram(prg[0].vprg);
int shaders;
// Basedir.
char dir_path[PATH_MAX];
char *ptr = NULL;
SSNES_LOG("Loading Cg meta-shader: %s\n", path);
config_file_t *conf = config_file_new(path);
if (!conf)
@@ -645,7 +701,6 @@ static bool load_preset(const char *path)
goto error;
}
int shaders;
if (!config_get_int(conf, "shaders", &shaders))
{
SSNES_ERR("Cannot find \"shaders\" param.\n");
@@ -671,7 +726,7 @@ static bool load_preset(const char *path)
prg[shaders + 1] = prg[0];
// Check filter params.
for (unsigned i = 0; i < shaders; i++)
for (int i = 0; i < shaders; i++)
{
bool smooth;
char filter_name_buf[64];
@@ -681,7 +736,7 @@ static bool load_preset(const char *path)
}
// Bigass for-loop ftw. Check scaling params.
for (unsigned i = 0; i < shaders; i++)
for (int i = 0; i < shaders; i++)
{
char *scale_type = NULL;
char *scale_type_x = NULL;
@@ -723,8 +778,8 @@ static bool load_preset(const char *path)
scale->type_y = SSNES_SCALE_INPUT;
scale->scale_x = 1.0;
scale->scale_y = 1.0;
scale->abs_x = 256;
scale->abs_y = 224;
scale->abs_x = g_extern.system.geom.base_width;
scale->abs_y = g_extern.system.geom.base_height;
if (strcmp(scale_type_x, "source") == 0)
scale->type_x = SSNES_SCALE_INPUT;
@@ -806,10 +861,8 @@ static bool load_preset(const char *path)
free(scale_type_y);
}
// Basedir.
char dir_path[256];
strlcpy(dir_path, path, sizeof(dir_path));
char *ptr = strrchr(dir_path, '/');
ptr = strrchr(dir_path, '/');
if (!ptr) ptr = strrchr(dir_path, '\\');
if (ptr)
ptr[1] = '\0';
@@ -817,11 +870,11 @@ static bool load_preset(const char *path)
dir_path[0] = '\0';
// Finally load shaders :)
for (unsigned i = 0; i < shaders; i++)
for (int i = 0; i < shaders; i++)
{
char *shader_path;
char attr_buf[64];
char path_buf[512];
char path_buf[PATH_MAX];
print_buf(attr_buf, "shader%u", i);
if (config_get_string(conf, attr_buf, &shader_path))
@@ -839,19 +892,31 @@ static bool load_preset(const char *path)
SSNES_LOG("Loading Cg shader: \"%s\".\n", path_buf);
struct cg_program *prog = &prg[i + 1];
char *listing_f = NULL;
prog->fprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, path_buf, cgFProf, "main_fragment", 0);
SET_LISTING(f);
char *listing_v = NULL;
prog->vprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, path_buf, cgVProf, "main_vertex", 0);
SET_LISTING(v);
if (!prog->fprg || !prog->vprg)
{
const char *listing = cgGetLastListing(cgCtx);
CGerror err = cgGetError();
SSNES_ERR("CG error: %s\n", cgGetErrorString(err));
if (listing)
SSNES_ERR("%s\n", listing);
if (listing_v)
SSNES_ERR("Vertex:\n%s\n", listing_v);
else if (listing_f)
SSNES_ERR("Fragment:\n%s\n", listing_f);
free(listing_f);
free(listing_v);
goto error;
}
free(listing_f);
free(listing_v);
cgGLLoadProgram(prog->fprg);
cgGLLoadProgram(prog->vprg);
}
@@ -884,6 +949,9 @@ error:
bool gl_cg_init(const char *path)
{
#ifdef __CELLOS_LV2__
cgRTCgcInit();
#endif
cgCtx = cgCreateContext();
if (cgCtx == NULL)
{
@@ -932,10 +1000,12 @@ bool gl_cg_init(const char *path)
prg[i].tex_size_f = cgGetNamedParameter(prg[i].fprg, "IN.texture_size");
prg[i].out_size_f = cgGetNamedParameter(prg[i].fprg, "IN.output_size");
prg[i].frame_cnt_f = cgGetNamedParameter(prg[i].fprg, "IN.frame_count");
prg[i].frame_dir_f = cgGetNamedParameter(prg[i].fprg, "IN.frame_direction");
prg[i].vid_size_v = cgGetNamedParameter(prg[i].vprg, "IN.video_size");
prg[i].tex_size_v = cgGetNamedParameter(prg[i].vprg, "IN.texture_size");
prg[i].out_size_v = cgGetNamedParameter(prg[i].vprg, "IN.output_size");
prg[i].frame_cnt_v = cgGetNamedParameter(prg[i].vprg, "IN.frame_count");
prg[i].frame_dir_v = cgGetNamedParameter(prg[i].vprg, "IN.frame_direction");
prg[i].mvp = cgGetNamedParameter(prg[i].vprg, "modelViewProj");
if (prg[i].mvp)
cgGLSetStateMatrixParameter(prg[i].mvp, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);
@@ -947,12 +1017,37 @@ bool gl_cg_init(const char *path)
prg[i].orig.tex_size_f = cgGetNamedParameter(prg[i].fprg, "ORIG.texture_size");
prg[i].orig.coord = cgGetNamedParameter(prg[i].vprg, "ORIG.tex_coord");
prg[i].prev.tex = cgGetNamedParameter(prg[i].fprg, "PREV.texture");
prg[i].prev.vid_size_v = cgGetNamedParameter(prg[i].vprg, "PREV.video_size");
prg[i].prev.vid_size_f = cgGetNamedParameter(prg[i].fprg, "PREV.video_size");
prg[i].prev.tex_size_v = cgGetNamedParameter(prg[i].vprg, "PREV.texture_size");
prg[i].prev.tex_size_f = cgGetNamedParameter(prg[i].fprg, "PREV.texture_size");
prg[i].prev.coord = cgGetNamedParameter(prg[i].vprg, "PREV.tex_coord");
for (unsigned j = 0; j < PREV_TEXTURES; j++)
{
char attr_buf_tex[64];
char attr_buf_vid_size[64];
char attr_buf_tex_size[64];
char attr_buf_coord[64];
static const char *prev_names[PREV_TEXTURES] = {
"PREV",
"PREV1",
"PREV2",
"PREV3",
"PREV4",
"PREV5",
"PREV6",
};
snprintf(attr_buf_tex, sizeof(attr_buf_tex), "%s.texture", prev_names[j]);
snprintf(attr_buf_vid_size, sizeof(attr_buf_vid_size), "%s.video_size", prev_names[j]);
snprintf(attr_buf_tex_size, sizeof(attr_buf_tex_size), "%s.texture_size", prev_names[j]);
snprintf(attr_buf_coord, sizeof(attr_buf_coord), "%s.tex_coord", prev_names[j]);
prg[i].prev[j].tex = cgGetNamedParameter(prg[i].fprg, attr_buf_tex);
prg[i].prev[j].vid_size_v = cgGetNamedParameter(prg[i].vprg, attr_buf_vid_size);
prg[i].prev[j].vid_size_f = cgGetNamedParameter(prg[i].fprg, attr_buf_vid_size);
prg[i].prev[j].tex_size_v = cgGetNamedParameter(prg[i].vprg, attr_buf_tex_size);
prg[i].prev[j].tex_size_f = cgGetNamedParameter(prg[i].fprg, attr_buf_tex_size);
prg[i].prev[j].coord = cgGetNamedParameter(prg[i].vprg, attr_buf_coord);
}
for (unsigned j = 0; j < i - 1; j++)
{
@@ -985,6 +1080,8 @@ void gl_cg_use(unsigned index)
{
if (cg_active && prg[index].vprg && prg[index].fprg)
{
gl_cg_reset_attrib();
active_index = index;
cgGLBindProgram(prg[index].vprg);
cgGLBindProgram(prg[index].fprg);
+2 -2
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -19,7 +19,7 @@
#ifndef __SSNES_CG_H
#define __SSNES_CG_H
#include <stdbool.h>
#include "../boolean.h"
#include "gl_common.h"
bool gl_cg_init(const char *path);
+248 -150
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -15,13 +15,14 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdbool.h>
#include "../boolean.h"
#include <string.h>
#include "general.h"
#include "../general.h"
#include "shader_glsl.h"
#include "strl.h"
#include "../strl.h"
#include "../posix_string.h"
#include "snes_state.h"
#include "dynamic.h"
#include "../dynamic.h"
#ifdef __APPLE__
#include <OpenGL/gl.h>
@@ -36,6 +37,7 @@
#include "sdlwrap.h"
#include "SDL_opengl.h"
#include <stdlib.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
@@ -55,6 +57,7 @@
#define pglLinkProgram glLinkProgram
#define pglGetUniformLocation glGetUniformLocation
#define pglUniform1i glUniform1i
#define pglUniform1f glUniform1f
#define pglUniform2fv glUniform2fv
#define pglUniform4fv glUniform4fv
#define pglGetShaderiv glGetShaderiv
@@ -65,6 +68,7 @@
#define pglGetAttachedShaders glGetAttachedShaders
#define pglGetAttribLocation glGetAttribLocation
#define pglEnableVertexAttribArray glEnableVertexAttribArray
#define pglDisableVertexAttribArray glDisableVertexAttribArray
#define pglVertexAttribPointer glVertexAttribPointer
#else
static PFNGLCREATEPROGRAMPROC pglCreateProgram = NULL;
@@ -78,6 +82,7 @@ static PFNGLDETACHSHADERPROC pglDetachShader = NULL;
static PFNGLLINKPROGRAMPROC pglLinkProgram = NULL;
static PFNGLGETUNIFORMLOCATIONPROC pglGetUniformLocation = NULL;
static PFNGLUNIFORM1IPROC pglUniform1i = NULL;
static PFNGLUNIFORM1FPROC pglUniform1f = NULL;
static PFNGLUNIFORM2FVPROC pglUniform2fv = NULL;
static PFNGLUNIFORM4FVPROC pglUniform4fv = NULL;
static PFNGLGETSHADERIVPROC pglGetShaderiv = NULL;
@@ -88,12 +93,14 @@ static PFNGLDELETEPROGRAMPROC pglDeleteProgram = NULL;
static PFNGLGETATTACHEDSHADERSPROC pglGetAttachedShaders = NULL;
static PFNGLGETATTRIBLOCATIONPROC pglGetAttribLocation = NULL;
static PFNGLENABLEVERTEXATTRIBARRAYPROC pglEnableVertexAttribArray = NULL;
static PFNGLDISABLEVERTEXATTRIBARRAYPROC pglDisableVertexAttribArray = NULL;
static PFNGLVERTEXATTRIBPOINTERPROC pglVertexAttribPointer = NULL;
#endif
#define MAX_PROGRAMS 16
#define MAX_TEXTURES 8
#define MAX_VARIABLES 256
#define PREV_TEXTURES 7
enum filter_type
{
@@ -116,10 +123,14 @@ static char gl_teximage_uniforms[MAX_TEXTURES][64];
static snes_tracker_t *gl_snes_tracker = NULL;
static struct snes_tracker_uniform_info gl_tracker_info[MAX_VARIABLES];
static unsigned gl_tracker_info_cnt = 0;
static char gl_tracker_script[256];
static char gl_tracker_script[PATH_MAX];
static char gl_tracker_script_class[64];
static xmlChar *gl_script_program = NULL;
static GLint gl_attribs[PREV_TEXTURES + 1 + MAX_PROGRAMS];
static unsigned gl_attrib_index = 0;
struct shader_program
{
char *vertex;
@@ -136,6 +147,21 @@ struct shader_program
bool valid_scale;
};
static const char *stock_vertex =
"varying vec4 color;\n"
"void main() {\n"
" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
" gl_TexCoord[0] = gl_MultiTexCoord0;\n"
" color = gl_Color;\n"
"}";
static const char *stock_fragment =
"uniform sampler2D rubyTexture;\n"
"varying vec4 color;\n"
"void main() {\n"
" gl_FragColor = color * texture2D(rubyTexture, gl_TexCoord[0].xy);\n"
"}";
static bool get_xml_attrs(struct shader_program *prog, xmlNodePtr ptr)
{
prog->scale_x = 1.0;
@@ -309,6 +335,8 @@ static bool get_texture_image(const char *shader_path, xmlNodePtr ptr)
xmlChar *filename = xmlGetProp(ptr, (const xmlChar*)"file");
xmlChar *filter = xmlGetProp(ptr, (const xmlChar*)"filter");
xmlChar *id = xmlGetProp(ptr, (const xmlChar*)"id");
char *last = NULL;
struct texture_image img;
if (!id)
{
@@ -325,16 +353,15 @@ static bool get_texture_image(const char *shader_path, xmlNodePtr ptr)
if (filter && strcmp((const char*)filter, "nearest") == 0)
linear = false;
char tex_path[256];
char tex_path[PATH_MAX];
strlcpy(tex_path, shader_path, sizeof(tex_path));
char *last = strrchr(tex_path, '/');
last = strrchr(tex_path, '/');
if (!last) last = strrchr(tex_path, '\\');
if (last) last[1] = '\0';
strlcat(tex_path, (const char*)filename, sizeof(tex_path));
struct texture_image img;
SSNES_LOG("Loading texture image from: \"%s\" ...\n", tex_path);
if (!texture_image_load(tex_path, &img))
{
@@ -453,13 +480,18 @@ static bool get_import_value(xmlNodePtr ptr)
xmlChar *cgram = xmlGetProp(ptr, (const xmlChar*)"cgram");
xmlChar *bitmask = xmlGetProp(ptr, (const xmlChar*)"mask");
unsigned memtype;
enum snes_tracker_type tracker_type;
enum snes_ram_type ram_type = SSNES_STATE_NONE;
uint32_t addr = 0;
unsigned mask_value = 0;
if (!semantic || !id)
{
SSNES_ERR("No semantic or ID for import value!\n");
goto error;
}
enum snes_tracker_type tracker_type;
if (strcmp((const char*)semantic, "capture") == 0)
tracker_type = SSNES_STATE_CAPTURE;
@@ -481,13 +513,10 @@ static bool get_import_value(xmlNodePtr ptr)
goto error;
}
enum snes_ram_type ram_type = SSNES_STATE_WRAM;
uint32_t addr = 0;
#ifdef HAVE_PYTHON
if (tracker_type != SSNES_STATE_PYTHON)
{
#endif
{
if (input)
{
unsigned slot = strtoul((const char*)input, NULL, 0);
@@ -515,11 +544,8 @@ static bool get_import_value(xmlNodePtr ptr)
SSNES_ERR("No RAM address specificed for import value.\n");
goto error;
}
#ifdef HAVE_PYTHON
}
#endif
int memtype = 0;
switch (ram_type)
{
case SSNES_STATE_WRAM:
@@ -539,16 +565,15 @@ static bool get_import_value(xmlNodePtr ptr)
break;
default:
memtype = SNES_MEMORY_WRAM;
memtype = -1u;
}
if (addr >= psnes_get_memory_size(memtype))
if ((memtype != -1u) && (addr >= psnes_get_memory_size(memtype)))
{
SSNES_ERR("Address out of bounds.\n");
goto error;
}
unsigned mask_value = 0;
if (bitmask)
mask_value = strtoul((const char*)bitmask, NULL, 16);
@@ -596,6 +621,10 @@ static unsigned get_xml_shaders(const char *path, struct shader_program *prog, s
SSNES_LOG("Loading XML shader: %s\n", path);
xmlDocPtr doc = xmlCtxtReadFile(ctx, path, NULL, 0);
xmlNodePtr head = NULL;
xmlNodePtr cur = NULL;
unsigned num = 0;
if (!doc)
{
SSNES_ERR("Failed to parse XML file: %s\n", path);
@@ -608,8 +637,8 @@ static unsigned get_xml_shaders(const char *path, struct shader_program *prog, s
goto error;
}
xmlNodePtr head = xmlDocGetRootElement(doc);
xmlNodePtr cur = NULL;
head = xmlDocGetRootElement(doc);
for (cur = head; cur; cur = cur->next)
{
if (cur->type == XML_ELEMENT_NODE && strcmp((const char*)cur->name, "shader") == 0)
@@ -630,7 +659,6 @@ static unsigned get_xml_shaders(const char *path, struct shader_program *prog, s
if (!cur) // We couldn't find any GLSL shader :(
goto error;
unsigned num = 0;
memset(prog, 0, sizeof(struct shader_program) * size);
// Iterate to check if we find fragment and/or vertex shaders.
@@ -717,11 +745,19 @@ static void print_shader_log(GLuint obj)
pglGetShaderiv(obj, GL_INFO_LOG_LENGTH, &max_len);
char info_log[max_len];
if (max_len == 0)
return;
char *info_log = (char*)malloc(max_len);
if (!info_log)
return;
pglGetShaderInfoLog(obj, max_len, &info_len, info_log);
if (info_len > 0)
SSNES_LOG("Shader log: %s\n", info_log);
free(info_log);
}
static void print_linker_log(GLuint obj)
@@ -731,11 +767,19 @@ static void print_linker_log(GLuint obj)
pglGetProgramiv(obj, GL_INFO_LOG_LENGTH, &max_len);
char info_log[max_len];
if (max_len == 0)
return;
char *info_log = (char*)malloc(max_len);
if (!info_log)
return;
pglGetProgramInfoLog(obj, max_len, &info_len, info_log);
if (info_len > 0)
SSNES_LOG("Linker log: %s\n", info_log);
free(info_log);
}
static bool compile_shader(GLuint shader, const char *program)
@@ -825,6 +869,13 @@ static bool compile_programs(GLuint *gl_prog, struct shader_program *progs, size
return true;
}
static void gl_glsl_reset_attrib(void)
{
for (unsigned i = 0; i < gl_attrib_index; i++)
pglDisableVertexAttribArray(gl_attribs[i]);
gl_attrib_index = 0;
}
#define LOAD_GL_SYM(SYM) if (!pgl##SYM) { SDL_SYM_WRAP(pgl##SYM, "gl" #SYM) }
bool gl_glsl_init(const char *path)
@@ -842,6 +893,7 @@ bool gl_glsl_init(const char *path)
LOAD_GL_SYM(LinkProgram);
LOAD_GL_SYM(GetUniformLocation);
LOAD_GL_SYM(Uniform1i);
LOAD_GL_SYM(Uniform1f);
LOAD_GL_SYM(Uniform2fv);
LOAD_GL_SYM(Uniform4fv);
LOAD_GL_SYM(GetShaderiv);
@@ -852,6 +904,7 @@ bool gl_glsl_init(const char *path)
LOAD_GL_SYM(GetAttachedShaders);
LOAD_GL_SYM(GetAttribLocation);
LOAD_GL_SYM(EnableVertexAttribArray);
LOAD_GL_SYM(DisableVertexAttribArray);
LOAD_GL_SYM(VertexAttribPointer);
#endif
@@ -862,19 +915,26 @@ bool gl_glsl_init(const char *path)
bool shader_support = pglCreateProgram && pglUseProgram && pglCreateShader
&& pglDeleteShader && pglShaderSource && pglCompileShader && pglAttachShader
&& pglDetachShader && pglLinkProgram && pglGetUniformLocation
&& pglUniform1i && pglUniform2fv && pglUniform4fv
&& pglUniform1i && pglUniform1f && pglUniform2fv && pglUniform4fv
&& pglGetShaderiv && pglGetShaderInfoLog && pglGetProgramiv && pglGetProgramInfoLog
&& pglDeleteProgram && pglGetAttachedShaders
&& pglGetAttribLocation && pglEnableVertexAttribArray
&& pglGetAttribLocation && pglEnableVertexAttribArray && pglDisableVertexAttribArray
&& pglVertexAttribPointer;
#endif
if (!shader_support)
{
SSNES_ERR("GLSL shaders aren't supported by your GL driver.\n");
SSNES_ERR("GLSL shaders aren't supported by your OpenGL driver.\n");
return false;
}
struct shader_program stock_prog = {0};
stock_prog.vertex = strdup(stock_vertex);
stock_prog.fragment = strdup(stock_fragment);
if (!compile_programs(&gl_program[0], &stock_prog, 1))
return false;
struct shader_program progs[MAX_PROGRAMS];
unsigned num_progs = get_xml_shaders(path, progs, MAX_PROGRAMS - 1);
@@ -920,15 +980,14 @@ bool gl_glsl_init(const char *path)
if (gl_tracker_info_cnt > 0)
{
struct snes_tracker_info info = {
.wram = psnes_get_memory_data(SNES_MEMORY_WRAM),
.vram = psnes_get_memory_data(SNES_MEMORY_VRAM),
.cgram = psnes_get_memory_data(SNES_MEMORY_CGRAM),
.apuram = psnes_get_memory_data(SNES_MEMORY_APURAM),
.oam = psnes_get_memory_data(SNES_MEMORY_OAM),
.info = gl_tracker_info,
.info_elem = gl_tracker_info_cnt,
};
struct snes_tracker_info info = {0};
info.wram = psnes_get_memory_data(SNES_MEMORY_WRAM);
info.vram = psnes_get_memory_data(SNES_MEMORY_VRAM);
info.cgram = psnes_get_memory_data(SNES_MEMORY_CGRAM);
info.apuram = psnes_get_memory_data(SNES_MEMORY_APURAM);
info.oam = psnes_get_memory_data(SNES_MEMORY_OAM);
info.info = gl_tracker_info;
info.info_elem = gl_tracker_info_cnt;
#ifdef HAVE_PYTHON
if (*gl_tracker_script)
@@ -949,6 +1008,10 @@ bool gl_glsl_init(const char *path)
glsl_enable = true;
gl_num_programs = num_progs;
gl_program[gl_num_programs + 1] = gl_program[0];
gl_glsl_reset_attrib();
return true;
}
@@ -957,10 +1020,10 @@ void gl_glsl_deinit(void)
if (glsl_enable)
{
pglUseProgram(0);
for (int i = 1; i < MAX_PROGRAMS; i++)
for (unsigned i = 0; i <= gl_num_programs; i++)
{
if (gl_program[i] == 0)
break;
continue;
GLsizei count;
GLuint shaders[2];
@@ -998,6 +1061,8 @@ void gl_glsl_deinit(void)
snes_tracker_free(gl_snes_tracker);
gl_snes_tracker = NULL;
}
gl_glsl_reset_attrib();
}
void gl_glsl_set_params(unsigned width, unsigned height,
@@ -1009,147 +1074,178 @@ void gl_glsl_set_params(unsigned width, unsigned height,
const struct gl_tex_info *fbo_info, unsigned fbo_info_cnt)
{
// We enforce a certain layout for our various texture types in the texunits.
// Unit 0: Regular SNES frame (rubyTexture).
// Unit 1-A: LUT textures.
// Unit A+1: Previous texture.
// Unit A+2: Original texture.
// Unit A+3-B: FBO textures.
// - Regular SNES frame (rubyTexture) (always bound).
// - LUT textures (always bound).
// - Original texture (always bound if meaningful).
// - FBO textures (always bound if available).
// - Previous textures.
if (glsl_enable && gl_program[active_index] > 0)
if (!glsl_enable || (gl_program[active_index] == 0))
return;
GLint location;
float inputSize[2] = {(float)width, (float)height};
location = pglGetUniformLocation(gl_program[active_index], "rubyInputSize");
pglUniform2fv(location, 1, inputSize);
float outputSize[2] = {(float)out_width, (float)out_height};
location = pglGetUniformLocation(gl_program[active_index], "rubyOutputSize");
pglUniform2fv(location, 1, outputSize);
float textureSize[2] = {(float)tex_width, (float)tex_height};
location = pglGetUniformLocation(gl_program[active_index], "rubyTextureSize");
pglUniform2fv(location, 1, textureSize);
location = pglGetUniformLocation(gl_program[active_index], "rubyFrameCount");
pglUniform1i(location, frame_count);
location = pglGetUniformLocation(gl_program[active_index], "rubyFrameDirection");
pglUniform1i(location, g_extern.frame_is_reverse ? -1 : 1);
for (unsigned i = 0; i < gl_teximage_cnt; i++)
{
GLint location;
location = pglGetUniformLocation(gl_program[active_index], gl_teximage_uniforms[i]);
pglUniform1i(location, i + 1);
}
float inputSize[2] = {width, height};
location = pglGetUniformLocation(gl_program[active_index], "rubyInputSize");
pglUniform2fv(location, 1, inputSize);
unsigned texunit = gl_teximage_cnt + 1;
float outputSize[2] = {out_width, out_height};
location = pglGetUniformLocation(gl_program[active_index], "rubyOutputSize");
pglUniform2fv(location, 1, outputSize);
// Set original texture unless we're in first pass (pointless).
if (active_index > 1)
{
// Bind original texture.
pglActiveTexture(GL_TEXTURE0 + texunit);
float textureSize[2] = {tex_width, tex_height};
location = pglGetUniformLocation(gl_program[active_index], "rubyTextureSize");
pglUniform2fv(location, 1, textureSize);
location = pglGetUniformLocation(gl_program[active_index], "rubyOrigTexture");
pglUniform1i(location, texunit++);
glBindTexture(GL_TEXTURE_2D, info->tex);
location = pglGetUniformLocation(gl_program[active_index], "rubyFrameCount");
pglUniform1i(location, frame_count);
for (unsigned i = 0; i < gl_teximage_cnt; i++)
{
location = pglGetUniformLocation(gl_program[active_index], gl_teximage_uniforms[i]);
pglUniform1i(location, i + 1);
}
// Set previous texture.
pglActiveTexture(GL_TEXTURE0 + gl_teximage_cnt + 1);
glBindTexture(GL_TEXTURE_2D, prev_info->tex);
location = pglGetUniformLocation(gl_program[active_index], "rubyPrevTexture");
pglUniform1i(location, gl_teximage_cnt + 1);
location = pglGetUniformLocation(gl_program[active_index], "rubyPrevTextureSize");
pglUniform2fv(location, 1, prev_info->tex_size);
location = pglGetUniformLocation(gl_program[active_index], "rubyPrevInputSize");
pglUniform2fv(location, 1, prev_info->input_size);
location = pglGetUniformLocation(gl_program[active_index], "rubyOrigTextureSize");
pglUniform2fv(location, 1, info->tex_size);
location = pglGetUniformLocation(gl_program[active_index], "rubyOrigInputSize");
pglUniform2fv(location, 1, info->input_size);
// Pass texture coordinates.
location = pglGetAttribLocation(gl_program[active_index], "rubyPrevTexCoord");
location = pglGetAttribLocation(gl_program[active_index], "rubyOrigTexCoord");
if (location >= 0)
{
pglEnableVertexAttribArray(location);
pglVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, 0, prev_info->coord);
pglVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, 0, info->coord);
gl_attribs[gl_attrib_index++] = location;
}
// Set original texture unless we're in first pass (pointless).
if (active_index > 1)
// Bind new texture in the chain.
if (fbo_info_cnt > 0)
{
// Bind original texture.
pglActiveTexture(GL_TEXTURE0 + gl_teximage_cnt + 2);
glBindTexture(GL_TEXTURE_2D, info->tex);
pglActiveTexture(GL_TEXTURE0 + texunit + fbo_info_cnt - 1);
glBindTexture(GL_TEXTURE_2D, fbo_info[fbo_info_cnt - 1].tex);
}
location = pglGetUniformLocation(gl_program[active_index], "rubyOrigTexture");
pglUniform1i(location, gl_teximage_cnt + 2);
// Bind FBO textures.
for (unsigned i = 0; i < fbo_info_cnt; i++)
{
char attrib_buf[64];
location = pglGetUniformLocation(gl_program[active_index], "rubyOrigTextureSize");
pglUniform2fv(location, 1, info->tex_size);
location = pglGetUniformLocation(gl_program[active_index], "rubyOrigInputSize");
pglUniform2fv(location, 1, info->input_size);
snprintf(attrib_buf, sizeof(attrib_buf), "rubyPass%uTexture", i + 1);
location = pglGetUniformLocation(gl_program[active_index], attrib_buf);
pglUniform1i(location, texunit++);
// Pass texture coordinates.
location = pglGetAttribLocation(gl_program[active_index], "rubyOrigTexCoord");
snprintf(attrib_buf, sizeof(attrib_buf), "rubyPass%uTextureSize", i + 1);
location = pglGetUniformLocation(gl_program[active_index], attrib_buf);
pglUniform2fv(location, 1, fbo_info[i].tex_size);
snprintf(attrib_buf, sizeof(attrib_buf), "rubyPass%uInputSize", i + 1);
location = pglGetUniformLocation(gl_program[active_index], attrib_buf);
pglUniform2fv(location, 1, fbo_info[i].input_size);
snprintf(attrib_buf, sizeof(attrib_buf), "rubyPass%uTexCoord", i + 1);
location = pglGetAttribLocation(gl_program[active_index], attrib_buf);
if (location >= 0)
{
pglEnableVertexAttribArray(location);
pglVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, 0, info->coord);
}
GLuint base_tex = GL_TEXTURE0 + gl_teximage_cnt + 3;
// Bind new texture in the chain.
if (fbo_info_cnt > 0)
{
pglActiveTexture(base_tex + fbo_info_cnt - 1);
glBindTexture(GL_TEXTURE_2D, fbo_info[fbo_info_cnt - 1].tex);
}
// Bind FBO textures.
for (unsigned i = 0; i < fbo_info_cnt; i++)
{
char attrib_buf[64];
snprintf(attrib_buf, sizeof(attrib_buf), "rubyPass%uTexture", i + 1);
location = pglGetUniformLocation(gl_program[active_index], attrib_buf);
pglUniform1i(location, base_tex + i - GL_TEXTURE0);
snprintf(attrib_buf, sizeof(attrib_buf), "rubyPass%uTextureSize", i + 1);
location = pglGetUniformLocation(gl_program[active_index], attrib_buf);
pglUniform2fv(location, 1, fbo_info[i].tex_size);
snprintf(attrib_buf, sizeof(attrib_buf), "rubyPass%uInputSize", i + 1);
location = pglGetUniformLocation(gl_program[active_index], attrib_buf);
pglUniform2fv(location, 1, fbo_info[i].input_size);
snprintf(attrib_buf, sizeof(attrib_buf), "rubyPass%uTexCoord", i + 1);
location = pglGetAttribLocation(gl_program[active_index], attrib_buf);
if (location >= 0)
{
pglEnableVertexAttribArray(location);
pglVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, 0, fbo_info[i].coord);
}
pglVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, 0, fbo_info[i].coord);
gl_attribs[gl_attrib_index++] = location;
}
}
else
}
else
{
// First pass, so unbind everything to avoid collitions.
// Unbind ORIG.
pglActiveTexture(GL_TEXTURE0 + texunit);
glBindTexture(GL_TEXTURE_2D, 0);
GLuint base_tex = texunit + 1;
// Unbind any lurking FBO passes.
// Rendering to a texture that is bound to a texture unit
// sounds very shaky ... ;)
for (unsigned i = 0; i < gl_num_programs; i++)
{
// First pass, so unbind everything to avoid collitions.
// Unbind ORIG.
pglActiveTexture(GL_TEXTURE0 + gl_teximage_cnt + 2);
pglActiveTexture(GL_TEXTURE0 + base_tex + i);
glBindTexture(GL_TEXTURE_2D, 0);
}
}
GLuint base_tex = GL_TEXTURE0 + gl_teximage_cnt + 3;
// Unbind any lurking FBO passes.
// Rendering to a texture that is bound to a texture unit
// sounds very shaky ... ;)
for (unsigned i = 0; i < gl_num_programs; i++)
{
pglActiveTexture(GL_TEXTURE0 + base_tex + i);
glBindTexture(GL_TEXTURE_2D, 0);
}
// Set previous textures. Only bind if they're actually used.
for (unsigned i = 0; i < PREV_TEXTURES; i++)
{
char attr_buf_tex[64];
char attr_buf_tex_size[64];
char attr_buf_input_size[64];
char attr_buf_coord[64];
static const char *prev_names[PREV_TEXTURES] = {
"Prev",
"Prev1",
"Prev2",
"Prev3",
"Prev4",
"Prev5",
"Prev6",
};
snprintf(attr_buf_tex, sizeof(attr_buf_tex), "ruby%sTexture", prev_names[i]);
snprintf(attr_buf_tex_size, sizeof(attr_buf_tex_size), "ruby%sTextureSize", prev_names[i]);
snprintf(attr_buf_input_size, sizeof(attr_buf_input_size), "ruby%sInputSize", prev_names[i]);
snprintf(attr_buf_coord, sizeof(attr_buf_coord), "ruby%sTexCoord", prev_names[i]);
location = pglGetUniformLocation(gl_program[active_index], attr_buf_tex);
if (location >= 0)
{
pglActiveTexture(GL_TEXTURE0 + texunit);
glBindTexture(GL_TEXTURE_2D, prev_info[i].tex);
pglUniform1i(location, texunit++);
}
pglActiveTexture(GL_TEXTURE0);
location = pglGetUniformLocation(gl_program[active_index], attr_buf_tex_size);
pglUniform2fv(location, 1, prev_info[i].tex_size);
location = pglGetUniformLocation(gl_program[active_index], attr_buf_input_size);
pglUniform2fv(location, 1, prev_info[i].input_size);
if (gl_snes_tracker)
// Pass texture coordinates.
location = pglGetAttribLocation(gl_program[active_index], attr_buf_coord);
if (location >= 0)
{
static struct snes_tracker_uniform info[MAX_VARIABLES];
static unsigned cnt = 0;
if (active_index == 1)
cnt = snes_get_uniform(gl_snes_tracker, info, MAX_VARIABLES, frame_count);
pglEnableVertexAttribArray(location);
pglVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, 0, prev_info[i].coord);
gl_attribs[gl_attrib_index++] = location;
}
}
for (unsigned i = 0; i < cnt; i++)
{
location = pglGetUniformLocation(gl_program[active_index], info[i].id);
pglUniform1i(location, info[i].value);
}
pglActiveTexture(GL_TEXTURE0);
if (gl_snes_tracker)
{
static struct snes_tracker_uniform info[MAX_VARIABLES];
static unsigned cnt = 0;
if (active_index == 1)
cnt = snes_get_uniform(gl_snes_tracker, info, MAX_VARIABLES, frame_count);
for (unsigned i = 0; i < cnt; i++)
{
location = pglGetUniformLocation(gl_program[active_index], info[i].id);
pglUniform1f(location, info[i].value);
}
}
}
@@ -1161,6 +1257,8 @@ void gl_glsl_use(unsigned index)
{
if (glsl_enable)
{
gl_glsl_reset_attrib();
active_index = index;
pglUseProgram(gl_program[index]);
}
+2 -2
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -19,7 +19,7 @@
#ifndef __SSNES_GLSL_H
#define __SSNES_GLSL_H
#include <stdbool.h>
#include "../boolean.h"
#include "gl_common.h"
bool gl_glsl_init(const char *path);
+15 -16
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -17,10 +17,9 @@
#include "snes_state.h"
#include <stdlib.h>
#include <assert.h>
#include "strl.h"
#include "general.h"
#include <libsnes.hpp>
#include "../strl.h"
#include "../general.h"
#include "../libsnes.hpp"
#ifdef HAVE_PYTHON
#include "py_state/py_state.h"
@@ -63,7 +62,7 @@ struct snes_tracker
snes_tracker_t* snes_tracker_init(const struct snes_tracker_info *info)
{
snes_tracker_t *tracker = calloc(1, sizeof(*tracker));
snes_tracker_t *tracker = (snes_tracker_t*)calloc(1, sizeof(*tracker));
if (!tracker)
return NULL;
@@ -80,7 +79,7 @@ snes_tracker_t* snes_tracker_init(const struct snes_tracker_info *info)
}
#endif
tracker->info = calloc(info->info_elem, sizeof(struct snes_tracker_internal));
tracker->info = (struct snes_tracker_internal*)calloc(info->info_elem, sizeof(struct snes_tracker_internal));
tracker->info_elem = info->info_elem;
for (unsigned i = 0; i < info->info_elem; i++)
@@ -88,32 +87,32 @@ snes_tracker_t* snes_tracker_init(const struct snes_tracker_info *info)
strlcpy(tracker->info[i].id, info->info[i].id, sizeof(tracker->info[i].id));
tracker->info[i].addr = info->info[i].addr;
tracker->info[i].type = info->info[i].type;
tracker->info[i].mask = (info->info[i].mask == 0) ? 0xffffffffu : info->info[i].mask;
tracker->info[i].mask = (info->info[i].mask == 0) ? -1u : info->info[i].mask;
#ifdef HAVE_PYTHON
if (info->info[i].type == SSNES_STATE_PYTHON)
tracker->info[i].py = tracker->py;
#endif
assert(info->wram && info->vram && info->cgram &&
info->oam && info->apuram);
// If we don't have a valid pointer.
static const uint8_t empty = 0;
switch (info->info[i].ram_type)
{
case SSNES_STATE_WRAM:
tracker->info[i].ptr = info->wram;
tracker->info[i].ptr = info->wram ? info->wram : &empty;
break;
case SSNES_STATE_APURAM:
tracker->info[i].ptr = info->apuram;
tracker->info[i].ptr = info->apuram ? info->apuram : &empty;
break;
case SSNES_STATE_OAM:
tracker->info[i].ptr = info->oam;
tracker->info[i].ptr = info->oam ? info->oam : &empty;
break;
case SSNES_STATE_CGRAM:
tracker->info[i].ptr = info->cgram;
tracker->info[i].ptr = info->cgram ? info->cgram : &empty;
break;
case SSNES_STATE_VRAM:
tracker->info[i].ptr = info->vram;
tracker->info[i].ptr = info->vram ? info->vram : &empty;
break;
case SSNES_STATE_INPUT_SLOT1:
tracker->info[i].input_ptr = &tracker->input_state[0];
@@ -125,7 +124,7 @@ snes_tracker_t* snes_tracker_init(const struct snes_tracker_info *info)
break;
default:
tracker->info[i].ptr = NULL;
tracker->info[i].ptr = &empty;
}
}
+4 -3
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -19,7 +19,7 @@
#define __SSNES_SNES_STATE_H
#include <stdint.h>
#include <stdbool.h>
#include "../boolean.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -39,6 +39,7 @@ enum snes_tracker_type
enum snes_ram_type
{
SSNES_STATE_NONE,
SSNES_STATE_WRAM,
SSNES_STATE_APURAM,
SSNES_STATE_OAM,
@@ -78,7 +79,7 @@ struct snes_tracker_info
struct snes_tracker_uniform
{
const char *id;
int value;
float value;
};
typedef struct snes_tracker snes_tracker_t;
+126 -105
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -37,8 +37,7 @@
// Adapted from bSNES and MPlayer source.
typedef struct xv xv_t;
struct xv
typedef struct xv
{
Display *display;
GC gc;
@@ -76,12 +75,12 @@ struct xv
uint8_t font_v;
#endif
void (*render_func)(xv_t*, const void *frame, unsigned width, unsigned height, unsigned pitch);
};
void (*render_func)(struct xv*, const void *frame, unsigned width, unsigned height, unsigned pitch);
} xv_t;
static void xv_set_nonblock_state(void *data, bool state)
{
xv_t *xv = data;
xv_t *xv = (xv_t*)data;
Atom atom = XInternAtom(xv->display, "XV_SYNC_TO_VBLANK", true);
if (atom != None && xv->port)
XvSetPortAttribute(xv->display, xv->port, atom, !state);
@@ -108,9 +107,9 @@ static inline void calculate_yuv(uint8_t *y, uint8_t *u, uint8_t *v, unsigned r,
static void init_yuv_tables(xv_t *xv)
{
xv->ytable = malloc(0x8000);
xv->utable = malloc(0x8000);
xv->vtable = malloc(0x8000);
xv->ytable = (uint8_t*)malloc(0x8000);
xv->utable = (uint8_t*)malloc(0x8000);
xv->vtable = (uint8_t*)malloc(0x8000);
for (unsigned i = 0; i < 0x8000; i++)
{
@@ -184,6 +183,9 @@ static void set_fullscreen(xv_t *xv)
static void xv_init_font(xv_t *xv, const char *font_path, unsigned font_size)
{
#ifdef HAVE_FREETYPE
if (!g_settings.video.font_enable)
return;
const char *path = font_path;
if (!*path)
path = font_renderer_get_default_font();
@@ -214,7 +216,7 @@ static void xv_init_font(xv_t *xv, const char *font_path, unsigned font_size)
// We render @ 2x scale to combat chroma downsampling. Also makes fonts more bearable :)
static void render16_yuy2(xv_t *xv, const void *input_, unsigned width, unsigned height, unsigned pitch)
{
const uint16_t *input = input_;
const uint16_t *input = (const uint16_t*)input_;
uint8_t *output = (uint8_t*)xv->image->data;
for (unsigned y = 0; y < height; y++)
@@ -242,7 +244,7 @@ static void render16_yuy2(xv_t *xv, const void *input_, unsigned width, unsigned
static void render16_uyvy(xv_t *xv, const void *input_, unsigned width, unsigned height, unsigned pitch)
{
const uint16_t *input = input_;
const uint16_t *input = (const uint16_t*)input_;
uint8_t *output = (uint8_t*)xv->image->data;
for (unsigned y = 0; y < height; y++)
@@ -270,7 +272,7 @@ static void render16_uyvy(xv_t *xv, const void *input_, unsigned width, unsigned
static void render32_yuy2(xv_t *xv, const void *input_, unsigned width, unsigned height, unsigned pitch)
{
const uint32_t *input = input_;
const uint32_t *input = (const uint32_t*)input_;
uint8_t *output = (uint8_t*)xv->image->data;
for (unsigned y = 0; y < height; y++)
@@ -299,7 +301,7 @@ static void render32_yuy2(xv_t *xv, const void *input_, unsigned width, unsigned
static void render32_uyvy(xv_t *xv, const void *input_, unsigned width, unsigned height, unsigned pitch)
{
const uint32_t *input = input_;
const uint32_t *input = (const uint32_t*)input_;
uint16_t *output = (uint16_t*)xv->image->data;
for (unsigned y = 0; y < height; y++)
@@ -326,13 +328,92 @@ static void render32_uyvy(xv_t *xv, const void *input_, unsigned width, unsigned
}
}
static void* xv_init(const video_info_t *video, const input_driver_t **input, void **input_data)
struct format_desc
{
xv_t *xv = calloc(1, sizeof(*xv));
void (*render_16)(xv_t *xv, const void *input,
unsigned width, unsigned height, unsigned pitch);
void (*render_32)(xv_t *xv, const void *input,
unsigned width, unsigned height, unsigned pitch);
char components[4];
unsigned luma_index[2];
unsigned u_index;
unsigned v_index;
};
static const struct format_desc formats[] = {
{
render16_yuy2,
render32_yuy2,
{ 'Y', 'U', 'Y', 'V' },
{ 0, 2 },
1,
3,
},
{
render16_uyvy,
render32_uyvy,
{ 'U', 'Y', 'V', 'Y' },
{ 1, 3 },
0,
2,
},
};
static bool adaptor_set_format(xv_t *xv, Display *dpy, XvPortID port, const video_info_t *video)
{
int format_count;
XvImageFormatValues *format = XvListImageFormats(xv->display, port, &format_count);
if (!format)
return false;
for (int i = 0; i < format_count; i++)
{
for (unsigned j = 0; j < sizeof(formats) / sizeof(formats[0]); j++)
{
if (format[i].type == XvYUV && format[i].bits_per_pixel == 16 && format[i].format == XvPacked)
{
if (format[i].component_order[0] == formats[j].components[0] &&
format[i].component_order[1] == formats[j].components[1] &&
format[i].component_order[2] == formats[j].components[2] &&
format[i].component_order[3] == formats[j].components[3])
{
xv->fourcc = format[i].id;
xv->render_func = video->rgb32 ? formats[j].render_32 : formats[j].render_16;
#ifdef HAVE_FREETYPE
xv->luma_index[0] = formats[j].luma_index[0];
xv->luma_index[1] = formats[j].luma_index[1];
xv->chroma_u_index = formats[j].u_index;
xv->chroma_v_index = formats[j].v_index;
#endif
XFree(format);
return true;
}
}
}
}
XFree(format);
return false;
}
static void *xv_init(const video_info_t *video, const input_driver_t **input, void **input_data)
{
xv_t *xv = (xv_t*)calloc(1, sizeof(*xv));
if (!xv)
return NULL;
xv->display = XOpenDisplay(NULL);
struct sigaction sa;
unsigned adaptor_count = 0;
int visualmatches = 0;
XSetWindowAttributes attributes = {0};
unsigned width = 0, height = 0;
char buf[128];
Atom atom = 0;
void *xinput = NULL;
XVisualInfo *visualinfo = NULL;
XVisualInfo visualtemplate = {0};
if (!XShmQueryExtension(xv->display))
{
@@ -345,7 +426,6 @@ static void* xv_init(const video_info_t *video, const input_driver_t **input, vo
// Find an appropriate Xv port.
xv->port = 0;
XvAdaptorInfo *adaptor_info;
unsigned adaptor_count = 0;
XvQueryAdaptors(xv->display, DefaultRootWindow(xv->display), &adaptor_count, &adaptor_info);
for (unsigned i = 0; i < adaptor_count; i++)
{
@@ -353,27 +433,28 @@ static void* xv_init(const video_info_t *video, const input_driver_t **input, vo
if (adaptor_info[i].num_formats < 1) continue;
if (!(adaptor_info[i].type & XvInputMask)) continue;
if (!(adaptor_info[i].type & XvImageMask)) continue;
if (!adaptor_set_format(xv, xv->display, adaptor_info[i].base_id, video)) continue;
xv->port = adaptor_info[i].base_id;
xv->depth = adaptor_info[i].formats->depth;
xv->visualid = adaptor_info[i].formats->visual_id;
SSNES_LOG("XVideo: Found suitable XvPort #%u\n", (unsigned)xv->port);
break;
}
XvFreeAdaptorInfo(adaptor_info);
if (xv->port == 0)
{
SSNES_ERR("XVideo: Failed to find valid XvPort.\n");
SSNES_ERR("XVideo: Failed to find valid XvPort or format.\n");
goto error;
}
XVisualInfo visualtemplate;
visualtemplate.visualid = xv->visualid;
visualtemplate.screen = DefaultScreen(xv->display);
visualtemplate.depth = xv->depth;
visualtemplate.visual = 0;
int visualmatches = 0;
XVisualInfo *visualinfo = XGetVisualInfo(xv->display, VisualIDMask | VisualScreenMask | VisualDepthMask, &visualtemplate, &visualmatches);
visualinfo = XGetVisualInfo(xv->display, VisualIDMask | VisualScreenMask | VisualDepthMask, &visualtemplate, &visualmatches);
if (visualmatches < 1 || !visualinfo->visual)
{
if (visualinfo) XFree(visualinfo);
@@ -382,13 +463,12 @@ static void* xv_init(const video_info_t *video, const input_driver_t **input, vo
}
xv->colormap = XCreateColormap(xv->display, DefaultRootWindow(xv->display), visualinfo->visual, AllocNone);
XSetWindowAttributes attributes;
attributes.colormap = xv->colormap;
attributes.border_pixel = 0;
attributes.event_mask = StructureNotifyMask | DestroyNotify | ClientMessage;
unsigned width = video->fullscreen ? ((video->width == 0) ? 256 : video->width) : video->width;
unsigned height = video->fullscreen ? ((video->height == 0) ? 224 : video->height) : video->height;
width = video->fullscreen ? ((video->width == 0) ? g_extern.system.geom.base_width : video->width) : video->width;
height = video->fullscreen ? ((video->height == 0) ? g_extern.system.geom.base_height : video->height) : video->height;
xv->window = XCreateWindow(xv->display, DefaultRootWindow(xv->display),
0, 0, width, height,
0, xv->depth, InputOutput, visualinfo->visual,
@@ -399,7 +479,6 @@ static void* xv_init(const video_info_t *video, const input_driver_t **input, vo
XMapWindow(xv->display, xv->window);
char buf[128];
if (gfx_window_title(buf, sizeof(buf)))
XStoreName(xv->display, xv->window, buf);
@@ -410,69 +489,11 @@ static void* xv_init(const video_info_t *video, const input_driver_t **input, vo
xv->gc = XCreateGC(xv->display, xv->window, 0, 0);
// Set colorkey to auto paint, so that Xv video output is always visible
Atom atom = XInternAtom(xv->display, "XV_AUTOPAINT_COLORKEY", true);
atom = XInternAtom(xv->display, "XV_AUTOPAINT_COLORKEY", true);
if (atom != None) XvSetPortAttribute(xv->display, xv->port, atom, 1);
int format_count;
XvImageFormatValues *format = XvListImageFormats(xv->display, xv->port, &format_count);
bool has_format = false;
for (int i = 0; i < format_count; i++)
{
if (format[i].type == XvYUV && format[i].bits_per_pixel == 16 && format[i].format == XvPacked)
{
if (format[i].component_order[0] == 'Y' && format[i].component_order[1] == 'U'
&& format[i].component_order[2] == 'Y' && format[i].component_order[3] == 'V')
{
has_format = true;
xv->fourcc = format[i].id;
xv->render_func = video->rgb32 ? render32_yuy2 : render16_yuy2;
#ifdef HAVE_FREETYPE
xv->luma_index[0] = 0;
xv->luma_index[1] = 2;
xv->chroma_u_index = 1;
xv->chroma_v_index = 3;
#endif
break;
}
}
}
if (!has_format)
{
for (int i = 0; i < format_count; i++)
{
if (format[i].type == XvYUV && format[i].bits_per_pixel == 16 && format[i].format == XvPacked)
{
if (format[i].component_order[0] == 'U' && format[i].component_order[1] == 'Y'
&& format[i].component_order[2] == 'V' && format[i].component_order[3] == 'Y')
{
has_format = true;
xv->fourcc = format[i].id;
xv->render_func = video->rgb32 ? render32_uyvy : render16_uyvy;
#ifdef HAVE_FREETYPE
xv->luma_index[0] = 1;
xv->luma_index[1] = 3;
xv->chroma_u_index = 0;
xv->chroma_v_index = 2;
#endif
break;
}
}
}
}
free(format);
if (!has_format)
{
SSNES_ERR("XVideo: unable to find a supported image format.\n");
goto error;
}
xv->width = 512;
xv->height = 512;
xv->width = g_extern.system.geom.max_width;
xv->height = g_extern.system.geom.max_height;
xv->image = XvShmCreateImage(xv->display, xv->port, xv->fourcc, NULL, xv->width, xv->height, &xv->shminfo);
if (!xv->image)
@@ -484,7 +505,7 @@ static void* xv_init(const video_info_t *video, const input_driver_t **input, vo
xv->height = xv->image->height;
xv->shminfo.shmid = shmget(IPC_PRIVATE, xv->image->data_size, IPC_CREAT | 0777);
xv->shminfo.shmaddr = xv->image->data = shmat(xv->shminfo.shmid, NULL, 0);
xv->shminfo.shmaddr = xv->image->data = (char*)shmat(xv->shminfo.shmid, NULL, 0);
xv->shminfo.readOnly = false;
if (!XShmAttach(xv->display, &xv->shminfo))
{
@@ -498,7 +519,6 @@ static void* xv_init(const video_info_t *video, const input_driver_t **input, vo
if (xv->quit_atom)
XSetWMProtocols(xv->display, xv->window, &xv->quit_atom, 1);
struct sigaction sa;
sa.sa_handler = sighandler;
sa.sa_flags = SA_RESTART;
sigemptyset(&sa.sa_mask);
@@ -508,7 +528,7 @@ static void* xv_init(const video_info_t *video, const input_driver_t **input, vo
xv_set_nonblock_state(xv, !video->vsync);
xv->focus = true;
void *xinput = input_x.init();
xinput = input_x.init();
if (xinput)
{
*input = &input_x;
@@ -558,7 +578,7 @@ static bool check_resize(xv_t *xv, unsigned width, unsigned height)
return false;
}
xv->shminfo.shmaddr = xv->image->data = shmat(xv->shminfo.shmid, NULL, 0);
xv->shminfo.shmaddr = xv->image->data = (char*)shmat(xv->shminfo.shmid, NULL, 0);
xv->shminfo.readOnly = false;
if (!XShmAttach(xv->display, &xv->shminfo))
@@ -631,13 +651,13 @@ static void xv_render_msg(xv_t *xv, const char *msg, unsigned width, unsigned he
int base_y = _base_y - head->off_y;
if (base_y >= 0)
{
for (int y = 0; y < head->height && (base_y + y) < height; y++)
for (int y = 0; y < (int)head->height && (base_y + y) < height; y++)
{
if (base_x < 0)
continue;
const uint8_t * restrict a = head->output + head->pitch * y;
uint8_t * restrict out = (uint8_t*)xv->image->data + (base_y - head->height + y) * pitch + base_x;
const uint8_t *a = head->output + head->pitch * y;
uint8_t *out = (uint8_t*)xv->image->data + (base_y - head->height + y) * pitch + base_x;
for (int x = 0; x < (head->width << 1) && (base_x + x) < pitch; x += 4)
{
@@ -679,9 +699,9 @@ static void xv_render_msg(xv_t *xv, const char *msg, unsigned width, unsigned he
#endif
}
static bool xv_frame(void *data, const void* frame, unsigned width, unsigned height, unsigned pitch, const char *msg)
static bool xv_frame(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch, const char *msg)
{
xv_t *xv = data;
xv_t *xv = (xv_t*)data;
if (!check_resize(xv, width, height))
return false;
@@ -711,7 +731,7 @@ static bool xv_frame(void *data, const void* frame, unsigned width, unsigned hei
static bool xv_alive(void *data)
{
xv_t *xv = data;
xv_t *xv = (xv_t*)data;
XEvent event;
while (XPending(xv->display))
@@ -720,7 +740,7 @@ static bool xv_alive(void *data)
switch (event.type)
{
case ClientMessage:
if (event.xclient.data.l[0] == xv->quit_atom)
if ((Atom)event.xclient.data.l[0] == xv->quit_atom)
return false;
break;
case DestroyNotify:
@@ -741,14 +761,14 @@ static bool xv_alive(void *data)
static bool xv_focus(void *data)
{
xv_t *xv = data;
xv_t *xv = (xv_t*)data;
return xv->focus;
}
static void xv_free(void *data)
{
xv_t *xv = data;
xv_t *xv = (xv_t*)data;
XShmDetach(xv->display, &xv->shminfo);
shmdt(xv->shminfo.shmaddr);
shmctl(xv->shminfo.shmid, IPC_RMID, NULL);
@@ -774,12 +794,13 @@ static void xv_free(void *data)
}
const video_driver_t video_xvideo = {
.init = xv_init,
.frame = xv_frame,
.alive = xv_alive,
.set_nonblock_state = xv_set_nonblock_state,
.focus = xv_focus,
.free = xv_free,
.ident = "xvideo"
xv_init,
xv_frame,
xv_set_nonblock_state,
xv_alive,
xv_focus,
NULL,
xv_free,
"xvideo"
};
+15 -5
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -18,7 +18,7 @@
#include "ssnes_dinput.h"
#include "SDL.h"
#include "SDL_syswm.h"
#include <stdbool.h>
#include "../boolean.h"
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
@@ -46,7 +46,7 @@ void sdl_dinput_free(sdl_dinput_t *di)
static BOOL CALLBACK enum_axes_cb(const DIDEVICEOBJECTINSTANCE *inst, void *p)
{
LPDIRECTINPUTDEVICE8 joypad = p;
LPDIRECTINPUTDEVICE8 joypad = (LPDIRECTINPUTDEVICE8)p;
DIPROPRANGE range;
memset(&range, 0, sizeof(range));
@@ -63,7 +63,7 @@ static BOOL CALLBACK enum_axes_cb(const DIDEVICEOBJECTINSTANCE *inst, void *p)
static BOOL CALLBACK enum_joypad_cb(const DIDEVICEINSTANCE *inst, void *p)
{
sdl_dinput_t *di = p;
sdl_dinput_t *di = (sdl_dinput_t*)p;
unsigned active = 0;
unsigned n;
@@ -82,7 +82,11 @@ static BOOL CALLBACK enum_joypad_cb(const DIDEVICEINSTANCE *inst, void *p)
if (n == MAX_PLAYERS)
return DIENUM_CONTINUE;
#ifdef __cplusplus
if (FAILED(IDirectInput8_CreateDevice(di->ctx, inst->guidInstance, &di->joypad[n], NULL)))
#else
if (FAILED(IDirectInput8_CreateDevice(di->ctx, &inst->guidInstance, &di->joypad[n], NULL)))
#endif
return DIENUM_CONTINUE;
IDirectInputDevice8_SetDataFormat(di->joypad[n], &c_dfDIJoystick2);
@@ -97,7 +101,7 @@ static BOOL CALLBACK enum_joypad_cb(const DIDEVICEINSTANCE *inst, void *p)
sdl_dinput_t* sdl_dinput_init(void)
{
sdl_dinput_t *di = calloc(1, sizeof(*di));
sdl_dinput_t *di = (sdl_dinput_t*)calloc(1, sizeof(*di));
if (!di)
return NULL;
@@ -118,9 +122,15 @@ sdl_dinput_t* sdl_dinput_init(void)
di->hWnd = info.window;
#endif
#ifdef __cplusplus
if (FAILED(DirectInput8Create(
GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8,
(void**)&di->ctx, NULL)))
#else
if (FAILED(DirectInput8Create(
GetModuleHandle(NULL), DIRECTINPUT_VERSION, &IID_IDirectInput8,
(void**)&di->ctx, NULL)))
#endif
{
SSNES_ERR("Failed to init DirectInput.\n");
goto error;
+1 -1
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
+19 -18
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -15,14 +15,14 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "driver.h"
#include "../driver.h"
#include "../gfx/sdlwrap.h"
#include <stdbool.h>
#include "general.h"
#include "../boolean.h"
#include "../general.h"
#include <stdint.h>
#include <stdlib.h>
#include <libsnes.hpp>
#include "../libsnes.hpp"
#include "ssnes_sdl_input.h"
#include "keysym.h"
@@ -123,10 +123,10 @@ static void init_lut(void)
keysym_lut[lut_binds[i].sk] = lut_binds[i].sdl;
}
static void* sdl_input_init(void)
static void *sdl_input_init(void)
{
init_lut();
sdl_input_t *sdl = calloc(1, sizeof(*sdl));
sdl_input_t *sdl = (sdl_input_t*)calloc(1, sizeof(*sdl));
if (!sdl)
return NULL;
@@ -189,7 +189,7 @@ static bool sdl_joykey_pressed(sdl_input_t *sdl, int port_num, uint16_t joykey)
if (GET_HAT_DIR(joykey))
{
int hat = GET_HAT(joykey);
if (hat < sdl->num_hats[port_num])
if (hat < (int)sdl->num_hats[port_num])
{
Uint8 dir = SDL_JoystickGetHat(sdl->joysticks[port_num], hat);
switch (GET_HAT_DIR(joykey))
@@ -273,7 +273,7 @@ static bool sdl_bind_button_pressed(void *data, int key)
for (unsigned i = 0; binds[i].id != -1; i++)
{
if (binds[i].id == key)
return sdl_is_pressed(data, 0, &binds[i]);
return sdl_is_pressed((sdl_input_t*)data, 0, &binds[i]);
}
return false;
}
@@ -352,8 +352,9 @@ static int16_t sdl_justifier_device_state(sdl_input_t *sdl, unsigned index, unsi
return 0;
}
static int16_t sdl_input_state(void *data, const struct snes_keybind **binds, bool port, unsigned device, unsigned index, unsigned id)
static int16_t sdl_input_state(void *data_, const struct snes_keybind **binds, bool port, unsigned device, unsigned index, unsigned id)
{
sdl_input_t *data = (sdl_input_t*)data_;
switch (device)
{
case SNES_DEVICE_JOYPAD:
@@ -381,7 +382,7 @@ static void sdl_input_free(void *data)
SDL_Event event;
while (SDL_PollEvent(&event));
sdl_input_t *sdl = data;
sdl_input_t *sdl = (sdl_input_t*)data;
#ifdef HAVE_DINPUT
sdl_dinput_free(sdl->di);
@@ -412,7 +413,7 @@ static void sdl_poll_mouse(sdl_input_t *sdl)
static void sdl_input_poll(void *data)
{
SDL_PumpEvents();
sdl_input_t *sdl = data;
sdl_input_t *sdl = (sdl_input_t*)data;
#ifdef HAVE_DINPUT
sdl_dinput_poll(sdl->di);
@@ -424,11 +425,11 @@ static void sdl_input_poll(void *data)
}
const input_driver_t input_sdl = {
.init = sdl_input_init,
.poll = sdl_input_poll,
.input_state = sdl_input_state,
.key_pressed = sdl_bind_button_pressed,
.free = sdl_input_free,
.ident = "sdl"
sdl_input_init,
sdl_input_poll,
sdl_input_state,
sdl_bind_button_pressed,
sdl_input_free,
"sdl"
};
+3 -3
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -22,8 +22,8 @@
#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>
#include <stdbool.h>
#include "general.h"
#include "../boolean.h"
#include "../general.h"
// Piggyback joypad driver for SDL.
+2 -2
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -19,7 +19,7 @@
#define __SSNES_SDL_INPUT_H
#include "SDL.h"
#include "general.h"
#include "../general.h"
#ifdef HAVE_DINPUT
#include "ssnes_dinput.h"
+16 -16
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -18,7 +18,7 @@
#include "driver.h"
#include "SDL.h"
#include <stdbool.h>
#include "../boolean.h"
#include "general.h"
#include <stdint.h>
#include <stdlib.h>
@@ -133,9 +133,9 @@ static void init_lut(void)
keysym_lut[lut_binds[i].sk] = lut_binds[i].x;
}
static void* x_input_init(void)
static void *x_input_init(void)
{
x11_input_t *x11 = calloc(1, sizeof(*x11));
x11_input_t *x11 = (x11_input_t*)calloc(1, sizeof(*x11));
if (!x11)
return NULL;
@@ -146,7 +146,7 @@ static void* x_input_init(void)
return NULL;
}
x11->sdl = input_sdl.init();
x11->sdl = (sdl_input_t*)input_sdl.init();
if (!x11->sdl)
{
free(x11);
@@ -171,7 +171,7 @@ static bool x_is_pressed(x11_input_t *x11, const struct snes_keybind *binds, uns
{
for (int i = 0; binds[i].id != -1; i++)
{
if (binds[i].id == id)
if (binds[i].id == (int)id)
return x_key_pressed(x11, binds[i].key);
}
@@ -180,7 +180,7 @@ static bool x_is_pressed(x11_input_t *x11, const struct snes_keybind *binds, uns
static bool x_bind_button_pressed(void *data, int key)
{
x11_input_t *x11 = data;
x11_input_t *x11 = (x11_input_t*)data;
bool pressed = x_is_pressed(x11, g_settings.input.binds[0], key);
if (!pressed)
return input_sdl.key_pressed(x11->sdl, key);
@@ -189,7 +189,7 @@ static bool x_bind_button_pressed(void *data, int key)
static int16_t x_input_state(void *data, const struct snes_keybind **binds, bool port, unsigned device, unsigned index, unsigned id)
{
x11_input_t *x11 = data;
x11_input_t *x11 = (x11_input_t*)data;
bool pressed = false;
switch (device)
@@ -213,7 +213,7 @@ static int16_t x_input_state(void *data, const struct snes_keybind **binds, bool
static void x_input_free(void *data)
{
x11_input_t *x11 = data;
x11_input_t *x11 = (x11_input_t*)data;
input_sdl.free(x11->sdl);
XCloseDisplay(x11->display);
free(data);
@@ -221,17 +221,17 @@ static void x_input_free(void *data)
static void x_input_poll(void *data)
{
x11_input_t *x11 = data;
x11_input_t *x11 = (x11_input_t*)data;
XQueryKeymap(x11->display, x11->state);
input_sdl.poll(x11->sdl);
}
const input_driver_t input_x = {
.init = x_input_init,
.poll = x_input_poll,
.input_state = x_input_state,
.key_pressed = x_bind_button_pressed,
.free = x_input_free,
.ident = "x"
x_input_init,
x_input_poll,
x_input_state,
x_bind_button_pressed,
x_input_free,
"x"
};
+54
View File
@@ -66,6 +66,60 @@ extern "C" {
#define SNES_MEMORY_OAM 103
#define SNES_MEMORY_CGRAM 104
// SSNES extension. Not required to be implemented for a working implementation.
#define SNES_ENVIRONMENT_GET_FULLPATH 0 // const char ** --
// Full path of game loaded.
//
#define SNES_ENVIRONMENT_SET_GEOMETRY 1 // const struct snes_geometry * --
// Window geometry information for the system/game.
//
#define SNES_ENVIRONMENT_SET_PITCH 2 // const unsigned * --
// Pitch of game image.
//
#define SNES_ENVIRONMENT_GET_OVERSCAN 3 // bool * --
// Boolean value whether or not the implementation should use overscan.
//
#define SNES_ENVIRONMENT_SET_TIMING 4 // const struct snes_system_timing * --
// Set exact timings of the system. Used primarily for video recording.
//
#define SNES_ENVIRONMENT_GET_CAN_DUPE 5 // bool * --
// Boolean value whether or not SSNES supports frame duping,
// passing NULL to video frame callback.
//
//
#define SNES_ENVIRONMENT_SET_NEED_FULLPATH 6 // const bool * --
// Boolean value telling if implementation needs a valid fullpath to be able to run.
// If this is the case, SSNES will not open the rom directly,
// and pass NULL to rom data.
// Implementation must then use SNES_ENVIRONMENT_GET_FULLPATH.
// This is useful for implementations with very large roms,
// which are impractical to load fully into RAM.
//
#define SNES_ENVIRONMENT_GET_CAN_REWIND 7 // bool * --
// Boolean value telling if SSNES is able to rewind.
// Some implementations might need to take extra precautions
// to allow this as smoothly as possible.
struct snes_geometry
{
unsigned base_width; // Nominal video width of system.
unsigned base_height; // Nominal video height of system.
unsigned max_width; // Maximum possible width of system.
unsigned max_height; // Maximum possible height of system.
};
struct snes_system_timing
{
double fps;
double sample_rate;
};
typedef bool (*snes_environment_t)(unsigned cmd, void *data);
// Must be called before calling snes_init().
void snes_set_environment(snes_environment_t);
////
typedef void (*snes_video_refresh_t)(const uint16_t *data, unsigned width, unsigned height);
typedef void (*snes_audio_sample_t)(uint16_t left, uint16_t right);
typedef void (*snes_input_poll_t)(void);
+6 -5
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -18,7 +18,8 @@
#include "message.h"
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "boolean.h"
#include "posix_string.h"
struct queue_elem
{
@@ -37,12 +38,12 @@ struct msg_queue
msg_queue_t *msg_queue_new(size_t size)
{
msg_queue_t *queue = calloc(1, sizeof(*queue));
msg_queue_t *queue = (msg_queue_t*)calloc(1, sizeof(*queue));
if (!queue)
return NULL;
queue->size = size + 1;
queue->elems = calloc(queue->size, sizeof(struct queue_elem*));
queue->elems = (struct queue_elem**)calloc(queue->size, sizeof(struct queue_elem*));
if (!queue->elems)
{
@@ -65,7 +66,7 @@ void msg_queue_push(msg_queue_t *queue, const char *msg, unsigned prio, unsigned
if (queue->ptr >= queue->size)
return;
struct queue_elem *new_elem = calloc(1, sizeof(struct queue_elem));
struct queue_elem *new_elem = (struct queue_elem*)calloc(1, sizeof(struct queue_elem));
new_elem->prio = prio;
new_elem->duration = duration;
new_elem->msg = msg ? strdup(msg) : NULL;
+1 -1
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
+118 -36
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -18,9 +18,9 @@
#include "movie.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "general.h"
#include "dynamic.h"
#include <assert.h>
// CRC32 implementation taken from BSNES source :)
@@ -88,13 +88,12 @@ struct bsv_movie
FILE *file;
uint8_t *state;
long *frame_pos; // A ring buffer keeping track of many key presses were requested per frame.
size_t *frame_pos; // A ring buffer keeping track of positions in the file for each frame.
size_t frame_mask;
uint16_t current_frame_count;
size_t frame_ptr;
bool playback;
unsigned min_file_pos;
size_t min_file_pos;
bool first_rewind;
bool did_rewind;
@@ -103,7 +102,7 @@ struct bsv_movie
#define BSV_MAGIC 0x42535631
#define MAGIC_INDEX 0
#define SERIALIZER_INDEX 1
#define SERIALIZER_INDEX 1 // Not current used.
#define CRC_INDEX 2
#define STATE_SIZE_INDEX 3
@@ -116,6 +115,14 @@ static inline uint32_t swap_if_big32(uint32_t val)
return (val >> 24) | ((val >> 8) & 0xFF00) | ((val << 8) & 0xFF0000) | (val << 24);
}
static inline uint32_t swap_if_little32(uint32_t val)
{
if (!is_little_endian()) // Big-endian
return val;
else
return (val >> 24) | ((val >> 8) & 0xFF00) | ((val << 8) & 0xFF0000) | (val << 24);
}
static inline uint16_t swap_if_big16(uint16_t val)
{
if (is_little_endian())
@@ -141,7 +148,8 @@ static bool init_playback(bsv_movie_t *handle, const char *path)
return false;
}
if (swap_if_big32(header[MAGIC_INDEX]) != BSV_MAGIC)
// Compatibility with old implementation that used incorrect documentation.
if (swap_if_little32(header[MAGIC_INDEX]) != BSV_MAGIC && swap_if_big32(header[MAGIC_INDEX]) != BSV_MAGIC)
{
SSNES_ERR("Movie file is not a valid BSV1 file!\n");
return false;
@@ -154,25 +162,32 @@ static bool init_playback(bsv_movie_t *handle, const char *path)
}
uint32_t state_size = swap_if_big32(header[STATE_SIZE_INDEX]);
handle->state = malloc(state_size);
if (!handle->state)
return false;
// If we're playing back from the start, state_size is 0.
if (state_size)
{
handle->state = (uint8_t*)malloc(state_size);
if (!handle->state)
return false;
if (fread(handle->state, 1, state_size, handle->file) != state_size)
{
SSNES_ERR("Couldn't read state from movie.\n");
return false;
}
if (psnes_serialize_size() != state_size)
{
SSNES_ERR("Movie format seems to have a different serializer version. Cannot continue.\n");
ssnes_fail(1, "init_playback()");
}
// Unserialize to start playback.
psnes_unserialize(handle->state, state_size);
}
handle->min_file_pos = sizeof(header) + state_size;
if (fread(handle->state, 1, state_size, handle->file) != state_size)
{
SSNES_ERR("Couldn't read state from movie.\n");
return false;
}
if (psnes_serialize_size() != state_size)
{
SSNES_ERR("Movie format seems to have a different serializer version. Cannot continue.\n");
exit(1);
}
// Unserialize to start playback.
psnes_unserialize(handle->state, state_size);
return true;
}
@@ -186,22 +201,29 @@ static bool init_record(bsv_movie_t *handle, const char *path)
}
uint32_t header[4] = {0};
header[MAGIC_INDEX] = swap_if_big32(BSV_MAGIC);
//header[SERIALIZER_INDEX] = 0; // TODO: Fix this.
// This value is supposed to show up as BSV1 in a HEX editor.
header[MAGIC_INDEX] = swap_if_little32(BSV_MAGIC);
header[CRC_INDEX] = swap_if_big32(g_extern.cart_crc);
uint32_t state_size = psnes_serialize_size();
header[STATE_SIZE_INDEX] = swap_if_big32(state_size);
fwrite(header, 4, sizeof(uint32_t), handle->file);
handle->state = malloc(state_size);
handle->state = (uint8_t*)malloc(state_size);
if (!handle->state)
return false;
handle->min_file_pos = sizeof(header) + state_size;
psnes_serialize(handle->state, state_size);
fwrite(handle->state, 1, state_size, handle->file);
if (state_size > 0)
{
psnes_serialize(handle->state, state_size);
fwrite(handle->state, 1, state_size, handle->file);
}
return true;
}
@@ -228,12 +250,13 @@ bool bsv_movie_get_input(bsv_movie_t *handle, int16_t *input)
void bsv_movie_set_input(bsv_movie_t *handle, int16_t input)
{
input = swap_if_big16(input);
fwrite(&input, sizeof(int16_t), 1, handle->file);
}
bsv_movie_t *bsv_movie_init(const char *path, enum ssnes_movie_type type)
{
bsv_movie_t *handle = calloc(1, sizeof(*handle));
bsv_movie_t *handle = (bsv_movie_t*)calloc(1, sizeof(*handle));
if (!handle)
return NULL;
@@ -245,8 +268,11 @@ bsv_movie_t *bsv_movie_init(const char *path, enum ssnes_movie_type type)
else if (!init_record(handle, path))
goto error;
if (!(handle->frame_pos = calloc((1 << 20), sizeof(long)))) // Just pick something really large :D
// Just pick something really large :D ~1 million frames rewind should do the trick.
if (!(handle->frame_pos = (size_t*)calloc((1 << 20), sizeof(size_t))))
goto error;
handle->frame_pos[0] = handle->min_file_pos;
handle->frame_mask = (1 << 20) - 1;
return handle;
@@ -258,14 +284,11 @@ error:
void bsv_movie_set_frame_start(bsv_movie_t *handle)
{
//fprintf(stderr, "Starting frame: %u, Pos: %ld\n", (unsigned)handle->frame_ptr, ftell(handle->file));
handle->frame_pos[handle->frame_ptr] = ftell(handle->file);
}
void bsv_movie_set_frame_end(bsv_movie_t *handle)
{
//fprintf(stderr, "Frame++\n");
handle->frame_ptr = (handle->frame_ptr + 1) & handle->frame_mask;
handle->first_rewind = !handle->did_rewind;
@@ -274,22 +297,27 @@ void bsv_movie_set_frame_end(bsv_movie_t *handle)
void bsv_movie_frame_rewind(bsv_movie_t *handle)
{
//fprintf(stderr, "Frame--\n");
handle->did_rewind = true;
if (handle->frame_ptr <= 1)
// If we're at the beginning ... :)
if ((handle->frame_ptr <= 1) && (handle->frame_pos[0] == handle->min_file_pos))
{
handle->frame_ptr = 0;
fseek(handle->file, handle->min_file_pos, SEEK_SET);
}
else
{
// First time rewind is performed, the old frame is simply replayed.
// However, playing back that frame caused us to read data, and push data to the ring buffer.
// Sucessively rewinding frames, we need to rewind past the read data, plus another.
handle->frame_ptr = (handle->frame_ptr - (handle->first_rewind ? 1 : 2)) & handle->frame_mask;
fseek(handle->file, handle->frame_pos[handle->frame_ptr], SEEK_SET);
}
// We rewound past the beginning. :O
if (ftell(handle->file) <= (long)handle->min_file_pos)
{
// If recording, we simply reset the starting point. Nice and easy.
if (!handle->playback)
{
fseek(handle->file, 4 * sizeof(uint32_t), SEEK_SET);
@@ -300,3 +328,57 @@ void bsv_movie_frame_rewind(bsv_movie_t *handle)
fseek(handle->file, handle->min_file_pos, SEEK_SET);
}
}
uint8_t *bsv_header_generate(size_t *size)
{
uint32_t bsv_header[4] = {0};
unsigned serialize_size = psnes_serialize_size();
size_t header_size = sizeof(bsv_header) + serialize_size;
*size = header_size;
uint8_t *header = (uint8_t*)malloc(header_size);
if (!header)
return NULL;
bsv_header[MAGIC_INDEX] = swap_if_little32(BSV_MAGIC);
bsv_header[CRC_INDEX] = swap_if_big32(g_extern.cart_crc);
bsv_header[STATE_SIZE_INDEX] = swap_if_big32(serialize_size);
if (serialize_size && !psnes_serialize(header + sizeof(bsv_header), serialize_size))
{
free(header);
return NULL;
}
memcpy(header, bsv_header, sizeof(bsv_header));
return header;
}
bool bsv_parse_header(const uint32_t *header)
{
uint32_t in_bsv = swap_if_little32(header[MAGIC_INDEX]);
if (in_bsv != BSV_MAGIC)
{
SSNES_ERR("BSV magic mismatch, got 0x%x, expected 0x%x!\n",
in_bsv, BSV_MAGIC);
return false;
}
uint32_t in_crc = swap_if_big32(header[CRC_INDEX]);
if (in_crc != g_extern.cart_crc)
{
SSNES_ERR("CRC32 mismatch, got 0x%x, expected 0x%x!\n", in_crc, g_extern.cart_crc);
return false;
}
uint32_t in_state_size = swap_if_big32(header[STATE_SIZE_INDEX]);
if (in_state_size != psnes_serialize_size())
{
SSNES_ERR("Serialization size mismatch, got 0x%x, expected 0x%x!\n",
in_state_size, psnes_serialize_size());
return false;
}
return true;
}
+7 -3
View File
@@ -1,5 +1,5 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
@@ -19,16 +19,20 @@
#define __SSNES_MOVIE_H
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "boolean.h"
typedef struct bsv_movie bsv_movie_t;
enum ssnes_movie_type
{
SSNES_MOVIE_PLAYBACK,
SSNES_MOVIE_RECORD,
SSNES_MOVIE_RECORD
};
uint8_t *bsv_header_generate(size_t *size);
bool bsv_parse_header(const uint32_t *header);
bsv_movie_t *bsv_movie_init(const char *path, enum ssnes_movie_type type);
// Playback
+32
View File
@@ -0,0 +1,32 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SSNES-360", "SSNES-360.vcxproj", "{9CE8EEF7-CC1C-4A04-BB5C-62411CB5BADE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
CodeAnalysis|Xbox 360 = CodeAnalysis|Xbox 360
Debug|Xbox 360 = Debug|Xbox 360
Profile_FastCap|Xbox 360 = Profile_FastCap|Xbox 360
Profile|Xbox 360 = Profile|Xbox 360
Release_LTCG|Xbox 360 = Release_LTCG|Xbox 360
Release|Xbox 360 = Release|Xbox 360
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9CE8EEF7-CC1C-4A04-BB5C-62411CB5BADE}.CodeAnalysis|Xbox 360.ActiveCfg = CodeAnalysis|Xbox 360
{9CE8EEF7-CC1C-4A04-BB5C-62411CB5BADE}.CodeAnalysis|Xbox 360.Build.0 = CodeAnalysis|Xbox 360
{9CE8EEF7-CC1C-4A04-BB5C-62411CB5BADE}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360
{9CE8EEF7-CC1C-4A04-BB5C-62411CB5BADE}.Debug|Xbox 360.Build.0 = Debug|Xbox 360
{9CE8EEF7-CC1C-4A04-BB5C-62411CB5BADE}.Profile_FastCap|Xbox 360.ActiveCfg = Profile_FastCap|Xbox 360
{9CE8EEF7-CC1C-4A04-BB5C-62411CB5BADE}.Profile_FastCap|Xbox 360.Build.0 = Profile_FastCap|Xbox 360
{9CE8EEF7-CC1C-4A04-BB5C-62411CB5BADE}.Profile|Xbox 360.ActiveCfg = Profile|Xbox 360
{9CE8EEF7-CC1C-4A04-BB5C-62411CB5BADE}.Profile|Xbox 360.Build.0 = Profile|Xbox 360
{9CE8EEF7-CC1C-4A04-BB5C-62411CB5BADE}.Release_LTCG|Xbox 360.ActiveCfg = Release_LTCG|Xbox 360
{9CE8EEF7-CC1C-4A04-BB5C-62411CB5BADE}.Release_LTCG|Xbox 360.Build.0 = Release_LTCG|Xbox 360
{9CE8EEF7-CC1C-4A04-BB5C-62411CB5BADE}.Release|Xbox 360.ActiveCfg = Release|Xbox 360
{9CE8EEF7-CC1C-4A04-BB5C-62411CB5BADE}.Release|Xbox 360.Build.0 = Release|Xbox 360
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
+307
View File
@@ -0,0 +1,307 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="CodeAnalysis|Xbox 360">
<Configuration>CodeAnalysis</Configuration>
<Platform>Xbox 360</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Xbox 360">
<Configuration>Debug</Configuration>
<Platform>Xbox 360</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Profile|Xbox 360">
<Configuration>Profile</Configuration>
<Platform>Xbox 360</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Profile_FastCap|Xbox 360">
<Configuration>Profile_FastCap</Configuration>
<Platform>Xbox 360</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Xbox 360">
<Configuration>Release</Configuration>
<Platform>Xbox 360</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release_LTCG|Xbox 360">
<Configuration>Release_LTCG</Configuration>
<Platform>Xbox 360</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{9CE8EEF7-CC1C-4A04-BB5C-62411CB5BADE}</ProjectGuid>
<Keyword>Xbox360Proj</Keyword>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='CodeAnalysis|Xbox 360'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Xbox 360'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Xbox 360'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile_FastCap|Xbox 360'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Xbox 360'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_LTCG|Xbox 360'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='CodeAnalysis|Xbox 360'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Xbox 360'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Profile|Xbox 360'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Profile_FastCap|Xbox 360'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Xbox 360'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release_LTCG|Xbox 360'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Xbox 360'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='CodeAnalysis|Xbox 360'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Xbox 360'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile_FastCap|Xbox 360'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Xbox 360'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_LTCG|Xbox 360'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Xbox 360'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<Optimization>Disabled</Optimization>
<ExceptionHandling>false</ExceptionHandling>
<MinimalRebuild>true</MinimalRebuild>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PreprocessorDefinitions>_DEBUG;_XBOX;PACKAGE_VERSION="0.9.4";%(PreprocessorDefinitions);PACKAGE_VERSION="0.9.4";_CRT_SECURE_NO_WARNINGS;main=ssnes_main;HAVE_CONFIGFILE</PreprocessorDefinitions>
<CallAttributedProfiling>Callcap</CallAttributedProfiling>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
<AdditionalDependencies>xapilibd.lib;d3d9d.lib;d3dx9d.lib;xgraphicsd.lib;xboxkrnl.lib;xnetd.lib;xaudiod2.lib;xactd3.lib;x3daudiod.lib;xmcored.lib;xbdm.lib;vcompd.lib;$(SolutionDir)\Debug\snes9x-next-360-msvc2010.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<Deploy>
<DeploymentType>CopyToHardDrive</DeploymentType>
</Deploy>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='CodeAnalysis|Xbox 360'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<Optimization>Disabled</Optimization>
<ExceptionHandling>false</ExceptionHandling>
<MinimalRebuild>true</MinimalRebuild>
<PREfast>AnalyzeOnly</PREfast>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PreprocessorDefinitions>_DEBUG;_XBOX;%(PreprocessorDefinitions);PACKAGE_VERSION="0.9.4";_CRT_SECURE_NO_WARNINGS;main=ssnes_main;HAVE_CONFIGFILE;SSNES_CONSOLE</PreprocessorDefinitions>
<CallAttributedProfiling>Callcap</CallAttributedProfiling>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
<AdditionalDependencies>xapilibd.lib;d3d9d.lib;d3dx9d.lib;xgraphicsd.lib;xboxkrnl.lib;xnetd.lib;xaudiod2.lib;xactd3.lib;x3daudiod.lib;xmcored.lib;xbdm.lib;vcompd.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Xbox 360'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>Full</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<ExceptionHandling>false</ExceptionHandling>
<StringPooling>true</StringPooling>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PreprocessorDefinitions>NDEBUG;_XBOX;PROFILE;%(PreprocessorDefinitions);PACKAGE_VERSION="0.9.4";_CRT_SECURE_NO_WARNINGS;main=ssnes_main;HAVE_CONFIGFILE</PreprocessorDefinitions>
<CallAttributedProfiling>Callcap</CallAttributedProfiling>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>false</EnableCOMDATFolding>
<IgnoreSpecificDefaultLibraries>xapilib.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
<OptimizeReferences>true</OptimizeReferences>
<ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
<SetChecksum>true</SetChecksum>
<AdditionalDependencies>xapilibi.lib;d3d9i.lib;d3dx9.lib;xgraphics.lib;xboxkrnl.lib;xnet.lib;xaudio2.lib;xact3i.lib;x3daudioi.lib;xmcorei.lib;xbdm.lib;vcomp.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Profile_FastCap|Xbox 360'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>Full</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<ExceptionHandling>false</ExceptionHandling>
<StringPooling>true</StringPooling>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallAttributedProfiling>Fastcap</CallAttributedProfiling>
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PreprocessorDefinitions>NDEBUG;_XBOX;PROFILE;FASTCAP;%(PreprocessorDefinitions);PACKAGE_VERSION="0.9.4";_CRT_SECURE_NO_WARNINGS;main=ssnes_main;HAVE_CONFIGFILE</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>false</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
<SetChecksum>true</SetChecksum>
<AdditionalDependencies>xapilib.lib;d3d9.lib;d3dx9.lib;xgraphics.lib;xboxkrnl.lib;xnet.lib;xaudio2.lib;xact3.lib;x3daudio.lib;xmcore.lib;vcomp.lib;xbdm.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Xbox 360'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>Full</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<StringPooling>true</StringPooling>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
<ExceptionHandling>false</ExceptionHandling>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PreprocessorDefinitions>NDEBUG;_XBOX;%(PreprocessorDefinitions);PACKAGE_VERSION="0.9.4";_CRT_SECURE_NO_WARNINGS;main=ssnes_main;HAVE_CONFIGFILE</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
<SetChecksum>true</SetChecksum>
<AdditionalDependencies>xapilib.lib;d3d9.lib;d3dx9.lib;xgraphics.lib;xboxkrnl.lib;xnet.lib;xaudio2.lib;xact3.lib;x3daudio.lib;xmcore.lib;vcomp.lib;xbdm.lib;$(SolutionDir)\Release\snes9x-next-360-msvc2010.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<Deploy>
<DeploymentType>CopyToHardDrive</DeploymentType>
</Deploy>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release_LTCG|Xbox 360'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>Full</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<StringPooling>true</StringPooling>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
<ExceptionHandling>false</ExceptionHandling>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PreprocessorDefinitions>NDEBUG;_XBOX;LTCG;%(PreprocessorDefinitions);PACKAGE_VERSION="0.9.4";_CRT_SECURE_NO_WARNINGS;main=ssnes_main;HAVE_CONFIGFILE</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
<SetChecksum>true</SetChecksum>
<AdditionalDependencies>xapilib.lib;d3d9ltcg.lib;d3dx9.lib;xgraphics.lib;xboxkrnl.lib;xnet.lib;xaudio2.lib;xact3ltcg.lib;x3daudioltcg.lib;xmcoreltcg.lib;vcomp.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\360\main.c" />
<ClCompile Include="..\..\360\xdk360_audio.cpp" />
<ClCompile Include="..\..\360\xdk360_input.cpp" />
<ClCompile Include="..\..\360\xdk360_video.cpp" />
<ClCompile Include="..\..\audio\hermite.c" />
<ClCompile Include="..\..\audio\utils.c" />
<ClCompile Include="..\..\autosave.c" />
<ClCompile Include="..\..\bps.c" />
<ClCompile Include="..\..\cheats.c">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Xbox 360'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\conf\config_file.c" />
<ClCompile Include="..\..\driver.c" />
<ClCompile Include="..\..\dynamic.c" />
<ClCompile Include="..\..\fifo_buffer.c" />
<ClCompile Include="..\..\file.c" />
<ClCompile Include="..\..\getopt.c" />
<ClCompile Include="..\..\message.c" />
<ClCompile Include="..\..\movie.c" />
<ClCompile Include="..\..\netplay.c">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Xbox 360'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\posix_string.c" />
<ClCompile Include="..\..\rewind.c" />
<ClCompile Include="..\..\screenshot.c" />
<ClCompile Include="..\..\settings.c" />
<ClCompile Include="..\..\sha256.c" />
<ClCompile Include="..\..\ssnes.c" />
<ClCompile Include="..\..\strl.c" />
<ClCompile Include="..\..\thread.c" />
<ClCompile Include="..\..\ups.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\360\msvc_compat.h" />
<ClInclude Include="..\..\360\xdk360_audio.h" />
<ClInclude Include="..\..\audio\hermite.h" />
<ClInclude Include="..\..\audio\utils.h" />
<ClInclude Include="..\..\autosave.h" />
<ClInclude Include="..\..\boolean.h" />
<ClInclude Include="..\..\bps.h" />
<ClInclude Include="..\..\cheats.h" />
<ClInclude Include="..\..\config.def.h" />
<ClInclude Include="..\..\config.features.h" />
<ClInclude Include="..\..\conf\config_file.h" />
<ClInclude Include="..\..\driver.h" />
<ClInclude Include="..\..\dynamic.h" />
<ClInclude Include="..\..\fifo_buffer.h" />
<ClInclude Include="..\..\file.h" />
<ClInclude Include="..\..\general.h" />
<ClInclude Include="..\..\getopt_ssnes.h" />
<ClInclude Include="..\..\libsnes.hpp" />
<ClInclude Include="..\..\message.h" />
<ClInclude Include="..\..\movie.h" />
<ClInclude Include="..\..\netplay.h" />
<ClInclude Include="..\..\posix_string.h" />
<ClInclude Include="..\..\rewind.h" />
<ClInclude Include="..\..\screenshot.h" />
<ClInclude Include="..\..\sha256.h" />
<ClInclude Include="..\..\strl.h" />
<ClInclude Include="..\..\thread.h" />
<ClInclude Include="..\..\ups.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,200 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Header Files\360">
<UniqueIdentifier>{740056e8-6476-4e8c-b9cb-767bebdb5c60}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\audio">
<UniqueIdentifier>{747ac5fa-bd8a-4e60-9246-7a8fb0d38b85}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Source Files\360">
<UniqueIdentifier>{b9371e8d-2e72-4ced-8bf6-6ee6a77a1f78}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\audio">
<UniqueIdentifier>{c8038d65-499b-493b-80e9-90bd7c57383f}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\conf">
<UniqueIdentifier>{755ce6db-d242-40fb-9c8b-c14154fc94e1}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\conf">
<UniqueIdentifier>{82e8787f-e939-4783-82e1-fcab34285121}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\360\xdk360_video.cpp">
<Filter>Source Files\360</Filter>
</ClCompile>
<ClCompile Include="..\..\360\xdk360_input.cpp">
<Filter>Source Files\360</Filter>
</ClCompile>
<ClCompile Include="..\..\ups.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\autosave.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\bps.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\cheats.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\driver.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\dynamic.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\fifo_buffer.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\file.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\getopt.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\message.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\movie.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\netplay.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\posix_string.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\rewind.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\screenshot.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\settings.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\sha256.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\ssnes.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\strl.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\thread.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\audio\hermite.c">
<Filter>Source Files\audio</Filter>
</ClCompile>
<ClCompile Include="..\..\audio\utils.c">
<Filter>Source Files\audio</Filter>
</ClCompile>
<ClCompile Include="..\..\360\xdk360_audio.cpp">
<Filter>Source Files\360</Filter>
</ClCompile>
<ClCompile Include="..\..\360\main.c">
<Filter>Source Files\360</Filter>
</ClCompile>
<ClCompile Include="..\..\conf\config_file.c">
<Filter>Source Files\conf</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\ups.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\autosave.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\boolean.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\bps.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\cheats.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\config.def.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\config.features.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\driver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\dynamic.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\fifo_buffer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\file.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\general.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\getopt_ssnes.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\libsnes.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\message.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\movie.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\netplay.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\posix_string.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\rewind.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\screenshot.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\sha256.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\strl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\thread.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\360\xdk360_audio.h">
<Filter>Header Files\360</Filter>
</ClInclude>
<ClInclude Include="..\..\360\msvc_compat.h">
<Filter>Header Files\360</Filter>
</ClInclude>
<ClInclude Include="..\..\audio\hermite.h">
<Filter>Header Files\audio</Filter>
</ClInclude>
<ClInclude Include="..\..\audio\utils.h">
<Filter>Header Files\audio</Filter>
</ClInclude>
<ClInclude Include="..\..\conf\config_file.h">
<Filter>Header Files\conf</Filter>
</ClInclude>
</ItemGroup>
</Project>
Loaded 100 of 162 files, more files were not shown because too many files have changed in this diff. Show more