Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for lighting peripherals #456

Merged
merged 15 commits into from
May 28, 2022
8 changes: 7 additions & 1 deletion Main/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,13 @@ source_group("Include\\FastGUI" FILES ${FAST_GUI_INC})
file(GLOB NUK_INC "${INCROOT}/nuklear/*.h")
source_group("Include\\nuklear" FILES ${NUK_INC})

set(MAIN_SRC ${SRC} ${INC} ${AUDIO_SRC} ${AUDIO_INC} ${FAST_GUI_SRC} ${FAST_GUI_INC} ${NUK_INC})
file(GLOB NUK_INC "${INCROOT}/nuklear/*.h")
source_group("Include\\nuklear" FILES ${NUK_INC})

file(GLOB LIGHT_INC "${INCROOT}/LightPlugin/*.h")
source_group("Include\\LightPlugin" FILES ${LIGHT_INC})

set(MAIN_SRC ${SRC} ${INC} ${AUDIO_SRC} ${AUDIO_INC} ${FAST_GUI_SRC} ${FAST_GUI_INC} ${NUK_INC} ${LIGHT_INC})

file(GLOB RESOURCE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/Resource.rc)
source_group("" FILES ${RESOURCE_SRC})
Expand Down
30 changes: 18 additions & 12 deletions Main/include/Application.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ extern struct GUIState g_guiState;
extern class Graphics::Window* g_gameWindow;
extern float g_aspectRatio;
extern Vector2i g_resolution;
extern class Application* g_application;
extern class JobSheduler* g_jobSheduler;
extern class Application *g_application;
extern class JobSheduler *g_jobSheduler;
extern class Input g_input;
extern class SkinConfig* g_skinConfig;
extern class TransitionScreen* g_transition;
extern class SkinConfig *g_skinConfig;
extern class TransitionScreen *g_transition;

class SharedTexture;

Expand Down Expand Up @@ -44,8 +44,8 @@ class Application
class Game* LaunchReplay(const String& replayPath, MapDatabase** database = nullptr);
void Shutdown();

void AddTickable(class IApplicationTickable* tickable, class IApplicationTickable* insertBefore = nullptr);
void RemoveTickable(class IApplicationTickable* tickable, bool noDelete = false);
void AddTickable(class IApplicationTickable *tickable, class IApplicationTickable *insertBefore = nullptr);
void RemoveTickable(class IApplicationTickable *tickable, bool noDelete = false);

// Current running map path (full file path)
String GetCurrentMapPath();
Expand All @@ -54,11 +54,11 @@ class Application
String GetCurrentSkin();

// Retrieves application command line parameters
const Vector<String>& GetAppCommandLine() const;
const Vector<String> &GetAppCommandLine() const;

// Gets a basic template for a render state, with all the application variables initialized
RenderState GetRenderStateBase() const;
RenderQueue* GetRenderQueueBase();
RenderQueue *GetRenderQueueBase();

#ifdef LoadImage
#undef LoadImage
Expand Down Expand Up @@ -102,15 +102,18 @@ class Application
void DiscordError(int errorCode, const char* message);
void DiscordPresenceMenu(String name);
void DiscordPresenceMulti(String secret, int partySize, int partyMax, String id);
void DiscordPresenceSong(const struct BeatmapSettings& song, int64 startTime, int64 endTime);
void DiscordPresenceSong(const struct BeatmapSettings &song, int64 startTime, int64 endTime);
void JoinMultiFromInvite(String secret);
void SetUpdateAvailable(const String& version, const String& url, const String& download);
void SetUpdateAvailable(const String &version, const String &url, const String &download);
void RunUpdater();
void CheckForUpdate();
void ForceRender();
void SetLuaBindings(struct lua_State* state);
Vector<String> GetLightPluginList();
void RenderTickables();
struct NVGcontext* GetVGContext();
void SetRgbLights(int left, int pos, Colori color);
void SetButtonLights(uint32 buttonbits);

//if empty: no update avaiable
//else: index 0 = url, index 1 = version
Expand Down Expand Up @@ -138,6 +141,7 @@ class Application
void m_OnFocusChanged(bool focused);
void m_unpackSkins();
void m_loadResponsiveInputSetting();
void m_InitLightPlugins();

