Switching to my turbo badger fork.
This commit is contained in:
parent
f2ce11d268
commit
253a685dde
|
@ -25,6 +25,6 @@
|
|||
[submodule "third_party/libav-xma-bin"]
|
||||
path = third_party/libav-xma-bin
|
||||
url = https://github.com/xenia-project/libav-xma-bin.git
|
||||
[submodule "third_party/turbobadger"]
|
||||
path = third_party/turbobadger
|
||||
url = https://github.com/xenia-project/turbobadger.git
|
||||
[submodule "third_party/elemental-forms"]
|
||||
path = third_party/elemental-forms
|
||||
url = https://github.com/xenia-project/elemental-forms.git
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)third_party\flatbuffers\include\;$(SolutionDir)third_party\turbobadger\src\;$(SolutionDir)third_party\gflags\src\;$(SolutionDir)src\;$(SolutionDir)third_party;$(SolutionDir)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)third_party\flatbuffers\include\;$(SolutionDir)third_party\turbobadger\src\;$(SolutionDir)third_party\gflags\src\;$(SolutionDir)third_party\elemental-forms\src\;$(SolutionDir)src\;$(SolutionDir)third_party;$(SolutionDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>GLEW_STATIC=1;GLEW_MX=1;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;WIN32;_WIN64=1;_AMD64=1;MICROPROFILE_MAX_THREADS=128;CAPSTONE_X86_ATT_DISABLE;CAPSTONE_DIET_NO;CAPSTONE_X86_REDUCE_NO;CAPSTONE_HAS_X86;CAPSTONE_USE_SYS_DYN_MEM;XBYAK_NO_OP_NAMES;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
|
|
|
@ -166,11 +166,13 @@
|
|||
<ClCompile Include="src\xenia\memory.cc" />
|
||||
<ClCompile Include="src\xenia\profiling.cc" />
|
||||
<ClCompile Include="src\xenia\ui\control.cc" />
|
||||
<ClCompile Include="src\xenia\ui\elemental_control.cc" />
|
||||
<ClCompile Include="src\xenia\ui\gl\blitter.cc" />
|
||||
<ClCompile Include="src\xenia\ui\gl\circular_buffer.cc" />
|
||||
<ClCompile Include="src\xenia\ui\gl\gl_context.cc" />
|
||||
<ClCompile Include="src\xenia\ui\gl\gl_profiler_display.cc" />
|
||||
<ClCompile Include="src\xenia\ui\gl\wgl_control.cc" />
|
||||
<ClCompile Include="src\xenia\ui\gl\wgl_elemental_control.cc" />
|
||||
<ClCompile Include="src\xenia\ui\main_window.cc" />
|
||||
<ClCompile Include="src\xenia\ui\menu_item.cc" />
|
||||
<ClCompile Include="src\xenia\ui\win32\win32_control.cc" />
|
||||
|
@ -394,6 +396,7 @@
|
|||
<ClInclude Include="src\xenia\memory.h" />
|
||||
<ClInclude Include="src\xenia\profiling.h" />
|
||||
<ClInclude Include="src\xenia\ui\control.h" />
|
||||
<ClInclude Include="src\xenia\ui\elemental_control.h" />
|
||||
<ClInclude Include="src\xenia\ui\file_picker.h" />
|
||||
<ClInclude Include="src\xenia\ui\gl\blitter.h" />
|
||||
<ClInclude Include="src\xenia\ui\gl\circular_buffer.h" />
|
||||
|
@ -401,6 +404,7 @@
|
|||
<ClInclude Include="src\xenia\ui\gl\gl_context.h" />
|
||||
<ClInclude Include="src\xenia\ui\gl\gl_profiler_display.h" />
|
||||
<ClInclude Include="src\xenia\ui\gl\wgl_control.h" />
|
||||
<ClInclude Include="src\xenia\ui\gl\wgl_elemental_control.h" />
|
||||
<ClInclude Include="src\xenia\ui\loop.h" />
|
||||
<ClInclude Include="src\xenia\ui\main_window.h" />
|
||||
<ClInclude Include="src\xenia\ui\menu_item.h" />
|
||||
|
@ -556,7 +560,7 @@
|
|||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<Lib>
|
||||
<AdditionalDependencies>libxenia-base.lib;libavcodec.a;libavutil.a;libgflags.lib;libglew.lib</AdditionalDependencies>
|
||||
<AdditionalDependencies>libelemental.lib;libxenia-base.lib;libavcodec.a;libavutil.a;libgflags.lib;libglew.lib</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(SolutionDir)third_party\libav-xma-bin\lib\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
|
@ -573,7 +577,7 @@
|
|||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<Lib>
|
||||
<AdditionalDependencies>libxenia-base.lib;libavcodec.a;libavutil.a;libgflags.lib;libglew.lib</AdditionalDependencies>
|
||||
<AdditionalDependencies>libelemental.lib;libxenia-base.lib;libavcodec.a;libavutil.a;libgflags.lib;libglew.lib</AdditionalDependencies>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
@ -592,7 +596,7 @@
|
|||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<Lib>
|
||||
<AdditionalDependencies>libxenia-base.lib;libavcodec.a;libavutil.a;libgflags.lib;libglew.lib</AdditionalDependencies>
|
||||
<AdditionalDependencies>libelemental.lib;libxenia-base.lib;libavcodec.a;libavutil.a;libgflags.lib;libglew.lib</AdditionalDependencies>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
|
|
@ -730,6 +730,12 @@
|
|||
<ClCompile Include="src\xenia\ui\gl\circular_buffer.cc">
|
||||
<Filter>src\xenia\ui\gl</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\xenia\ui\elemental_control.cc">
|
||||
<Filter>src\xenia\ui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\xenia\ui\gl\wgl_elemental_control.cc">
|
||||
<Filter>src\xenia\ui\gl</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\xenia\emulator.h">
|
||||
|
@ -1374,6 +1380,12 @@
|
|||
<ClInclude Include="src\xenia\ui\gl\gl.h">
|
||||
<Filter>src\xenia\ui\gl</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\xenia\ui\elemental_control.h">
|
||||
<Filter>src\xenia\ui</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\xenia\ui\gl\wgl_elemental_control.h">
|
||||
<Filter>src\xenia\ui\gl</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="src\xenia\cpu\hir\opcodes.inl">
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
|
||||
#include "xenia/debug/ui/application.h"
|
||||
|
||||
#include "el/message_handler.h"
|
||||
#include "el/util/metrics.h"
|
||||
#include "el/util/timer.h"
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/platform.h"
|
||||
|
@ -16,10 +19,6 @@
|
|||
#include "xenia/debug/ui/main_window.h"
|
||||
#include "xenia/profiling.h"
|
||||
|
||||
#include "third_party/turbobadger/src/tb/message_handler.h"
|
||||
#include "third_party/turbobadger/src/tb/util/metrics.h"
|
||||
#include "third_party/turbobadger/src/tb/util/timer.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
|
@ -82,16 +81,16 @@ void Application::Quit() {
|
|||
|
||||
// This doesn't really belong here (it belongs in tb_system_[linux/windows].cpp.
|
||||
// This is here since the proper implementations has not yet been done.
|
||||
void tb::util::RescheduleTimer(uint64_t fire_time) {
|
||||
if (fire_time == tb::MessageHandler::kNotSoon) {
|
||||
void el::util::RescheduleTimer(uint64_t fire_time) {
|
||||
if (fire_time == el::MessageHandler::kNotSoon) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t now = tb::util::GetTimeMS();
|
||||
uint64_t now = el::util::GetTimeMS();
|
||||
uint64_t delay_millis = fire_time >= now ? fire_time - now : 0;
|
||||
xe::debug::ui::Application::current()->loop()->PostDelayed([]() {
|
||||
uint64_t next_fire_time = tb::MessageHandler::GetNextMessageFireTime();
|
||||
uint64_t now = tb::util::GetTimeMS();
|
||||
uint64_t next_fire_time = el::MessageHandler::GetNextMessageFireTime();
|
||||
uint64_t now = el::util::GetTimeMS();
|
||||
if (now < next_fire_time) {
|
||||
// We timed out *before* we were supposed to (the OS is not playing nice).
|
||||
// Calling ProcessMessages now won't achieve a thing so force a reschedule
|
||||
|
@ -100,11 +99,11 @@ void tb::util::RescheduleTimer(uint64_t fire_time) {
|
|||
return;
|
||||
}
|
||||
|
||||
tb::MessageHandler::ProcessMessages();
|
||||
el::MessageHandler::ProcessMessages();
|
||||
|
||||
// If we still have things to do (because we didn't process all messages,
|
||||
// or because there are new messages), we need to rescedule, so call
|
||||
// RescheduleTimer.
|
||||
tb::util::RescheduleTimer(tb::MessageHandler::GetNextMessageFireTime());
|
||||
el::util::RescheduleTimer(el::MessageHandler::GetNextMessageFireTime());
|
||||
}, delay_millis);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,9 @@
|
|||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/platform.h"
|
||||
#include "xenia/base/threading.h"
|
||||
#include "xenia/debug/ui/turbo_badger_control.h"
|
||||
|
||||
// TODO(benvanik): platform based.
|
||||
#include "xenia/ui/gl/wgl_elemental_control.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
|
@ -89,7 +91,7 @@ bool MainWindow::Initialize() {
|
|||
// Setup the GL control that actually does the drawing.
|
||||
// We run here in the loop and only touch it (and its context) on this
|
||||
// thread. That means some sync-fu when we want to swap.
|
||||
control_ = std::make_unique<TurboBadgerControl>(loop());
|
||||
control_ = std::make_unique<xe::ui::gl::WGLElementalControl>(loop());
|
||||
AddChild(control_.get());
|
||||
|
||||
Resize(1440, 1200);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <memory>
|
||||
|
||||
#include "xenia/debug/ui/application.h"
|
||||
#include "xenia/ui/elemental_control.h"
|
||||
#include "xenia/ui/platform.h"
|
||||
#include "xenia/ui/window.h"
|
||||
|
||||
|
@ -20,8 +21,6 @@ namespace xe {
|
|||
namespace debug {
|
||||
namespace ui {
|
||||
|
||||
class TurboBadgerControl;
|
||||
|
||||
class MainWindow : public xe::ui::PlatformWindow {
|
||||
public:
|
||||
MainWindow(Application* app);
|
||||
|
@ -37,7 +36,7 @@ class MainWindow : public xe::ui::PlatformWindow {
|
|||
|
||||
Application* app_ = nullptr;
|
||||
xe::ui::PlatformMenu main_menu_;
|
||||
std::unique_ptr<TurboBadgerControl> control_;
|
||||
std::unique_ptr<xe::ui::ElementalControl> control_;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,82 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_DEBUG_UI_TURBO_BADGER_CONTROL_H_
|
||||
#define XENIA_DEBUG_UI_TURBO_BADGER_CONTROL_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "xenia/ui/gl/wgl_control.h"
|
||||
#include "xenia/ui/loop.h"
|
||||
|
||||
#include "third_party/turbobadger/src/tb/element.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
|
||||
class TurboBadgerControl : public xe::ui::gl::WGLControl {
|
||||
public:
|
||||
TurboBadgerControl(xe::ui::Loop* loop);
|
||||
~TurboBadgerControl() override;
|
||||
|
||||
static bool InitializeTurboBadger(tb::graphics::Renderer* renderer);
|
||||
static void ShutdownTurboBadger();
|
||||
|
||||
tb::graphics::Renderer* renderer() const { return renderer_.get(); }
|
||||
tb::Element* root_element() const { return root_element_.get(); }
|
||||
|
||||
protected:
|
||||
using super = xe::ui::gl::WGLControl;
|
||||
|
||||
bool Create() override;
|
||||
void Destroy() override;
|
||||
|
||||
void OnLayout(xe::ui::UIEvent& e) override;
|
||||
void OnPaint(xe::ui::UIEvent& e) override;
|
||||
|
||||
void OnGotFocus(xe::ui::UIEvent& e) override;
|
||||
void OnLostFocus(xe::ui::UIEvent& e) override;
|
||||
|
||||
tb::ModifierKeys GetModifierKeys();
|
||||
|
||||
void OnKeyPress(xe::ui::KeyEvent& e, bool is_down);
|
||||
bool CheckShortcutKey(xe::ui::KeyEvent& e, tb::SpecialKey special_key,
|
||||
bool is_down);
|
||||
void OnKeyDown(xe::ui::KeyEvent& e) override;
|
||||
void OnKeyUp(xe::ui::KeyEvent& e) override;
|
||||
|
||||
void OnMouseDown(xe::ui::MouseEvent& e) override;
|
||||
void OnMouseMove(xe::ui::MouseEvent& e) override;
|
||||
void OnMouseUp(xe::ui::MouseEvent& e) override;
|
||||
void OnMouseWheel(xe::ui::MouseEvent& e) override;
|
||||
|
||||
std::unique_ptr<tb::graphics::Renderer> renderer_;
|
||||
std::unique_ptr<tb::Element> root_element_;
|
||||
|
||||
uint32_t frame_count_ = 0;
|
||||
uint32_t fps_ = 0;
|
||||
uint64_t fps_update_time_ = 0;
|
||||
uint64_t fps_frame_count_ = 0;
|
||||
|
||||
bool modifier_shift_pressed_ = false;
|
||||
bool modifier_cntrl_pressed_ = false;
|
||||
bool modifier_alt_pressed_ = false;
|
||||
bool modifier_super_pressed_ = false;
|
||||
uint64_t last_click_time_ = 0;
|
||||
int last_click_x_ = 0;
|
||||
int last_click_y_ = 0;
|
||||
int last_click_counter_ = 0;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_DEBUG_UI_TURBO_BADGER_CONTROL_H_
|
|
@ -1,68 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_DEBUG_UI_TURBO_BADGER_RENDERER_H_
|
||||
#define XENIA_DEBUG_UI_TURBO_BADGER_RENDERER_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
|
||||
#include "xenia/ui/gl/circular_buffer.h"
|
||||
#include "xenia/ui/gl/gl_context.h"
|
||||
#include "xenia/ui/gl/gl.h"
|
||||
|
||||
#include "third_party/turbobadger/src/tb/graphics/batching_renderer.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
|
||||
class TBRendererGL4 : public tb::graphics::BatchingRenderer {
|
||||
public:
|
||||
TBRendererGL4(xe::ui::gl::GLContext* context);
|
||||
~TBRendererGL4() override;
|
||||
|
||||
static std::unique_ptr<TBRendererGL4> Create(xe::ui::gl::GLContext* context);
|
||||
|
||||
void BeginPaint(int render_target_w, int render_target_h) override;
|
||||
void EndPaint() override;
|
||||
|
||||
tb::graphics::Bitmap* CreateBitmap(int width, int height,
|
||||
uint32_t* data) override;
|
||||
|
||||
void RenderBatch(Batch* batch) override;
|
||||
void SetClipRect(const tb::Rect& rect) override;
|
||||
|
||||
private:
|
||||
class TBBitmapGL4;
|
||||
|
||||
bool Initialize();
|
||||
void Flush();
|
||||
|
||||
xe::ui::gl::GLContext* context_ = nullptr;
|
||||
|
||||
GLuint program_ = 0;
|
||||
GLuint vao_ = 0;
|
||||
xe::ui::gl::CircularBuffer vertex_buffer_;
|
||||
|
||||
static const size_t kMaxCommands = 512;
|
||||
struct {
|
||||
GLenum prim_type;
|
||||
size_t vertex_offset;
|
||||
size_t vertex_count;
|
||||
} draw_commands_[kMaxCommands] = {0};
|
||||
uint32_t draw_command_count_ = 0;
|
||||
TBBitmapGL4* current_bitmap_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_DEBUG_UI_TURBO_BADGER_RENDERER_H_
|
|
@ -77,15 +77,11 @@
|
|||
<ClInclude Include="..\..\base\main.h" />
|
||||
<ClInclude Include="application.h" />
|
||||
<ClInclude Include="main_window.h" />
|
||||
<ClInclude Include="turbo_badger_control.h" />
|
||||
<ClInclude Include="turbo_badger_renderer.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\base\main_win.cc" />
|
||||
<ClCompile Include="application.cc" />
|
||||
<ClCompile Include="main_window.cc" />
|
||||
<ClCompile Include="turbo_badger_control.cc" />
|
||||
<ClCompile Include="turbo_badger_renderer.cc" />
|
||||
<ClCompile Include="xe-debug-ui.cc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
<Filter Include="src\xenia\base">
|
||||
<UniqueIdentifier>{9a5724c2-5473-4d53-93b4-26531201f38d}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="src\xenia\debug\ui\elements">
|
||||
<UniqueIdentifier>{f0ac4999-4700-4b41-b73d-c6dc8b23c5e6}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\base\main.h">
|
||||
|
@ -27,12 +30,6 @@
|
|||
<ClInclude Include="application.h">
|
||||
<Filter>src\xenia\debug\ui</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="turbo_badger_control.h">
|
||||
<Filter>src\xenia\debug\ui</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="turbo_badger_renderer.h">
|
||||
<Filter>src\xenia\debug\ui</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\base\main_win.cc">
|
||||
|
@ -47,11 +44,5 @@
|
|||
<ClCompile Include="application.cc">
|
||||
<Filter>src\xenia\debug\ui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="turbo_badger_control.cc">
|
||||
<Filter>src\xenia\debug\ui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="turbo_badger_renderer.cc">
|
||||
<Filter>src\xenia\debug\ui</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -87,7 +87,7 @@ class Control {
|
|||
protected:
|
||||
explicit Control(uint32_t flags);
|
||||
|
||||
virtual bool Create() = 0;
|
||||
virtual bool Create() { return true; }
|
||||
virtual void Destroy() {}
|
||||
|
||||
virtual void OnCreate() {}
|
||||
|
|
|
@ -0,0 +1,478 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/ui/elemental_control.h"
|
||||
|
||||
#include "el/animation_manager.h"
|
||||
#include "el/elemental_forms.h"
|
||||
#include "el/text/font_manager.h"
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/clock.h"
|
||||
#include "xenia/base/logging.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
|
||||
constexpr bool kContinuousRepaint = false;
|
||||
|
||||
// Enables long press behaviors (context menu, etc).
|
||||
constexpr bool kTouch = false;
|
||||
|
||||
constexpr uint64_t kDoubleClickDelayMillis = 600;
|
||||
constexpr double kDoubleClickDistance = 5;
|
||||
|
||||
constexpr int32_t kMouseWheelDetent = 120;
|
||||
|
||||
class RootElement : public el::Element {
|
||||
public:
|
||||
RootElement(ElementalControl* owner) : owner_(owner) {}
|
||||
void OnInvalid() override { owner_->Invalidate(); }
|
||||
|
||||
private:
|
||||
ElementalControl* owner_ = nullptr;
|
||||
};
|
||||
|
||||
bool ElementalControl::InitializeElemental(el::graphics::Renderer* renderer) {
|
||||
static bool has_initialized = false;
|
||||
if (has_initialized) {
|
||||
return true;
|
||||
}
|
||||
has_initialized = true;
|
||||
|
||||
if (!el::Initialize(
|
||||
renderer,
|
||||
"third_party/turbobadger/resources/language/lng_en.tb.txt")) {
|
||||
XELOGE("Failed to initialize turbobadger core");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load the default skin, and override skin that contains the graphics
|
||||
// specific to the demo.
|
||||
if (!el::Skin::get()->Load(
|
||||
"third_party/elemental-forms/resources/default_skin/skin.tb.txt",
|
||||
"third_party/elemental-forms/testbed/resources/skin/skin.tb.txt")) {
|
||||
XELOGE("Failed to load turbobadger skin");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Register font renderers.
|
||||
#ifdef EL_FONT_RENDERER_TBBF
|
||||
void register_tbbf_font_renderer();
|
||||
register_tbbf_font_renderer();
|
||||
#endif
|
||||
#ifdef EL_FONT_RENDERER_STB
|
||||
void register_stb_font_renderer();
|
||||
register_stb_font_renderer();
|
||||
#endif
|
||||
#ifdef EL_FONT_RENDERER_FREETYPE
|
||||
void register_freetype_font_renderer();
|
||||
register_freetype_font_renderer();
|
||||
#endif
|
||||
auto font_manager = el::text::FontManager::get();
|
||||
|
||||
// Add fonts we can use to the font manager.
|
||||
#if defined(EL_FONT_RENDERER_STB) || defined(EL_FONT_RENDERER_FREETYPE)
|
||||
font_manager->AddFontInfo("third_party/elemental-forms/resources/vera.ttf",
|
||||
"Default");
|
||||
#endif
|
||||
#ifdef EL_FONT_RENDERER_TBBF
|
||||
font_manager->AddFontInfo(
|
||||
"third_party/elemental-forms/resources/default_font/"
|
||||
"segoe_white_with_shadow.tb.txt",
|
||||
"Default");
|
||||
#endif
|
||||
|
||||
// Set the default font description for elements to one of the fonts we just
|
||||
// added.
|
||||
el::FontDescription fd;
|
||||
fd.set_id(TBIDC("Default"));
|
||||
fd.set_size(el::Skin::get()->dimension_converter()->DpToPx(14));
|
||||
font_manager->set_default_font_description(fd);
|
||||
|
||||
// Create the font now.
|
||||
auto font =
|
||||
font_manager->CreateFontFace(font_manager->default_font_description());
|
||||
return true;
|
||||
}
|
||||
|
||||
ElementalControl::ElementalControl(Loop* loop, uint32_t flags) : super(flags) {}
|
||||
|
||||
ElementalControl::~ElementalControl() = default;
|
||||
|
||||
bool ElementalControl::Create() {
|
||||
if (!super::Create()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create subclass renderer (GL, etc).
|
||||
renderer_ = CreateRenderer();
|
||||
|
||||
// Initialize elemental.
|
||||
// TODO(benvanik): once? Do we care about multiple controls?
|
||||
if (!InitializeElemental(renderer_.get())) {
|
||||
XELOGE("Unable to initialize turbobadger");
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO(benvanik): setup elements.
|
||||
root_element_ = std::make_unique<RootElement>(this);
|
||||
root_element_->set_background_skin(TBIDC("background"));
|
||||
root_element_->set_rect({0, 0, 1000, 1000});
|
||||
|
||||
// Block animations during init.
|
||||
el::AnimationBlocker anim_blocker;
|
||||
|
||||
// TODO(benvanik): dummy UI.
|
||||
auto message_window = new el::MessageWindow(root_element(), TBIDC(""));
|
||||
message_window->Show("Title", "Hello!");
|
||||
|
||||
// el::ShowDebugInfoSettingsWindow(root_element());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ElementalControl::Destroy() {
|
||||
el::Shutdown();
|
||||
super::Destroy();
|
||||
}
|
||||
|
||||
void ElementalControl::OnLayout(UIEvent& e) {
|
||||
super::OnLayout(e);
|
||||
if (!root_element()) {
|
||||
return;
|
||||
}
|
||||
// TODO(benvanik): subregion?
|
||||
root_element()->set_rect({0, 0, width(), height()});
|
||||
}
|
||||
|
||||
void ElementalControl::OnPaint(UIEvent& e) {
|
||||
super::OnPaint(e);
|
||||
if (!root_element()) {
|
||||
return;
|
||||
}
|
||||
|
||||
++frame_count_;
|
||||
++fps_frame_count_;
|
||||
uint64_t now_ns = xe::Clock::QueryHostSystemTime();
|
||||
if (now_ns > fps_update_time_ + 1000 * 10000) {
|
||||
fps_ = uint32_t(fps_frame_count_ /
|
||||
(double(now_ns - fps_update_time_) / 10000000.0));
|
||||
fps_update_time_ = now_ns;
|
||||
fps_frame_count_ = 0;
|
||||
}
|
||||
|
||||
// Update TB (run animations, handle deferred input, etc).
|
||||
el::AnimationManager::Update();
|
||||
root_element()->InvokeProcessStates();
|
||||
root_element()->InvokeProcess();
|
||||
|
||||
renderer()->BeginPaint(width(), height());
|
||||
|
||||
// Render entire control hierarchy.
|
||||
root_element()->InvokePaint(el::Element::PaintProps());
|
||||
|
||||
// Render debug overlay.
|
||||
root_element()->computed_font()->DrawString(
|
||||
5, 5, el::Color(255, 0, 0),
|
||||
el::format_string("Frame %lld", frame_count_));
|
||||
if (kContinuousRepaint) {
|
||||
root_element()->computed_font()->DrawString(
|
||||
5, 20, el::Color(255, 0, 0), el::format_string("FPS: %d", fps_));
|
||||
}
|
||||
|
||||
renderer()->EndPaint();
|
||||
|
||||
// If animations are running, reinvalidate immediately.
|
||||
if (el::AnimationManager::has_running_animations()) {
|
||||
root_element()->Invalidate();
|
||||
}
|
||||
if (kContinuousRepaint) {
|
||||
// Force an immediate repaint, always.
|
||||
root_element()->Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void ElementalControl::OnGotFocus(UIEvent& e) { super::OnGotFocus(e); }
|
||||
|
||||
void ElementalControl::OnLostFocus(UIEvent& e) {
|
||||
super::OnLostFocus(e);
|
||||
modifier_shift_pressed_ = false;
|
||||
modifier_cntrl_pressed_ = false;
|
||||
modifier_alt_pressed_ = false;
|
||||
modifier_super_pressed_ = false;
|
||||
last_click_time_ = 0;
|
||||
}
|
||||
|
||||
el::ModifierKeys ElementalControl::GetModifierKeys() {
|
||||
auto modifiers = el::ModifierKeys::kNone;
|
||||
if (modifier_shift_pressed_) {
|
||||
modifiers |= el::ModifierKeys::kShift;
|
||||
}
|
||||
if (modifier_cntrl_pressed_) {
|
||||
modifiers |= el::ModifierKeys::kCtrl;
|
||||
}
|
||||
if (modifier_alt_pressed_) {
|
||||
modifiers |= el::ModifierKeys::kAlt;
|
||||
}
|
||||
if (modifier_super_pressed_) {
|
||||
modifiers |= el::ModifierKeys::kSuper;
|
||||
}
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
void ElementalControl::OnKeyPress(KeyEvent& e, bool is_down) {
|
||||
if (!root_element()) {
|
||||
return;
|
||||
}
|
||||
auto special_key = el::SpecialKey::kUndefined;
|
||||
switch (e.key_code()) {
|
||||
case 38:
|
||||
special_key = el::SpecialKey::kUp;
|
||||
break;
|
||||
case 39:
|
||||
special_key = el::SpecialKey::kRight;
|
||||
break;
|
||||
case 40:
|
||||
special_key = el::SpecialKey::kDown;
|
||||
break;
|
||||
case 37:
|
||||
special_key = el::SpecialKey::kLeft;
|
||||
break;
|
||||
case 112:
|
||||
special_key = el::SpecialKey::kF1;
|
||||
break;
|
||||
case 113:
|
||||
special_key = el::SpecialKey::kF2;
|
||||
break;
|
||||
case 114:
|
||||
special_key = el::SpecialKey::kF3;
|
||||
break;
|
||||
case 115:
|
||||
special_key = el::SpecialKey::kF4;
|
||||
break;
|
||||
case 116:
|
||||
special_key = el::SpecialKey::kF5;
|
||||
break;
|
||||
case 117:
|
||||
special_key = el::SpecialKey::kF6;
|
||||
break;
|
||||
case 118:
|
||||
special_key = el::SpecialKey::kF7;
|
||||
break;
|
||||
case 119:
|
||||
special_key = el::SpecialKey::kF8;
|
||||
break;
|
||||
case 120:
|
||||
special_key = el::SpecialKey::kF9;
|
||||
break;
|
||||
case 121:
|
||||
special_key = el::SpecialKey::kF10;
|
||||
break;
|
||||
case 122:
|
||||
special_key = el::SpecialKey::kF11;
|
||||
break;
|
||||
case 123:
|
||||
special_key = el::SpecialKey::kF12;
|
||||
break;
|
||||
case 33:
|
||||
special_key = el::SpecialKey::kPageUp;
|
||||
break;
|
||||
case 34:
|
||||
special_key = el::SpecialKey::kPageDown;
|
||||
break;
|
||||
case 36:
|
||||
special_key = el::SpecialKey::kHome;
|
||||
break;
|
||||
case 35:
|
||||
special_key = el::SpecialKey::kEnd;
|
||||
break;
|
||||
case 45:
|
||||
special_key = el::SpecialKey::kInsert;
|
||||
break;
|
||||
case 9:
|
||||
special_key = el::SpecialKey::kTab;
|
||||
break;
|
||||
case 46:
|
||||
special_key = el::SpecialKey::kDelete;
|
||||
break;
|
||||
case 8:
|
||||
special_key = el::SpecialKey::kBackspace;
|
||||
break;
|
||||
case 13:
|
||||
special_key = el::SpecialKey::kEnter;
|
||||
break;
|
||||
case 27:
|
||||
special_key = el::SpecialKey::kEsc;
|
||||
break;
|
||||
case 93:
|
||||
if (!is_down && el::Element::focused_element) {
|
||||
el::Event ev(el::EventType::kContextMenu);
|
||||
ev.modifierkeys = GetModifierKeys();
|
||||
el::Element::focused_element->InvokeEvent(ev);
|
||||
e.set_handled(true);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
modifier_shift_pressed_ = is_down;
|
||||
break;
|
||||
case 17:
|
||||
modifier_cntrl_pressed_ = is_down;
|
||||
break;
|
||||
// case xx:
|
||||
// // alt ??
|
||||
// modifier_alt_pressed_ = is_down;
|
||||
// break;
|
||||
case 91:
|
||||
modifier_super_pressed_ = is_down;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!CheckShortcutKey(e, special_key, is_down)) {
|
||||
e.set_handled(root_element()->InvokeKey(
|
||||
special_key != el::SpecialKey::kUndefined ? e.key_code() : 0,
|
||||
special_key, GetModifierKeys(), is_down));
|
||||
}
|
||||
}
|
||||
|
||||
bool ElementalControl::CheckShortcutKey(KeyEvent& e, el::SpecialKey special_key,
|
||||
bool is_down) {
|
||||
bool shortcut_key = modifier_cntrl_pressed_;
|
||||
if (!el::Element::focused_element || !is_down || !shortcut_key) {
|
||||
return false;
|
||||
}
|
||||
bool reverse_key = modifier_shift_pressed_;
|
||||
int upper_key = e.key_code();
|
||||
if (upper_key >= 'a' && upper_key <= 'z') {
|
||||
upper_key += 'A' - 'a';
|
||||
}
|
||||
el::TBID id;
|
||||
if (upper_key == 'X') {
|
||||
id = TBIDC("cut");
|
||||
} else if (upper_key == 'C' || special_key == el::SpecialKey::kInsert) {
|
||||
id = TBIDC("copy");
|
||||
} else if (upper_key == 'V' ||
|
||||
(special_key == el::SpecialKey::kInsert && reverse_key)) {
|
||||
id = TBIDC("paste");
|
||||
} else if (upper_key == 'A') {
|
||||
id = TBIDC("selectall");
|
||||
} else if (upper_key == 'Z' || upper_key == 'Y') {
|
||||
bool undo = upper_key == 'Z';
|
||||
if (reverse_key) {
|
||||
undo = !undo;
|
||||
}
|
||||
id = undo ? TBIDC("undo") : TBIDC("redo");
|
||||
} else if (upper_key == 'N') {
|
||||
id = TBIDC("new");
|
||||
} else if (upper_key == 'O') {
|
||||
id = TBIDC("open");
|
||||
} else if (upper_key == 'S') {
|
||||
id = TBIDC("save");
|
||||
} else if (upper_key == 'W') {
|
||||
id = TBIDC("close");
|
||||
} else if (special_key == el::SpecialKey::kPageUp) {
|
||||
id = TBIDC("prev_doc");
|
||||
} else if (special_key == el::SpecialKey::kPageDown) {
|
||||
id = TBIDC("next_doc");
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
el::Event ev(el::EventType::kShortcut);
|
||||
ev.modifierkeys = GetModifierKeys();
|
||||
ev.ref_id = id;
|
||||
if (!el::Element::focused_element->InvokeEvent(ev)) {
|
||||
return false;
|
||||
}
|
||||
e.set_handled(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ElementalControl::OnKeyDown(KeyEvent& e) {
|
||||
super::OnKeyDown(e);
|
||||
OnKeyPress(e, true);
|
||||
}
|
||||
|
||||
void ElementalControl::OnKeyUp(KeyEvent& e) {
|
||||
super::OnKeyUp(e);
|
||||
OnKeyPress(e, false);
|
||||
}
|
||||
|
||||
void ElementalControl::OnMouseDown(MouseEvent& e) {
|
||||
super::OnMouseDown(e);
|
||||
if (!root_element()) {
|
||||
return;
|
||||
}
|
||||
// TODO(benvanik): more button types.
|
||||
if (e.button() == MouseEvent::Button::kLeft) {
|
||||
// Simulated click count support.
|
||||
// TODO(benvanik): move into Control?
|
||||
uint64_t now = xe::Clock::QueryHostUptimeMillis();
|
||||
if (now < last_click_time_ + kDoubleClickDelayMillis) {
|
||||
double distance_moved = std::sqrt(std::pow(e.x() - last_click_x_, 2.0) +
|
||||
std::pow(e.y() - last_click_y_, 2.0));
|
||||
if (distance_moved < kDoubleClickDistance) {
|
||||
++last_click_counter_;
|
||||
} else {
|
||||
last_click_counter_ = 1;
|
||||
}
|
||||
} else {
|
||||
last_click_counter_ = 1;
|
||||
}
|
||||
last_click_x_ = e.x();
|
||||
last_click_y_ = e.y();
|
||||
last_click_time_ = now;
|
||||
|
||||
e.set_handled(root_element()->InvokePointerDown(
|
||||
e.x(), e.y(), last_click_counter_, GetModifierKeys(), kTouch));
|
||||
}
|
||||
}
|
||||
|
||||
void ElementalControl::OnMouseMove(MouseEvent& e) {
|
||||
super::OnMouseMove(e);
|
||||
if (!root_element()) {
|
||||
return;
|
||||
}
|
||||
root_element()->InvokePointerMove(e.x(), e.y(), GetModifierKeys(), kTouch);
|
||||
e.set_handled(true);
|
||||
}
|
||||
|
||||
void ElementalControl::OnMouseUp(MouseEvent& e) {
|
||||
super::OnMouseUp(e);
|
||||
if (!root_element()) {
|
||||
return;
|
||||
}
|
||||
if (e.button() == MouseEvent::Button::kLeft) {
|
||||
e.set_handled(root_element()->InvokePointerUp(e.x(), e.y(),
|
||||
GetModifierKeys(), kTouch));
|
||||
} else if (e.button() == MouseEvent::Button::kRight) {
|
||||
root_element()->InvokePointerMove(e.x(), e.y(), GetModifierKeys(), kTouch);
|
||||
if (el::Element::hovered_element) {
|
||||
int x = e.x();
|
||||
int y = e.y();
|
||||
el::Element::hovered_element->ConvertFromRoot(x, y);
|
||||
el::Event ev(el::EventType::kContextMenu, x, y, kTouch,
|
||||
GetModifierKeys());
|
||||
el::Element::hovered_element->InvokeEvent(ev);
|
||||
}
|
||||
e.set_handled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void ElementalControl::OnMouseWheel(MouseEvent& e) {
|
||||
super::OnMouseWheel(e);
|
||||
if (!root_element()) {
|
||||
return;
|
||||
}
|
||||
e.set_handled(root_element()->InvokeWheel(
|
||||
e.x(), e.y(), e.dx(), -e.dy() / kMouseWheelDetent, GetModifierKeys()));
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
} // namespace xe
|
|
@ -0,0 +1,80 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_UI_ELEMENTAL_CONTROL_H_
|
||||
#define XENIA_UI_ELEMENTAL_CONTROL_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "el/element.h"
|
||||
#include "el/graphics/renderer.h"
|
||||
#include "xenia/ui/control.h"
|
||||
#include "xenia/ui/loop.h"
|
||||
#include "xenia/ui/platform.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
|
||||
class ElementalControl : public PlatformControl {
|
||||
public:
|
||||
ElementalControl(Loop* loop, uint32_t flags);
|
||||
~ElementalControl() override;
|
||||
|
||||
el::graphics::Renderer* renderer() const { return renderer_.get(); }
|
||||
el::Element* root_element() const { return root_element_.get(); }
|
||||
|
||||
protected:
|
||||
using super = PlatformControl;
|
||||
|
||||
bool InitializeElemental(el::graphics::Renderer* renderer);
|
||||
virtual std::unique_ptr<el::graphics::Renderer> CreateRenderer() = 0;
|
||||
|
||||
bool Create() override;
|
||||
void Destroy() override;
|
||||
|
||||
void OnLayout(UIEvent& e) override;
|
||||
void OnPaint(UIEvent& e) override;
|
||||
|
||||
void OnGotFocus(UIEvent& e) override;
|
||||
void OnLostFocus(UIEvent& e) override;
|
||||
|
||||
el::ModifierKeys GetModifierKeys();
|
||||
|
||||
void OnKeyPress(KeyEvent& e, bool is_down);
|
||||
bool CheckShortcutKey(KeyEvent& e, el::SpecialKey special_key, bool is_down);
|
||||
void OnKeyDown(KeyEvent& e) override;
|
||||
void OnKeyUp(KeyEvent& e) override;
|
||||
|
||||
void OnMouseDown(MouseEvent& e) override;
|
||||
void OnMouseMove(MouseEvent& e) override;
|
||||
void OnMouseUp(MouseEvent& e) override;
|
||||
void OnMouseWheel(MouseEvent& e) override;
|
||||
|
||||
std::unique_ptr<el::graphics::Renderer> renderer_;
|
||||
std::unique_ptr<el::Element> root_element_;
|
||||
|
||||
uint32_t frame_count_ = 0;
|
||||
uint32_t fps_ = 0;
|
||||
uint64_t fps_update_time_ = 0;
|
||||
uint64_t fps_frame_count_ = 0;
|
||||
|
||||
bool modifier_shift_pressed_ = false;
|
||||
bool modifier_cntrl_pressed_ = false;
|
||||
bool modifier_alt_pressed_ = false;
|
||||
bool modifier_super_pressed_ = false;
|
||||
uint64_t last_click_time_ = 0;
|
||||
int last_click_x_ = 0;
|
||||
int last_click_y_ = 0;
|
||||
int last_click_counter_ = 0;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_UI_ELEMENTAL_CONTROL_H_
|
|
@ -7,44 +7,195 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/debug/ui/turbo_badger_renderer.h"
|
||||
#include "xenia/ui/gl/wgl_elemental_control.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "el/graphics/batching_renderer.h"
|
||||
#include "el/graphics/bitmap_fragment.h"
|
||||
#include "el/util/math.h"
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/logging.h"
|
||||
|
||||
#include "third_party/turbobadger/src/tb/graphics/bitmap_fragment.h"
|
||||
#include "third_party/turbobadger/src/tb/util/math.h"
|
||||
#include "xenia/profiling.h"
|
||||
#include "xenia/ui/gl/circular_buffer.h"
|
||||
#include "xenia/ui/gl/gl_context.h"
|
||||
#include "xenia/ui/gl/gl.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
namespace gl {
|
||||
|
||||
using namespace tb;
|
||||
|
||||
class TBRendererGL4::TBBitmapGL4 : public tb::graphics::Bitmap {
|
||||
class GL4BatchingRenderer : public el::graphics::BatchingRenderer {
|
||||
public:
|
||||
TBBitmapGL4(xe::ui::gl::GLContext* context, TBRendererGL4* renderer);
|
||||
~TBBitmapGL4();
|
||||
GL4BatchingRenderer(GLContext* context);
|
||||
~GL4BatchingRenderer() override;
|
||||
|
||||
static std::unique_ptr<GL4BatchingRenderer> Create(GLContext* context);
|
||||
|
||||
void BeginPaint(int render_target_w, int render_target_h) override;
|
||||
void EndPaint() override;
|
||||
|
||||
std::unique_ptr<el::graphics::Bitmap> CreateBitmap(int width, int height,
|
||||
uint32_t* data) override;
|
||||
|
||||
void RenderBatch(Batch* batch) override;
|
||||
void set_clip_rect(const el::Rect& rect) override;
|
||||
|
||||
private:
|
||||
class GL4Bitmap : public el::graphics::Bitmap {
|
||||
public:
|
||||
GL4Bitmap(GLContext* context, GL4BatchingRenderer* renderer);
|
||||
~GL4Bitmap();
|
||||
|
||||
bool Init(int width, int height, uint32_t* data);
|
||||
int Width() override { return width_; }
|
||||
int Height() override { return height_; }
|
||||
void SetData(uint32_t* data) override;
|
||||
int width() override { return width_; }
|
||||
int height() override { return height_; }
|
||||
void set_data(uint32_t* data) override;
|
||||
|
||||
xe::ui::gl::GLContext* context_ = nullptr;
|
||||
TBRendererGL4* renderer_ = nullptr;
|
||||
GLContext* context_ = nullptr;
|
||||
GL4BatchingRenderer* renderer_ = nullptr;
|
||||
int width_ = 0;
|
||||
int height_ = 0;
|
||||
GLuint handle_ = 0;
|
||||
GLuint64 gpu_handle_ = 0;
|
||||
};
|
||||
|
||||
bool Initialize();
|
||||
void Flush();
|
||||
|
||||
GLContext* context_ = nullptr;
|
||||
|
||||
GLuint program_ = 0;
|
||||
GLuint vao_ = 0;
|
||||
CircularBuffer vertex_buffer_;
|
||||
|
||||
static const size_t kMaxCommands = 512;
|
||||
struct {
|
||||
GLenum prim_type;
|
||||
size_t vertex_offset;
|
||||
size_t vertex_count;
|
||||
} draw_commands_[kMaxCommands] = {0};
|
||||
uint32_t draw_command_count_ = 0;
|
||||
GL4Bitmap* current_bitmap_ = nullptr;
|
||||
};
|
||||
|
||||
TBRendererGL4::TBBitmapGL4::TBBitmapGL4(xe::ui::gl::GLContext* context,
|
||||
TBRendererGL4* renderer)
|
||||
WGLElementalControl::WGLElementalControl(Loop* loop)
|
||||
: ElementalControl(loop, Flags::kFlagOwnPaint), loop_(loop) {}
|
||||
|
||||
WGLElementalControl::~WGLElementalControl() = default;
|
||||
|
||||
bool WGLElementalControl::Create() {
|
||||
HINSTANCE hInstance = GetModuleHandle(nullptr);
|
||||
|
||||
WNDCLASSEX wcex;
|
||||
wcex.cbSize = sizeof(WNDCLASSEX);
|
||||
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
|
||||
wcex.lpfnWndProc = Win32Control::WndProcThunk;
|
||||
wcex.cbClsExtra = 0;
|
||||
wcex.cbWndExtra = 0;
|
||||
wcex.hInstance = hInstance;
|
||||
wcex.hIcon = nullptr;
|
||||
wcex.hIconSm = nullptr;
|
||||
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
||||
wcex.lpszMenuName = nullptr;
|
||||
wcex.lpszClassName = L"XeniaWglElementalClass";
|
||||
if (!RegisterClassEx(&wcex)) {
|
||||
XELOGE("WGL RegisterClassEx failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create window.
|
||||
DWORD window_style = WS_CHILD | WS_VISIBLE | SS_NOTIFY;
|
||||
DWORD window_ex_style = 0;
|
||||
hwnd_ =
|
||||
CreateWindowEx(window_ex_style, L"XeniaWglElementalClass", L"Xenia",
|
||||
window_style, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
CW_USEDEFAULT, parent_hwnd(), nullptr, hInstance, this);
|
||||
if (!hwnd_) {
|
||||
XELOGE("WGL CreateWindow failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!context_.Initialize(hwnd_)) {
|
||||
XEFATAL(
|
||||
"Unable to initialize GL context. Xenia requires OpenGL 4.5. Ensure "
|
||||
"you have the latest drivers for your GPU and that it supports OpenGL "
|
||||
"4.5. See http://xenia.jp/faq/ for more information.");
|
||||
return false;
|
||||
}
|
||||
|
||||
context_.AssertExtensionsPresent();
|
||||
|
||||
SetFocus(hwnd_);
|
||||
|
||||
return super::Create();
|
||||
}
|
||||
|
||||
std::unique_ptr<el::graphics::Renderer> WGLElementalControl::CreateRenderer() {
|
||||
return GL4BatchingRenderer::Create(&context_);
|
||||
}
|
||||
|
||||
void WGLElementalControl::OnLayout(UIEvent& e) {
|
||||
Control::ResizeToFill();
|
||||
super::OnLayout(e);
|
||||
}
|
||||
|
||||
LRESULT WGLElementalControl::WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||
LPARAM lParam) {
|
||||
switch (message) {
|
||||
case WM_PAINT: {
|
||||
invalidated_ = false;
|
||||
ValidateRect(hWnd, nullptr);
|
||||
SCOPE_profile_cpu_i("gpu", "xe::ui::gl::WGLElementalControl::WM_PAINT");
|
||||
{
|
||||
GLContextLock context_lock(&context_);
|
||||
|
||||
float clear_color[] = {rand() / (float)RAND_MAX, 1.0f, 0, 1.0f};
|
||||
glClearNamedFramebufferfv(0, GL_COLOR, 0, clear_color);
|
||||
|
||||
if (current_paint_callback_) {
|
||||
current_paint_callback_();
|
||||
current_paint_callback_ = nullptr;
|
||||
}
|
||||
|
||||
UIEvent e(this);
|
||||
OnPaint(e);
|
||||
|
||||
// TODO(benvanik): profiler present.
|
||||
Profiler::Present();
|
||||
}
|
||||
{
|
||||
SCOPE_profile_cpu_i("gpu",
|
||||
"xe::ui::gl::WGLElementalControl::SwapBuffers");
|
||||
SwapBuffers(context_.dc());
|
||||
}
|
||||
return 0;
|
||||
} break;
|
||||
}
|
||||
return Win32Control::WndProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
void WGLElementalControl::SynchronousRepaint(
|
||||
std::function<void()> paint_callback) {
|
||||
SCOPE_profile_cpu_f("gpu");
|
||||
|
||||
// We may already have a pending paint from a previous request when we
|
||||
// were minimized. We just overwrite it.
|
||||
current_paint_callback_ = std::move(paint_callback);
|
||||
|
||||
// This will not return until the WM_PAINT has completed.
|
||||
// Note, if we are minimized this won't do anything.
|
||||
RedrawWindow(hwnd(), nullptr, nullptr,
|
||||
RDW_INTERNALPAINT | RDW_UPDATENOW | RDW_ALLCHILDREN);
|
||||
}
|
||||
|
||||
GL4BatchingRenderer::GL4Bitmap::GL4Bitmap(GLContext* context,
|
||||
GL4BatchingRenderer* renderer)
|
||||
: context_(context), renderer_(renderer) {}
|
||||
|
||||
TBRendererGL4::TBBitmapGL4::~TBBitmapGL4() {
|
||||
xe::ui::gl::GLContextLock lock(context_);
|
||||
GL4BatchingRenderer::GL4Bitmap::~GL4Bitmap() {
|
||||
GLContextLock lock(context_);
|
||||
|
||||
// Must flush and unbind before we delete the texture.
|
||||
renderer_->FlushBitmap(this);
|
||||
|
@ -52,9 +203,10 @@ TBRendererGL4::TBBitmapGL4::~TBBitmapGL4() {
|
|||
glDeleteTextures(1, &handle_);
|
||||
}
|
||||
|
||||
bool TBRendererGL4::TBBitmapGL4::Init(int width, int height, uint32_t* data) {
|
||||
assert(width == tb::util::GetNearestPowerOfTwo(width));
|
||||
assert(height == tb::util::GetNearestPowerOfTwo(height));
|
||||
bool GL4BatchingRenderer::GL4Bitmap::Init(int width, int height,
|
||||
uint32_t* data) {
|
||||
assert(width == el::util::GetNearestPowerOfTwo(width));
|
||||
assert(height == el::util::GetNearestPowerOfTwo(height));
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
|
||||
|
@ -68,32 +220,30 @@ bool TBRendererGL4::TBBitmapGL4::Init(int width, int height, uint32_t* data) {
|
|||
gpu_handle_ = glGetTextureHandleARB(handle_);
|
||||
glMakeTextureHandleResidentARB(gpu_handle_);
|
||||
|
||||
SetData(data);
|
||||
set_data(data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TBRendererGL4::TBBitmapGL4::SetData(uint32_t* data) {
|
||||
void GL4BatchingRenderer::GL4Bitmap::set_data(uint32_t* data) {
|
||||
renderer_->FlushBitmap(this);
|
||||
glTextureSubImage2D(handle_, 0, 0, 0, width_, height_, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, data);
|
||||
}
|
||||
|
||||
TBRendererGL4::TBRendererGL4(xe::ui::gl::GLContext* context)
|
||||
: context_(context),
|
||||
vertex_buffer_(graphics::BatchingRenderer::kVertexBatchSize *
|
||||
sizeof(Vertex)) {}
|
||||
GL4BatchingRenderer::GL4BatchingRenderer(GLContext* context)
|
||||
: context_(context), vertex_buffer_(kVertexBatchSize * sizeof(Vertex)) {}
|
||||
|
||||
TBRendererGL4::~TBRendererGL4() {
|
||||
xe::ui::gl::GLContextLock lock(context_);
|
||||
GL4BatchingRenderer::~GL4BatchingRenderer() {
|
||||
GLContextLock lock(context_);
|
||||
vertex_buffer_.Shutdown();
|
||||
glDeleteVertexArrays(1, &vao_);
|
||||
glDeleteProgram(program_);
|
||||
}
|
||||
|
||||
std::unique_ptr<TBRendererGL4> TBRendererGL4::Create(
|
||||
xe::ui::gl::GLContext* context) {
|
||||
auto renderer = std::make_unique<TBRendererGL4>(context);
|
||||
std::unique_ptr<GL4BatchingRenderer> GL4BatchingRenderer::Create(
|
||||
GLContext* context) {
|
||||
auto renderer = std::make_unique<GL4BatchingRenderer>(context);
|
||||
if (!renderer->Initialize()) {
|
||||
XELOGE("Failed to initialize TurboBadger GL4 renderer");
|
||||
return nullptr;
|
||||
|
@ -101,7 +251,7 @@ std::unique_ptr<TBRendererGL4> TBRendererGL4::Create(
|
|||
return renderer;
|
||||
}
|
||||
|
||||
bool TBRendererGL4::Initialize() {
|
||||
bool GL4BatchingRenderer::Initialize() {
|
||||
if (!vertex_buffer_.Initialize()) {
|
||||
XELOGE("Failed to initialize circular buffer");
|
||||
return false;
|
||||
|
@ -188,23 +338,23 @@ void main() { \n\
|
|||
return true;
|
||||
}
|
||||
|
||||
graphics::Bitmap* TBRendererGL4::CreateBitmap(int width, int height,
|
||||
uint32_t* data) {
|
||||
auto bitmap = std::make_unique<TBBitmapGL4>(context_, this);
|
||||
std::unique_ptr<el::graphics::Bitmap> GL4BatchingRenderer::CreateBitmap(
|
||||
int width, int height, uint32_t* data) {
|
||||
auto bitmap = std::make_unique<GL4Bitmap>(context_, this);
|
||||
if (!bitmap->Init(width, height, data)) {
|
||||
return nullptr;
|
||||
}
|
||||
return bitmap.release();
|
||||
return std::unique_ptr<el::graphics::Bitmap>(bitmap.release());
|
||||
}
|
||||
|
||||
void TBRendererGL4::SetClipRect(const Rect& rect) {
|
||||
void GL4BatchingRenderer::set_clip_rect(const el::Rect& rect) {
|
||||
Flush();
|
||||
glScissor(clip_rect_.x, screen_rect_.h - (clip_rect_.y + clip_rect_.h),
|
||||
clip_rect_.w, clip_rect_.h);
|
||||
}
|
||||
|
||||
void TBRendererGL4::BeginPaint(int render_target_w, int render_target_h) {
|
||||
tb::graphics::BatchingRenderer::BeginPaint(render_target_w, render_target_h);
|
||||
void GL4BatchingRenderer::BeginPaint(int render_target_w, int render_target_h) {
|
||||
BatchingRenderer::BeginPaint(render_target_w, render_target_h);
|
||||
|
||||
glEnablei(GL_BLEND, 0);
|
||||
glBlendFunci(0, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
@ -237,8 +387,8 @@ void TBRendererGL4::BeginPaint(int render_target_w, int render_target_h) {
|
|||
glBindVertexArray(vao_);
|
||||
}
|
||||
|
||||
void TBRendererGL4::EndPaint() {
|
||||
tb::graphics::BatchingRenderer::EndPaint();
|
||||
void GL4BatchingRenderer::EndPaint() {
|
||||
BatchingRenderer::EndPaint();
|
||||
|
||||
Flush();
|
||||
|
||||
|
@ -246,7 +396,7 @@ void TBRendererGL4::EndPaint() {
|
|||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
void TBRendererGL4::Flush() {
|
||||
void GL4BatchingRenderer::Flush() {
|
||||
if (!draw_command_count_) {
|
||||
return;
|
||||
}
|
||||
|
@ -261,8 +411,8 @@ void TBRendererGL4::Flush() {
|
|||
vertex_buffer_.WaitUntilClean();
|
||||
}
|
||||
|
||||
void TBRendererGL4::RenderBatch(Batch* batch) {
|
||||
auto bitmap = static_cast<TBBitmapGL4*>(batch->bitmap);
|
||||
void GL4BatchingRenderer::RenderBatch(Batch* batch) {
|
||||
auto bitmap = static_cast<GL4Bitmap*>(batch->bitmap);
|
||||
if (bitmap != current_bitmap_) {
|
||||
current_bitmap_ = bitmap;
|
||||
Flush();
|
||||
|
@ -300,6 +450,6 @@ void TBRendererGL4::RenderBatch(Batch* batch) {
|
|||
vertex_buffer_.Commit(std::move(allocation));
|
||||
}
|
||||
|
||||
} // namespace gl
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_UI_GL_WGL_ELEMENTAL_CONTROL_H_
|
||||
#define XENIA_UI_GL_WGL_ELEMENTAL_CONTROL_H_
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "xenia/base/threading.h"
|
||||
#include "xenia/ui/elemental_control.h"
|
||||
#include "xenia/ui/gl/gl_context.h"
|
||||
#include "xenia/ui/loop.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
namespace gl {
|
||||
|
||||
class WGLElementalControl : public ElementalControl {
|
||||
public:
|
||||
WGLElementalControl(Loop* loop);
|
||||
~WGLElementalControl() override;
|
||||
|
||||
GLContext* context() { return &context_; }
|
||||
|
||||
void SynchronousRepaint(std::function<void()> paint_callback);
|
||||
|
||||
protected:
|
||||
using super = ElementalControl;
|
||||
|
||||
std::unique_ptr<el::graphics::Renderer> CreateRenderer() override;
|
||||
|
||||
bool Create() override;
|
||||
|
||||
void OnLayout(UIEvent& e) override;
|
||||
|
||||
LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||
LPARAM lParam) override;
|
||||
|
||||
private:
|
||||
Loop* loop_;
|
||||
GLContext context_;
|
||||
std::function<void()> current_paint_callback_;
|
||||
};
|
||||
|
||||
} // namespace gl
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_UI_GL_WGL_ELEMENTAL_CONTROL_H_
|
|
@ -12,6 +12,7 @@
|
|||
#define XENIA_UI_PLATFORM_H_
|
||||
|
||||
// TODO(benvanik): only on windows.
|
||||
#include "xenia/ui/win32/win32_control.h"
|
||||
#include "xenia/ui/win32/win32_file_picker.h"
|
||||
#include "xenia/ui/win32/win32_loop.h"
|
||||
#include "xenia/ui/win32/win32_menu_item.h"
|
||||
|
@ -20,6 +21,7 @@
|
|||
namespace xe {
|
||||
namespace ui {
|
||||
|
||||
using PlatformControl = xe::ui::win32::Win32Control;
|
||||
using PlatformFilePicker = xe::ui::win32::Win32FilePicker;
|
||||
using PlatformLoop = xe::ui::win32::Win32Loop;
|
||||
using PlatformMenu = xe::ui::win32::Win32MenuItem;
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit b7322a960063620938d76156c0ce4a4328788e71
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 5075e6995e7946c6d14cd86a813281f19f5853a9
|
32
xenia.sln
32
xenia.sln
|
@ -14,6 +14,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxenia", "libxenia.vcxpro
|
|||
ProjectSection(ProjectDependencies) = postProject
|
||||
{AE4AF147-715A-4C24-8BFA-136332DED28F} = {AE4AF147-715A-4C24-8BFA-136332DED28F}
|
||||
{93533067-6449-4691-88A8-026EBCFDCA97} = {93533067-6449-4691-88A8-026EBCFDCA97}
|
||||
{156102D7-F2DD-4618-B2EB-2DFE607EE6DD} = {156102D7-F2DD-4618-B2EB-2DFE607EE6DD}
|
||||
{838020F9-94AA-4314-996D-69B923C45D39} = {838020F9-94AA-4314-996D-69B923C45D39}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
|
@ -52,8 +53,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xe-gpu-trace-viewer", "src\
|
|||
{838020F9-94AA-4314-996D-69B923C45D39} = {838020F9-94AA-4314-996D-69B923C45D39}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libturbobadger", "third_party\turbobadger\libturbobadger.vcxproj", "{156102D7-F2DD-4618-B2EB-2DFE607EE6DD}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xe-debug-ui", "src\xenia\debug\ui\xe-debug-ui.vcxproj", "{C5BA52F0-C86B-4817-921C-CCA257FC04BE}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{AE4AF147-715A-4C24-8BFA-136332DED28F} = {AE4AF147-715A-4C24-8BFA-136332DED28F}
|
||||
|
@ -64,6 +63,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xe-debug-ui", "src\xenia\de
|
|||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxenia-base", "libxenia-base.vcxproj", "{93533067-6449-4691-88A8-026EBCFDCA97}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libelemental", "third_party\elemental-forms\libelemental.vcxproj", "{156102D7-F2DD-4618-B2EB-2DFE607EE6DD}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "elemental-forms-demo", "third_party\elemental-forms\testbed\elemental-testbed.vcxproj", "{C3FDE1FE-1FCB-4156-BB37-2E38F5C2DFE7}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Checked|x64 = Checked|x64
|
||||
|
@ -125,14 +128,8 @@ Global
|
|||
{21DDCB81-68A3-4AB2-8CB0-C2B051B9FDDC}.Debug|x64.Build.0 = Debug|x64
|
||||
{21DDCB81-68A3-4AB2-8CB0-C2B051B9FDDC}.Release|x64.ActiveCfg = Release|x64
|
||||
{21DDCB81-68A3-4AB2-8CB0-C2B051B9FDDC}.Release|x64.Build.0 = Release|x64
|
||||
{156102D7-F2DD-4618-B2EB-2DFE607EE6DD}.Checked|x64.ActiveCfg = Debug|x64
|
||||
{156102D7-F2DD-4618-B2EB-2DFE607EE6DD}.Checked|x64.Build.0 = Debug|x64
|
||||
{156102D7-F2DD-4618-B2EB-2DFE607EE6DD}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{156102D7-F2DD-4618-B2EB-2DFE607EE6DD}.Debug|x64.Build.0 = Debug|x64
|
||||
{156102D7-F2DD-4618-B2EB-2DFE607EE6DD}.Release|x64.ActiveCfg = Release|x64
|
||||
{156102D7-F2DD-4618-B2EB-2DFE607EE6DD}.Release|x64.Build.0 = Release|x64
|
||||
{C5BA52F0-C86B-4817-921C-CCA257FC04BE}.Checked|x64.ActiveCfg = Release|x64
|
||||
{C5BA52F0-C86B-4817-921C-CCA257FC04BE}.Checked|x64.Build.0 = Release|x64
|
||||
{C5BA52F0-C86B-4817-921C-CCA257FC04BE}.Checked|x64.ActiveCfg = Debug|x64
|
||||
{C5BA52F0-C86B-4817-921C-CCA257FC04BE}.Checked|x64.Build.0 = Debug|x64
|
||||
{C5BA52F0-C86B-4817-921C-CCA257FC04BE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C5BA52F0-C86B-4817-921C-CCA257FC04BE}.Debug|x64.Build.0 = Debug|x64
|
||||
{C5BA52F0-C86B-4817-921C-CCA257FC04BE}.Release|x64.ActiveCfg = Release|x64
|
||||
|
@ -143,6 +140,18 @@ Global
|
|||
{93533067-6449-4691-88A8-026EBCFDCA97}.Debug|x64.Build.0 = Debug|x64
|
||||
{93533067-6449-4691-88A8-026EBCFDCA97}.Release|x64.ActiveCfg = Release|x64
|
||||
{93533067-6449-4691-88A8-026EBCFDCA97}.Release|x64.Build.0 = Release|x64
|
||||
{156102D7-F2DD-4618-B2EB-2DFE607EE6DD}.Checked|x64.ActiveCfg = Checked|x64
|
||||
{156102D7-F2DD-4618-B2EB-2DFE607EE6DD}.Checked|x64.Build.0 = Checked|x64
|
||||
{156102D7-F2DD-4618-B2EB-2DFE607EE6DD}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{156102D7-F2DD-4618-B2EB-2DFE607EE6DD}.Debug|x64.Build.0 = Debug|x64
|
||||
{156102D7-F2DD-4618-B2EB-2DFE607EE6DD}.Release|x64.ActiveCfg = Release|x64
|
||||
{156102D7-F2DD-4618-B2EB-2DFE607EE6DD}.Release|x64.Build.0 = Release|x64
|
||||
{C3FDE1FE-1FCB-4156-BB37-2E38F5C2DFE7}.Checked|x64.ActiveCfg = Checked|x64
|
||||
{C3FDE1FE-1FCB-4156-BB37-2E38F5C2DFE7}.Checked|x64.Build.0 = Checked|x64
|
||||
{C3FDE1FE-1FCB-4156-BB37-2E38F5C2DFE7}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C3FDE1FE-1FCB-4156-BB37-2E38F5C2DFE7}.Debug|x64.Build.0 = Debug|x64
|
||||
{C3FDE1FE-1FCB-4156-BB37-2E38F5C2DFE7}.Release|x64.ActiveCfg = Release|x64
|
||||
{C3FDE1FE-1FCB-4156-BB37-2E38F5C2DFE7}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -155,7 +164,8 @@ Global
|
|||
{6EC54AD0-4F5B-48D9-B820-43DF2F0DC83C} = {9C5BDD9E-831B-4AEE-957F-0E88ADED79C6}
|
||||
{9B8AC22F-9147-490F-BE03-3B8BA31990A8} = {9C5BDD9E-831B-4AEE-957F-0E88ADED79C6}
|
||||
{21DDCB81-68A3-4AB2-8CB0-C2B051B9FDDC} = {345BD157-B21D-4989-9CE4-FA3C90FFC095}
|
||||
{156102D7-F2DD-4618-B2EB-2DFE607EE6DD} = {FCCBE57F-ECAE-420A-8A82-4B85F722C272}
|
||||
{C5BA52F0-C86B-4817-921C-CCA257FC04BE} = {345BD157-B21D-4989-9CE4-FA3C90FFC095}
|
||||
{156102D7-F2DD-4618-B2EB-2DFE607EE6DD} = {FCCBE57F-ECAE-420A-8A82-4B85F722C272}
|
||||
{C3FDE1FE-1FCB-4156-BB37-2E38F5C2DFE7} = {9C5BDD9E-831B-4AEE-957F-0E88ADED79C6}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
Loading…
Reference in New Issue