Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion game.libretro/addon.xml.in
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="game.libretro"
name="Libretro Compatibility"
version="22.2.5"
version="22.3.0"
provider-name="Team Kodi">
<backwards-compatibility abi="1.0.0"/>
<requires>@ADDON_DEPENDS@</requires>
Expand Down
55 changes: 55 additions & 0 deletions src/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -544,4 +544,59 @@ GAME_ERROR CGameLibRetro::RCResetRuntime()
return GAME_ERROR_NO_ERROR;
}

bool CGameLibRetro::GetEjectState()
{
return m_clientBridge.GetEjectState();
}

GAME_ERROR CGameLibRetro::SetEjectState(bool ejected)
{
return m_clientBridge.SetEjectState(ejected);
}

unsigned int CGameLibRetro::GetImageIndex()
{
return m_clientBridge.GetImageIndex();
}

GAME_ERROR CGameLibRetro::SetImageIndex(unsigned int imageIndex)
{
return m_clientBridge.SetImageIndex(imageIndex);
}

unsigned int CGameLibRetro::GetImageCount()
{
return m_clientBridge.GetImageCount();
}

GAME_ERROR CGameLibRetro::AddImageIndex()
{
return m_clientBridge.AddImageIndex();
}

GAME_ERROR CGameLibRetro::ReplaceImageIndex(unsigned int imageIndex, const std::string& filePath)
{
return m_clientBridge.ReplaceImageIndex(imageIndex, filePath);
}

GAME_ERROR CGameLibRetro::RemoveImageIndex(unsigned int imageIndex)
{
return m_clientBridge.RemoveImageIndex(imageIndex);
}

GAME_ERROR CGameLibRetro::SetInitialImage(unsigned int imageIndex, const std::string& filePath)
{
return m_clientBridge.SetInitialImage(imageIndex, filePath);
}

std::string CGameLibRetro::GetImagePath(unsigned int imageIndex)
{
return m_clientBridge.GetImagePath(imageIndex);
}

std::string CGameLibRetro::GetImageLabel(unsigned int imageIndex)
{
return m_clientBridge.GetImageLabel(imageIndex);
}

ADDONCREATOR(CGameLibRetro)
14 changes: 14 additions & 0 deletions src/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,20 @@ class ATTR_DLL_LOCAL CGameLibRetro
GAME_ERROR RCGetRichPresenceEvaluation(std::string& evaluation, unsigned int consoleID) override;
GAME_ERROR RCResetRuntime() override;

// --- Disc control interface

bool GetEjectState() override;
GAME_ERROR SetEjectState(bool ejected) override;
unsigned int GetImageIndex() override;
GAME_ERROR SetImageIndex(unsigned int imageIndex) override;
unsigned int GetImageCount() override;
GAME_ERROR AddImageIndex() override;
GAME_ERROR ReplaceImageIndex(unsigned int imageIndex, const std::string& filePath) override;
GAME_ERROR RemoveImageIndex(unsigned int imageIndex) override;
GAME_ERROR SetInitialImage(unsigned int imageIndex, const std::string& filePath) override;
std::string GetImagePath(unsigned int imageIndex) override;
std::string GetImageLabel(unsigned int imageIndex) override;

private:
GAME_ERROR AudioAvailable();

Expand Down
138 changes: 136 additions & 2 deletions src/libretro/ClientBridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

#include "ClientBridge.h"

#include "libretro-common/libretro.h"
#include "GameInfoLoader.h"

// Causing errors with std::numeric_limits<int>::max()
#ifdef max
Expand All @@ -18,13 +18,28 @@

using namespace LIBRETRO;

namespace
{
constexpr unsigned int MAX_PATH = 4096;
}

CClientBridge::CClientBridge()
: m_retro_keyboard_event(nullptr),
m_retro_hw_context_reset(nullptr),
m_retro_hw_context_destroy(nullptr),
m_retro_audio_set_state_callback(nullptr),
m_retro_audio_callback(nullptr),
m_retro_frame_time_callback(nullptr)
m_retro_frame_time_callback(nullptr),
m_retro_set_eject_state(nullptr),
m_retro_get_eject_state(nullptr),
m_retro_get_image_index(nullptr),
m_retro_set_image_index(nullptr),
m_retro_get_num_images(nullptr),
m_retro_replace_image_index(nullptr),
m_retro_add_image_index(nullptr),
m_retro_set_initial_image(nullptr),
m_retro_get_image_path(nullptr),
m_retro_get_image_label(nullptr)
{
}

Expand Down Expand Up @@ -87,3 +102,122 @@ GAME_ERROR CClientBridge::FrameTime(int64_t usec)

