Red GL4.5 screen.
This commit is contained in:
parent
577ab0a4f1
commit
bbb7de6bff
|
@ -9,12 +9,14 @@
|
||||||
|
|
||||||
#include <poly/ui/control.h>
|
#include <poly/ui/control.h>
|
||||||
|
|
||||||
|
#include <poly/assert.h>
|
||||||
|
|
||||||
namespace poly {
|
namespace poly {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
Control::Control(Control* parent, uint32_t flags)
|
Control::Control(uint32_t flags)
|
||||||
: parent_(parent),
|
: flags_(flags),
|
||||||
flags_(flags),
|
parent_(nullptr),
|
||||||
width_(0),
|
width_(0),
|
||||||
height_(0),
|
height_(0),
|
||||||
is_cursor_visible_(true),
|
is_cursor_visible_(true),
|
||||||
|
@ -34,23 +36,39 @@ void Control::AddChild(std::unique_ptr<Control> child_control) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Control::AddChild(ControlPtr control) {
|
void Control::AddChild(ControlPtr control) {
|
||||||
|
assert_null(control->parent());
|
||||||
|
control->parent_ = this;
|
||||||
auto control_ptr = control.get();
|
auto control_ptr = control.get();
|
||||||
children_.emplace_back(std::move(control));
|
children_.emplace_back(std::move(control));
|
||||||
OnChildAdded(control_ptr);
|
OnChildAdded(control_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Control::RemoveChild(Control* child_control) {
|
Control::ControlPtr Control::RemoveChild(Control* child_control) {
|
||||||
|
assert_true(child_control->parent() == this);
|
||||||
for (auto& it = children_.begin(); it != children_.end(); ++it) {
|
for (auto& it = children_.begin(); it != children_.end(); ++it) {
|
||||||
if (it->get() == child_control) {
|
if (it->get() == child_control) {
|
||||||
|
auto control_ptr = std::move(*it);
|
||||||
|
child_control->parent_ = nullptr;
|
||||||
children_.erase(it);
|
children_.erase(it);
|
||||||
OnChildRemoved(child_control);
|
OnChildRemoved(child_control);
|
||||||
break;
|
return control_ptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return ControlPtr(nullptr, [](Control*) {});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Control::Layout() {
|
||||||
|
auto e = UIEvent(this);
|
||||||
|
OnLayout(e);
|
||||||
|
for (auto& child_control : children_) {
|
||||||
|
child_control->OnLayout(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Control::OnResize(UIEvent& e) { on_resize(e); }
|
void Control::OnResize(UIEvent& e) { on_resize(e); }
|
||||||
|
|
||||||
|
void Control::OnLayout(UIEvent& e) { on_layout(e); }
|
||||||
|
|
||||||
void Control::OnVisible(UIEvent& e) { on_visible(e); }
|
void Control::OnVisible(UIEvent& e) { on_visible(e); }
|
||||||
|
|
||||||
void Control::OnHidden(UIEvent& e) { on_hidden(e); }
|
void Control::OnHidden(UIEvent& e) { on_hidden(e); }
|
||||||
|
|
|
@ -34,15 +34,17 @@ class Control {
|
||||||
void AddChild(Control* child_control);
|
void AddChild(Control* child_control);
|
||||||
void AddChild(std::unique_ptr<Control> child_control);
|
void AddChild(std::unique_ptr<Control> child_control);
|
||||||
void AddChild(ControlPtr child_control);
|
void AddChild(ControlPtr child_control);
|
||||||
void RemoveChild(Control* child_control);
|
ControlPtr RemoveChild(Control* child_control);
|
||||||
|
|
||||||
int32_t width() const { return width_; }
|
int32_t width() const { return width_; }
|
||||||
int32_t height() const { return height_; }
|
int32_t height() const { return height_; }
|
||||||
virtual void Resize(int32_t width, int32_t height) = 0;
|
virtual void Resize(int32_t width, int32_t height) = 0;
|
||||||
virtual void Resize(int32_t left, int32_t top, int32_t right,
|
virtual void Resize(int32_t left, int32_t top, int32_t right,
|
||||||
int32_t bottom) = 0;
|
int32_t bottom) = 0;
|
||||||
|
void ResizeToFill() { ResizeToFill(0, 0, 0, 0); }
|
||||||
virtual void ResizeToFill(int32_t pad_left, int32_t pad_top,
|
virtual void ResizeToFill(int32_t pad_left, int32_t pad_top,
|
||||||
int32_t pad_right, int32_t pad_bottom) = 0;
|
int32_t pad_right, int32_t pad_bottom) = 0;
|
||||||
|
void Layout();
|
||||||
|
|
||||||
// TODO(benvanik): colors/brushes/etc.
|
// TODO(benvanik): colors/brushes/etc.
|
||||||
// TODO(benvanik): fonts.
|
// TODO(benvanik): fonts.
|
||||||
|
@ -61,6 +63,7 @@ class Control {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
poly::Delegate<UIEvent> on_resize;
|
poly::Delegate<UIEvent> on_resize;
|
||||||
|
poly::Delegate<UIEvent> on_layout;
|
||||||
|
|
||||||
poly::Delegate<UIEvent> on_visible;
|
poly::Delegate<UIEvent> on_visible;
|
||||||
poly::Delegate<UIEvent> on_hidden;
|
poly::Delegate<UIEvent> on_hidden;
|
||||||
|
@ -77,7 +80,10 @@ class Control {
|
||||||
poly::Delegate<MouseEvent> on_mouse_wheel;
|
poly::Delegate<MouseEvent> on_mouse_wheel;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Control(Control* parent, uint32_t flags);
|
explicit Control(uint32_t flags);
|
||||||
|
|
||||||
|
virtual bool Create() = 0;
|
||||||
|
virtual void Destroy() {}
|
||||||
|
|
||||||
virtual void OnCreate() {}
|
virtual void OnCreate() {}
|
||||||
virtual void OnDestroy() {}
|
virtual void OnDestroy() {}
|
||||||
|
@ -86,6 +92,7 @@ class Control {
|
||||||
virtual void OnChildRemoved(Control* child_control) {}
|
virtual void OnChildRemoved(Control* child_control) {}
|
||||||
|
|
||||||
virtual void OnResize(UIEvent& e);
|
virtual void OnResize(UIEvent& e);
|
||||||
|
virtual void OnLayout(UIEvent& e);
|
||||||
|
|
||||||
virtual void OnVisible(UIEvent& e);
|
virtual void OnVisible(UIEvent& e);
|
||||||
virtual void OnHidden(UIEvent& e);
|
virtual void OnHidden(UIEvent& e);
|
||||||
|
|
|
@ -13,26 +13,7 @@ namespace poly {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
namespace win32 {
|
namespace win32 {
|
||||||
|
|
||||||
LRESULT CALLBACK
|
Win32Control::Win32Control(uint32_t flags) : Control(flags), hwnd_(nullptr) {}
|
||||||
Win32Control::WndProcThunk(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
|
||||||
Win32Control* control = 0;
|
|
||||||
if (message == WM_NCCREATE) {
|
|
||||||
auto create_struct = reinterpret_cast<LPCREATESTRUCT>(lParam);
|
|
||||||
control = reinterpret_cast<Win32Control*>(create_struct->lpCreateParams);
|
|
||||||
SetWindowLongPtr(hWnd, GWLP_USERDATA, (__int3264)(LONG_PTR)control);
|
|
||||||
} else {
|
|
||||||
control =
|
|
||||||
reinterpret_cast<Win32Control*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
|
|
||||||
}
|
|
||||||
if (control) {
|
|
||||||
return control->WndProc(hWnd, message, wParam, lParam);
|
|
||||||
} else {
|
|
||||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Win32Control::Win32Control(Control* parent, uint32_t flags)
|
|
||||||
: Control(parent, flags), hwnd_(nullptr) {}
|
|
||||||
|
|
||||||
Win32Control::~Win32Control() {
|
Win32Control::~Win32Control() {
|
||||||
if (hwnd_) {
|
if (hwnd_) {
|
||||||
|
@ -43,6 +24,18 @@ Win32Control::~Win32Control() {
|
||||||
|
|
||||||
void Win32Control::OnCreate() {
|
void Win32Control::OnCreate() {
|
||||||
Control::OnCreate();
|
Control::OnCreate();
|
||||||
|
|
||||||
|
// Create all children, if needed.
|
||||||
|
for (auto& child_control : children_) {
|
||||||
|
auto win32_control = static_cast<Win32Control*>(child_control.get());
|
||||||
|
if (!win32_control->hwnd()) {
|
||||||
|
win32_control->Create();
|
||||||
|
} else {
|
||||||
|
SetParent(win32_control->hwnd(), hwnd());
|
||||||
|
}
|
||||||
|
win32_control->Layout();
|
||||||
|
}
|
||||||
|
|
||||||
if (!is_cursor_visible_) {
|
if (!is_cursor_visible_) {
|
||||||
ShowCursor(FALSE);
|
ShowCursor(FALSE);
|
||||||
}
|
}
|
||||||
|
@ -57,6 +50,35 @@ void Win32Control::OnCreate() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Win32Control::OnDestroy() {
|
||||||
|
// Destroy all children, if needed.
|
||||||
|
for (auto& child_control : children_) {
|
||||||
|
auto win32_control = static_cast<Win32Control*>(child_control.get());
|
||||||
|
if (!win32_control->hwnd()) {
|
||||||
|
win32_control->Destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32Control::OnChildAdded(Control* child_control) {
|
||||||
|
auto win32_control = static_cast<Win32Control*>(child_control);
|
||||||
|
if (hwnd_) {
|
||||||
|
if (!win32_control->hwnd()) {
|
||||||
|
win32_control->Create();
|
||||||
|
} else {
|
||||||
|
SetParent(win32_control->hwnd(), hwnd());
|
||||||
|
}
|
||||||
|
child_control->Layout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32Control::OnChildRemoved(Control* child_control) {
|
||||||
|
auto win32_control = static_cast<Win32Control*>(child_control);
|
||||||
|
if (win32_control->hwnd()) {
|
||||||
|
SetParent(win32_control->hwnd(), nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Win32Control::Resize(int32_t width, int32_t height) {
|
void Win32Control::Resize(int32_t width, int32_t height) {
|
||||||
MoveWindow(hwnd_, 0, 0, width, height, TRUE);
|
MoveWindow(hwnd_, 0, 0, width, height, TRUE);
|
||||||
}
|
}
|
||||||
|
@ -77,7 +99,23 @@ void Win32Control::ResizeToFill(int32_t pad_left, int32_t pad_top,
|
||||||
GetClientRect(parent_control->hwnd(), &parent_rect);
|
GetClientRect(parent_control->hwnd(), &parent_rect);
|
||||||
MoveWindow(hwnd_, parent_rect.left + pad_left, parent_rect.top + pad_top,
|
MoveWindow(hwnd_, parent_rect.left + pad_left, parent_rect.top + pad_top,
|
||||||
parent_rect.right - pad_right - pad_left,
|
parent_rect.right - pad_right - pad_left,
|
||||||
parent_rect.right - pad_bottom - pad_top, TRUE);
|
parent_rect.bottom - pad_bottom - pad_top, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32Control::OnResize(UIEvent& e) {
|
||||||
|
RECT client_rect;
|
||||||
|
GetClientRect(hwnd_, &client_rect);
|
||||||
|
int32_t width = client_rect.right - client_rect.left;
|
||||||
|
int32_t height = client_rect.bottom - client_rect.top;
|
||||||
|
if (width != width_ || height != height_) {
|
||||||
|
width_ = width;
|
||||||
|
height_ = height;
|
||||||
|
Layout();
|
||||||
|
for (auto& child_control : children_) {
|
||||||
|
auto win32_control = static_cast<Win32Control*>(child_control.get());
|
||||||
|
win32_control->OnResize(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Win32Control::set_cursor_visible(bool value) {
|
void Win32Control::set_cursor_visible(bool value) {
|
||||||
|
@ -129,6 +167,24 @@ void Win32Control::set_focus(bool value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LRESULT CALLBACK Win32Control::WndProcThunk(HWND hWnd, UINT message,
|
||||||
|
WPARAM wParam, LPARAM lParam) {
|
||||||
|
Win32Control* control = nullptr;
|
||||||
|
if (message == WM_NCCREATE) {
|
||||||
|
auto create_struct = reinterpret_cast<LPCREATESTRUCT>(lParam);
|
||||||
|
control = reinterpret_cast<Win32Control*>(create_struct->lpCreateParams);
|
||||||
|
SetWindowLongPtr(hWnd, GWLP_USERDATA, (__int3264)(LONG_PTR)control);
|
||||||
|
} else {
|
||||||
|
control =
|
||||||
|
reinterpret_cast<Win32Control*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
|
||||||
|
}
|
||||||
|
if (control) {
|
||||||
|
return control->WndProc(hWnd, message, wParam, lParam);
|
||||||
|
} else {
|
||||||
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LRESULT Win32Control::WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
LRESULT Win32Control::WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||||
LPARAM lParam) {
|
LPARAM lParam) {
|
||||||
if (message >= WM_MOUSEFIRST && message <= WM_MOUSELAST) {
|
if (message >= WM_MOUSEFIRST && message <= WM_MOUSELAST) {
|
||||||
|
@ -147,10 +203,8 @@ LRESULT Win32Control::WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||||
|
|
||||||
switch (message) {
|
switch (message) {
|
||||||
case WM_NCCREATE:
|
case WM_NCCREATE:
|
||||||
hwnd_ = hWnd;
|
|
||||||
break;
|
break;
|
||||||
case WM_CREATE:
|
case WM_CREATE:
|
||||||
OnCreate();
|
|
||||||
break;
|
break;
|
||||||
case WM_DESTROY:
|
case WM_DESTROY:
|
||||||
OnDestroy();
|
OnDestroy();
|
||||||
|
@ -163,25 +217,12 @@ LRESULT Win32Control::WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||||
case WM_SIZING:
|
case WM_SIZING:
|
||||||
break;
|
break;
|
||||||
case WM_SIZE: {
|
case WM_SIZE: {
|
||||||
RECT client_rect;
|
auto e = UIEvent(this);
|
||||||
GetClientRect(hwnd_, &client_rect);
|
OnResize(e);
|
||||||
int32_t width = client_rect.right - client_rect.left;
|
|
||||||
int32_t height = client_rect.bottom - client_rect.top;
|
|
||||||
if (width != width_ || height != height_) {
|
|
||||||
width_ = width;
|
|
||||||
height_ = height;
|
|
||||||
auto e = UIEvent(this);
|
|
||||||
OnResize(e);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case WM_PAINT:
|
case WM_PAINT:
|
||||||
if (flags_ & kFlagOwnPaint) {
|
|
||||||
PAINTSTRUCT ps;
|
|
||||||
HDC hdc = BeginPaint(hWnd, &ps);
|
|
||||||
EndPaint(hWnd, &ps);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case WM_ERASEBKGND:
|
case WM_ERASEBKGND:
|
||||||
if (flags_ & kFlagOwnPaint) {
|
if (flags_ & kFlagOwnPaint) {
|
||||||
|
|
|
@ -24,6 +24,9 @@ class Win32Control : public Control {
|
||||||
~Win32Control() override;
|
~Win32Control() override;
|
||||||
|
|
||||||
HWND hwnd() const { return hwnd_; }
|
HWND hwnd() const { return hwnd_; }
|
||||||
|
HWND parent_hwnd() const {
|
||||||
|
return parent_ ? static_cast<Win32Control*>(parent_)->hwnd() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void Resize(int32_t width, int32_t height) override;
|
void Resize(int32_t width, int32_t height) override;
|
||||||
void Resize(int32_t left, int32_t top, int32_t right,
|
void Resize(int32_t left, int32_t top, int32_t right,
|
||||||
|
@ -37,11 +40,15 @@ class Win32Control : public Control {
|
||||||
void set_focus(bool value) override;
|
void set_focus(bool value) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Win32Control(Control* parent, uint32_t flags);
|
explicit Win32Control(uint32_t flags);
|
||||||
|
|
||||||
virtual bool CreateHWND() = 0;
|
|
||||||
|
|
||||||
void OnCreate() override;
|
void OnCreate() override;
|
||||||
|
void OnDestroy() override;
|
||||||
|
|
||||||
|
void OnChildAdded(Control* child_control) override;
|
||||||
|
void OnChildRemoved(Control* child_control) override;
|
||||||
|
|
||||||
|
void OnResize(UIEvent& e) override;
|
||||||
|
|
||||||
static LRESULT CALLBACK
|
static LRESULT CALLBACK
|
||||||
WndProcThunk(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
|
WndProcThunk(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
|
||||||
|
|
|
@ -25,16 +25,16 @@ Win32Window::Win32Window(const std::wstring& title)
|
||||||
Win32Window::~Win32Window() {}
|
Win32Window::~Win32Window() {}
|
||||||
|
|
||||||
bool Win32Window::Initialize() {
|
bool Win32Window::Initialize() {
|
||||||
CreateHWND();
|
Create();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Win32Window::CreateHWND() {
|
bool Win32Window::Create() {
|
||||||
HINSTANCE hInstance = GetModuleHandle(nullptr);
|
HINSTANCE hInstance = GetModuleHandle(nullptr);
|
||||||
|
|
||||||
WNDCLASSEX wcex;
|
WNDCLASSEX wcex;
|
||||||
wcex.cbSize = sizeof(WNDCLASSEX);
|
wcex.cbSize = sizeof(WNDCLASSEX);
|
||||||
wcex.style = CS_OWNDC;
|
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
|
||||||
wcex.lpfnWndProc = Win32Control::WndProcThunk;
|
wcex.lpfnWndProc = Win32Control::WndProcThunk;
|
||||||
wcex.cbClsExtra = 0;
|
wcex.cbClsExtra = 0;
|
||||||
wcex.cbWndExtra = 0;
|
wcex.cbWndExtra = 0;
|
||||||
|
@ -52,7 +52,7 @@ bool Win32Window::CreateHWND() {
|
||||||
|
|
||||||
// Setup initial size.
|
// Setup initial size.
|
||||||
DWORD window_style = WS_OVERLAPPEDWINDOW;
|
DWORD window_style = WS_OVERLAPPEDWINDOW;
|
||||||
DWORD window_ex_style = WS_EX_APPWINDOW;
|
DWORD window_ex_style = WS_EX_APPWINDOW | WS_EX_CONTROLPARENT;
|
||||||
RECT rc = {0, 0, width_, height_};
|
RECT rc = {0, 0, width_, height_};
|
||||||
AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
|
AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ LRESULT Win32Window::WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
return Win32Control::WndProc(hWnd, message, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace win32
|
} // namespace win32
|
||||||
|
|
|
@ -35,8 +35,7 @@ class Win32Window : public Window<Win32Control> {
|
||||||
int32_t pad_bottom) override;
|
int32_t pad_bottom) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool CreateHWND() override;
|
bool Create() override;
|
||||||
|
|
||||||
void OnClose() override;
|
void OnClose() override;
|
||||||
|
|
||||||
LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||||
|
|
|
@ -52,7 +52,7 @@ class Window : public T {
|
||||||
poly::Delegate<UIEvent> on_closed;
|
poly::Delegate<UIEvent> on_closed;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Window(const std::wstring& title) : T(nullptr, 0), title_(title) {}
|
Window(const std::wstring& title) : T(0), title_(title) {}
|
||||||
|
|
||||||
void OnShow() {
|
void OnShow() {
|
||||||
if (is_visible_) {
|
if (is_visible_) {
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <xenia/debug_agent.h>
|
#include <xenia/debug_agent.h>
|
||||||
#include <xenia/kernel/kernel_state.h>
|
#include <xenia/kernel/kernel_state.h>
|
||||||
#include <xenia/memory.h>
|
#include <xenia/memory.h>
|
||||||
|
#include <xenia/ui/main_window.h>
|
||||||
#include <xenia/xbox.h>
|
#include <xenia/xbox.h>
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
#include <xenia/gpu/gl4/gl4_gpu.h>
|
#include <xenia/gpu/gl4/gl4_gpu.h>
|
||||||
|
|
||||||
//#include <xenia/gpu/gl4/gl4_graphics_system.h>
|
#include <xenia/gpu/gl4/gl4_graphics_system.h>
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
|
@ -32,12 +32,6 @@ void InitializeIfNeeded() {
|
||||||
|
|
||||||
void CleanupOnShutdown() {}
|
void CleanupOnShutdown() {}
|
||||||
|
|
||||||
class GL4GraphicsSystem : public GraphicsSystem {
|
|
||||||
public:
|
|
||||||
GL4GraphicsSystem(Emulator* emulator) : GraphicsSystem(emulator) {}
|
|
||||||
~GL4GraphicsSystem() override = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unique_ptr<GraphicsSystem> Create(Emulator* emulator) {
|
std::unique_ptr<GraphicsSystem> Create(Emulator* emulator) {
|
||||||
InitializeIfNeeded();
|
InitializeIfNeeded();
|
||||||
return std::make_unique<GL4GraphicsSystem>(emulator);
|
return std::make_unique<GL4GraphicsSystem>(emulator);
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <xenia/gpu/gl4/gl4_graphics_system.h>
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace gpu {
|
||||||
|
namespace gl4 {
|
||||||
|
|
||||||
|
GL4GraphicsSystem::GL4GraphicsSystem(Emulator* emulator)
|
||||||
|
: GraphicsSystem(emulator) {}
|
||||||
|
|
||||||
|
GL4GraphicsSystem::~GL4GraphicsSystem() = default;
|
||||||
|
|
||||||
|
X_STATUS GL4GraphicsSystem::Setup() {
|
||||||
|
auto loop = emulator_->main_window()->loop();
|
||||||
|
loop->Post([this]() {
|
||||||
|
control_ = std::make_unique<WGLControl>();
|
||||||
|
emulator_->main_window()->AddChild(control_.get());
|
||||||
|
});
|
||||||
|
return X_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GL4GraphicsSystem::Shutdown() {
|
||||||
|
control_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace gl4
|
||||||
|
} // namespace gpu
|
||||||
|
} // namespace xe
|
|
@ -0,0 +1,39 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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_GPU_GL4_GL4_GRAPHICS_SYSTEM_H_
|
||||||
|
#define XENIA_GPU_GL4_GL4_GRAPHICS_SYSTEM_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <xenia/common.h>
|
||||||
|
#include <xenia/gpu/gl4/wgl_control.h>
|
||||||
|
#include <xenia/gpu/graphics_system.h>
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace gpu {
|
||||||
|
namespace gl4 {
|
||||||
|
|
||||||
|
class GL4GraphicsSystem : public GraphicsSystem {
|
||||||
|
public:
|
||||||
|
GL4GraphicsSystem(Emulator* emulator);
|
||||||
|
~GL4GraphicsSystem() override;
|
||||||
|
|
||||||
|
X_STATUS Setup() override;
|
||||||
|
void Shutdown() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<WGLControl> control_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace gl4
|
||||||
|
} // namespace gpu
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
#endif // XENIA_GPU_GL4_GL4_GRAPHICS_SYSTEM_H_
|
|
@ -0,0 +1,119 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <xenia/gpu/gl4/gl_context.h>
|
||||||
|
|
||||||
|
#include <poly/logging.h>
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace gpu {
|
||||||
|
namespace gl4 {
|
||||||
|
|
||||||
|
thread_local GLEWContext* tls_glew_context_ = nullptr;
|
||||||
|
thread_local WGLEWContext* tls_wglew_context_ = nullptr;
|
||||||
|
extern "C" GLEWContext* glewGetContext() { return tls_glew_context_; }
|
||||||
|
extern "C" WGLEWContext* wglewGetContext() { return tls_wglew_context_; }
|
||||||
|
|
||||||
|
GLContext::GLContext() : dc_(nullptr), glrc_(nullptr) {}
|
||||||
|
|
||||||
|
GLContext::~GLContext() {
|
||||||
|
wglMakeCurrent(nullptr, nullptr);
|
||||||
|
if (glrc_) {
|
||||||
|
wglDeleteContext(glrc_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLContext::Initialize(HDC dc) {
|
||||||
|
dc_ = dc;
|
||||||
|
|
||||||
|
PIXELFORMATDESCRIPTOR pfd = {0};
|
||||||
|
pfd.nSize = sizeof(pfd);
|
||||||
|
pfd.nVersion = 1;
|
||||||
|
pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
|
||||||
|
pfd.iPixelType = PFD_TYPE_RGBA;
|
||||||
|
pfd.cColorBits = 32;
|
||||||
|
pfd.cDepthBits = 32;
|
||||||
|
pfd.iLayerType = PFD_MAIN_PLANE;
|
||||||
|
int pixel_format = ChoosePixelFormat(dc_, &pfd);
|
||||||
|
if (!pixel_format) {
|
||||||
|
PLOGE("Unable to choose pixel format");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!SetPixelFormat(dc_, pixel_format, &pfd)) {
|
||||||
|
PLOGE("Unable to set pixel format");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
HGLRC temp_context = wglCreateContext(dc_);
|
||||||
|
if (!temp_context) {
|
||||||
|
PLOGE("Unable to create temporary GL context");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
wglMakeCurrent(dc_, temp_context);
|
||||||
|
|
||||||
|
tls_glew_context_ = &glew_context_;
|
||||||
|
tls_wglew_context_ = &wglew_context_;
|
||||||
|
if (glewInit() != GLEW_OK) {
|
||||||
|
PLOGE("Unable to initialize GLEW");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (wglewInit() != GLEW_OK) {
|
||||||
|
PLOGE("Unable to initialize WGLEW");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!WGLEW_ARB_create_context) {
|
||||||
|
PLOGE("WGL_ARG_create_context not supported by GL ICD");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int context_flags = WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
|
||||||
|
#if DEBUG
|
||||||
|
context_flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
|
||||||
|
#endif // DEBUG
|
||||||
|
|
||||||
|
int attrib_list[] = {WGL_CONTEXT_MAJOR_VERSION_ARB, 4, //
|
||||||
|
WGL_CONTEXT_MINOR_VERSION_ARB, 5, //
|
||||||
|
WGL_CONTEXT_FLAGS_ARB, context_flags, //
|
||||||
|
0};
|
||||||
|
|
||||||
|
glrc_ = wglCreateContextAttribsARB(dc_, nullptr, attrib_list);
|
||||||
|
wglMakeCurrent(nullptr, nullptr);
|
||||||
|
wglDeleteContext(temp_context);
|
||||||
|
if (!glrc_) {
|
||||||
|
PLOGE("Unable to create real GL context");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!MakeCurrent()) {
|
||||||
|
PLOGE("Could not make real GL context current");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLContext::MakeCurrent() {
|
||||||
|
if (!wglMakeCurrent(dc_, glrc_)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
tls_glew_context_ = &glew_context_;
|
||||||
|
tls_wglew_context_ = &wglew_context_;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLContext::ClearCurrent() {
|
||||||
|
wglMakeCurrent(nullptr, nullptr);
|
||||||
|
tls_glew_context_ = nullptr;
|
||||||
|
tls_wglew_context_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace gl4
|
||||||
|
} // namespace gpu
|
||||||
|
} // namespace xe
|
|
@ -0,0 +1,44 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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_GPU_GL4_GL_CONTEXT_H_
|
||||||
|
#define XENIA_GPU_GL4_GL_CONTEXT_H_
|
||||||
|
|
||||||
|
#include <third_party/GL/glew.h>
|
||||||
|
#include <third_party/GL/wglew.h>
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace gpu {
|
||||||
|
namespace gl4 {
|
||||||
|
|
||||||
|
class GLContext {
|
||||||
|
public:
|
||||||
|
GLContext();
|
||||||
|
~GLContext();
|
||||||
|
|
||||||
|
bool Initialize(HDC dc);
|
||||||
|
|
||||||
|
HDC dc() const { return dc_; }
|
||||||
|
|
||||||
|
bool MakeCurrent();
|
||||||
|
void ClearCurrent();
|
||||||
|
|
||||||
|
private:
|
||||||
|
HDC dc_;
|
||||||
|
HGLRC glrc_;
|
||||||
|
|
||||||
|
GLEWContext glew_context_;
|
||||||
|
WGLEWContext wglew_context_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace gl4
|
||||||
|
} // namespace gpu
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
#endif // XENIA_GPU_GL4_GL_CONTEXT_H_
|
|
@ -4,5 +4,18 @@
|
||||||
'gl4_gpu-private.h',
|
'gl4_gpu-private.h',
|
||||||
'gl4_gpu.cc',
|
'gl4_gpu.cc',
|
||||||
'gl4_gpu.h',
|
'gl4_gpu.h',
|
||||||
|
'gl4_graphics_system.cc',
|
||||||
|
'gl4_graphics_system.h',
|
||||||
|
'gl_context.cc',
|
||||||
|
'gl_context.h',
|
||||||
|
],
|
||||||
|
|
||||||
|
'conditions': [
|
||||||
|
['OS == "win"', {
|
||||||
|
'sources': [
|
||||||
|
'wgl_control.cc',
|
||||||
|
'wgl_control.h',
|
||||||
|
],
|
||||||
|
}],
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <xenia/gpu/gl4/wgl_control.h>
|
||||||
|
|
||||||
|
#include <poly/logging.h>
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace gpu {
|
||||||
|
namespace gl4 {
|
||||||
|
|
||||||
|
WGLControl::WGLControl()
|
||||||
|
: poly::ui::win32::Win32Control(Flags::kFlagOwnPaint) {}
|
||||||
|
|
||||||
|
WGLControl::~WGLControl() = default;
|
||||||
|
|
||||||
|
bool WGLControl::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"XeniaWglClass";
|
||||||
|
if (!RegisterClassEx(&wcex)) {
|
||||||
|
PLOGE("WGL RegisterClassEx failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create window.
|
||||||
|
DWORD window_style = WS_CHILD | WS_VISIBLE;
|
||||||
|
DWORD window_ex_style = 0;
|
||||||
|
hwnd_ =
|
||||||
|
CreateWindowEx(window_ex_style, L"XeniaWglClass", L"Xenia", window_style,
|
||||||
|
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
||||||
|
parent_hwnd(), nullptr, hInstance, this);
|
||||||
|
if (!hwnd_) {
|
||||||
|
PLOGE("WGL CreateWindow failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
HDC dc = GetDC(hwnd_);
|
||||||
|
if (!dc) {
|
||||||
|
PLOGE("No DC for WGL window");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!context_.Initialize(dc)) {
|
||||||
|
PFATAL("Unable to initialize GL context");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
OnCreate();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WGLControl::OnLayout(poly::ui::UIEvent& e) {
|
||||||
|
Control::ResizeToFill();
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT WGLControl::WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||||
|
LPARAM lParam) {
|
||||||
|
switch (message) {
|
||||||
|
case WM_PAINT:
|
||||||
|
context_.MakeCurrent();
|
||||||
|
glViewport(0, 0, width_, height_);
|
||||||
|
glClearColor(1.0f, 0, 0, 1.0f);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
SwapBuffers(context_.dc());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return Win32Control::WndProc(hWnd, message, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace gl4
|
||||||
|
} // namespace gpu
|
||||||
|
} // namespace xe
|
|
@ -0,0 +1,43 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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_GPU_GL4_WGL_CONTROL_H_
|
||||||
|
#define XENIA_GPU_GL4_WGL_CONTROL_H_
|
||||||
|
|
||||||
|
#include <poly/ui/win32/win32_control.h>
|
||||||
|
#include <xenia/gpu/gl4/gl_context.h>
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace gpu {
|
||||||
|
namespace gl4 {
|
||||||
|
|
||||||
|
class WGLControl : public poly::ui::win32::Win32Control {
|
||||||
|
public:
|
||||||
|
WGLControl();
|
||||||
|
~WGLControl() override;
|
||||||
|
|
||||||
|
GLContext* context() { return &context_; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool Create() override;
|
||||||
|
|
||||||
|
void OnLayout(poly::ui::UIEvent& e) override;
|
||||||
|
|
||||||
|
LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||||
|
LPARAM lParam) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
GLContext context_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace gl4
|
||||||
|
} // namespace gpu
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
#endif // XENIA_GPU_GL4_WGL_CONTROL_H_
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <poly/logging.h>
|
#include <poly/logging.h>
|
||||||
#include <poly/threading.h>
|
#include <poly/threading.h>
|
||||||
|
#include <xenia/emulator.h>
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
|
@ -11,12 +11,16 @@
|
||||||
#define XENIA_UI_MAIN_WINDOW_H_
|
#define XENIA_UI_MAIN_WINDOW_H_
|
||||||
|
|
||||||
#include <poly/ui/window.h>
|
#include <poly/ui/window.h>
|
||||||
#include <xenia/emulator.h>
|
#include <xenia/xbox.h>
|
||||||
|
|
||||||
// TODO(benvanik): only on windows.
|
// TODO(benvanik): only on windows.
|
||||||
#include <poly/ui/win32/win32_loop.h>
|
#include <poly/ui/win32/win32_loop.h>
|
||||||
#include <poly/ui/win32/win32_window.h>
|
#include <poly/ui/win32/win32_window.h>
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
class Emulator;
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
],
|
],
|
||||||
'defines': [
|
'defines': [
|
||||||
'GLEW_STATIC=1',
|
'GLEW_STATIC=1',
|
||||||
|
'GLEW_MX=1',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -20,6 +21,7 @@
|
||||||
|
|
||||||
'defines': [
|
'defines': [
|
||||||
'GLEW_STATIC=1',
|
'GLEW_STATIC=1',
|
||||||
|
'GLEW_MX=1',
|
||||||
],
|
],
|
||||||
|
|
||||||
'sources': [
|
'sources': [
|
||||||
|
|
Loading…
Reference in New Issue