RenderState m_renderStateBase;
RenderQueue m_renderQueueBase;
Expand Down Expand Up @@ -170,8 +174,10 @@ class Application
String m_skin;
bool m_needSkinReload = false;
Timer m_jobTimer;
struct LightPlugin* m_activeLightPlugin = nullptr;
//gauge colors, 0 = normal fail, 1 = normal clear, 2 = hard lower, 3 = hard upper
Color m_gaugeColors[4] = { Colori(0, 204, 255), Colori(255, 102, 255), Colori(200, 50, 0), Colori(255, 100, 0) };
Map<String, struct LightPlugin> m_lightPlugins;

String m_multiRoomSecret;
String m_multiRoomId;
Expand All @@ -194,7 +200,7 @@ class JacketLoadingJob : public JobBase
String imagePath;
int w = 0, h = 0;
bool web = false;
Application::CachedJacketImage* target;
Application::CachedJacketImage *target;
};

void __discordJoinGame(const char* joins);
Expand All @@ -206,4 +212,4 @@ class SharedTexture {
bool Valid();
int nvgTexture = 0;
Texture texture;
};
};
2 changes: 2 additions & 0 deletions Main/include/GameConfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ DefineEnum(GameConfigKeys,
WASAPI_Exclusive,
MuteUnfocused,
PrerenderEffects,
UseLightPlugins,
LightPlugin,

CheckForUpdates,
OnlyRelease,
Expand Down
1 change: 1 addition & 0 deletions Main/include/Input.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class Input : Unique
bool GetButton(Button button) const;
float GetAbsoluteLaser(int laser) const;
bool Are3BTsHeld() const;
uint32 GetButtonBits() const;

// Controller state as a string
// Primarily used for debugging
Expand Down
29 changes: 29 additions & 0 deletions Main/include/LightPlugin/LightPlugin.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>

typedef struct LightPlugin {
void* handle;
char* (*GetName)();
void (*SetButtons)(uint32_t bitfield);
void (*Tick)(float deltaTime);

//6 rgb sections, left/right + pos: (bottom/middle/top) = (0/1/2)
void (*SetLights)(uint8_t left, uint32_t pos, uint8_t r, uint8_t g, uint8_t b);
int (*Init)(void(*)(char*));
int (*Close)();
} LightPlugin;

char* GetName();
void SetButtons(uint32_t bitfield);
void SetLights(uint8_t left, uint32_t pos, uint8_t r, uint8_t g, uint8_t b);
void Tick(float deltaTime);

//Return 0 on success
int Init(void(*)(char*));
int Close();

#ifdef __cplusplus
}
#endif
132 changes: 131 additions & 1 deletion Main/src/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#endif
#include "archive.h"
#include "archive_entry.h"
#include "LightPlugin/LightPlugin.h"

GameConfig g_gameConfig;
SkinConfig *g_skinConfig;
Expand Down Expand Up @@ -98,6 +99,12 @@ void Application::SetCommandLine(const char *cmdLine)
// Split up command line parameters
m_commandLine = Path::SplitCommandLine(cmdLine);
}

static void PluginLog(char* msg)
{
Logf("[Light Plugin]: %s", Logger::Severity::Info, msg);
}

void Application::ApplySettings()
{
String newskin = g_gameConfig.GetString(GameConfigKeys::Skin);
Expand All @@ -111,6 +118,25 @@ void Application::ApplySettings()
m_loadResponsiveInputSetting();
m_UpdateWindowPosAndShape();
m_OnWindowResized(g_gameWindow->GetWindowSize());

//restart light plugin
if (m_activeLightPlugin)
{
m_activeLightPlugin->Close();
m_activeLightPlugin = nullptr;
}

String newPlugin = g_gameConfig.GetString(GameConfigKeys::LightPlugin);
if (m_lightPlugins.Contains(newPlugin))
{
m_activeLightPlugin = &m_lightPlugins.at(newPlugin);
if (m_activeLightPlugin->Init(PluginLog) != 0)
{
Logf("Failed to initialize light plugin: \"%s\"", Logger::Severity::Warning, newPlugin);
m_activeLightPlugin = nullptr;
}
}

m_SaveConfig();
}
int32 Application::Run()
Expand Down Expand Up @@ -219,7 +245,21 @@ NVGcontext *Application::GetVGContext()
return g_guiState.vg;
}

void Application::SetRgbLights(int left, int pos, Colori color)
{
if (m_activeLightPlugin)
{
m_activeLightPlugin->SetLights(left, pos, color.x, color.y, color.z);
}
}

void Application::SetButtonLights(uint32 buttonbits)
{
if (m_activeLightPlugin)
{
m_activeLightPlugin->SetButtons(buttonbits);
}
}