return GAME_ERROR_NO_ERROR;
}

GAME_ERROR CClientBridge::SetEjectState(bool ejected)
{
if (!m_retro_set_eject_state)
return GAME_ERROR_FAILED;

if (!m_retro_set_eject_state(ejected))
return GAME_ERROR_FAILED;

return GAME_ERROR_NO_ERROR;
}

bool CClientBridge::GetEjectState()
{
if (!m_retro_get_eject_state)
return false;

return m_retro_get_eject_state();
}

unsigned int CClientBridge::GetImageIndex()
{
if (!m_retro_get_image_index)
return 0;

return m_retro_get_image_index();
}

GAME_ERROR CClientBridge::SetImageIndex(unsigned int imageIndex)
{
if (!m_retro_set_image_index)
return GAME_ERROR_FAILED;

if (!m_retro_set_image_index(imageIndex))
return GAME_ERROR_FAILED;

return GAME_ERROR_NO_ERROR;
}

unsigned int CClientBridge::GetImageCount()
{
if (!m_retro_get_num_images)
return 0;

return m_retro_get_num_images();
}

GAME_ERROR CClientBridge::ReplaceImageIndex(unsigned int imageIndex, const std::string& filePath)
{
if (!m_retro_replace_image_index)
return GAME_ERROR_FAILED;

retro_game_info gameInfo;

CGameInfoLoader gameInfoLoader(filePath, false);
gameInfoLoader.GetPathStruct(gameInfo);

if (!m_retro_replace_image_index(imageIndex, &gameInfo))
return GAME_ERROR_FAILED;

return GAME_ERROR_NO_ERROR;
}

GAME_ERROR CClientBridge::RemoveImageIndex(unsigned int imageIndex)
{
if (!m_retro_replace_image_index)
return GAME_ERROR_FAILED;

if (!m_retro_replace_image_index(imageIndex, nullptr))
return GAME_ERROR_FAILED;

return GAME_ERROR_NO_ERROR;
}

GAME_ERROR CClientBridge::AddImageIndex()
{
if (!m_retro_add_image_index)
return GAME_ERROR_FAILED;

if (!m_retro_add_image_index())
return GAME_ERROR_FAILED;

return GAME_ERROR_NO_ERROR;
}

GAME_ERROR CClientBridge::SetInitialImage(unsigned int imageIndex, const std::string& filePath)
{
if (!m_retro_set_initial_image)
return GAME_ERROR_FAILED;

if (!m_retro_set_initial_image(imageIndex, filePath.c_str()))
return GAME_ERROR_FAILED;

return GAME_ERROR_NO_ERROR;
}

std::string CClientBridge::GetImagePath(unsigned int imageIndex)
{
if (!m_retro_get_image_path)
return "";

char imagePath[MAX_PATH] = {};
if (!m_retro_get_image_path(imageIndex, imagePath, sizeof(imagePath)))
return "";

return imagePath;
}

std::string CClientBridge::GetImageLabel(unsigned int imageIndex)
{
if (!m_retro_get_image_label)
return "";

char imageLabel[MAX_PATH] = {};
if (!m_retro_get_image_label(imageIndex, imageLabel, sizeof(imageLabel)))
return "";

return imageLabel;
}
32 changes: 32 additions & 0 deletions src/libretro/ClientBridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#pragma once

#include <kodi/addon-instance/Game.h>
#include <libretro-common/libretro.h>

struct retro_game_info;

Expand Down Expand Up @@ -36,6 +37,17 @@ namespace LIBRETRO
GAME_ERROR AudioEnable(bool enabled);
GAME_ERROR AudioAvailable(void);
GAME_ERROR FrameTime(int64_t);
bool GetEjectState();
GAME_ERROR SetEjectState(bool ejected);
unsigned int GetImageIndex();
GAME_ERROR SetImageIndex(unsigned int imageIndex);
unsigned int GetImageCount();
GAME_ERROR ReplaceImageIndex(unsigned int imageIndex, const std::string& filePath);
GAME_ERROR RemoveImageIndex(unsigned int imageIndex);
GAME_ERROR AddImageIndex();
GAME_ERROR SetInitialImage(unsigned int imageIndex, const std::string& filePath);
std::string GetImagePath(unsigned int imageIndex);
std::string GetImageLabel(unsigned int imageIndex);

