Plugin Examples
Π ΡΡΠΎΠΌ ΡΠ°Π·Π΄Π΅Π»Π΅ ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π»Π΅Π½Ρ ΠΏΡΠΈΠΌΠ΅ΡΡ ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠ² Π΄Π»Ρ Wudgine, ΠΊΠΎΡΠΎΡΡΠ΅ ΠΏΠΎΠΌΠΎΠ³ΡΡ Π²Π°ΠΌ ΠΏΠΎΠ½ΡΡΡ, ΠΊΠ°ΠΊ ΡΠΎΠ·Π΄Π°Π²Π°ΡΡ ΡΠΎΠ±ΡΡΠ²Π΅Π½Π½ΡΠ΅ ΡΠ°ΡΡΠΈΡΠ΅Π½ΠΈΡ.
ΠΠ»Π°Π³ΠΈΠ½ Π΄Π»Ρ ΠΏΠΎΡΡΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ
ΠΡΠΎΡ ΠΏΡΠΈΠΌΠ΅Ρ Π΄Π΅ΠΌΠΎΠ½ΡΡΡΠΈΡΡΠ΅Ρ ΡΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΏΠ»Π°Π³ΠΈΠ½Π° Π΄Π»Ρ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΡ ΡΡΡΠ΅ΠΊΡΠΎΠ² ΠΏΠΎΡΡΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ:
Π‘ΡΡΡΠΊΡΡΡΠ° ΠΏΠ»Π°Π³ΠΈΠ½Π°
PostProcessPlugin/
βββ CMakeLists.txt
βββ plugin.json
βββ src/
β βββ PostProcessPlugin.h
β βββ PostProcessPlugin.cpp
β βββ Effects/
β β βββ BloomEffect.h
β β βββ BloomEffect.cpp
β β βββ VignetteEffect.h
β β βββ VignetteEffect.cpp
β βββ Components/
β βββ PostProcessComponent.h
β βββ PostProcessComponent.cpp
βββ resources/
βββ shaders/
β βββ bloom.frag
β βββ vignette.frag
βββ icons/
βββ post_process.png
Π€Π°ΠΉΠ» ΠΌΠ°Π½ΠΈΡΠ΅ΡΡΠ°
{
"name": "PostProcessPlugin",
"version": "1.0.0",
"author": "Wudgine Team",
"description": "ΠΠ»Π°Π³ΠΈΠ½ Π΄Π»Ρ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΡ ΡΡΡΠ΅ΠΊΡΠΎΠ² ΠΏΠΎΡΡΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ",
"engineVersion": "1.0.0",
"dependencies": [],
"entryPoint": "PostProcessPlugin"
}
ΠΡΠ½ΠΎΠ²Π½ΠΎΠΉ ΠΊΠ»Π°ΡΡ ΠΏΠ»Π°Π³ΠΈΠ½Π°
// PostProcessPlugin.h
#pragma once
#include <Wudgine/Plugin/IPlugin.h>
#include <Wudgine/Core/ServiceLocator.h>
#include <Wudgine/Render/RenderPipeline.h>
class PostProcessPlugin : public Wudgine::Plugin::IPlugin {
public:
PostProcessPlugin();
~PostProcessPlugin();
// Π Π΅Π°Π»ΠΈΠ·Π°ΡΠΈΡ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΠ° IPlugin
bool Initialize() override;
void Shutdown() override;
const char* GetName() const override { return "PostProcessPlugin"; }
const char* GetVersion() const override { return "1.0.0"; }
const char* GetAuthor() const override { return "Wudgine Team"; }
const char* GetDescription() const override { return "ΠΠ»Π°Π³ΠΈΠ½ Π΄Π»Ρ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΡ ΡΡΡΠ΅ΠΊΡΠΎΠ² ΠΏΠΎΡΡΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ"; }
// ΠΠ°ΡΡΡΠΎΠΉΠΊΠΈ ΠΏΠ»Π°Π³ΠΈΠ½Π°
void RenderSettings() override;
private:
// Π Π΅Π³ΠΈΡΡΡΠ°ΡΠΈΡ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠΎΠ² ΠΈ ΡΠΈΡΡΠ΅ΠΌ
void RegisterComponents();
void RegisterSystems();
void RegisterEditorTools();
// ΠΠ°Π³ΡΡΠ·ΠΊΠ° ΡΠ΅ΡΡΡΡΠΎΠ²
bool LoadResources();
// ΠΠ°ΡΡΡΠΎΠΉΠΊΠΈ ΠΏΠ»Π°Π³ΠΈΠ½Π°
struct Settings {
bool enableBloom = true;
float bloomIntensity = 1.0f;
bool enableVignette = true;
float vignetteIntensity = 0.5f;
template<typename Archive>
void serialize(Archive& ar) {
ar & enableBloom;
ar & bloomIntensity;
ar & enableVignette;
ar & vignetteIntensity;
}
};
Settings m_settings;
};
// PostProcessPlugin.cpp
#include "PostProcessPlugin.h"
#include "Components/PostProcessComponent.h"
#include "Effects/BloomEffect.h"
#include "Effects/VignetteEffect.h"
#include <Wudgine/Core/Log.h>
#include <Wudgine/Core/SettingsManager.h>
#include <Wudgine/ECS/ComponentRegistry.h>
#include <Wudgine/Editor/EditorToolManager.h>
#include <Wudgine/Resource/ResourceManager.h>
#include <imgui.h>
PostProcessPlugin::PostProcessPlugin() = default;
PostProcessPlugin::~PostProcessPlugin() = default;
bool PostProcessPlugin::Initialize() {
WG_LOG_INFO("[PostProcessPlugin] ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ...");
// ΠΠ°Π³ΡΡΠ·ΠΊΠ° Π½Π°ΡΡΡΠΎΠ΅ΠΊ
if (Wudgine::Core::SettingsManager::GetInstance().HasPluginSettings(GetName())) {
m_settings = Wudgine::Core::SettingsManager::GetInstance().LoadPluginSettings<Settings>(GetName());
}
// Π Π΅Π³ΠΈΡΡΡΠ°ΡΠΈΡ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠΎΠ² ΠΈ ΡΠΈΡΡΠ΅ΠΌ
RegisterComponents();
RegisterSystems();
// Π Π΅Π³ΠΈΡΡΡΠ°ΡΠΈΡ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΠΎΠ² ΡΠ΅Π΄Π°ΠΊΡΠΎΡΠ° (Π΅ΡΠ»ΠΈ Π² ΡΠ΅ΠΆΠΈΠΌΠ΅ ΡΠ΅Π΄Π°ΠΊΡΠΎΡΠ°)
if (Wudgine::Core::IsEditor()) {
RegisterEditorTools();
}
// ΠΠ°Π³ΡΡΠ·ΠΊΠ° ΡΠ΅ΡΡΡΡΠΎΠ²
if (!LoadResources()) {
WG_LOG_ERROR("[PostProcessPlugin] ΠΡΠΈΠ±ΠΊΠ° Π·Π°Π³ΡΡΠ·ΠΊΠΈ ΡΠ΅ΡΡΡΡΠΎΠ²");
return false;
}
// Π Π΅Π³ΠΈΡΡΡΠ°ΡΠΈΡ Ρ
ΡΠΊΠΎΠ² ΡΠ΅Π½Π΄Π΅ΡΠΈΠ½Π³Π°
auto& renderPipeline = Wudgine::Render::RenderPipeline::GetInstance();
// ΠΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ ΡΡΡΠ΅ΠΊΡΠΎΠ² ΠΏΠΎΡΡΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ Π² ΠΊΠΎΠ½Π²Π΅ΠΉΠ΅Ρ ΡΠ΅Π½Π΄Π΅ΡΠΈΠ½Π³Π°
if (m_settings.enableBloom) {
renderPipeline.AddPostProcessEffect(new BloomEffect(m_settings.bloomIntensity));
}
if (m_settings.enableVignette) {
renderPipeline.AddPostProcessEffect(new VignetteEffect(m_settings.vignetteIntensity));
}
WG_LOG_INFO("[PostProcessPlugin] ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ Π·Π°Π²Π΅ΡΡΠ΅Π½Π°");
return true;
}
void PostProcessPlugin::Shutdown() {
WG_LOG_INFO("[PostProcessPlugin] ΠΠ°Π²Π΅ΡΡΠ΅Π½ΠΈΠ΅ ΡΠ°Π±ΠΎΡΡ...");
// Π‘ΠΎΡ
ΡΠ°Π½Π΅Π½ΠΈΠ΅ Π½Π°ΡΡΡΠΎΠ΅ΠΊ
Wudgine::Core::SettingsManager::GetInstance().SavePluginSettings(GetName(), m_settings);
// Π£Π΄Π°Π»Π΅Π½ΠΈΠ΅ ΡΡΡΠ΅ΠΊΡΠΎΠ² ΠΈΠ· ΠΊΠΎΠ½Π²Π΅ΠΉΠ΅ΡΠ° ΡΠ΅Π½Π΄Π΅ΡΠΈΠ½Π³Π°
auto& renderPipeline = Wudgine::Render::RenderPipeline::GetInstance();
renderPipeline.RemoveAllPostProcessEffects();
WG_LOG_INFO("[PostProcessPlugin] ΠΠ°Π²Π΅ΡΡΠ΅Π½ΠΈΠ΅ ΡΠ°Π±ΠΎΡΡ Π·Π°Π²Π΅ΡΡΠ΅Π½ΠΎ");
}
void PostProcessPlugin::RegisterComponents() {
// Π Π΅Π³ΠΈΡΡΡΠ°ΡΠΈΡ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠ° ΠΏΠΎΡΡΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ
Wudgine::ECS::ComponentRegistry::GetInstance().RegisterComponent<PostProcessComponent>(
"PostProcessComponent",
[]() { return new PostProcessComponent(); }
);
}
void PostProcessPlugin::RegisterSystems() {
// Π ΡΡΠΎΠΌ ΠΏΡΠΈΠΌΠ΅ΡΠ΅ ΡΠΈΡΡΠ΅ΠΌΡ Π½Π΅ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡΡΡΡ
}
void PostProcessPlugin::RegisterEditorTools() {
// Π Π΅Π³ΠΈΡΡΡΠ°ΡΠΈΡ ΠΈΠ½ΡΠΏΠ΅ΠΊΡΠΎΡΠ° Π΄Π»Ρ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠ° ΠΏΠΎΡΡΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ
class PostProcessInspector : public Wudgine::Editor::ComponentInspector {
public:
bool CanInspect(Wudgine::ECS::Component* component) override {
return dynamic_cast<PostProcessComponent*>(component) != nullptr;
}
void Render(Wudgine::ECS::Component* component) override {
auto* ppComponent = static_cast<PostProcessComponent*>(component);
// ΠΡΡΠΈΡΠΎΠ²ΠΊΠ° ΠΏΠΎΠ»Π΅ΠΉ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠ°
bool enableBloom = ppComponent->IsBloomEnabled();
if (ImGui::Checkbox("ΠΠΊΠ»ΡΡΠΈΡΡ Bloom", &enableBloom)) {
ppComponent->SetBloomEnabled(enableBloom);
MarkDirty();
}
float bloomIntensity = ppComponent->GetBloomIntensity();
if (ImGui::SliderFloat("ΠΠ½ΡΠ΅Π½ΡΠΈΠ²Π½ΠΎΡΡΡ Bloom", &bloomIntensity, 0.0f, 2.0f)) {
ppComponent->SetBloomIntensity(bloomIntensity);
MarkDirty();
}
bool enableVignette = ppComponent->IsVignetteEnabled();
if (ImGui::Checkbox("ΠΠΊΠ»ΡΡΠΈΡΡ ΠΠΈΠ½ΡΠ΅ΡΠΊΡ", &enableVignette)) {
ppComponent->SetVignetteEnabled(enableVignette);
MarkDirty();
}
float vignetteIntensity = ppComponent->GetVignetteIntensity();
if (ImGui::SliderFloat("ΠΠ½ΡΠ΅Π½ΡΠΈΠ²Π½ΠΎΡΡΡ ΠΠΈΠ½ΡΠ΅ΡΠΊΠΈ", &vignetteIntensity, 0.0f, 1.0f)) {
ppComponent->SetVignetteIntensity(vignetteIntensity);
MarkDirty();
}
}
};
Wudgine::Editor::InspectorManager::GetInstance().RegisterInspector(new PostProcessInspector());
}
bool PostProcessPlugin::LoadResources() {
// ΠΠ°Π³ΡΡΠ·ΠΊΠ° ΡΠ΅ΠΉΠ΄Π΅ΡΠΎΠ²
auto& resourceManager = Wudgine::Resource::ResourceManager::GetInstance();
if (!resourceManager.LoadShader("plugins/PostProcessPlugin/shaders/bloom.frag")) {
WG_LOG_ERROR("[PostProcessPlugin] ΠΠ΅ ΡΠ΄Π°Π»ΠΎΡΡ Π·Π°Π³ΡΡΠ·ΠΈΡΡ ΡΠ΅ΠΉΠ΄Π΅Ρ bloom.frag");
return false;
}
if (!resourceManager.LoadShader("plugins/PostProcessPlugin/shaders/vignette.frag")) {
WG_LOG_ERROR("[PostProcessPlugin] ΠΠ΅ ΡΠ΄Π°Π»ΠΎΡΡ Π·Π°Π³ΡΡΠ·ΠΈΡΡ ΡΠ΅ΠΉΠ΄Π΅Ρ vignette.frag");
return false;
}
return true;
}
void PostProcessPlugin::RenderSettings() {
ImGui::Checkbox("ΠΠΊΠ»ΡΡΠΈΡΡ Bloom", &m_settings.enableBloom);
if (m_settings.enableBloom) {
ImGui::SliderFloat("ΠΠ½ΡΠ΅Π½ΡΠΈΠ²Π½ΠΎΡΡΡ Bloom", &m_settings.bloomIntensity, 0.0f, 2.0f);
}
ImGui::Checkbox("ΠΠΊΠ»ΡΡΠΈΡΡ ΠΠΈΠ½ΡΠ΅ΡΠΊΡ", &m_settings.enableVignette);
if (m_settings.enableVignette) {
ImGui::SliderFloat("ΠΠ½ΡΠ΅Π½ΡΠΈΠ²Π½ΠΎΡΡΡ ΠΠΈΠ½ΡΠ΅ΡΠΊΠΈ", &m_settings.vignetteIntensity, 0.0f, 1.0f);
}
// ΠΡΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ
auto& renderPipeline = Wudgine::Render::RenderPipeline::GetInstance();
renderPipeline.UpdatePostProcessEffects();
// Π‘ΠΎΡ
ΡΠ°Π½Π΅Π½ΠΈΠ΅ Π½Π°ΡΡΡΠΎΠ΅ΠΊ
Wudgine::Core::SettingsManager::GetInstance().SavePluginSettings(GetName(), m_settings);
}
// ΠΠΊΡΠΏΠΎΡΡ ΠΏΠ»Π°Π³ΠΈΠ½Π°
extern "C" {
WUDGINE_PLUGIN_API Wudgine::Plugin::IPlugin* CreatePlugin() {
return new PostProcessPlugin();
}
}
ΠΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ ΠΏΠΎΡΡΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ
// PostProcessComponent.h
#pragma once
#include <Wudgine/ECS/Component.h>
#include <Wudgine/Core/Serializable.h>
class PostProcessComponent : public Wudgine::ECS::Component, public Wudgine::Core::Serializable {
public:
PostProcessComponent();
~PostProcessComponent() override;
// Bloom
bool IsBloomEnabled() const { return m_bloomEnabled; }
void SetBloomEnabled(bool enabled);
float GetBloomIntensity() const { return m_bloomIntensity; }
void SetBloomIntensity(float intensity);
// Vignette
bool IsVignetteEnabled() const { return m_vignetteEnabled; }
void SetVignetteEnabled(bool enabled);
float GetVignetteIntensity() const { return m_vignetteIntensity; }
void SetVignetteIntensity(float intensity);
// Π‘Π΅ΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ
template<typename Archive>
void serialize(Archive& ar) {
ar & m_bloomEnabled;
ar & m_bloomIntensity;
ar & m_vignetteEnabled;
ar & m_vignetteIntensity;
}
private:
bool m_bloomEnabled;
float m_bloomIntensity;
bool m_vignetteEnabled;
float m_vignetteIntensity;
};
// PostProcessComponent.cpp
#include "PostProcessComponent.h"
#include <Wudgine/Render/RenderPipeline.h>
PostProcessComponent::PostProcessComponent()
: m_bloomEnabled(true)
, m_bloomIntensity(1.0f)
, m_vignetteEnabled(true)
, m_vignetteIntensity(0.5f)
{
}
PostProcessComponent::~PostProcessComponent() = default;
void PostProcessComponent::SetBloomEnabled(bool enabled) {
m_bloomEnabled = enabled;
// ΠΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ ΡΡΡΠ΅ΠΊΡΠ° Π² ΠΊΠΎΠ½Π²Π΅ΠΉΠ΅ΡΠ΅ ΡΠ΅Π½Π΄Π΅ΡΠΈΠ½Π³Π°
auto& renderPipeline = Wudgine::Render::RenderPipeline::GetInstance();
if (enabled) {
renderPipeline.EnablePostProcessEffect("Bloom");
} else {
renderPipeline.DisablePostProcessEffect("Bloom");
}
}
void PostProcessComponent::SetBloomIntensity(float intensity) {
m_bloomIntensity = intensity;
// ΠΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠΎΠ² ΡΡΡΠ΅ΠΊΡΠ°
auto& renderPipeline = Wudgine::Render::RenderPipeline::GetInstance();
renderPipeline.SetPostProcessEffectParameter("Bloom", "intensity", intensity);
}
void PostProcessComponent::SetVignetteEnabled(bool enabled) {
m_vignetteEnabled = enabled;
// ΠΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ ΡΡΡΠ΅ΠΊΡΠ° Π² ΠΊΠΎΠ½Π²Π΅ΠΉΠ΅ΡΠ΅ ΡΠ΅Π½Π΄Π΅ΡΠΈΠ½Π³Π°
auto& renderPipeline = Wudgine::Render::RenderPipeline::GetInstance();
if (enabled) {
renderPipeline.EnablePostProcessEffect("Vignette");
} else {
renderPipeline.DisablePostProcessEffect("Vignette");
}
}
void PostProcessComponent::SetVignetteIntensity(float intensity) {
m_vignetteIntensity = intensity;
// ΠΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠΎΠ² ΡΡΡΠ΅ΠΊΡΠ°
auto& renderPipeline = Wudgine::Render::RenderPipeline::GetInstance();
renderPipeline.SetPostProcessEffectParameter("Vignette", "intensity", intensity);
}
Π€Π°ΠΉΠ» CMake
# CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project(PostProcessPlugin)
# ΠΠ΅ΡΡΠΈΡ C++
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# ΠΡΡ
ΠΎΠ΄Π½ΡΠ΅ ΡΠ°ΠΉΠ»Ρ
set(SOURCES
src/PostProcessPlugin.cpp
src/Components/PostProcessComponent.cpp
src/Effects/BloomEffect.cpp
src/Effects/VignetteEffect.cpp
)
# ΠΠ°Π³ΠΎΠ»ΠΎΠ²ΠΎΡΠ½ΡΠ΅ ΡΠ°ΠΉΠ»Ρ
set(HEADERS
src/PostProcessPlugin.h
src/Components/PostProcessComponent.h
src/Effects/BloomEffect.h
src/Effects/VignetteEffect.h
)
# ΠΡΡΡ ΠΊ Wudgine SDK
set(WUDGINE_SDK_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../WudgineSDK" CACHE PATH "ΠΡΡΡ ΠΊ Wudgine SDK")
# ΠΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ Π΄ΠΈΡΠ΅ΠΊΡΠΎΡΠΈΠΉ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡΠ½ΡΡ
ΡΠ°ΠΉΠ»ΠΎΠ²
include_directories(
${WUDGINE_SDK_PATH}/include
${CMAKE_CURRENT_SOURCE_DIR}/src
)
# Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ ΠΏΠ»Π°Π³ΠΈΠ½Π°
add_library(${PROJECT_NAME} SHARED ${SOURCES} ${HEADERS})
# ΠΠΏΡΠ΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ ΠΌΠ°ΠΊΡΠΎΡΠ° Π΄Π»Ρ ΡΠΊΡΠΏΠΎΡΡΠ° API ΠΏΠ»Π°Π³ΠΈΠ½Π°
target_compile_definitions(${PROJECT_NAME} PRIVATE WUDGINE_PLUGIN_EXPORTS)
# Π‘Π²ΡΠ·ΡΠ²Π°Π½ΠΈΠ΅ Ρ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠ°ΠΌΠΈ Wudgine
target_link_libraries(${PROJECT_NAME}
${WUDGINE_SDK_PATH}/lib/WudgineCore
${WUDGINE_SDK_PATH}/lib/WudgineRender
${WUDGINE_SDK_PATH}/lib/WudgineECS
)
# ΠΠΎΠΏΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΡΠ΅ΡΡΡΡΠΎΠ² ΠΏΠ»Π°Π³ΠΈΠ½Π°
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_CURRENT_SOURCE_DIR}/resources
${CMAKE_BINARY_DIR}/plugins/${PROJECT_NAME}/resources
)
# ΠΠΎΠΏΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΡΠ°ΠΉΠ»Π° ΠΌΠ°Π½ΠΈΡΠ΅ΡΡΠ°
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/plugin.json
${CMAKE_BINARY_DIR}/plugins/${PROJECT_NAME}/plugin.json
)
# ΠΠΎΠΏΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ ΠΏΠ»Π°Π³ΠΈΠ½Π°
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_FILE:${PROJECT_NAME}>
${CMAKE_BINARY_DIR}/plugins/${PROJECT_NAME}/$<TARGET_FILE_NAME:${PROJECT_NAME}>
)
ΠΠ»Π°Π³ΠΈΠ½ Π΄Π»Ρ ΡΠΈΠ·ΠΈΠΊΠΈ
ΠΡΠΎΡ ΠΏΡΠΈΠΌΠ΅Ρ Π΄Π΅ΠΌΠΎΠ½ΡΡΡΠΈΡΡΠ΅Ρ ΡΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΏΠ»Π°Π³ΠΈΠ½Π° Π΄Π»Ρ ΠΈΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΠΈ ΡΠΈΠ·ΠΈΡΠ΅ΡΠΊΠΎΠ³ΠΎ Π΄Π²ΠΈΠΆΠΊΠ°:
Π‘ΡΡΡΠΊΡΡΡΠ° ΠΏΠ»Π°Π³ΠΈΠ½Π°
PhysicsPlugin/
βββ CMakeLists.txt
βββ plugin.json
βββ src/
β βββ PhysicsPlugin.h
β βββ PhysicsPlugin.cpp
β βββ Components/
β β βββ RigidBodyComponent.h
β β βββ RigidBodyComponent.cpp
β β βββ ColliderComponent.h
β β βββ ColliderComponent.cpp
β βββ Systems/
β βββ PhysicsSystem.h
β βββ PhysicsSystem.cpp
βββ resources/
βββ icons/
βββ physics.png
Π€Π°ΠΉΠ» ΠΌΠ°Π½ΠΈΡΠ΅ΡΡΠ°
{
"name": "PhysicsPlugin",
"version": "1.0.0",
"author": "Wudgine Team",
"description": "ΠΠ»Π°Π³ΠΈΠ½ Π΄Π»Ρ ΠΈΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΠΈ ΡΠΈΠ·ΠΈΡΠ΅ΡΠΊΠΎΠ³ΠΎ Π΄Π²ΠΈΠΆΠΊΠ°",
"engineVersion": "1.0.0",
"dependencies": [],
"entryPoint": "PhysicsPlugin"
}
ΠΡΠ½ΠΎΠ²Π½ΠΎΠΉ ΠΊΠ»Π°ΡΡ ΠΏΠ»Π°Π³ΠΈΠ½Π°
// PhysicsPlugin.h
#pragma once
#include <Wudgine/Plugin/IPlugin.h>
class PhysicsPlugin : public Wudgine::Plugin::IPlugin {
public:
PhysicsPlugin();
~PhysicsPlugin();
// Π Π΅Π°Π»ΠΈΠ·Π°ΡΠΈΡ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΠ° IPlugin
bool Initialize() override;
void Shutdown() override;
const char* GetName() const override { return "PhysicsPlugin"; }
const char* GetVersion() const override { return "1.0.0"; }
const char* GetAuthor() const override { return "Wudgine Team"; }
const char* GetDescription() const override { return "ΠΠ»Π°Π³ΠΈΠ½ Π΄Π»Ρ ΠΈΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΠΈ ΡΠΈΠ·ΠΈΡΠ΅ΡΠΊΠΎΠ³ΠΎ Π΄Π²ΠΈΠΆΠΊΠ°"; }
// ΠΠ°ΡΡΡΠΎΠΉΠΊΠΈ ΠΏΠ»Π°Π³ΠΈΠ½Π°
void RenderSettings() override;
private:
// Π Π΅Π³ΠΈΡΡΡΠ°ΡΠΈΡ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠΎΠ² ΠΈ ΡΠΈΡΡΠ΅ΠΌ
void RegisterComponents();
void RegisterSystems();
void RegisterEditorTools();
// ΠΠ°ΡΡΡΠΎΠΉΠΊΠΈ ΠΏΠ»Π°Π³ΠΈΠ½Π°
struct Settings {
float gravity = -9.81f;
int solverIterations = 10;
bool enableContinuousDetection = true;
template<typename Archive>
void serialize(Archive& ar) {
ar & gravity;
ar & solverIterations;
ar & enableContinuousDetection;
}
};
Settings m_settings;
};
// PhysicsPlugin.cpp
#include "PhysicsPlugin.h"
#include "Components/RigidBodyComponent.h"
#include "Components/ColliderComponent.h"
#include "Systems/PhysicsSystem.h"
#include <Wudgine/Core/Log.h>
#include <Wudgine/Core/SettingsManager.h>
#include <Wudgine/ECS/ComponentRegistry.h>
#include <Wudgine/ECS/SystemRegistry.h>
#include <Wudgine/Editor/EditorToolManager.h>
#include <imgui.h>
PhysicsPlugin::PhysicsPlugin() = default;
PhysicsPlugin::~PhysicsPlugin() = default;
bool PhysicsPlugin::Initialize() {
WG_LOG_INFO("[PhysicsPlugin] ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ...");
// ΠΠ°Π³ΡΡΠ·ΠΊΠ° Π½Π°ΡΡΡΠΎΠ΅ΠΊ
if (Wudgine::Core::SettingsManager::GetInstance().HasPluginSettings(GetName())) {
m_settings = Wudgine::Core::SettingsManager::GetInstance().LoadPluginSettings<Settings>(GetName());
}
// Π Π΅Π³ΠΈΡΡΡΠ°ΡΠΈΡ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠΎΠ² ΠΈ ΡΠΈΡΡΠ΅ΠΌ
RegisterComponents();
RegisterSystems();
// Π Π΅Π³ΠΈΡΡΡΠ°ΡΠΈΡ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΠΎΠ² ΡΠ΅Π΄Π°ΠΊΡΠΎΡΠ° (Π΅ΡΠ»ΠΈ Π² ΡΠ΅ΠΆΠΈΠΌΠ΅ ΡΠ΅Π΄Π°ΠΊΡΠΎΡΠ°)
if (Wudgine::Core::IsEditor()) {
RegisterEditorTools();
}
// ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ ΡΠΈΠ·ΠΈΡΠ΅ΡΠΊΠΎΠ³ΠΎ Π΄Π²ΠΈΠΆΠΊΠ° Ρ Π½Π°ΡΡΡΠΎΠΉΠΊΠ°ΠΌΠΈ
PhysicsSystem::GetInstance().SetGravity(m_settings.gravity);
PhysicsSystem::GetInstance().SetSolverIterations(m_settings.solverIterations);
PhysicsSystem::GetInstance().SetContinuousDetection(m_settings.enableContinuousDetection);
WG_LOG_INFO("[PhysicsPlugin] ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ Π·Π°Π²Π΅ΡΡΠ΅Π½Π°");
return true;
}
void PhysicsPlugin::Shutdown() {
WG_LOG_INFO("[PhysicsPlugin] ΠΠ°Π²Π΅ΡΡΠ΅Π½ΠΈΠ΅ ΡΠ°Π±ΠΎΡΡ...");
// Π‘ΠΎΡ
ΡΠ°Π½Π΅Π½ΠΈΠ΅ Π½Π°ΡΡΡΠΎΠ΅ΠΊ
Wudgine::Core::SettingsManager::GetInstance().SavePluginSettings(GetName(), m_settings);
// ΠΠ°Π²Π΅ΡΡΠ΅Π½ΠΈΠ΅ ΡΠ°Π±ΠΎΡΡ ΡΠΈΠ·ΠΈΡΠ΅ΡΠΊΠΎΠ³ΠΎ Π΄Π²ΠΈΠΆΠΊΠ°
PhysicsSystem::GetInstance().Shutdown();
WG_LOG_INFO("[PhysicsPlugin] ΠΠ°Π²Π΅ΡΡΠ΅Π½ΠΈΠ΅ ΡΠ°Π±ΠΎΡΡ Π·Π°Π²Π΅ΡΡΠ΅Π½ΠΎ");
}
void PhysicsPlugin::RegisterComponents() {
// Π Π΅Π³ΠΈΡΡΡΠ°ΡΠΈΡ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠΎΠ² ΡΠΈΠ·ΠΈΠΊΠΈ
Wudgine::ECS::ComponentRegistry::GetInstance().RegisterComponent<RigidBodyComponent>(
"RigidBodyComponent",
[]() { return new RigidBodyComponent(); }
);
Wudgine::ECS::ComponentRegistry::GetInstance().RegisterComponent<ColliderComponent>(
"ColliderComponent",
[]() { return new ColliderComponent(); }
);
}
void PhysicsPlugin::RegisterSystems() {
// Π Π΅Π³ΠΈΡΡΡΠ°ΡΠΈΡ ΡΠΈΡΡΠ΅ΠΌΡ ΡΠΈΠ·ΠΈΠΊΠΈ
Wudgine::ECS::SystemRegistry::GetInstance().RegisterSystem<PhysicsSystem>(
"PhysicsSystem",
[]() { return &PhysicsSystem::GetInstance(); }
);
}
void PhysicsPlugin::RegisterEditorTools() {
// Π Π΅Π³ΠΈΡΡΡΠ°ΡΠΈΡ ΠΈΠ½ΡΠΏΠ΅ΠΊΡΠΎΡΠ° Π΄Π»Ρ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠ° ΡΠ²Π΅ΡΠ΄ΠΎΠ³ΠΎ ΡΠ΅Π»Π°
class RigidBodyInspector : public Wudgine::Editor::ComponentInspector {
public:
bool CanInspect(Wudgine::ECS::Component* component) override {
return dynamic_cast<RigidBodyComponent*>(component) != nullptr;
}
void Render(Wudgine::ECS::Component* component) override {
auto* rbComponent = static_cast<RigidBodyComponent*>(component);
// ΠΡΡΠΈΡΠΎΠ²ΠΊΠ° ΠΏΠΎΠ»Π΅ΠΉ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠ°
float mass = rbComponent->GetMass();
if (ImGui::DragFloat("ΠΠ°ΡΡΠ°", &mass, 0.1f, 0.0f, 1000.0f)) {
rbComponent->SetMass(mass);
MarkDirty();
}
bool isKinematic = rbComponent->IsKinematic();
if (ImGui::Checkbox("ΠΠΈΠ½Π΅ΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈΠΉ", &isKinematic)) {
rbComponent->SetKinematic(isKinematic);
MarkDirty();
}
float linearDamping = rbComponent->GetLinearDamping();
if (ImGui::SliderFloat("ΠΠΈΠ½Π΅ΠΉΠ½ΠΎΠ΅ Π·Π°ΡΡΡ
Π°Π½ΠΈΠ΅", &linearDamping, 0.0f, 1.0f)) {
rbComponent->SetLinearDamping(linearDamping);
MarkDirty();
}
float angularDamping = rbComponent->GetAngularDamping();
if (ImGui::SliderFloat("Π£Π³Π»ΠΎΠ²ΠΎΠ΅ Π·Π°ΡΡΡ
Π°Π½ΠΈΠ΅", &angularDamping, 0.0f, 1.0f)) {
rbComponent->SetAngularDamping(angularDamping);
MarkDirty();
}
}
};
// Π Π΅Π³ΠΈΡΡΡΠ°ΡΠΈΡ ΠΈΠ½ΡΠΏΠ΅ΠΊΡΠΎΡΠ° Π΄Π»Ρ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠ° ΠΊΠΎΠ»Π»Π°ΠΉΠ΄Π΅ΡΠ°
class ColliderInspector : public Wudgine::Editor::ComponentInspector {
public:
bool CanInspect(Wudgine::ECS::Component* component) override {
return dynamic_cast<ColliderComponent*>(component) != nullptr;
}
void Render(Wudgine::ECS::Component* component) override {
auto* colliderComponent = static_cast<ColliderComponent*>(component);
// ΠΡΡΠΈΡΠΎΠ²ΠΊΠ° ΠΏΠΎΠ»Π΅ΠΉ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠ°
const char* colliderTypes[] = { "Box", "Sphere", "Capsule", "Mesh" };
int currentType = static_cast<int>(colliderComponent->GetColliderType());
if (ImGui::Combo("Π’ΠΈΠΏ ΠΊΠΎΠ»Π»Π°ΠΉΠ΄Π΅ΡΠ°", ¤tType, colliderTypes, IM_ARRAYSIZE(colliderTypes))) {
colliderComponent->SetColliderType(static_cast<ColliderComponent::ColliderType>(currentType));
MarkDirty();
}
// ΠΡΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠ΅ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠΎΠ² Π² Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠΈ ΠΎΡ ΡΠΈΠΏΠ° ΠΊΠΎΠ»Π»Π°ΠΉΠ΄Π΅ΡΠ°
switch (colliderComponent->GetColliderType()) {
case ColliderComponent::ColliderType::Box: {
auto size = colliderComponent->GetBoxSize();
if (ImGui::DragFloat3("Π Π°Π·ΠΌΠ΅Ρ", &size.x, 0.1f, 0.01f, 100.0f)) {
colliderComponent->SetBoxSize(size);
MarkDirty();
}
break;
}
case ColliderComponent::ColliderType::Sphere: {
float radius = colliderComponent->GetSphereRadius();
if (ImGui::DragFloat("Π Π°Π΄ΠΈΡΡ", &radius, 0.1f, 0.01f, 100.0f)) {
colliderComponent->SetSphereRadius(radius);
MarkDirty();
}
break;
}
case ColliderComponent::ColliderType::Capsule: {
float radius = colliderComponent->GetCapsuleRadius();
float height = colliderComponent->GetCapsuleHeight();
if (ImGui::DragFloat("Π Π°Π΄ΠΈΡΡ", &radius, 0.1f, 0.01f, 100.0f)) {
colliderComponent->SetCapsuleRadius(radius);
MarkDirty();
}
if (ImGui::DragFloat("ΠΡΡΠΎΡΠ°", &height, 0.1f, 0.01f, 100.0f)) {
colliderComponent->SetCapsuleHeight(height);
MarkDirty();
}
break;
}
case ColliderComponent::ColliderType::Mesh: {
std::string meshPath = colliderComponent->GetMeshPath();
char buffer[256];
strcpy(buffer, meshPath.c_str());
if (ImGui::InputText("ΠΡΡΡ ΠΊ ΠΌΠ΅Ρ", buffer, sizeof(buffer))) {
colliderComponent->SetMeshPath(buffer);
MarkDirty();
}
if (ImGui::Button("ΠΠ±Π·ΠΎΡ...")) {
// ΠΡΠΊΡΡΡΠΈΠ΅ Π΄ΠΈΠ°Π»ΠΎΠ³Π° Π²ΡΠ±ΠΎΡΠ° ΡΠ°ΠΉΠ»Π°
// ...
}
break;
}
}
float friction = colliderComponent->GetFriction();
if (ImGui::SliderFloat("Π’ΡΠ΅Π½ΠΈΠ΅", &friction, 0.0f, 1.0f)) {
colliderComponent->SetFriction(friction);
MarkDirty();
}
float restitution = colliderComponent->GetRestitution();
if (ImGui::SliderFloat("Π£ΠΏΡΡΠ³ΠΎΡΡΡ", &restitution, 0.0f, 1.0f)) {
colliderComponent->SetRestitution(restitution);
MarkDirty();
}
}
};
Wudgine::Editor::InspectorManager::GetInstance().RegisterInspector(new RigidBodyInspector());
Wudgine::Editor::InspectorManager::GetInstance().RegisterInspector(new ColliderInspector());
}
void PhysicsPlugin::RenderSettings() {
ImGui::DragFloat("ΠΡΠ°Π²ΠΈΡΠ°ΡΠΈΡ", &m_settings.gravity, 0.1f, -20.0f, 20.0f);
ImGui::SliderInt("ΠΡΠ΅ΡΠ°ΡΠΈΠΈ ΡΠ΅ΡΠ°ΡΠ΅Π»Ρ", &m_settings.solverIterations, 1, 20);
ImGui::Checkbox("ΠΠ΅ΠΏΡΠ΅ΡΡΠ²Π½ΠΎΠ΅ ΠΎΠ±Π½Π°ΡΡΠΆΠ΅Π½ΠΈΠ΅ ΡΡΠΎΠ»ΠΊΠ½ΠΎΠ²Π΅Π½ΠΈΠΉ", &m_settings.enableContinuousDetection);
// ΠΡΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ
PhysicsSystem::GetInstance().SetGravity(m_settings.gravity);
PhysicsSystem::GetInstance().SetSolverIterations(m_settings.solverIterations);
PhysicsSystem::GetInstance().SetContinuousDetection(m_settings.enableContinuousDetection);
// Π‘ΠΎΡ
ΡΠ°Π½Π΅Π½ΠΈΠ΅ Π½Π°ΡΡΡΠΎΠ΅ΠΊ
Wudgine::Core::SettingsManager::GetInstance().SavePluginSettings(GetName(), m_settings);
}
// ΠΠΊΡΠΏΠΎΡΡ ΠΏΠ»Π°Π³ΠΈΠ½Π°
extern "C" {
WUDGINE_PLUGIN_API Wudgine::Plugin::IPlugin* CreatePlugin() {
return new PhysicsPlugin();
}
}
ΠΠ»Π°Π³ΠΈΠ½ Π΄Π»Ρ ΠΈΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΠΈ Ρ Π²Π½Π΅ΡΠ½ΠΈΠΌ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΠΎΠΌ
ΠΡΠΎΡ ΠΏΡΠΈΠΌΠ΅Ρ Π΄Π΅ΠΌΠΎΠ½ΡΡΡΠΈΡΡΠ΅Ρ ΡΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΏΠ»Π°Π³ΠΈΠ½Π° Π΄Π»Ρ ΠΈΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΠΈ Ρ Π²Π½Π΅ΡΠ½ΠΈΠΌ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΠΎΠΌ:
Π‘ΡΡΡΠΊΡΡΡΠ° ΠΏΠ»Π°Π³ΠΈΠ½Π°
ExternalToolPlugin/
βββ CMakeLists.txt
βββ plugin.json
βββ src/
β βββ ExternalToolPlugin.h
β βββ ExternalToolPlugin.cpp
β βββ Tools/
β β βββ ExternalToolIntegration.h
β β βββ ExternalToolIntegration.cpp
β βββ Editor/
β βββ ExternalToolWindow.h
β βββ ExternalToolWindow.cpp
βββ resources/
βββ icons/
βββ external_tool.png
Π€Π°ΠΉΠ» ΠΌΠ°Π½ΠΈΡΠ΅ΡΡΠ°
{
"name": "ExternalToolPlugin",
"version": "1.0.0",
"author": "Wudgine Team",
"description": "ΠΠ»Π°Π³ΠΈΠ½ Π΄Π»Ρ ΠΈΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΠΈ Ρ Π²Π½Π΅ΡΠ½ΠΈΠΌ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΠΎΠΌ",
"engineVersion": "1.0.0",
"dependencies": [],
"entryPoint": "ExternalToolPlugin"
}
ΠΡΠ½ΠΎΠ²Π½ΠΎΠΉ ΠΊΠ»Π°ΡΡ ΠΏΠ»Π°Π³ΠΈΠ½Π°
// ExternalToolPlugin.h
#pragma once
#include <Wudgine/Plugin/IPlugin.h>
#include "Tools/ExternalToolIntegration.h"
class ExternalToolPlugin : public Wudgine::Plugin::IPlugin {
public:
ExternalToolPlugin();
~ExternalToolPlugin();
// Π Π΅Π°Π»ΠΈΠ·Π°ΡΠΈΡ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΠ° IPlugin
bool Initialize() override;
void Shutdown() override;
const char* GetName() const override { return "ExternalToolPlugin"; }
const char* GetVersion() const override { return "1.0.0"; }
const char* GetAuthor() const override { return "Wudgine Team"; }
const char* GetDescription() const override { return "ΠΠ»Π°Π³ΠΈΠ½ Π΄Π»Ρ ΠΈΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΠΈ Ρ Π²Π½Π΅ΡΠ½ΠΈΠΌ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΠΎΠΌ"; }
// ΠΠ°ΡΡΡΠΎΠΉΠΊΠΈ ΠΏΠ»Π°Π³ΠΈΠ½Π°
void RenderSettings() override;
// ΠΠΎΡΡΡΠΏ ΠΊ ΠΈΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΠΈ
ExternalToolIntegration* GetIntegration() { return m_integration.get(); }
private:
// Π Π΅Π³ΠΈΡΡΡΠ°ΡΠΈΡ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΠΎΠ² ΡΠ΅Π΄Π°ΠΊΡΠΎΡΠ°
void RegisterEditorTools();
// ΠΠ°ΡΡΡΠΎΠΉΠΊΠΈ ΠΏΠ»Π°Π³ΠΈΠ½Π°
struct Settings {
std::string externalToolPath;
bool autoSync = true;
int syncInterval = 5; // Π² ΡΠ΅ΠΊΡΠ½Π΄Π°Ρ
template<typename Archive>
void serialize(Archive& ar) {
ar & externalToolPath;
ar & autoSync;
ar & syncInterval;
}
};
Settings m_settings;
std::unique_ptr<ExternalToolIntegration> m_integration;
};
// ExternalToolPlugin.cpp
#include "ExternalToolPlugin.h"
#include "Editor/ExternalToolWindow.h"
#include <Wudgine/Core/Log.h>
#include <Wudgine/Core/SettingsManager.h>
#include <Wudgine/Editor/EditorToolManager.h>
#include <Wudgine/Editor/EditorMenuManager.h>
#include <imgui.h>
ExternalToolPlugin::ExternalToolPlugin() = default;
ExternalToolPlugin::~ExternalToolPlugin() = default;
bool ExternalToolPlugin::Initialize() {
WG_LOG_INFO("[ExternalToolPlugin] ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ...");
// ΠΠ°Π³ΡΡΠ·ΠΊΠ° Π½Π°ΡΡΡΠΎΠ΅ΠΊ
if (Wudgine::Core::SettingsManager::GetInstance().HasPluginSettings(GetName())) {
m_settings = Wudgine::Core::SettingsManager::GetInstance().LoadPluginSettings<Settings>(GetName());
}
// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΈΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΠΈ Ρ Π²Π½Π΅ΡΠ½ΠΈΠΌ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΠΎΠΌ
m_integration = std::make_unique<ExternalToolIntegration>(m_settings.externalToolPath);
// ΠΠ°ΡΡΡΠΎΠΉΠΊΠ° ΠΈΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΠΈ
m_integration->SetAutoSync(m_settings.autoSync);
m_integration->SetSyncInterval(m_settings.syncInterval);
// Π Π΅Π³ΠΈΡΡΡΠ°ΡΠΈΡ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΠΎΠ² ΡΠ΅Π΄Π°ΠΊΡΠΎΡΠ° (Π΅ΡΠ»ΠΈ Π² ΡΠ΅ΠΆΠΈΠΌΠ΅ ΡΠ΅Π΄Π°ΠΊΡΠΎΡΠ°)
if (Wudgine::Core::IsEditor()) {
RegisterEditorTools();
}
// ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ ΠΈΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΠΈ
if (!m_integration->Initialize()) {
WG_LOG_ERROR("[ExternalToolPlugin] ΠΡΠΈΠ±ΠΊΠ° ΠΈΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΠΈ ΠΈΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΠΈ Ρ Π²Π½Π΅ΡΠ½ΠΈΠΌ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΠΎΠΌ");
return false;
}
WG_LOG_INFO("[ExternalToolPlugin] ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ Π·Π°Π²Π΅ΡΡΠ΅Π½Π°");
return true;
}
void ExternalToolPlugin::Shutdown() {
WG_LOG_INFO("[ExternalToolPlugin] ΠΠ°Π²Π΅ΡΡΠ΅Π½ΠΈΠ΅ ΡΠ°Π±ΠΎΡΡ...");
// Π‘ΠΎΡ
ΡΠ°Π½Π΅Π½ΠΈΠ΅ Π½Π°ΡΡΡΠΎΠ΅ΠΊ
Wudgine::Core::SettingsManager::GetInstance().SavePluginSettings(GetName(), m_settings);
// ΠΠ°Π²Π΅ΡΡΠ΅Π½ΠΈΠ΅ ΡΠ°Π±ΠΎΡΡ ΠΈΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΠΈ
if (m_integration) {
m_integration->Shutdown();
}
WG_LOG_INFO("[ExternalToolPlugin] ΠΠ°Π²Π΅ΡΡΠ΅Π½ΠΈΠ΅ ΡΠ°Π±ΠΎΡΡ Π·Π°Π²Π΅ΡΡΠ΅Π½ΠΎ");
}
void ExternalToolPlugin::RegisterEditorTools() {
// Π Π΅Π³ΠΈΡΡΡΠ°ΡΠΈΡ ΠΎΠΊΠ½Π° Π²Π½Π΅ΡΠ½Π΅Π³ΠΎ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΠ°
auto* window = new ExternalToolWindow(m_integration.get());
Wudgine::Editor::EditorToolManager::GetInstance().RegisterTool(window);
// ΠΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΏΡΠ½ΠΊΡΠΎΠ² ΠΌΠ΅Π½Ρ
Wudgine::Editor::EditorMenuManager::GetInstance().AddMenuItem(
"ΠΠ½ΡΡΡΡΠΌΠ΅Π½ΡΡ/ΠΠ½Π΅ΡΠ½ΠΈΠΉ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½Ρ/ΠΡΠΊΡΡΡΡ",
[window]() {
window->SetVisible(true);
}
);
Wudgine::Editor::EditorMenuManager::GetInstance().AddMenuItem(
"ΠΠ½ΡΡΡΡΠΌΠ΅Π½ΡΡ/ΠΠ½Π΅ΡΠ½ΠΈΠΉ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½Ρ/Π‘ΠΈΠ½Ρ
ΡΠΎΠ½ΠΈΠ·ΠΈΡΠΎΠ²Π°ΡΡ",
[this]() {
m_integration->SyncNow();
}
);
Wudgine::Editor::EditorMenuManager::GetInstance().AddMenuItem(
"ΠΠ½ΡΡΡΡΠΌΠ΅Π½ΡΡ/ΠΠ½Π΅ΡΠ½ΠΈΠΉ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½Ρ/ΠΠ°ΠΏΡΡΡΠΈΡΡ Π²Π½Π΅ΡΠ½ΠΈΠΉ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½Ρ",
[this]() {
m_integration->LaunchExternalTool();
}
);
}
void ExternalToolPlugin::RenderSettings() {
char buffer[256];
strcpy(buffer, m_settings.externalToolPath.c_str());
if (ImGui::InputText("ΠΡΡΡ ΠΊ Π²Π½Π΅ΡΠ½Π΅ΠΌΡ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΡ", buffer, sizeof(buffer))) {
m_settings.externalToolPath = buffer;
m_integration->SetExternalToolPath(m_settings.externalToolPath);
}
if (ImGui::Button("ΠΠ±Π·ΠΎΡ...")) {
// ΠΡΠΊΡΡΡΠΈΠ΅ Π΄ΠΈΠ°Π»ΠΎΠ³Π° Π²ΡΠ±ΠΎΡΠ° ΡΠ°ΠΉΠ»Π°
// ...
}
if (ImGui::Checkbox("ΠΠ²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠ°Ρ ΡΠΈΠ½Ρ
ΡΠΎΠ½ΠΈΠ·Π°ΡΠΈΡ", &m_settings.autoSync)) {
m_integration->SetAutoSync(m_settings.autoSync);
}
if (m_settings.autoSync) {
if (ImGui::SliderInt("ΠΠ½ΡΠ΅ΡΠ²Π°Π» ΡΠΈΠ½Ρ
ΡΠΎΠ½ΠΈΠ·Π°ΡΠΈΠΈ (ΡΠ΅ΠΊ)", &m_settings.syncInterval, 1, 60)) {
m_integration->SetSyncInterval(m_settings.syncInterval);
}
}
if (ImGui::Button("ΠΡΠΎΠ²Π΅ΡΠΈΡΡ ΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΠ΅")) {
bool connected = m_integration->TestConnection();
if (connected) {
WG_LOG_INFO("[ExternalToolPlugin] Π‘ΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΠ΅ Ρ Π²Π½Π΅ΡΠ½ΠΈΠΌ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΠΎΠΌ ΡΡΡΠ°Π½ΠΎΠ²Π»Π΅Π½ΠΎ");
} else {
WG_LOG_ERROR("[ExternalToolPlugin] ΠΡΠΈΠ±ΠΊΠ° ΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΡ Ρ Π²Π½Π΅ΡΠ½ΠΈΠΌ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΠΎΠΌ");
}
}
// Π‘ΠΎΡ
ΡΠ°Π½Π΅Π½ΠΈΠ΅ Π½Π°ΡΡΡΠΎΠ΅ΠΊ
Wudgine::Core::SettingsManager::GetInstance().SavePluginSettings(GetName(), m_settings);
}
// ΠΠΊΡΠΏΠΎΡΡ ΠΏΠ»Π°Π³ΠΈΠ½Π°
extern "C" {
WUDGINE_PLUGIN_API Wudgine::Plugin::IPlugin* CreatePlugin() {
return new ExternalToolPlugin();
}
}
Π§ΡΠΎ Π΄Π°Π»ΡΡΠ΅?
Π’Π΅ΠΏΠ΅ΡΡ, ΠΊΠΎΠ³Π΄Π° Π²Ρ ΠΎΠ·Π½Π°ΠΊΠΎΠΌΠΈΠ»ΠΈΡΡ Ρ ΠΏΡΠΈΠΌΠ΅ΡΠ°ΠΌΠΈ ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠ², Π²Ρ ΠΌΠΎΠΆΠ΅ΡΠ΅:
- Π£Π·Π½Π°ΡΡ, ΠΊΠ°ΠΊ ΠΏΡΠ±Π»ΠΈΠΊΠΎΠ²Π°ΡΡ ΡΠ²ΠΎΠΈ ΠΏΠ»Π°Π³ΠΈΠ½Ρ
- ΠΠ·ΡΡΠΈΡΡ ΠΏΡΠΎΠ΄Π²ΠΈΠ½ΡΡΡΠ΅ ΡΠ΅ΠΌΡ Π΄Π»Ρ Π±ΠΎΠ»Π΅Π΅ Π³Π»ΡΠ±ΠΎΠΊΠΎΠ³ΠΎ ΠΏΠΎΠ½ΠΈΠΌΠ°Π½ΠΈΡ Wudgine
ΠΠΊΡΠΏΠ΅ΡΠΈΠΌΠ΅Π½ΡΠΈΡΡΠΉΡΠ΅ Ρ ΠΏΠ»Π°Π³ΠΈΠ½Π°ΠΌΠΈ ΠΈ ΡΠΎΠ·Π΄Π°Π²Π°ΠΉΡΠ΅ ΡΠ½ΠΈΠΊΠ°Π»ΡΠ½ΡΠ΅ ΡΠ°ΡΡΠΈΡΠ΅Π½ΠΈΡ Π΄Π»Ρ Wudgine, ΠΊΠΎΡΠΎΡΡΠ΅ ΠΏΠΎΠΌΠΎΠ³ΡΡ Π²Π°ΠΌ Π² ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΠ΅ ΠΈΠ³Ρ!