From b02910b47fdb709c587b131d978f8848eb4db9c8 Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Tue, 23 Jun 2020 13:47:30 +0200 Subject: [PATCH] retro: implement video output for libretro core and make it build on Windows. --- src/3rdparty/lolengine | 2 +- src/libretro-zepto8.vcxproj | 72 +++++++++++++++ src/libretro.cpp | 174 ++++++++++++++++++++++++++++++------ zepto8.sln | 29 ++++-- 4 files changed, 244 insertions(+), 33 deletions(-) create mode 100644 src/libretro-zepto8.vcxproj diff --git a/src/3rdparty/lolengine b/src/3rdparty/lolengine index ad2f4aa..8e9dd28 160000 --- a/src/3rdparty/lolengine +++ b/src/3rdparty/lolengine @@ -1 +1 @@ -Subproject commit ad2f4aacfd0f2eae4a71a74dba74cf4e154c9a7e +Subproject commit 8e9dd2866a62cd5a5e674efe9bdfaa0373b5db7f diff --git a/src/libretro-zepto8.vcxproj b/src/libretro-zepto8.vcxproj new file mode 100644 index 0000000..3d76ce7 --- /dev/null +++ b/src/libretro-zepto8.vcxproj @@ -0,0 +1,72 @@ + + + + $(SolutionDir)src\3rdparty\lolengine\ + + + + Debug + NX64 + + + Debug + ORBIS + + + Debug + Win32 + + + Debug + x64 + + + Release + NX64 + + + Release + ORBIS + + + Release + Win32 + + + Release + x64 + + + + {57423C2D-5F70-4D60-AE8C-F5FBE39B1464} + DynamicLibrary + Win32Proj + 8.1 + + + + .dll + + + + .;3rdparty/libretro-common/include;%(AdditionalIncludeDirectories) + PACKAGE_VERSION="0.0";%(PreprocessorDefinitions) + + + + + + + + + + {5168dfab-3b54-4caa-8654-da760bc53b74} + + + {141365e7-f8f3-4d95-b8db-1a093f92f436} + + + {9ae29931-c72e-43df-805b-27e4ddfbb582} + + + \ No newline at end of file diff --git a/src/libretro.cpp b/src/libretro.cpp index c8627d7..1c7a1b0 100644 --- a/src/libretro.cpp +++ b/src/libretro.cpp @@ -14,67 +14,191 @@ # include "config.h" #endif -#include // lol::input -#include // lol::mat4 -#include // lol::color - -#include "player.h" +#include // lol::msg +#include // std::memset +#include // std::shared_ptr +#include // std::vector #include "zepto8.h" #include "pico8/vm.h" #include "pico8/pico8.h" #include "raccoon/vm.h" +#include "libretro.h" + +#define EXPORT extern "C" RETRO_API + +// Callbacks provided by retroarch +static retro_video_refresh_t video_cb; +static retro_audio_sample_t audio_cb; +static retro_audio_sample_batch_t audio_batch_cb; +static retro_environment_t enviro_cb; +static retro_input_poll_t input_poll_cb; +static retro_input_state_t input_state_cb; -extern "C" +static bool is_raccoon; +static std::shared_ptr vm; +static lol::array2d fb32; +static lol::array2d fb16; + +EXPORT void retro_set_environment(retro_environment_t cb) { -#include "libretro.h" + enviro_cb = cb; + // We can run without a cartridge + bool no_rom = true; + enviro_cb(RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME, &no_rom); +} + +EXPORT void retro_set_video_refresh(retro_video_refresh_t cb) +{ + video_cb = cb; +} + +EXPORT void retro_set_audio_sample(retro_audio_sample_t cb) +{ + audio_cb = cb; +} + +EXPORT void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb) +{ + audio_batch_cb = cb; +} + +EXPORT void retro_set_input_poll(retro_input_poll_t cb) +{ + input_poll_cb = cb; +} + +EXPORT void retro_set_input_state(retro_input_state_t cb) +{ + input_state_cb = cb; +} + +EXPORT void retro_init() +{ + // Allocate framebuffer and VM + vm.reset((z8::vm_base *)new z8::pico8::vm()); + fb32.resize(lol::ivec2(128, 128)); + fb16.resize(lol::ivec2(128, 128)); +} + +EXPORT void retro_deinit() +{ + fb32.clear(); + fb16.clear(); } -namespace z8 +EXPORT unsigned retro_api_version() { + return RETRO_API_VERSION; +} -extern "C" void retro_get_system_info(struct retro_system_info *info) +EXPORT void retro_get_system_info(struct retro_system_info *info) { memset(info, 0, sizeof(*info)); info->library_name = "zepto8"; - info->library_version = "0.0.0"; - info->valid_extensions = "p8|p8.png"; + info->library_version = PACKAGE_VERSION; + info->valid_extensions = "p8|png|rcn.json"; info->need_fullpath = true; // we load our own carts for now } -extern "C" void retro_get_system_av_info(struct retro_system_av_info *info) +EXPORT void retro_get_system_av_info(struct retro_system_av_info *info) { memset(info, 0, sizeof(*info)); - info->geometry.base_width = info->geometry.max_width = 128; - info->geometry.base_height = info->geometry.max_height = 128; + info->geometry.base_width = 128; + info->geometry.base_height = 128; + info->geometry.max_width = 128; + info->geometry.max_height = 128; info->geometry.aspect_ratio = 1.f; info->timing.fps = 60.f; info->timing.sample_rate = 44100.f; + + retro_pixel_format pf = RETRO_PIXEL_FORMAT_RGB565; + enviro_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &pf); } -extern "C" void retro_set_environment(retro_environment_t cb) +EXPORT void retro_set_controller_port_device(unsigned port, unsigned device) { - // We can run without a cartridge - bool no_rom = true; - cb(RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME, &no_rom); } -extern "C" bool retro_load_game(const struct retro_game_info *info) +EXPORT void retro_reset() +{ +} + +EXPORT void retro_run() +{ + // Update input + + // Step VM + vm->step(1.f / 60); + + // Render video, convert to RGB565 + vm->render(fb32.data()); + for (int y = 0; y < 128; ++y) + for (int x = 0; x < 128; ++x) + fb16[x][y] = uint16_t(lol::dot(lol::ivec3(fb32[x][y].rgb) / lol::ivec3(8, 4, 8), + lol::ivec3(2048, 32, 1))); + video_cb(fb16.data(), 128, 128, 2 * 128); + + // Render audio +} + +EXPORT size_t retro_serialize_size() +{ + return 0; +} + +EXPORT bool retro_serialize(void *data, size_t size) +{ + return false; +} + +EXPORT bool retro_unserialize(const void *data, size_t size) { - // TODO: load cart - (void)info; + return false; +} + +EXPORT void retro_cheat_reset() +{ +} + +EXPORT void retro_cheat_set(unsigned index, bool enabled, const char *code) +{ +} + +EXPORT bool retro_load_game(struct retro_game_info const *info) +{ + is_raccoon = lol::ends_with(info->path, ".rcn.json"); + if (is_raccoon) + vm.reset((z8::vm_base *)new z8::raccoon::vm()); + else + vm.reset((z8::vm_base *)new z8::pico8::vm()); + vm->load(info->path); + vm->run(); return true; } -extern "C" void retro_unload_game() +EXPORT bool retro_load_game_special(unsigned game_type, + const struct retro_game_info *info, size_t num_info) +{ + return false; +} + +EXPORT void retro_unload_game() { } -extern "C" void retro_run(void) +EXPORT unsigned retro_get_region() { - // TODO: vm->step(), audio_cb(), video_cb() + return 0; } +EXPORT void *retro_get_memory_data(unsigned id) +{ + return nullptr; +} -} // namespace z8 +EXPORT size_t retro_get_memory_size(unsigned id) +{ + return 0; +} diff --git a/zepto8.sln b/zepto8.sln index 98be973..3072955 100644 --- a/zepto8.sln +++ b/zepto8.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28010.2036 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30204.135 MinimumVisualStudioVersion = 15.0.26730.03 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lol-core", "src\3rdparty\lolengine\src\lol-core.vcxproj", "{9E62F2FE-3408-4EAE-8238-FD84238CEEDA}" EndProject @@ -17,7 +17,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "z8dev", "src\z8dev.vcxproj" {141365E7-F8F3-4D95-B8DB-1A093F92F436} = {141365E7-F8F3-4D95-B8DB-1A093F92F436} EndProjectSection EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "z8dev", "z8dev", "{03B9D2E1-AFBA-4F66-8DE0-6499C9F9155F}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lib", "lib", "{03B9D2E1-AFBA-4F66-8DE0-6499C9F9155F}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zepto8", "src\zepto8.vcxproj", "{948C0C9A-2C25-41D9-BF1B-92B14A8C061B}" ProjectSection(ProjectDependencies) = postProject @@ -37,6 +37,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "z8lua", "src\z8lua.vcxproj" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libquickjs", "src\libquickjs.vcxproj", "{5168DFAB-3B54-4CAA-8654-DA760BC53B74}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libretro-zepto8", "src\libretro-zepto8.vcxproj", "{57423C2D-5F70-4D60-AE8C-F5FBE39B1464}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|NX64 = Debug|NX64 @@ -185,6 +187,22 @@ Global {5168DFAB-3B54-4CAA-8654-DA760BC53B74}.Release|Win32.Build.0 = Release|Win32 {5168DFAB-3B54-4CAA-8654-DA760BC53B74}.Release|x64.ActiveCfg = Release|x64 {5168DFAB-3B54-4CAA-8654-DA760BC53B74}.Release|x64.Build.0 = Release|x64 + {57423C2D-5F70-4D60-AE8C-F5FBE39B1464}.Debug|NX64.ActiveCfg = Debug|NX64 + {57423C2D-5F70-4D60-AE8C-F5FBE39B1464}.Debug|NX64.Build.0 = Debug|NX64 + {57423C2D-5F70-4D60-AE8C-F5FBE39B1464}.Debug|ORBIS.ActiveCfg = Debug|ORBIS + {57423C2D-5F70-4D60-AE8C-F5FBE39B1464}.Debug|ORBIS.Build.0 = Debug|ORBIS + {57423C2D-5F70-4D60-AE8C-F5FBE39B1464}.Debug|Win32.ActiveCfg = Debug|Win32 + {57423C2D-5F70-4D60-AE8C-F5FBE39B1464}.Debug|Win32.Build.0 = Debug|Win32 + {57423C2D-5F70-4D60-AE8C-F5FBE39B1464}.Debug|x64.ActiveCfg = Debug|x64 + {57423C2D-5F70-4D60-AE8C-F5FBE39B1464}.Debug|x64.Build.0 = Debug|x64 + {57423C2D-5F70-4D60-AE8C-F5FBE39B1464}.Release|NX64.ActiveCfg = Release|NX64 + {57423C2D-5F70-4D60-AE8C-F5FBE39B1464}.Release|NX64.Build.0 = Release|NX64 + {57423C2D-5F70-4D60-AE8C-F5FBE39B1464}.Release|ORBIS.ActiveCfg = Release|ORBIS + {57423C2D-5F70-4D60-AE8C-F5FBE39B1464}.Release|ORBIS.Build.0 = Release|ORBIS + {57423C2D-5F70-4D60-AE8C-F5FBE39B1464}.Release|Win32.ActiveCfg = Release|Win32 + {57423C2D-5F70-4D60-AE8C-F5FBE39B1464}.Release|Win32.Build.0 = Release|Win32 + {57423C2D-5F70-4D60-AE8C-F5FBE39B1464}.Release|x64.ActiveCfg = Release|x64 + {57423C2D-5F70-4D60-AE8C-F5FBE39B1464}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -192,13 +210,10 @@ Global GlobalSection(NestedProjects) = preSolution {9E62F2FE-3408-4EAE-8238-FD84238CEEDA} = {1AFD580B-98B8-4689-B661-38C41132C60E} {D84021CA-B233-4E0F-8A52-071B83BBCCC4} = {1AFD580B-98B8-4689-B661-38C41132C60E} - {28F5DE0F-B162-4833-8F61-A1AF782850A2} = {03B9D2E1-AFBA-4F66-8DE0-6499C9F9155F} - {948C0C9A-2C25-41D9-BF1B-92B14A8C061B} = {03B9D2E1-AFBA-4F66-8DE0-6499C9F9155F} - {CC700045-8E2C-4516-9159-43FC4FFD4783} = {03B9D2E1-AFBA-4F66-8DE0-6499C9F9155F} {9AE29931-C72E-43DF-805B-27E4DDFBB582} = {03B9D2E1-AFBA-4F66-8DE0-6499C9F9155F} {141365E7-F8F3-4D95-B8DB-1A093F92F436} = {03B9D2E1-AFBA-4F66-8DE0-6499C9F9155F} - {DC847AF8-FF9C-4F24-AE83-B86FC5C6777D} = {03B9D2E1-AFBA-4F66-8DE0-6499C9F9155F} {5168DFAB-3B54-4CAA-8654-DA760BC53B74} = {03B9D2E1-AFBA-4F66-8DE0-6499C9F9155F} + {57423C2D-5F70-4D60-AE8C-F5FBE39B1464} = {03B9D2E1-AFBA-4F66-8DE0-6499C9F9155F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4F6F88E8-5604-4BA7-89AA-7A8DC8C3374B}