typedef void (*KeyboardEventCallback)(bool down, unsigned keycode, uint32_t character, uint16_t key_modifiers);
typedef void (*HwContextResetCallback)(void);
Expand All @@ -50,6 +62,16 @@ namespace LIBRETRO
void SetAudioEnable(AudioEnableCallback callback) { m_retro_audio_set_state_callback = callback; }
void SetAudioAvailable(AudioAvailableCallback callback) { m_retro_audio_callback = callback; }
void SetFrameTime(FrameTimeCallback callback) { m_retro_frame_time_callback = callback; }
void SetSetEjectState(retro_set_eject_state_t callback) { m_retro_set_eject_state = callback; }
void SetGetEjectState(retro_get_eject_state_t callback) { m_retro_get_eject_state = callback; }
void SetGetImageIndex(retro_get_image_index_t callback) { m_retro_get_image_index = callback; }
void SetSetImageIndex(retro_set_image_index_t callback) { m_retro_set_image_index = callback; }
void SetGetImageCount(retro_get_num_images_t callback) { m_retro_get_num_images = callback; }
void SetReplaceImageIndex(retro_replace_image_index_t callback) { m_retro_replace_image_index = callback; }
void SetAddImageIndex(retro_add_image_index_t callback) { m_retro_add_image_index = callback; }
void SetSetInitialImage(retro_set_initial_image_t callback) { m_retro_set_initial_image = callback; }
void SetGetImagePath(retro_get_image_path_t callback) { m_retro_get_image_path = callback; }
void SetGetImageLabel(retro_get_image_label_t callback) { m_retro_get_image_label = callback; }

private:
// The bridge is accomplished by invoking the callback provided by libretro's
Expand All @@ -61,5 +83,15 @@ namespace LIBRETRO
AudioEnableCallback m_retro_audio_set_state_callback;
AudioAvailableCallback m_retro_audio_callback;
FrameTimeCallback m_retro_frame_time_callback;
retro_set_eject_state_t m_retro_set_eject_state;
retro_get_eject_state_t m_retro_get_eject_state;
retro_get_image_index_t m_retro_get_image_index;
retro_set_image_index_t m_retro_set_image_index;
retro_get_num_images_t m_retro_get_num_images;
retro_replace_image_index_t m_retro_replace_image_index;
retro_add_image_index_t m_retro_add_image_index;
retro_set_initial_image_t m_retro_set_initial_image;
retro_get_image_path_t m_retro_get_image_path;
retro_get_image_label_t m_retro_get_image_label;
};
} // namespace LIBRETRO
39 changes: 29 additions & 10 deletions src/libretro/LibretroEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,14 @@ bool CLibretroEnvironment::EnvironmentCallback(unsigned int cmd, void *data)
const retro_disk_control_callback *typedData = static_cast<const retro_disk_control_callback*>(data);
if (typedData)
{
// Disk control interface not implemented
return false;
// Store callbacks from libretro client
m_clientBridge->SetSetEjectState(typedData->set_eject_state);
m_clientBridge->SetGetEjectState(typedData->get_eject_state);
m_clientBridge->SetGetImageIndex(typedData->get_image_index);
m_clientBridge->SetSetImageIndex(typedData->set_image_index);
m_clientBridge->SetGetImageCount(typedData->get_num_images);
m_clientBridge->SetReplaceImageIndex(typedData->replace_image_index);
m_clientBridge->SetAddImageIndex(typedData->add_image_index);
}
break;
}
Expand Down Expand Up @@ -732,18 +738,31 @@ bool CLibretroEnvironment::EnvironmentCallback(unsigned int cmd, void *data)
case RETRO_ENVIRONMENT_GET_DISK_CONTROL_INTERFACE_VERSION:
{
unsigned int* typedData = static_cast<unsigned int*>(data);

// Not implemented
(void)typedData;
return false;
if (typedData != nullptr)
{
// Extended interface is supported
*typedData = 1;
}
break;
}
case RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE:
{
const retro_disk_control_ext_callback* typedData = static_cast<const retro_disk_control_ext_callback*>(data);

// Not implemented
(void)typedData;
return false;
if (typedData)
{
// Store callbacks from libretro client
m_clientBridge->SetSetEjectState(typedData->set_eject_state);
m_clientBridge->SetGetEjectState(typedData->get_eject_state);
m_clientBridge->SetGetImageIndex(typedData->get_image_index);
m_clientBridge->SetSetImageIndex(typedData->set_image_index);
m_clientBridge->SetGetImageCount(typedData->get_num_images);
m_clientBridge->SetReplaceImageIndex(typedData->replace_image_index);
m_clientBridge->SetAddImageIndex(typedData->add_image_index);
m_clientBridge->SetSetInitialImage(typedData->set_initial_image);
m_clientBridge->SetGetImagePath(typedData->get_image_path);
m_clientBridge->SetGetImageLabel(typedData->get_image_label);
}
break;
}
case RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION:
{
Expand Down
Loading