Vector<String> Application::GetUpdateAvailable()
{
Expand Down Expand Up @@ -809,6 +849,70 @@ void Application::m_InitDiscord()
Discord_Initialize(DISCORD_APPLICATION_ID, &dhe, 1, nullptr);
}

void Application::m_InitLightPlugins()
{
ProfilerScope $("Load Light Plugins");

String pluginpath = Path::Absolute("LightPlugins");

#if WIN32
Vector<FileInfo> plugins = Files::ScanFiles(pluginpath, "dll");
#else
Vector<FileInfo> plugins = Files::ScanFiles("LightPlugins", "so");
#endif

Logf("Found %d light plugins.", Logger::Severity::Info, plugins.size());

auto verifyPlugin = [this](const LightPlugin& lp)
{
return lp.Close != nullptr &&
lp.GetName != nullptr &&
lp.Init != nullptr &&
lp.SetButtons != nullptr &&
lp.SetLights != nullptr &&
lp.Tick != nullptr;
};

for (auto& p : plugins)
{
SDL_ClearError();
void* handle = SDL_LoadObject(*p.fullPath);
if (handle)
{
LightPlugin lp;
lp.Init = (int(*)(void(*)(char*)))SDL_LoadFunction(handle, "Init");
lp.Close = (int(*)())SDL_LoadFunction(handle, "Close");
lp.SetButtons = (void(*)(uint32))SDL_LoadFunction(handle, "SetButtons");
lp.GetName = (char*(*)())SDL_LoadFunction(handle, "GetName");
lp.SetLights = (void(*)(uint8, uint32, uint8, uint8, uint8))SDL_LoadFunction(handle, "SetLights");
lp.Tick = (void(*)(float))SDL_LoadFunction(handle, "Tick");
if (verifyPlugin(lp))
m_lightPlugins.Add(lp.GetName(), lp);
else
{
Logf("Failed to verify light plugin \"%s\": %s", Logger::Severity::Warning, p.fullPath, SDL_GetError());
SDL_UnloadObject(handle);
}
}
else {
Logf("Failed to load light plugin \"%s\": %s", Logger::Severity::Warning, p.fullPath, SDL_GetError());
}
}


String newPlugin = g_gameConfig.GetString(GameConfigKeys::LightPlugin);
if (m_lightPlugins.Contains(newPlugin))
{
m_activeLightPlugin = &m_lightPlugins.at(newPlugin);
int res = m_activeLightPlugin->Init(PluginLog);
if (res != 0)
{
Logf("Failed to initialize light plugin: \"%s\"", Logger::Severity::Warning, newPlugin);
m_activeLightPlugin = nullptr;
}
}
}

SDL_semaphore* renderSema = nullptr; //TODO: move to somewhere better
std::atomic<bool> rendering;
void threadedRenderer() {
Expand Down Expand Up @@ -1062,6 +1166,11 @@ bool Application::m_Init()


m_InitDiscord();
if (g_gameConfig.GetBool(GameConfigKeys::UseLightPlugins))
{
m_InitLightPlugins();
}


CheckedLoad(m_fontMaterial = LoadMaterial("font"));
m_fontMaterial->opaque = false;
Expand Down Expand Up @@ -1228,7 +1337,6 @@ void Application::m_Tick()
{
tickable->Tick(m_deltaTime);
}

// Not minimized / Valid resolution
if (g_resolution.x > 0 && g_resolution.y > 0)
{
Expand Down Expand Up @@ -1259,6 +1367,13 @@ void Application::m_Tick()
m_needSkinReload = false;
ReloadSkin();
}

// Tick light plugin
if (m_activeLightPlugin)
{
m_activeLightPlugin->Tick(m_deltaTime);
}

}

// Checks and clears OpenGL errors
Expand Down Expand Up @@ -1418,6 +1533,11 @@ void Application::m_Cleanup()
delete g_transition;
g_transition = nullptr;
}
if (m_activeLightPlugin)
{
m_activeLightPlugin->Close();
m_activeLightPlugin = nullptr;
}

//if (m_skinHtpp)
//{
Expand Down Expand Up @@ -2789,6 +2909,16 @@ void Application::SetLuaBindings(lua_State *state)
m_skinHttp.PushFunctions(state);
}

Vector<String> Application::GetLightPluginList()
{
Vector<String> names;
names.Add("");
for (auto& p : m_lightPlugins)
{
names.Add(p.first);
}
return names;
}


bool JacketLoadingJob::Run()
Expand Down
Loading