Clean project structure.

This commit is contained in:
jmsgrogan 2023-01-17 10:13:25 +00:00
parent 78a4fa99ff
commit 947bf937fd
496 changed files with 206 additions and 137 deletions

4
src/ui/CMakeLists.txt Normal file
View file

@ -0,0 +1,4 @@
add_subdirectory(client)
add_subdirectory(ui_controls)
add_subdirectory(ui_elements)
add_subdirectory(windows)

View file

@ -0,0 +1,29 @@
set(MODULE_NAME client)
list(APPEND TARGET_HEADERS
TopBar.h
StatusBar.h
GuiApplication.h
TabbedPanelWidget.h
TopBarMenu.h)
list(APPEND TARGET_SOURCES
TopBar.cpp
StatusBar.cpp
GuiApplication.cpp
TabbedPanelWidget.cpp
TopBarMenu.cpp)
add_library(${MODULE_NAME} SHARED ${TARGET_SOURCES} ${TARGET_HEADERS})
target_link_libraries(${MODULE_NAME} ui_controls windows core console database geometry)
target_include_directories(${MODULE_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/text_editor
${CMAKE_CURRENT_SOURCE_DIR}/audio_editor
${CMAKE_CURRENT_SOURCE_DIR}/image_editor
${CMAKE_CURRENT_SOURCE_DIR}/web_client
)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER src/ui)
set_target_properties( ${MODULE_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )

View file

@ -0,0 +1,66 @@
#include "GuiApplication.h"
#include "UiInterfaceFactory.h"
#include "Window.h"
#include "WindowManager.h"
#include "DesktopManager.h"
#include "FontsManager.h"
#include "MainApplication.h"
#include "AbstractUiInterface.h"
#include "Widget.h"
#include "FileLogger.h"
GuiApplication::GuiApplication(std::unique_ptr<CommandLineArgs> args, std::unique_ptr<MainApplication> mainApp)
: AbstractDesktopApp(),
mDesktopManager(DesktopManager::Create(this))
{
if (mainApp)
{
mMainApplication = std::move(mainApp);
}
else
{
mMainApplication = MainApplication::Create();
mMainApplication->initialize(args ? std::move(args) : CommandLineArgs::Create());
}
}
GuiApplication::~GuiApplication()
{
}
AbstractApp* GuiApplication::getMainApplication() const
{
return mMainApplication.get();
}
AbstractUIInterface* GuiApplication::getUiInterface() const
{
return mUiInterface.get();
}
void GuiApplication::initializeViews()
{
mDesktopManager->getWindowManager()->getMainWindow()->setSize(800, 600);
}
void GuiApplication::setUiInterfaceBackend(UiInterfaceFactory::Backend backend)
{
mUiInterfaceBackend = backend;
}
void GuiApplication::run()
{
initializeViews();
MLOG_INFO("Creating Window Interface");
mUiInterface = UiInterfaceFactory::create(mDesktopManager.get(), mUiInterfaceBackend);
mUiInterface->loop();
MLOG_INFO("Window Interface Shut Down");
mMainApplication->shutDown();
}

View file

@ -0,0 +1,37 @@
#pragma once
#include "AbstractDesktopApp.h"
#include "UiInterfaceFactory.h"
#include "CommandLineArgs.h"
#include <memory>
class MainApplication;
class DesktopManager;
class AbstractUiInterface;
class GuiApplication : public AbstractDesktopApp
{
public:
GuiApplication(std::unique_ptr<CommandLineArgs> args = nullptr, std::unique_ptr<MainApplication> mainApp = nullptr);
~GuiApplication();
AbstractApp* getMainApplication() const override;
AbstractUIInterface* getUiInterface() const override;
void setUiInterfaceBackend(UiInterfaceFactory::Backend backend);
void run();
protected:
virtual void initializeViews();
std::unique_ptr<DesktopManager> mDesktopManager;
std::unique_ptr<MainApplication> mMainApplication;
private:
UiInterfaceFactory::Backend mUiInterfaceBackend = UiInterfaceFactory::Backend::UNSET;
std::unique_ptr<AbstractUIInterface> mUiInterface;
};

View file

@ -0,0 +1,13 @@
#include "StatusBar.h"
#include "Color.h"
StatusBar::StatusBar()
{
setBackgroundColor(Color(200, 200, 200));
}
std::unique_ptr<StatusBar> StatusBar::Create()
{
return std::make_unique<StatusBar>();
}

13
src/ui/client/StatusBar.h Normal file
View file

@ -0,0 +1,13 @@
#pragma once
#include "Widget.h"
class StatusBar : public Widget
{
public:
StatusBar();
static std::unique_ptr<StatusBar> Create();
};
using StatusBarUPtr = std::unique_ptr<StatusBar>;

View file

@ -0,0 +1,57 @@
#include "TabbedPanelWidget.h"
#include "StackWidget.h"
#include "HorizontalSpacer.h"
#include "VerticalSpacer.h"
#include "TextNode.h"
#include "Button.h"
TabbedPanelWidget::TabbedPanelWidget()
: mNavPanel(),
mStack()
{
auto stack = StackWidget::Create();
mStack = stack.get();
auto nav = HorizontalSpacer::Create();
mNavPanel = nav.get();
nav->setSize({0, 0, 0, 0, 200, 0});
auto vertSpacer = VerticalSpacer::Create();
vertSpacer->addWidgetWithScale(std::move(nav), 1);
vertSpacer->addWidgetWithScale(std::move(stack), 4);
addWidget(std::move(vertSpacer));
}
std::unique_ptr<TabbedPanelWidget> TabbedPanelWidget::Create()
{
return std::make_unique<TabbedPanelWidget>();
}
StackWidget* TabbedPanelWidget::getStack() const
{
return mStack;
}
void TabbedPanelWidget::addPanel(WidgetUPtr panel, const std::string& label)
{
auto button = Button::Create();
button->setLabel(label);
button->setBackgroundColor(Color(156, 156, 156));
button->setMargin({1, 0, 0, 1});
auto rawPanel = panel.get();
auto onClick = [this, rawPanel](Widget*){
if(this && rawPanel)
{
this->getStack()->showChild(rawPanel);
}
};
button->setOnClickFunction(onClick);
mStack->addWidget(std::move(panel));
mStack->showChild(rawPanel);
mNavPanel->addWidget(std::move(button));
}

View file

@ -0,0 +1,23 @@
#pragma once
#include "Widget.h"
#include "StackWidget.h"
#include <string>
class TabbedPanelWidget : public Widget
{
public:
TabbedPanelWidget();
static std::unique_ptr<TabbedPanelWidget> Create();
void addPanel(WidgetUPtr panel, const std::string& label);
StackWidget* getStack() const;
private:
Widget* mNavPanel;
StackWidget* mStack;
};
using TabbedPanelWidgetUPtr = std::unique_ptr<TabbedPanelWidget>;

39
src/ui/client/TopBar.cpp Normal file
View file

@ -0,0 +1,39 @@
#include "TopBar.h"
#include "Color.h"
#include "Theme.h"
#include "Button.h"
#include "TopBarMenu.h"
TopBar::TopBar()
{
setBackgroundColor(Theme::getBackgroundPrimary());
auto fileButton = Button::Create();
fileButton->setLabel("File");
fileButton->setBackgroundColor(Theme::getBackgroundPrimary());
fileButton->setMargin(2);
fileButton->setMaxWidth(60);
auto onClick = [this](Widget* self){
if(this)
{
auto menu = std::make_unique<TopBarMenu>();
auto window = getTopLevelWindow();
window->addPopup(std::move(menu));
};
};
fileButton->setOnClickFunction(onClick);
addWidget(std::move(fileButton));
}
TopBar::~TopBar()
{
}
std::unique_ptr<TopBar> TopBar::Create()
{
return std::make_unique<TopBar>();
}

17
src/ui/client/TopBar.h Normal file
View file

@ -0,0 +1,17 @@
#pragma once
#include "Widget.h"
class TopBarMenu;
class TopBar : public Widget
{
public:
TopBar();
~TopBar();
static std::unique_ptr<TopBar> Create();
};
using TopBarUPtr = std::unique_ptr<TopBar>;

View file

View file

@ -0,0 +1,16 @@
#pragma once
#include "Widget.h"
#include "Window.h"
class TopBarMenu : public Widget
{
public:
void popupFrom(Widget* parent)
{
auto window = parent->getTopLevelWindow();
}
};

View file

@ -0,0 +1,110 @@
#include "Button.h"
#include "TextNode.h"
#include "GeometryNode.h"
#include "TransformNode.h"
#include "MouseEvent.h"
#include "FileLogger.h"
Button::Button()
: Widget(),
mLabel(),
mCachedColor(255, 255, 255),
mClickedColor(Color(180, 180, 180)),
mClickFunc()
{
mName = "Button";
}
Button::~Button()
{
}
std::unique_ptr<Button> Button::Create()
{
return std::make_unique<Button>();
}
void Button::setOnClickFunction(clickFunc func)
{
mClickFunc = func;
}
void Button::setLabel(const std::string& text)
{
if (text != mLabel)
{
mLabel = text;
mContentDirty = true;
}
}
void Button::onMyMouseEvent(const MouseEvent* event)
{
MLOG_INFO("Widget mouse event");
if(event->getAction() == MouseEvent::Action::Pressed)
{
mCachedColor = mBackgroundColor;
setBackgroundColor(mClickedColor);
if(mClickFunc)
{
mClickFunc(this);
}
}
else if(event->getAction() == MouseEvent::Action::Released)
{
setBackgroundColor(mCachedColor);
}
}
bool Button::isDirty() const
{
return Widget::isDirty() || mContentDirty;
}
void Button::doPaint(const PaintEvent* event)
{
updateBackground(event);
updateLabel(event);
}
void Button::updateLabel(const PaintEvent* event)
{
unsigned fontOffset = unsigned(mLabel.size()) * 4;
auto middle = DiscretePoint(mLocation.getX() + mSize.mWidth/2 - fontOffset, mLocation.getY() + mSize.mHeight/2 + 4);
if (!mTextNode)
{
mTextNode = TextNode::Create(mLabel, middle);
mTextNode->setName(mName + "_TextNode");
mTextNode->setContent(mLabel);
mTextNode->setWidth(mSize.mWidth);
mTextNode->setHeight(mSize.mHeight);
mRootNode->addChild(mTextNode.get());
}
if (mTransformDirty)
{
mTextNode->setLocation(middle);
mTextNode->setWidth(mSize.mWidth);
mTextNode->setHeight(mSize.mHeight);
}
if (mMaterialDirty)
{
mTextNode->setFillColor(mBackgroundColor);
}
if (mContentDirty)
{
mTextNode->setContent(mLabel);
mContentDirty = false;
}
if (mVisibilityDirty)
{
mTextNode->setIsVisible(mVisible);
}
}

View file

@ -0,0 +1,46 @@
#pragma once
#include "Widget.h"
#include "Color.h"
#include <functional>
#include <string>
class PaintEvent;
class MouseEvent;
class TextNode;
class Button : public Widget
{
public:
using clickFunc = std::function<void(Widget* self)>;
Button();
~Button();
static std::unique_ptr<Button> Create();
void setLabel(const std::string& text);
void setOnClickFunction(clickFunc func);
protected:
void onMyMouseEvent(const MouseEvent* event) override;
bool isDirty() const override;
void doPaint(const PaintEvent* event) override;
void updateLabel(const PaintEvent* event);
private:
std::string mLabel;
clickFunc mClickFunc;
Color mCachedColor;
Color mClickedColor;
std::unique_ptr<TextNode> mTextNode;
bool mContentDirty{true};
};
using ButtonUPtr = std::unique_ptr<Button>;

View file

View file

@ -0,0 +1,23 @@
#pragma once
#include "Widget.h"
class ButtonGroup : public Widget
{
public:
enum class Orientation
{
HORIZONTAL,
VERTICAL
};
ButtonGroup();
~ButtonGroup();
static std::unique_ptr<ButtonGroup> Create();
private:
bool mExclusiveActivation{true};
};

View file

@ -0,0 +1,32 @@
set(MODULE_NAME ui_controls)
list(APPEND HEADERS
Button.h
ButtonGroup.h
Label.h
HorizontalSpacer.h
VerticalSpacer.h
StackWidget.h
TextBox.h
)
list(APPEND LIB_INCLUDES
Button.cpp
ButtonGroup.cpp
Label.cpp
HorizontalSpacer.cpp
VerticalSpacer.cpp
StackWidget.cpp
TextBox.cpp
)
add_library(${MODULE_NAME} SHARED ${LIB_INCLUDES} ${HEADERS})
target_include_directories(${MODULE_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/
)
target_link_libraries(${MODULE_NAME} PUBLIC ui_elements)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER src/ui)
set_target_properties( ${MODULE_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )

View file

@ -0,0 +1,54 @@
#include "HorizontalSpacer.h"
#include <algorithm>
#include <numeric>
#include <iostream>
HorizontalSpacer::HorizontalSpacer()
: Widget(),
mScales()
{
mName = "HorizontalSpacer";
}
std::unique_ptr<HorizontalSpacer> HorizontalSpacer::Create()
{
return std::make_unique<HorizontalSpacer>();
}
void HorizontalSpacer::addWidget(WidgetUPtr widget)
{
addWidgetWithScale(std::move(widget), 1.0);
}
void HorizontalSpacer::addWidgetWithScale(WidgetUPtr widget, double scale)
{
Widget::addWidget(std::move(widget));
mScales.push_back(scale);
}
void HorizontalSpacer::updateChildLocations()
{
double scaleSum = std::accumulate(mScales.begin(), mScales.end(), 0.0);
double offset = 0;
double height = mSize.mHeight;
if (mSize.mMaxHeight > 0 && height > mSize.mMaxHeight)
{
height = mSize.mMaxHeight;
}
for(std::size_t idx=0; idx<mChildren.size(); idx++)
{
auto& child = mChildren[idx];
double scale = mScales[idx];
double delta = height * (scale/scaleSum);
auto size = child->getSize();
if (size.mMaxHeight > 0 && delta > size.mMaxHeight)
{
delta = size.mMaxHeight;
}
child->setBounds(mSize.mWidth, unsigned(delta));
child->setLocation(DiscretePoint(mLocation.getX(), mLocation.getY() + unsigned(offset)));
offset += delta;
}
}

View file

@ -0,0 +1,21 @@
#pragma once
#include "Widget.h"
#include <vector>
class HorizontalSpacer : public Widget
{
public:
HorizontalSpacer();
static std::unique_ptr<HorizontalSpacer> Create();
void addWidget(WidgetUPtr widget) override;
void addWidgetWithScale(WidgetUPtr widget, double scale);
private:
void updateChildLocations() override;
std::vector<double> mScales;
};
using HorizontalSpacerUPtr = std::unique_ptr<HorizontalSpacer>;

View file

@ -0,0 +1,74 @@
#include "Label.h"
#include "TextNode.h"
#include "TransformNode.h"
#include "GeometryNode.h"
Label::Label()
: Widget(),
mLabel()
{
mName = "Label";
}
std::unique_ptr<Label> Label::Create()
{
return std::make_unique<Label>();
}
void Label::setLabel(const std::string& text)
{
if (text != mLabel)
{
mLabel = text;
mContentDirty = true;
}
}
bool Label::isDirty() const
{
return Widget::isDirty() || mContentDirty;
}
void Label::doPaint(const PaintEvent* event)
{
updateBackground(event);
updateLabel(event);
}
void Label::updateLabel(const PaintEvent* event)
{
unsigned fontOffset = unsigned(mLabel.size()) * 4;
auto middle = DiscretePoint(mLocation.getX() + mSize.mWidth/2 - fontOffset, mLocation.getY() + mSize.mHeight/2 + 4);
if (!mTextNode)
{
mTextNode = TextNode::Create(mLabel, middle);
mTextNode->setWidth(mSize.mWidth);
mTextNode->setHeight(mSize.mHeight);
mRootNode->addChild(mTextNode.get());
}
if (mMaterialDirty)
{
mTextNode->setFillColor(mBackgroundColor);
}
if (mTransformDirty)
{
mTextNode->setLocation(middle);
mTextNode->setWidth(mSize.mWidth);
mTextNode->setHeight(mSize.mHeight);
}
if (mContentDirty)
{
mTextNode->setContent(mLabel);
mContentDirty = false;
}
if (mVisibilityDirty)
{
mTextNode->setIsVisible(mVisible);
}
}

View file

@ -0,0 +1,34 @@
#pragma once
#include "Widget.h"
#include <string>
class TextNode;
class Label : public Widget
{
public:
Label();
virtual ~Label() = default;
static std::unique_ptr<Label> Create();
void setLabel(const std::string& text);
private:
bool isDirty() const override;
void doPaint(const PaintEvent* event) override;
void updateLabel(const PaintEvent* event);
std::string mLabel;
std::unique_ptr<TextNode> mTextNode;
bool mContentDirty{true};
};
using LabelUPtr = std::unique_ptr<Label>;

View file

@ -0,0 +1,28 @@
#include "StackWidget.h"
#include <iostream>
StackWidget::StackWidget()
{
}
std::unique_ptr<StackWidget> StackWidget::Create()
{
return std::make_unique<StackWidget>();
}
void StackWidget::showChild(Widget* target)
{
for(auto& child : mChildren)
{
if(child.get() == target)
{
child->setVisible(true);
}
else
{
child->setVisible(false);
}
}
}

View file

@ -0,0 +1,15 @@
#pragma once
#include "Widget.h"
class StackWidget : public Widget
{
public:
StackWidget();
static std::unique_ptr<StackWidget> Create();
void showChild(Widget* child);
};
using StackWidgetUPtr = std::unique_ptr<StackWidget>;

View file

@ -0,0 +1,113 @@
#include "TextBox.h"
#include "TextNode.h"
#include "GeometryNode.h"
#include "KeyboardEvent.h"
#include "TransformNode.h"
#include <sstream>
TextBox::TextBox()
: Widget(),
mContent(),
mCaps(false)
{
mBackgroundColor = Color(250, 250, 250);
mPadding = {20, 0, 20, 0};
}
std::unique_ptr<TextBox> TextBox::Create()
{
return std::make_unique<TextBox>();
}
void TextBox::setContent(const std::string& text)
{
mContent = text;
mContentDirty = true;
}
std::string TextBox::getContent() const
{
return mContent;
}
void TextBox::appendContent(const std::string& text)
{
mContent += text;
mContentDirty = true;
}
bool TextBox::onMyKeyboardEvent(const KeyboardEvent* event)
{
if(!event || !mVisible) return false;
if(event->isFunctionKey())
{
if (event->getFunction() == Keyboard::Function::ENTER)
{
appendContent("\n");
}
else if(event->getFunction() == Keyboard::Function::BACKSPACE)
{
mContent = mContent.substr(0, mContent.size()-1);
mContentDirty = true;
}
}
else
{
const auto keyString = event->getKeyString();
if (keyString.length() < 2)
{
appendContent(keyString);
}
else
{
appendContent("?");
}
}
return true;
}
bool TextBox::isDirty() const
{
return Widget::isDirty() || mContentDirty;
}
void TextBox::doPaint(const PaintEvent* event)
{
updateBackground(event);
updateLabel(event);
}
void TextBox::updateLabel(const PaintEvent* event)
{
auto loc = DiscretePoint(mLocation.getX() + mPadding.mLeft, mLocation.getY() + mPadding.mTop + unsigned(0));
if (!mTextNode)
{
mTextNode = TextNode::Create(mContent, loc);
mTextNode->setWidth(mSize.mWidth);
mTextNode->setHeight(mSize.mHeight);
mRootNode->addChild(mTextNode.get());
}
if (mMaterialDirty)
{
mTextNode->setFillColor(mBackgroundColor);
}
if (mTransformDirty)
{
mTextNode->setLocation(loc);
mTextNode->setWidth(mSize.mWidth);
mTextNode->setHeight(mSize.mHeight);
}
if (mContentDirty)
{
mTextNode->setContent(mContent);
mContentDirty = false;
}
}

View file

@ -0,0 +1,38 @@
#pragma once
#include "Widget.h"
#include <string>
class TextNode;
class TextBox : public Widget
{
public:
TextBox();
static std::unique_ptr<TextBox> Create();
void setContent(const std::string& text);
std::string getContent() const;
void appendContent(const std::string& text);
//void onPaintEvent(const PaintEvent* event) override;
bool onMyKeyboardEvent(const KeyboardEvent* event) override;
private:
bool isDirty() const override;
void doPaint(const PaintEvent* event) override;
void updateLabel(const PaintEvent* event);
std::string mContent;
std::unique_ptr<TextNode> mTextNode;
bool mContentDirty{true};
bool mCaps;
};
using TextBoxUPtr = std::unique_ptr<TextBox>;

View file

@ -0,0 +1,44 @@
#include "VerticalSpacer.h"
#include <algorithm>
#include <numeric>
VerticalSpacer::VerticalSpacer()
: Widget(),
mScales()
{
}
std::unique_ptr<VerticalSpacer> VerticalSpacer::Create()
{
return std::make_unique<VerticalSpacer>();
}
void VerticalSpacer::addWidget(WidgetUPtr widget)
{
addWidgetWithScale(std::move(widget), 1.0);
}
void VerticalSpacer::addWidgetWithScale(WidgetUPtr widget, double scale)
{
Widget::addWidget(std::move(widget));
mScales.push_back(scale);
}
void VerticalSpacer::updateChildLocations()
{
double scaleSum = std::accumulate(mScales.begin(), mScales.end(), 0.0);
double offset = 0;
unsigned delta = mSize.mWidth / unsigned(mChildren.size());
for(std::size_t idx=0; idx<mChildren.size(); idx++)
{
auto& child = mChildren[idx];
double scale = mScales[idx];
double delta = mSize.mWidth * (scale/scaleSum);
child->setBounds(unsigned(delta), mSize.mHeight);
child->setLocation(DiscretePoint(mLocation.getX() + unsigned(offset), mLocation.getY()));
offset += delta;
}
}

View file

@ -0,0 +1,22 @@
#pragma once
#include "Widget.h"
class VerticalSpacer : public Widget
{
public:
VerticalSpacer();
static std::unique_ptr<VerticalSpacer> Create();
void addWidget(WidgetUPtr widget) override;
void addWidgetWithScale(WidgetUPtr widget, double scale);
private:
void updateChildLocations() override;
std::vector<double> mScales;
};
using VerticalSpacerUPtr = std::unique_ptr<VerticalSpacer>;

View file

@ -0,0 +1,43 @@
set(MODULE_NAME ui_elements)
list(APPEND LIB_INCLUDES
desktop_elements/Keyboard.h
desktop_elements/Keyboard.cpp
desktop_elements/IPlatformScreen.h
desktop_elements/Screen.h
desktop_elements/Screen.cpp
desktop_elements/IPlatformWindow.h
desktop_elements/Window.h
desktop_elements/Window.cpp
ui_events/KeyboardEvent.h
ui_events/KeyboardEvent.cpp
ui_events/MouseEvent.h
ui_events/MouseEvent.cpp
ui_events/UiEvent.h
ui_events/UiEvent.cpp
ui_events/PaintEvent.h
ui_events/PaintEvent.cpp
ui_events/ResizeEvent.h
ui_events/ResizeEvent.cpp
widgets/Widget.h
widgets/Widget.cpp
widgets/WidgetState.h
widgets/WidgetState.cpp
style/Theme.h
style/Theme.cpp
)
add_library(${MODULE_NAME} SHARED ${LIB_INCLUDES})
target_include_directories(${MODULE_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/
${CMAKE_CURRENT_SOURCE_DIR}/widgets
${CMAKE_CURRENT_SOURCE_DIR}/style
${CMAKE_CURRENT_SOURCE_DIR}/ui_events
${CMAKE_CURRENT_SOURCE_DIR}/desktop_elements
)
target_link_libraries(${MODULE_NAME} PUBLIC core geometry graphics visual_elements image)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER src/ui)
set_target_properties( ${MODULE_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )

View file

@ -0,0 +1,12 @@
#pragma once
namespace WindowState
{
enum class Display
{
NORMAL,
MINIMIZED,
MAXIMIZED,
FULL_SCREEN
};
}

View file

@ -0,0 +1,11 @@
#pragma once
#include <memory>
class IPlatformScreen
{
public:
virtual ~IPlatformScreen() = default;
};
using IPlatformScreenPtr = std::unique_ptr<IPlatformScreen>;

View file

@ -0,0 +1,41 @@
#pragma once
#include <memory>
namespace mt
{
class Screen;
class Window;
}
class IPlatformSurface
{
public:
virtual ~IPlatformSurface() = default;
virtual void beforePaint(mt::Screen* screen) = 0;
virtual void afterPaint(mt::Screen* screen) = 0;
};
class IPlatformWindow : public IPlatformSurface
{
public:
IPlatformWindow(mt::Window* window)
: mWindow(window)
{
}
virtual ~IPlatformWindow() = default;
virtual void show() = 0;
virtual void map() = 0;
virtual void clear() = 0;
virtual void onResize(unsigned width, unsigned height) = 0;
protected:
mt::Window* mWindow{nullptr};
};
using IPlatformWindowPtr = std::unique_ptr<IPlatformWindow>;

View file

@ -0,0 +1,22 @@
#include "Keyboard.h"
Keyboard::Keyboard()
{
}
std::unique_ptr<Keyboard> Keyboard::Create()
{
return std::make_unique<Keyboard>();
}
std::string Keyboard::getKeyString(KeyCode code)
{
return "";
}
Keyboard::Function Keyboard::getFunction(KeyCode code)
{
return Function::UNSET;
}

View file

@ -0,0 +1,34 @@
#pragma once
#include <memory>
#include <map>
#include <string>
class Keyboard
{
public:
enum class Function
{
UNSET,
ENTER,
BACKSPACE,
TAB
};
using KeyCode = unsigned;
using KeyState = unsigned;
public:
Keyboard();
virtual ~Keyboard() = default;
static std::unique_ptr<Keyboard> Create();
virtual std::string getKeyString(KeyCode code);
virtual Function getFunction(KeyCode code);
};
using KeyboardUPtr = std::unique_ptr<Keyboard>;

View file

@ -0,0 +1,34 @@
#include "Screen.h"
#include "IPlatformScreen.h"
namespace mt{
Screen::Screen()
{
}
Screen::~Screen()
{
}
std::unique_ptr<Screen> Screen::Create()
{
return std::make_unique<Screen>();
}
IPlatformScreen* Screen::GetPlatformScreen() const
{
if (mPlatformScreen)
{
return mPlatformScreen.get();
}
return nullptr;
}
void Screen::SetPlatformScreen(IPlatformScreenPtr screen)
{
mPlatformScreen = std::move(screen);
}
}

View file

@ -0,0 +1,29 @@
#pragma once
#include <memory>
class IPlatformScreen;
using IPlatformScreenPtr = std::unique_ptr<IPlatformScreen>;
namespace mt{
class Screen
{
public:
Screen();
~Screen();
static std::unique_ptr<Screen> Create();
IPlatformScreen* GetPlatformScreen() const;
void SetPlatformScreen(IPlatformScreenPtr screen);
private:
IPlatformScreenPtr mPlatformScreen {nullptr};
};
}
using ScreenPtr = std::unique_ptr<mt::Screen>;

View file

@ -0,0 +1,221 @@
#include "Window.h"
#include "PaintEvent.h"
#include "MouseEvent.h"
#include "KeyboardEvent.h"
#include "Widget.h"
#include "Scene.h"
#include "TriMesh.h"
#include "RootNode.h"
#include "TransformNode.h"
#include "AbstractPainter.h"
#include "DrawingContext.h"
#include "FontsManager.h"
#include "IPlatformWindow.h"
#include "Screen.h"
#include "Image.h"
#include <iostream>
namespace mt
{
Window::Window(DrawingMode drawingMode, FontsManager* fontsManager)
: DrawingSurface(),
mWidget(Widget::Create())
{
mWidth = 800;
mHeight = 600;
mWidget->setBounds(mWidth, mHeight);
mWidget->setWindow(this);
mDrawingContext = std::make_unique<DrawingContext>(this, fontsManager, drawingMode);
}
Window::~Window()
{
}
std::unique_ptr<Window> Window::Create(DrawingMode drawingMode, FontsManager* fontsManager)
{
return std::make_unique<Window>(drawingMode, fontsManager);
}
void Window::setIsSizingOnGoing(bool sizingOngoing)
{
mSizingOngoing = sizingOngoing;
}
bool Window::getIsSizingOnGoing() const
{
return mSizingOngoing;
}
void Window::setSize(unsigned width, unsigned height, bool triggerResize)
{
if (width == mWidth && height == mHeight)
{
return;
}
DrawingSurface::setSize(width, height);
if (triggerResize && !mSizingOngoing)
{
onResize();
}
}
void Window::onResize()
{
mWidget->setBounds(mWidth, mHeight);
if (mPlatformWindow)
{
mPlatformWindow->onResize(mWidth, mHeight);
}
}
void Window::clearPlatformWindow()
{
mPlatformWindow.reset();
}
void Window::onMouseEvent(const MouseEvent* event)
{
mWidget->onMouseEvent(event);
}
void Window::onKeyboardEvent(const KeyboardEvent* event)
{
mWidget->onKeyboardEvent(event);
}
void Window::onPaint(const PaintEvent* event)
{
mWidget->onPaintEvent(event);
}
void Window::setWidget(WidgetPtr widget)
{
if (mWidget)
{
mWidget.reset();
}
mWidget = std::move(widget);
mWidget->setBounds(mWidth, mHeight);
mWidget->setWindow(this);
}
IPlatformWindow* Window::getPlatformWindow() const
{
if (mPlatformWindow)
{
return mPlatformWindow.get();
}
return nullptr;
}
void Window::setPlatformWindow(IPlatformWindowPtr window)
{
mPlatformWindow = std::move(window);
}
void Window::map()
{
if (mPlatformWindow)
{
mPlatformWindow->map();
}
}
void Window::show()
{
if (mPlatformWindow)
{
mPlatformWindow->show();
}
}
DrawingContext* Window::getDrawingContent() const
{
return mDrawingContext.get();
}
void Window::doPaint(mt::Screen* screen)
{
if (mPlatformWindow)
{
mPlatformWindow->beforePaint(screen);
if (auto scene = getScene(); scene->isEmpty())
{
scene->addNode(mWidget->getRootNode());
}
mDrawingContext->paint();
mPlatformWindow->afterPaint(screen);
}
}
void Window::clear()
{
if (mPlatformWindow)
{
mPlatformWindow->clear();
}
}
bool Window::isDirty() const
{
return mWidget->needsUpdate();
}
void Window::setDisplayState(WindowState::Display state)
{
mDisplayState = state;
}
WindowState::Display Window::getDisplayState() const
{
return mDisplayState;
}
void Window::setTitle(const std::string& title)
{
mTitle = title;
}
const std::string& Window::getTitle() const
{
return mTitle;
}
void Window::addPopup(std::unique_ptr<Widget> popupWidget)
{
if (mPopupFunc)
{
mPopupFunc(this, std::move(popupWidget));
}
}
void Window::setPopupHandler(onPopupFunc func)
{
mPopupFunc = func;
}
void Window::setParent(Window* parent)
{
mParent = parent;
}
Window* Window::getParent() const
{
return mParent;
}
}

View file

@ -0,0 +1,107 @@
#pragma once
#include "DrawingSurface.h"
#include "DisplayState.h"
#include "DrawingContext.h"
#include "Widget.h"
#include <memory>
#include <vector>
#include <cstdint>
#include <string>
#include <functional>
class PaintEvent;
class MouseEvent;
class KeyboardEvent;
class DrawingContext;
class FontsManager;
enum class DrawingMode;
using WidgetPtr = std::unique_ptr<Widget>;
class IPlatformWindow;
using IPlatformWindowPtr = std::unique_ptr<IPlatformWindow>;
namespace mt
{
class Screen;
class Window : public DrawingSurface
{
public:
using onPopupFunc = std::function<void(mt::Window* parent, std::unique_ptr<Widget> popup)>;
Window(DrawingMode drawingMode = DrawingMode::GRAPH, FontsManager* fontsManager = nullptr);
~Window();
static std::unique_ptr<Window> Create(DrawingMode drawingMode = DrawingMode::GRAPH, FontsManager* fontsManager = nullptr);
void addPopup(std::unique_ptr<Widget> popupWidget);
void clear();
void clearPlatformWindow();
void doPaint(mt::Screen* screen);
IPlatformWindow* getPlatformWindow() const;
const std::string& getTitle() const;
Window* getParent() const;
DrawingContext* getDrawingContent() const;
WindowState::Display getDisplayState() const;
bool getIsSizingOnGoing() const;
bool isDirty() const;
void map();
void onPaint(const PaintEvent* event);
void onMouseEvent(const MouseEvent* event);
void onResize();
void onKeyboardEvent(const KeyboardEvent* event);
void setPlatformWindow(IPlatformWindowPtr window);
void setPopupHandler(onPopupFunc func);
void setParent(Window* parent);
void show();
void setIsSizingOnGoing(bool sizingOngoing);
void setSize(unsigned width, unsigned height, bool triggerResize = true) override;
void setTitle(const std::string& title);
void setWidget(WidgetPtr widget);
void setDisplayState(WindowState::Display state);
private:
WidgetPtr mWidget {nullptr};
std::string mTitle;
IPlatformWindowPtr mPlatformWindow {nullptr};
std::unique_ptr<DrawingContext> mDrawingContext;
onPopupFunc mPopupFunc;
Window* mParent{nullptr};
bool mSizingOngoing{ false };
WindowState::Display mDisplayState{ WindowState::Display::NORMAL };
};
}
using WindowUPtr = std::unique_ptr<mt::Window>;

View file

@ -0,0 +1,26 @@
#include "Theme.h"
Color Theme::getBackgroundPrimary()
{
return {245, 245, 245};
}
Color Theme::getBannerBackground()
{
return {181, 189, 200};
}
Color Theme::getButtonPrimaryBackground()
{
return {200, 200, 200};
}
Color Theme::getButtonPrimaryPressed()
{
return {};
}
Color Theme::getTextPrimary()
{
return {};
}

View file

@ -0,0 +1,15 @@
#include "Color.h"
class Theme
{
public:
static Color getBackgroundPrimary();
static Color getBannerBackground();
static Color getButtonPrimaryBackground();
static Color getButtonPrimaryPressed();
static Color getTextPrimary();
};

View file

@ -0,0 +1,54 @@
#include "KeyboardEvent.h"
KeyboardEvent::KeyboardEvent()
: UiEvent(),
mAction(),
mKeyString()
{
mType = UiEvent::Type::Keyboard;
}
KeyboardEvent::~KeyboardEvent()
{
}
std::unique_ptr<KeyboardEvent> KeyboardEvent::Create()
{
return std::make_unique<KeyboardEvent>();
}
void KeyboardEvent::setKeyString(const std::string& key)
{
mKeyString = key;
}
std::string KeyboardEvent::getKeyString() const
{
return mKeyString;
}
void KeyboardEvent::setAction(Action action)
{
mAction = action;
}
KeyboardEvent::Action KeyboardEvent::getAction() const
{
return mAction;
}
bool KeyboardEvent::isFunctionKey() const
{
return mFunction != Keyboard::Function::UNSET;
}
Keyboard::Function KeyboardEvent::getFunction() const
{
return mFunction;
}
void KeyboardEvent::setFunction(Keyboard::Function function)
{
mFunction = function;
}

View file

@ -0,0 +1,47 @@
#pragma once
#include <memory>
#include <string>
#include "UiEvent.h"
#include "Keyboard.h"
class KeyboardEvent : public UiEvent
{
public:
enum class Action
{
Pressed,
Released
};
public:
KeyboardEvent();
~KeyboardEvent();
static std::unique_ptr<KeyboardEvent> Create();
void setKeyString(const std::string& key);
std::string getKeyString() const;
void setAction(Action action);
Action getAction() const;
bool isFunctionKey() const;
Keyboard::Function getFunction() const;
void setFunction(Keyboard::Function function);
private:
Keyboard::Function mFunction{Keyboard::Function::UNSET};
Action mAction;
std::string mKeyString;
};
using KeyboardEventUPtr = std::unique_ptr<KeyboardEvent>;

View file

@ -0,0 +1,51 @@
#include "MouseEvent.h"
MouseEvent::MouseEvent()
: UiEvent(),
mClientLocation(0, 0),
mScreenLocation(0, 0),
mAction()
{
mType = UiEvent::Type::Mouse;
}
MouseEvent::~MouseEvent()
{
}
std::unique_ptr<MouseEvent> MouseEvent::Create()
{
return std::make_unique<MouseEvent>();
}
void MouseEvent::setClientLocation(Pixel location)
{
mClientLocation = location;
}
void MouseEvent::setScreenLocation(Pixel location)
{
mScreenLocation = location;
}
void MouseEvent::setAction(MouseEvent::Action action)
{
mAction = action;
}
Pixel MouseEvent::getClientLocation() const
{
return mClientLocation;
}
Pixel MouseEvent::getScreenLocation() const
{
return mScreenLocation;
}
MouseEvent::Action MouseEvent::getAction() const
{
return mAction;
}

View file

@ -0,0 +1,42 @@
#pragma once
#include <memory>
#include "DiscretePoint.h"
#include "UiEvent.h"
class MouseEvent : public UiEvent
{
public:
enum class Action
{
Pressed,
Released
};
public:
MouseEvent();
~MouseEvent();
static std::unique_ptr<MouseEvent> Create();
Pixel getClientLocation() const;
Pixel getScreenLocation() const;
Action getAction() const;
void setClientLocation(Pixel location);
void setScreenLocation(Pixel location);
void setAction(Action action);
private:
Pixel mClientLocation;
Pixel mScreenLocation;
Action mAction;
};
using MouseEventUPtr = std::unique_ptr<MouseEvent>;

View file

@ -0,0 +1,18 @@
#include "PaintEvent.h"
PaintEvent::PaintEvent()
: UiEvent()
{
mType = UiEvent::Type::Paint;
}
PaintEvent::~PaintEvent()
{
}
std::unique_ptr<PaintEvent> PaintEvent::Create()
{
return std::make_unique<PaintEvent>();
}

View file

@ -0,0 +1,16 @@
#pragma once
#include <memory>
#include "UiEvent.h"
class PaintEvent : public UiEvent
{
public:
PaintEvent();
~PaintEvent();
static std::unique_ptr<PaintEvent> Create();
};
using PaintEventUPtr = std::unique_ptr<PaintEvent>;

View file

@ -0,0 +1,20 @@
#include "ResizeEvent.h"
ResizeEvent::ResizeEvent(unsigned width, unsigned height)
: UiEvent(),
mWidth(width),
mHeight(height)
{
mType = UiEvent::Type::Resize;
}
ResizeEvent::~ResizeEvent()
{
}
std::unique_ptr<ResizeEvent> ResizeEvent::Create(unsigned width, unsigned height)
{
return std::make_unique<ResizeEvent>(width, height);
}

View file

@ -0,0 +1,30 @@
#pragma once
#include <memory>
#include "UiEvent.h"
class ResizeEvent : public UiEvent
{
public:
ResizeEvent(unsigned width, unsigned height);
~ResizeEvent();
static std::unique_ptr<ResizeEvent> Create(unsigned width, unsigned height);
unsigned getWidth() const
{
return mWidth;
}
unsigned getHeight() const
{
return mHeight;
}
private:
unsigned mWidth{0};
unsigned mHeight{0};
};
using ResizeEventPtr = std::unique_ptr<ResizeEvent>;

View file

@ -0,0 +1,23 @@
#include "UiEvent.h"
UiEvent::UiEvent()
: mType(Type::Unknown)
{
}
UiEvent::~UiEvent()
{
}
std::unique_ptr<UiEvent> UiEvent::Create()
{
return std::make_unique<UiEvent>();
}
UiEvent::Type UiEvent::GetType() const
{
return mType;
}

View file

@ -0,0 +1,30 @@
#pragma once
#include <memory>
class UiEvent
{
public:
enum class Type{
Unknown,
Paint,
Mouse,
Keyboard,
Resize
};
protected:
UiEvent::Type mType;
public:
UiEvent();
virtual ~UiEvent();
static std::unique_ptr<UiEvent> Create();
Type GetType() const;
};
using UiEventUPtr = std::unique_ptr<UiEvent>;

View file

@ -0,0 +1,395 @@
#include "Widget.h"
#include "RectangleNode.h"
#include "MouseEvent.h"
#include "KeyboardEvent.h"
#include "PaintEvent.h"
#include "AbstractVisualNode.h"
#include "TextNode.h"
#include "TransformNode.h"
#include "RootNode.h"
#include "Window.h"
#include "FileLogger.h"
#include <algorithm>
#include <iterator>
#include <iostream>
Widget::Widget()
: mLocation(DiscretePoint(0, 0)),
mSize({100, 0, 0, 100, 0, 0}),
mPadding(),
mMargin(),
mRootNode(std::make_unique<TransformNode>()),
mChildren(),
mBorderThickness(0),
mBackgroundColor(Color(255, 255, 255)),
mBorderColor(Color(0, 0, 0)),
mVisible(true)
{
mName = "Widget";
}
Widget::~Widget()
{
}
std::unique_ptr<Widget> Widget::Create()
{
return std::make_unique<Widget>();
}
void Widget::addWidget(WidgetUPtr widget)
{
widget->setParent(this);
mPendingChildNodes.push_back(widget->getRootNode());
mChildren.push_back(std::move(widget));
}
Widget::BoundedSize Widget::getSize() const
{
return mSize;
}
const DiscretePoint& Widget::getLocation() const
{
return mLocation;
}
TransformNode* Widget::getRootNode() const
{
return mRootNode.get();
}
void Widget::setSize(const BoundedSize& size)
{
if (size != mSize)
{
mSize = size;
mTransformDirty = true;
}
}
void Widget::setMargin(unsigned margin)
{
setMargin({margin, margin, margin, margin});
}
void Widget::setMargin(const BoundaryOffset& margin)
{
if (margin != mMargin)
{
mMargin = margin;
mTransformDirty = true;
}
}
void Widget::setPadding(unsigned padding)
{
setPadding({padding, padding, padding, padding});
}
void Widget::setPadding(const BoundaryOffset& padding)
{
if (padding != mPadding)
{
mPadding = padding;
mTransformDirty = true;
}
}
void Widget::setBounds(unsigned width, unsigned height)
{
if (mSize.mMaxWidth > 0 && width > mSize.mMaxWidth)
{
width = mSize.mMaxWidth;
}
if (mSize.mMaxHeight > 0 && height > mSize.mMaxHeight)
{
height = mSize.mMaxHeight;
}
if (width != mSize.mWidth || height != mSize.mHeight)
{
mTransformDirty = true;
mSize.mWidth = width;
mSize.mHeight = height;
}
}
void Widget::setBackgroundColor(const Color& color)
{
if (mBackgroundColor != color)
{
mBackgroundColor = color;
mMaterialDirty = true;
}
}
void Widget::setLocation(const DiscretePoint& loc)
{
if (mLocation != loc)
{
mLocation = loc;
mTransformDirty = true;
}
}
void Widget::setVisible(bool visible)
{
if (mVisible != visible)
{
mVisibilityDirty = true;
mVisible = visible;
for (auto& child : mChildren)
{
child->setVisible(mVisible);
}
}
}
bool Widget::isDirty() const
{
return mTransformDirty || mMaterialDirty || mVisibilityDirty || mPendingChildNodes.size() > 0;
}
bool Widget::needsUpdate() const
{
if (isDirty())
{
return true;
}
for(auto& child: mChildren)
{
if (child->needsUpdate())
{
return true;
}
}
return false;
}
void Widget::setMaxWidth(unsigned maxWidth)
{
if (mSize.mMaxWidth != maxWidth)
{
mTransformDirty = true;
mSize.mMaxWidth = maxWidth;
}
}
void Widget::doPaint(const PaintEvent* event)
{
updateBackground(event);
}
void Widget::onPaintEvent(const PaintEvent* event)
{
if (!needsUpdate())
{
return;
}
if (isDirty())
{
mRootNode->setName(mName + "_RootNode");
doPaint(event);
if (mVisibilityDirty)
{
mRootNode->setIsVisible(mVisible);
}
mTransformDirty = false;
mMaterialDirty = false;
mVisibilityDirty = false;
}
for (auto node : mPendingChildNodes)
{
mRootNode->addChild(node);
}
mPendingChildNodes.clear();
updateChildLocations();
for(auto& child: mChildren)
{
child->onPaintEvent(event);
}
}
void Widget::updateChildLocations()
{
for(auto& child: mChildren)
{
child->setBounds(mSize.mWidth, mSize.mHeight);
child->setLocation(mLocation);
}
}
bool Widget::contains(const DiscretePoint& loc) const
{
if(loc.getX() < mLocation.getX())
{
return false;
}
if(loc.getX() > mLocation.getX() + mSize.mWidth)
{
return false;
}
if(loc.getY() > mLocation.getY() + mSize.mHeight)
{
return false;
}
if(loc.getY() < mLocation.getY())
{
return false;
}
return true;
}
bool Widget::onKeyboardEvent(const KeyboardEvent* event)
{
bool inChild = false;
for(const auto& child : mChildren)
{
if(child->onKeyboardEvent(event))
{
inChild = true;
break;
}
}
if(!inChild)
{
return onMyKeyboardEvent(event);
}
return true;
}
bool Widget::onMyKeyboardEvent(const KeyboardEvent* event)
{
return false;
}
bool Widget::onMouseEvent(const MouseEvent* event)
{
bool inChild = false;
for(const auto& child : mChildren)
{
if(child->onMouseEvent(event))
{
inChild = true;
break;
}
}
if(!inChild)
{
if(mVisible && contains(event->getClientLocation()))
{
onMyMouseEvent(event);
return true;
}
else
{
return false;
}
}
return true;
}
void Widget::onMyMouseEvent(const MouseEvent* event)
{
MLOG_INFO("Widget mouse event");
}
void Widget::updateBackground(const PaintEvent* event)
{
unsigned locX = mLocation.getX() + mMargin.mLeft;
unsigned locY = mLocation.getY() + mMargin.mTop;
unsigned deltaX = mSize.mWidth - mMargin.mLeft - mMargin.mRight;
unsigned deltaY = mSize.mHeight - mMargin.mTop - mMargin.mBottom;
if (!mBackgroundNode)
{
mBackgroundNode = std::make_unique<RectangleNode>(DiscretePoint(locX, locY), deltaX, deltaY);
mBackgroundNode->setName(mName + "_BackgroundNode");
mRootNode->addChild(mBackgroundNode.get());
}
if (mTransformDirty)
{
mBackgroundNode->setWidth(deltaX);
mBackgroundNode->setHeight(deltaY);
mBackgroundNode->setLocation(DiscretePoint(locX, locY));
}
if (mMaterialDirty)
{
mBackgroundNode->setFillColor(mBackgroundColor);
mBackgroundNode->setStrokeColor(mBorderColor);
mBackgroundNode->setStrokeThickness(mBorderThickness);
}
if (mVisibilityDirty)
{
mBackgroundNode->setIsVisible(mVisible);
}
}
mt::Window* Widget::getTopLevelWindow() const
{
if(mWindow)
{
return mWindow;
}
std::cout << "I am " << getName() << std::endl;
auto lastParent = mParent;
auto nextParent = mParent;
while(nextParent)
{
lastParent = nextParent;
nextParent = lastParent->getParent();
std::cout << "Checking if " << lastParent->getName() << std::endl;
if (nextParent)
{
std::cout << "Next is " << nextParent->getName() << std::endl;
}
else
{
std::cout << "no next" << std::endl;
}
}
return lastParent->getTopLevelWindow();
}
Widget* Widget::getParent() const
{
return mParent;
}
mt::Window* Widget::getWindow() const
{
return mWindow;
}
void Widget::setParent(Widget* parent)
{
mParent = parent;
}
void Widget::setWindow(mt::Window* window)
{
mWindow = window;
}

View file

@ -0,0 +1,176 @@
#pragma once
#include "DiscretePoint.h"
#include "FontItem.h"
#include "Color.h"
#include <memory>
#include <vector>
#include <string>
class MouseEvent;
class KeyboardEvent;
class PaintEvent;
class AbstractVisualNode;
class TransformNode;
class RectangleNode;
namespace mt
{
class Window;
}
class Widget
{
public:
struct BoundaryOffset
{
bool operator==(const BoundaryOffset& rhs) const
{
return (mLeft == rhs.mLeft)
&& (mRight == rhs.mRight)
&& (mTop == rhs.mTop)
&& (mBottom == rhs.mBottom);
}
bool operator!=(const BoundaryOffset& rhs) const
{
return !operator==(rhs);
}
unsigned mLeft = 0;
unsigned mRight = 0;
unsigned mTop = 0;
unsigned mBottom = 0;
};
struct BoundedSize
{
bool operator==(const BoundedSize& rhs) const
{
return (mWidth == rhs.mWidth)
&& (mMaxWidth == rhs.mMaxWidth)
&& (mMinWidth == rhs.mMinWidth)
&& (mHeight == rhs.mHeight)
&& (mMaxHeight == rhs.mMaxHeight)
&& (mMinHeight == rhs.mMinHeight);
}
bool operator!=(const BoundedSize& rhs) const
{
return !operator==(rhs);
}
unsigned mWidth = 0;
unsigned mMaxWidth = 0;
unsigned mMinWidth = 0;
unsigned mHeight = 0;
unsigned mMaxHeight = 0;
unsigned mMinHeight = 0;
};
public:
Widget();
virtual ~Widget();
static std::unique_ptr<Widget> Create();
virtual void addWidget(std::unique_ptr<Widget> widget);
BoundedSize getSize() const;
TransformNode* getRootNode() const;
const DiscretePoint& getLocation() const;
virtual void onPaintEvent(const PaintEvent* event);
virtual bool onMouseEvent(const MouseEvent* event);
virtual bool onKeyboardEvent(const KeyboardEvent* event);
bool contains(const DiscretePoint& loc) const;
void setBackgroundColor(const Color& color);
void setBounds(unsigned width, unsigned height);
void setSize(const BoundedSize& size);
void setMaxWidth(unsigned maxWidth);
void setMargin(unsigned margin);
void setMargin(const BoundaryOffset& margin);
void setPadding(unsigned padding);
void setPadding(const BoundaryOffset& padding);
void setLocation(const DiscretePoint& loc);
void setVisible(bool visible);
void setName(const std::string& name)
{
mName = name;
}
const std::string& getName() const
{
return mName;
}
bool needsUpdate() const;
void setWindow(mt::Window* window);
mt::Window* getTopLevelWindow() const;
protected:
virtual bool onMyKeyboardEvent(const KeyboardEvent* event);
virtual void onMyMouseEvent(const MouseEvent* event);
virtual void updateBackground(const PaintEvent* event);
virtual void doPaint(const PaintEvent* event);
virtual void updateChildLocations();
virtual bool isDirty() const;
void setParent(Widget* parent);
Widget* getParent() const;
mt::Window* getWindow() const;
DiscretePoint mLocation;
BoundedSize mSize;
BoundaryOffset mPadding;
BoundaryOffset mMargin;
std::unique_ptr<TransformNode> mRootNode;
std::vector<std::unique_ptr<Widget> > mChildren;
unsigned mBorderThickness{0};
Color mBackgroundColor;
Color mBorderColor;
bool mVisible{true};
std::unique_ptr<RectangleNode> mBackgroundNode;
bool mTransformDirty{true};
bool mMaterialDirty{true};
bool mVisibilityDirty{true};
std::string mName;
std::vector<TransformNode*> mPendingChildNodes;
FontItem mDefaultFont;
Widget* mParent{nullptr};
mt::Window* mWindow{nullptr};
};
using WidgetUPtr = std::unique_ptr<Widget>;

View file

View file

@ -0,0 +1,20 @@
#pragma once
#include <memory>
#include "AbstractApp.h"
class AbstractUIInterface;
class AbstractDesktopApp
{
public:
AbstractDesktopApp() = default;
virtual ~AbstractDesktopApp() = default;
virtual AbstractApp* getMainApplication() const = 0;
virtual AbstractUIInterface* getUiInterface() const = 0;
};
using AbstractDesktopAppPtr = std::shared_ptr<AbstractDesktopApp>;

View file

@ -0,0 +1,112 @@
set(MODULE_NAME windows)
set (platform_INCLUDES "")
set (platform_LIBS "")
if(UNIX)
message(STATUS "Checking dependencies for module: window")
find_package(X11 QUIET)
if(X11_FOUND)
list(APPEND platform_INCLUDES
ui_interfaces/x11/XcbInterface.cpp
ui_interfaces/x11/XcbEventInterface.cpp
ui_interfaces/x11/XcbWindow.cpp
ui_interfaces/x11/XcbScreen.cpp
ui_interfaces/x11/XcbImage.cpp
ui_interfaces/x11/XcbTextInterface.cpp
ui_interfaces/x11/XcbKeyboard.cpp
ui_interfaces/x11/XcbGlInterface.cpp
ui_interfaces/x11/XcbExtensionInterface.cpp
ui_interfaces/x11/XcbGlWindowInterface.cpp
)
list(APPEND platform_LIBS ${X11_LIBRARIES} ${X11_xcb_LIB} ${X11_X11_xcb_LIB} ${X11_xkbcommon_LIB} ${X11_xkbcommon_X11_LIB} libxcb-image.so)
list(APPEND X11_INCLUDE_DIRS ${X11_xkbcommon_INCLUDE_PATH})
list(APPEND DEFINES "HAS_X11")
else()
message(STATUS "X11 not found - skipping support")
endif()
find_package(Wayland QUIET)
if(WAYLAND_FOUND)
list(APPEND platform_INCLUDES
ui_interfaces/wayland/WaylandInterface.cpp
ui_interfaces/wayland/WaylandSurface.cpp
ui_interfaces/wayland/WaylandBuffer.cpp
ui_interfaces/wayland/WaylandPointerInterface.cpp
ui_interfaces/wayland/WaylandSeatInterface.cpp
ui_interfaces/wayland/WaylandKeyboard.cpp
ui_interfaces/wayland/WaylandEglInterface.cpp
ui_interfaces/wayland/WaylandEglWindowInterface.cpp
${WAYLAND_XDG_SOURCE}
)
list(APPEND platform_LIBS OpenGL::EGL)
list(APPEND DEFINES "HAS_WAYLAND")
set(OpenGL_GL_PREFERENCE "GLVND")
find_package(OpenGL QUIET)
if (OpenGL_FOUND)
list(APPEND platform_LIBS ${WAYLAND_LIBRARIES})
endif()
else()
Message(STATUS "Wayland not found - skipping support")
endif()
else()
list(APPEND platform_INCLUDES
ui_interfaces/win32/Win32UIInterface.h
ui_interfaces/win32/Win32UIInterface.cpp
ui_interfaces/win32/Win32WindowInterface.h
ui_interfaces/win32/Win32WindowInterface.cpp
ui_interfaces/win32/Win32Window.h
ui_interfaces/win32/Win32Window.cpp
ui_interfaces/win32/directx/Win32DxWindowInterface.h
ui_interfaces/win32/directx/Win32DxWindowInterface.cpp
ui_interfaces/win32/directx/DirectXDescriptors.h
ui_interfaces/win32/directx/DirectXDescriptors.cpp
ui_interfaces/win32/directx/DirectX2dIntegration.h
ui_interfaces/win32/directx/DirectX2dIntegration.cpp
ui_interfaces/win32/directx/DirectXBuffers.h
ui_interfaces/win32/directx/DirectXBuffers.cpp
ui_interfaces/win32/directx/DirectXCommandList.h
ui_interfaces/win32/directx/DirectXCommandList.cpp
)
list(APPEND platform_LIBS D3D12.lib D3DCompiler.lib DXGI.lib Dwrite.lib D2d1.lib D3D11.lib)
find_package(DirectX-Headers REQUIRED)
list(APPEND platform_LIBS Microsoft::DirectX-Headers)
endif()
list(APPEND windows_LIB_INCLUDES
ui_interfaces/AbstractUiInterface.h
ui_interfaces/UiInterfaceFactory.cpp
managers/WindowManager.h
managers/DesktopManager.h
managers/EventManager.h
managers/WindowManager.cpp
managers/DesktopManager.cpp
managers/EventManager.cpp
)
# add the library
add_library(windows SHARED ${windows_LIB_INCLUDES} ${platform_INCLUDES})
target_include_directories(windows PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/managers
${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces
${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces/x11
${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces/wayland
${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces/win32
${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces/win32/directx
${WAYLAND_INCLUDE_DIRS}
${X11_INCLUDE_DIRS}
)
target_compile_definitions(${MODULE_NAME} PRIVATE ${DEFINES})
if(UNIX)
target_compile_options(${MODULE_NAME} PRIVATE -Wno-attributes) # From xdg shell autogen code
endif()
target_link_libraries(${MODULE_NAME} PUBLIC ${platform_LIBS} core geometry graphics ui_elements)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER src/ui)
set_target_properties( ${MODULE_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )

View file

@ -0,0 +1,142 @@
#include "DesktopManager.h"
#include "AbstractDesktopApp.h"
#include "AbstractUiInterface.h"
#include "FileLogger.h"
#include "Widget.h"
#include <iostream>
DesktopManager::DesktopManager(AbstractDesktopApp* application)
: mScreens(),
mKeyboard(Keyboard::Create()),
mUiApplication(application),
mEventManager(EventManager::Create()),
mFontsManager(FontsManager::Create())
{
mWindowManager = WindowManager::Create(this);
}
DesktopManager::~DesktopManager()
{
}
std::unique_ptr<DesktopManager> DesktopManager::Create(AbstractDesktopApp* application)
{
return std::make_unique<DesktopManager>(application);
}
void DesktopManager::clearEvents()
{
mEventManager->ClearEvents();
}
FontsManager* DesktopManager::getFontsManager() const
{
return mFontsManager.get();
}
void DesktopManager::onKeyboardEvent(const KeyboardEvent* event)
{
mWindowManager->onKeyboardEvent(event);
}
void DesktopManager::onPaintEvent(const PaintEvent* event)
{
mWindowManager->onPaintEvent(event);
}
void DesktopManager::onMouseEvent(const MouseEvent* event)
{
mWindowManager->onMouseEvent(event);
}
void DesktopManager::onUiEvent(UiEventUPtr eventUPtr)
{
const auto event = mEventManager->AddEvent(std::move(eventUPtr));
switch (event->GetType())
{
case (UiEvent::Type::Paint):
{
onPaintEvent(dynamic_cast<const PaintEvent*>(event));
break;
}
case (UiEvent::Type::Keyboard):
{
onKeyboardEvent(dynamic_cast<const KeyboardEvent*>(event));
break;
}
case (UiEvent::Type::Resize):
{
auto resize_event = dynamic_cast<const ResizeEvent*>(event);
mWindowManager->onResizeEvent(resize_event);
break;
}
case (UiEvent::Type::Mouse):
{
auto mouseEvent = dynamic_cast<const MouseEvent*>(event);
onMouseEvent(mouseEvent);
break;
}
default:
break;
}
}
Keyboard* DesktopManager::getKeyboard() const
{
return mKeyboard.get();
}
void DesktopManager::setKeyboard(KeyboardUPtr keyboard)
{
mKeyboard = std::move(keyboard);
}
AbstractApp* DesktopManager::getMainApp() const
{
return mUiApplication->getMainApplication();
}
void DesktopManager::addScreen(ScreenPtr screen)
{
mScreens.push_back(std::move(screen));
}
mt::Screen* DesktopManager::getDefaultScreen() const
{
if (mScreens.size() > 0)
{
return mScreens[0].get();
}
return nullptr;
}
void DesktopManager::setWindowManager(WindowManagerUPtr windowManager)
{
mWindowManager = std::move(windowManager);
}
WindowManager* DesktopManager::getWindowManager() const
{
return mWindowManager.get();
}
void DesktopManager::addWindow(mt::Window* window)
{
if (auto ui_interface = mUiApplication->getUiInterface())
{
std::cout << "Adding popup window" << std::endl;
ui_interface->addWindow(window);
ui_interface->showWindow(window);
}
}
void DesktopManager::onLoopIteration()
{
auto defaultScreen = getDefaultScreen();
mWindowManager->onLoopIteration(defaultScreen);
}

View file

@ -0,0 +1,68 @@
#pragma once
#include <vector>
#include <memory>
#include "Keyboard.h"
#include "Screen.h"
#include "KeyboardEvent.h"
#include "PaintEvent.h"
#include "MouseEvent.h"
#include "WindowManager.h"
#include "UiEvent.h"
#include "AbstractApp.h"
#include "EventManager.h"
#include "FontsManager.h"
class AbstractDesktopApp;
class DesktopManager
{
public:
DesktopManager(AbstractDesktopApp* application);
~DesktopManager();
static std::unique_ptr<DesktopManager> Create(AbstractDesktopApp* application);
void setWindowManager(WindowManagerUPtr windowManager);
AbstractApp* getMainApp() const;
WindowManager* getWindowManager() const;
Keyboard* getKeyboard() const;
FontsManager* getFontsManager() const;
void addScreen(ScreenPtr screen);
mt::Screen* getDefaultScreen() const;
void setKeyboard(KeyboardUPtr keyboard);
void onUiEvent(UiEventUPtr event);
void onKeyboardEvent(const KeyboardEvent* keyboardEvent);
void onMouseEvent(const MouseEvent* mouseEvent);
void onPaintEvent(const PaintEvent* paintEvent);
void clearEvents();
void onLoopIteration();
void addWindow(mt::Window* window);
private:
std::vector<ScreenPtr> mScreens;
FontsManagerPtr mFontsManager;
WindowManagerUPtr mWindowManager;
KeyboardUPtr mKeyboard;
EventManagerUPtr mEventManager;
AbstractDesktopApp* mUiApplication;
};
using DesktopManagerUPtr = std::unique_ptr<DesktopManager>;

View file

@ -0,0 +1,23 @@
#include "EventManager.h"
EventManager::EventManager()
: mEvents()
{
}
std::unique_ptr<EventManager> EventManager::Create()
{
return std::make_unique<EventManager>();
}
UiEvent* EventManager::AddEvent(UiEventUPtr event)
{
mEvents.push_back(std::move(event));
return mEvents[mEvents.size()-1].get();
}
void EventManager::ClearEvents()
{
mEvents.clear();
}

View file

@ -0,0 +1,22 @@
#pragma once
#include "UiEvent.h"
#include <vector>
class EventManager
{
std::vector<UiEventUPtr> mEvents;
public:
EventManager();
static std::unique_ptr<EventManager> Create();
UiEvent* AddEvent(UiEventUPtr event);
void ClearEvents();
};
using EventManagerUPtr = std::unique_ptr<EventManager>;

View file

@ -0,0 +1,93 @@
#include "WindowManager.h"
#include "DesktopManager.h"
WindowManager::WindowManager(DesktopManager* desktopManager)
: mWindows(),
mDesktopManager(desktopManager)
{
addWindow(mt::Window::Create(mDrawMode, desktopManager->getFontsManager()));
}
WindowManager::~WindowManager()
{
}
std::unique_ptr<WindowManager> WindowManager::Create(DesktopManager* desktopManager)
{
return std::make_unique<WindowManager>(desktopManager);
}
void WindowManager::onPaintEvent(const PaintEvent* event)
{
getMainWindow()->onPaint(event);
}
void WindowManager::onMouseEvent(const MouseEvent* event)
{
getMainWindow()->onMouseEvent(event);
}
void WindowManager::onResizeEvent(const ResizeEvent* event)
{
getMainWindow()->setSize(event->getWidth(), event->getHeight());
}
void WindowManager::onKeyboardEvent(const KeyboardEvent* event)
{
getMainWindow()->onKeyboardEvent(event);
}
void WindowManager::addWindow(WindowUPtr window)
{
auto popup_handler = [this](mt::Window* parent, std::unique_ptr<Widget> popup){
onAddPopupWindow(parent, std::move(popup));
};
window->setPopupHandler(popup_handler);
mWindows.push_back(std::move(window));
}
void WindowManager::onAddPopupWindow(mt::Window* parent, std::unique_ptr<Widget> widget)
{
auto popup = mt::Window::Create(mDrawMode, mDesktopManager->getFontsManager());
popup->setWidget(std::move(widget));
popup->setParent(parent);
auto popup_raw = popup.get();
addWindow(std::move(popup));
mDesktopManager->addWindow(popup_raw);
}
void WindowManager::clearPlatformWindows()
{
for (auto& window : mWindows)
{
window->clearPlatformWindow();
}
}
mt::Window* WindowManager::getMainWindow() const
{
if(mWindows.size()>0)
{
return mWindows[0].get();
}
else
{
return nullptr;
}
}
void WindowManager::onLoopIteration(mt::Screen* screen)
{
for (auto& window : mWindows)
{
if (window->isDirty())
{
window->onPaint(nullptr);
window->doPaint(screen);
}
}
}

View file

@ -0,0 +1,60 @@
#pragma once
#include <vector>
#include <memory>
#include "Window.h"
#include "DrawingContext.h"
#include "PaintEvent.h"
#include "MouseEvent.h"
#include "ResizeEvent.h"
#include "KeyboardEvent.h"
class Widget;
class DesktopManager;
class WindowManager
{
public:
WindowManager(DesktopManager* desktopManager);
~WindowManager();
static std::unique_ptr<WindowManager> Create(DesktopManager* desktopManager);
void addWindow(WindowUPtr window);
mt::Window* getMainWindow() const;
void onPaintEvent(const PaintEvent* event);
void onMouseEvent(const MouseEvent* event);
void onKeyboardEvent(const KeyboardEvent* event);
void onResizeEvent(const ResizeEvent* event);
void clearPlatformWindows();
std::size_t getNumWindows() const
{
return mWindows.size();
}
mt::Window* getWindow(std::size_t idx) const
{
return mWindows[idx].get();
}
void onLoopIteration(mt::Screen* screen);
void onAddPopupWindow(mt::Window* parent, std::unique_ptr<Widget> widget);
private:
std::vector<WindowUPtr> mWindows;
DrawingMode mDrawMode{ DrawingMode::GRAPH };
DesktopManager* mDesktopManager{nullptr};
};
using WindowManagerUPtr = std::unique_ptr<WindowManager>;

View file

@ -0,0 +1,38 @@
#pragma once
#include <memory>
namespace mt
{
class Window;
}
class DesktopManager;
class AbstractUIInterface
{
public:
AbstractUIInterface(DesktopManager* desktopManager, bool useHardware = false)
: mDesktopManager(desktopManager),
mUseHardwareRendering(useHardware)
{
}
virtual ~AbstractUIInterface() = default;
virtual void loop() = 0;
virtual void showWindow(mt::Window* window) = 0;
virtual void addWindow(mt::Window* window) = 0;
protected:
virtual void initialize() = 0;
virtual void shutDown() = 0;
virtual void initializeHardwareRendering() {};
DesktopManager* mDesktopManager{nullptr};
bool mUseHardwareRendering{false};
};

View file

@ -0,0 +1,27 @@
#pragma once
#include "AbstractUiInterface.h"
#include "DesktopManager.h"
#include "FontsManager.h"
class NullUIInterface : public AbstractUIInterface
{
public:
NullUIInterface(DesktopManager* desktopManager, bool useHardware = false)
: AbstractUIInterface(desktopManager, useHardware)
{
};
virtual ~NullUIInterface() = default;
void loop() override{};
void showWindow(mt::Window* window) override{};
void addWindow(mt::Window* window) override{};
protected:
void initialize() override{};
void shutDown() override{};
};

View file

@ -0,0 +1,48 @@
#include "UiInterfaceFactory.h"
#ifdef __linux__
#ifdef HAS_X11
#include "XcbInterface.h"
#endif
#ifdef HAS_WAYLAND
#include "WaylandInterface.h"
#endif
#else
#include "Win32UiInterface.h"
#endif
#include "NullUiInterface.h"
#include "Widget.h"
std::unique_ptr<AbstractUIInterface> UiInterfaceFactory::create(DesktopManager* desktopManager, Backend backend)
{
#ifdef __linux__
if (backend == Backend::UNSET || backend == Backend::X11 || backend == Backend::X11_RASTER)
{
#ifdef HAS_X11
const bool use_hardware = (backend != Backend::X11_RASTER);
return std::make_unique<XcbInterface>(desktopManager, use_hardware);
#else
return std::make_unique<NullUIInterface>(desktopManager);
#endif
}
else
{
#ifdef HAS_WAYLAND
const bool use_hardware = (backend != Backend::WAYLAND_RASTER);
return std::make_unique<WaylandInterface>(desktopManager, use_hardware);
#else
#ifdef HAS_X11
const bool use_hardware = (backend != Backend::X11_RASTER);
return std::make_unique<XcbInterface>(desktopManager, use_hardware);
#else
return std::make_unique<NullUIInterface>(desktopManager);
#endif
#endif
}
#else
return std::make_unique<Win32UIInterface>(desktopManager, true);
#endif
}

View file

@ -0,0 +1,22 @@
#pragma once
#include "AbstractUiInterface.h"
#include <memory>
class DesktopManager;
class UiInterfaceFactory
{
public:
enum class Backend
{
UNSET,
X11_RASTER,
X11,
WAYLAND_RASTER,
WAYLAND
};
static std::unique_ptr<AbstractUIInterface> create(DesktopManager* desktopManager, Backend backend = Backend::UNSET);
};

View file

@ -0,0 +1,78 @@
#include "WaylandBuffer.h"
#include "FileLogger.h"
#include <sys/mman.h>
#include <unistd.h>
void WaylandBuffer::initializeSharedBuffer(int size)
{
mSharedMemory = std::make_unique<SharedMemory>();
mSharedMemory->allocate("/wl_shm-XXXXXX", size);
if (!mSharedMemory->isValid())
{
return;
}
mPoolData = static_cast<uint8_t*>(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, mSharedMemory->getFileDescriptor(), 0));
if (mPoolData == MAP_FAILED)
{
close(mSharedMemory->getFileDescriptor());
mPoolData = nullptr;
}
}
void WaylandBuffer::setSharedMemory(wl_shm* shared_memory)
{
mWlSharedMemory = shared_memory;
}
void WaylandBuffer::setUpPool(int size, int width, int height, int stride)
{
if (!mSharedMemory->isValid())
{
MLOG_ERROR("Failed to allocate shared memory.");
return;
}
if (!mPoolData)
{
MLOG_ERROR("Failed to allocate shared memory.");
return;
}
auto pool = wl_shm_create_pool(mWlSharedMemory, mSharedMemory->getFileDescriptor(), size);
int index = 0;
// int offset = height * stride * index; // Two buffers, offset to starting point of second
int offset = 0;
mWorkingBuffer = wl_shm_pool_create_buffer(pool, offset, width, height, stride, WL_SHM_FORMAT_XRGB8888);
wl_shm_pool_destroy(pool);
close(mSharedMemory->getFileDescriptor());
}
void WaylandBuffer::tearDownPool(int size)
{
munmap(mPoolData, size);
auto wl_buffer_release = [](void *data, struct wl_buffer *wl_buffer)
{
wl_buffer_destroy(wl_buffer);
};
mBufferListener.release = wl_buffer_release;
wl_buffer_add_listener(mWorkingBuffer, &mBufferListener, nullptr);
}
uint8_t* WaylandBuffer::getPoolData()
{
return mPoolData;
}
wl_buffer* WaylandBuffer::getWorkingBuffer()
{
return mWorkingBuffer;
}

View file

@ -0,0 +1,33 @@
#pragma once
#include "wayland-client.h"
#include "SharedMemory.h"
#include <memory>
class WaylandBuffer
{
public:
WaylandBuffer() = default;
void initializeSharedBuffer(int size);
uint8_t* getPoolData();
wl_buffer* getWorkingBuffer();
void setUpPool(int size, int width, int height, int stride);
void setSharedMemory(wl_shm* shared_memory);
void tearDownPool(int size);
private:
wl_shm* mWlSharedMemory{nullptr};
std::unique_ptr<SharedMemory> mSharedMemory;
uint8_t* mPoolData{nullptr};
wl_shm_pool* mPool{nullptr};
wl_buffer* mWorkingBuffer{nullptr};
wl_buffer_listener mBufferListener;
};

View file

@ -0,0 +1,78 @@
#include "WaylandEglInterface.h"
#include "FileLogger.h"
#include <wayland-egl.h>
WaylandEglInterface::WaylandEglInterface(wl_display* display)
{
initialize(display);
}
void WaylandEglInterface::initialize(wl_display* display)
{
mEglDisplay = eglGetDisplay((EGLNativeDisplayType) display);
if (mEglDisplay == EGL_NO_DISPLAY)
{
MLOG_ERROR("Can't create egl display")
return;
}
EGLint major{0};
EGLint minor{0};
if (eglInitialize(mEglDisplay, &major, &minor) != EGL_TRUE)
{
MLOG_ERROR("Can't initialise egl display")
return;
}
EGLint count{0};
eglGetConfigs(mEglDisplay, nullptr, 0, &count);
EGLConfig* configs;
configs = static_cast<EGLConfig*>(calloc(count, sizeof* configs));
EGLint n{0};
EGLint config_attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NONE
};
eglChooseConfig(mEglDisplay, config_attribs, configs, count, &n);
EGLint size{0};
for (int i = 0; i < n; i++)
{
eglGetConfigAttrib(mEglDisplay, configs[i], EGL_BUFFER_SIZE, &size);
// printf("Buffer size for config %d is %d\n", i, size);
eglGetConfigAttrib(mEglDisplay, configs[i], EGL_RED_SIZE, &size);
// printf("Red size for config %d is %d\n", i, size);
// just choose the first one
mEglConfig = configs[i];
break;
}
static const EGLint context_attribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, context_attribs);
}
EGLDisplay WaylandEglInterface::getDisplay() const
{
return mEglDisplay;
}
EGLConfig WaylandEglInterface::getConfig() const
{
return mEglConfig;
}
EGLContext WaylandEglInterface::getContext() const
{
return mEglContext;
}

View file

@ -0,0 +1,24 @@
#pragma once
#include <EGL/egl.h>
struct wl_display;
class WaylandEglInterface
{
public:
WaylandEglInterface(wl_display* display);
EGLDisplay getDisplay() const;
EGLConfig getConfig() const;
EGLContext getContext() const;
private:
void initialize(wl_display* display);
EGLDisplay mEglDisplay;
EGLConfig mEglConfig;
EGLContext mEglContext;
};

View file

@ -0,0 +1,85 @@
#include "WaylandEglWindowInterface.h"
#include "FileLogger.h"
#include <wayland-egl.h>
WaylandEglWindowInterface::WaylandEglWindowInterface(WaylandEglInterface* eglInterface)
: mEglInterface(eglInterface)
{
}
void WaylandEglWindowInterface::initialize(wl_surface* surface, int width, int height)
{
if (mEglSurface)
{
return;
}
mEglWindow = wl_egl_window_create(surface, width, height);
if (mEglWindow == EGL_NO_SURFACE)
{
MLOG_ERROR("Can't create egl window");
return;
}
mEglSurface = eglCreateWindowSurface(mEglInterface->getDisplay(), mEglInterface->getConfig(), reinterpret_cast<EGLNativeWindowType>(mEglWindow), nullptr);
if (!mEglSurface)
{
switch(eglGetError())
{
case EGL_BAD_DISPLAY:
fprintf(stderr, "EGL_BAD_DISPLAY\n");
break;
case EGL_NOT_INITIALIZED:
fprintf(stderr, "EGL_NOT_INITIALIZED\n");
break;
case EGL_BAD_CONFIG:
fprintf(stderr, "EGL_BAD_CONFIG\n");
break;
case EGL_BAD_NATIVE_WINDOW:
fprintf(stderr, "EGL_BAD_NATIVE_WINDOW\n");
break;
case EGL_BAD_ATTRIBUTE:
fprintf(stderr, "EGL_BAD_ATTRIBUTE\n");
break;
case EGL_BAD_ALLOC:
fprintf(stderr, "EGL_BAD_ALLOC\n");
break;
case EGL_BAD_MATCH:
fprintf(stderr, "EGL_BAD_MATCH\n");
break;
default:
fprintf(stderr, "Unknown EGL error\n");
}
MLOG_ERROR("Created surface failed");
}
}
void WaylandEglWindowInterface::beforePaint()
{
if (!mEglSurface)
{
return;
}
if (!eglMakeCurrent(mEglInterface->getDisplay(), mEglSurface, mEglSurface, mEglInterface->getContext()))
{
MLOG_ERROR("Made current failed");
}
}
void WaylandEglWindowInterface::afterPaint()
{
if (!mEglSurface)
{
return;
}
if (!eglSwapBuffers(mEglInterface->getDisplay(), mEglSurface))
{
MLOG_ERROR("Swapped buffers failed");
}
}

View file

@ -0,0 +1,25 @@
#pragma once
#include "WaylandEglInterface.h"
#include <EGL/egl.h>
struct wl_egl_window;
struct wl_surface;
class WaylandEglWindowInterface
{
public:
WaylandEglWindowInterface(WaylandEglInterface* eglInterface);
void initialize(wl_surface* surface, int width, int height);
void beforePaint();
void afterPaint();
private:
wl_egl_window* mEglWindow{nullptr};
EGLSurface mEglSurface{nullptr};
WaylandEglInterface* mEglInterface;
};

View file

@ -0,0 +1,157 @@
#include "WaylandInterface.h"
#include "FileLogger.h"
#include "DesktopManager.h"
#include "WindowManager.h"
#include "FontsManager.h"
#include "WaylandSurface.h"
#include "WaylandBuffer.h"
#include "WaylandSeatInterface.h"
#include "WaylandEglInterface.h"
#include <cstring>
#include <sstream>
void WaylandInterface::registryHandleGlobalEvent(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version)
{
auto thisClass = static_cast<WaylandInterface*>(data);
std::stringstream sstrm;
sstrm << "interface: " << interface << " version " << version << " name " << name;
//MLOG_INFO(sstrm.str());
if (strcmp(interface, wl_compositor_interface.name) == 0)
{
thisClass->setCompositor(static_cast<wl_compositor*>(wl_registry_bind(registry, name, &wl_compositor_interface, 4)));
}
else if (strcmp(interface, wl_shm_interface.name) == 0)
{
thisClass->setSharedMemory(static_cast<wl_shm*>(wl_registry_bind(registry, name, &wl_shm_interface, 1)));
}
else if (strcmp(interface, xdg_wm_base_interface.name) == 0)
{
thisClass->setXdgBase(static_cast<xdg_wm_base*>(wl_registry_bind(registry, name, &xdg_wm_base_interface, 1)));
}
else if (strcmp(interface, wl_seat_interface.name) == 0)
{
thisClass->setSeat(static_cast<wl_seat*>(wl_registry_bind(registry, name, &wl_seat_interface, 5)));
}
}
void WaylandInterface::registryHandleGlobalRemoveEvent(void *data, struct wl_registry *registry, uint32_t name)
{
}
WaylandInterface::WaylandInterface(DesktopManager* desktopManager, std::unique_ptr<FontsManager> fontsManager, bool useHardware)
: AbstractUIInterface(desktopManager, std::move(fontsManager), useHardware),
mBuffer(std::make_shared<WaylandBuffer>())
{
mRegistryListener.global = registryHandleGlobalEvent;
mRegistryListener.global_remove = registryHandleGlobalRemoveEvent;
}
WaylandInterface::~WaylandInterface()
{
shutDown();
}
void WaylandInterface::initialize()
{
mDisplay = wl_display_connect(nullptr);
if (!mDisplay)
{
MLOG_ERROR("Display connect error");
return;
}
auto registry = wl_display_get_registry(mDisplay);
if (!registry)
{
MLOG_ERROR("Failed to get registry");
return;
}
wl_registry_add_listener(registry, &mRegistryListener, this);
wl_display_roundtrip(mDisplay);
if (mUseHardwareRendering)
{
initializeHardwareRendering();
}
const auto num_windows = mDesktopManager->getWindowManager()->getNumWindows();
for(std::size_t idx=0; idx< num_windows; idx++)
{
addWindow(mDesktopManager->getWindowManager()->getWindow(idx));
}
mDesktopManager->getWindowManager()->getMainWindow()->show();
}
void WaylandInterface::initializeHardwareRendering()
{
mEglInterface = std::make_unique<WaylandEglInterface>(mDisplay);
}
void WaylandInterface::setSeat(wl_seat* seat)
{
mSeatInterface = std::make_unique<WaylandSeatInterface>(seat);
}
void WaylandInterface::setXdgBase(xdg_wm_base* xdg_base)
{
mXdgBase = xdg_base;
auto xdg_ping_handler = [](void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial)
{
auto thisClass = static_cast<WaylandInterface*>(data);
thisClass->doXdgPong(serial);
};
mXdgBaseListener.ping = xdg_ping_handler;
xdg_wm_base_add_listener(mXdgBase, &mXdgBaseListener, this);
}
void WaylandInterface::setCompositor(wl_compositor* compositor)
{
mCompositor = compositor;
}
void WaylandInterface::setSharedMemory(wl_shm* shared_memory)
{
mBuffer->setSharedMemory(shared_memory);
}
void WaylandInterface::doXdgPong(uint32_t serial)
{
xdg_wm_base_pong(mXdgBase, serial);
}
void WaylandInterface::addWindow(mt::Window* window)
{
WaylandSurface::add(window, mCompositor, mXdgBase, mBuffer, mFontsManager.get(), mEglInterface.get());
}
void WaylandInterface::showWindow(mt::Window* window)
{
window->show();
}
void WaylandInterface::shutDown()
{
if (mDisplay)
{
wl_display_disconnect(mDisplay);
}
}
void WaylandInterface::loop()
{
initialize();
while (wl_display_dispatch(mDisplay) != -1)
{
/* This space deliberately left blank */
}
}

View file

@ -0,0 +1,61 @@
#pragma once
#include "Window.h"
#include "SharedMemory.h"
#include "AbstractUiInterface.h"
#include "wayland-client.h"
#include "xdg-shell-client-protocol.h"
#include <vector>
#include <memory>
class WaylandBuffer;
class WaylandSeatInterface;
class WaylandEglInterface;
class WaylandInterface : public AbstractUIInterface
{
public:
WaylandInterface(DesktopManager* desktopManager, std::unique_ptr<FontsManager> fontsManager, bool useHardware = true);
~WaylandInterface();
void loop() override;
void addWindow(mt::Window* window) override;
void showWindow(mt::Window* window) override;
private:
void initialize() override;
void initializeHardwareRendering() override;
void shutDown() override;
static void registryHandleGlobalEvent(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version);
static void registryHandleGlobalRemoveEvent(void *data, struct wl_registry *registry, uint32_t name);
void doXdgPong(uint32_t serial);
void setCompositor(wl_compositor* compositor);
void setSharedMemory(wl_shm* shared_memory);
void setSeat(wl_seat* seat);
void setXdgBase(xdg_wm_base* xdg_base);
wl_display* mDisplay{nullptr};
wl_compositor* mCompositor{nullptr};
wl_registry_listener mRegistryListener;
xdg_wm_base* mXdgBase{nullptr};
xdg_wm_base_listener mXdgBaseListener;
std::shared_ptr<WaylandBuffer> mBuffer;
std::unique_ptr<WaylandSeatInterface> mSeatInterface;
std::unique_ptr<WaylandEglInterface> mEglInterface;
};

View file

@ -0,0 +1,111 @@
#include "WaylandKeyboard.h"
#include "FileLogger.h"
#include <unistd.h>
#include <sys/mman.h>
void WaylandKeyboard::keyboardKeymapEvent(void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size)
{
auto thisClass = static_cast<WaylandKeyboard*>(data);
thisClass->onKeymapEvent(wl_keyboard, format, fd, size);
}
void WaylandKeyboard::keyboardEnterEvent(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys)
{
auto thisClass = static_cast<WaylandKeyboard*>(data);
thisClass->onEnterEvent(keys);
}
void WaylandKeyboard::keyboardPressedEvent(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
{
auto thisClass = static_cast<WaylandKeyboard*>(data);
thisClass->onPressedEvent(key, state);
}
static void wl_keyboard_leave(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface)
{
}
static void wl_keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int32_t rate, int32_t delay)
{
}
void WaylandKeyboard::keyboardModifierEvent(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
{
auto thisClass = static_cast<WaylandKeyboard*>(data);
thisClass->onKeyboardModifier(mods_depressed, mods_latched, mods_locked, group);
}
void WaylandKeyboard::onKeyboardModifier(uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
{
xkb_state_update_mask(mXkbState, mods_depressed, mods_latched, mods_locked, 0, 0, group);
}
void WaylandKeyboard::onEnterEvent(struct wl_array *keys)
{
void* key;
wl_array_for_each(key, keys)
{
uint32_t* key_type = static_cast<uint32_t*>(key);
char buf[128];
xkb_keysym_t sym = xkb_state_key_get_one_sym(mXkbState, *key_type + 8);
xkb_keysym_get_name(sym, buf, sizeof(buf));
//fprintf(stderr, "sym: %-12s (%d), ", buf, sym);
xkb_state_key_get_utf8(mXkbState, *key_type + 8, buf, sizeof(buf));
//fprintf(stderr, "utf8: '%s'\n", buf);
}
}
void WaylandKeyboard::onPressedEvent(uint32_t key, uint32_t state)
{
char buf[128];
uint32_t keycode = key + 8;
xkb_keysym_t sym = xkb_state_key_get_one_sym(mXkbState, keycode);
xkb_keysym_get_name(sym, buf, sizeof(buf));
const char *action = state == WL_KEYBOARD_KEY_STATE_PRESSED ? "press" : "release";
//fprintf(stderr, "key %s: sym: %-12s (%d), ", action, buf, sym);
xkb_state_key_get_utf8(mXkbState, keycode, buf, sizeof(buf));
//fprintf(stderr, "utf8: '%s'\n", buf);
}
void WaylandKeyboard::onKeymapEvent(struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size)
{
// assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1);
char* map_shm = static_cast<char*>(mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0));
// assert(map_shm != MAP_FAILED);
struct xkb_keymap* xkb_keymap = xkb_keymap_new_from_string(mXkbContext, map_shm, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
munmap(map_shm, size);
close(fd);
struct xkb_state* xkb_state = xkb_state_new(xkb_keymap);
xkb_keymap_unref(mXkbKeymap);
xkb_state_unref(mXkbState);
mXkbKeymap = xkb_keymap;
mXkbState = xkb_state;
}
WaylandKeyboard::WaylandKeyboard(wl_keyboard* keyboard)
: mKeyboard(keyboard)
{
mXkbContext = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
mKeyboardListener.keymap = keyboardKeymapEvent;
mKeyboardListener.enter = keyboardEnterEvent;
mKeyboardListener.key = keyboardPressedEvent;
mKeyboardListener.leave = wl_keyboard_leave;
mKeyboardListener.modifiers = keyboardModifierEvent;
mKeyboardListener.repeat_info = wl_keyboard_repeat_info;
wl_keyboard_add_listener(mKeyboard, &mKeyboardListener, this);
}
WaylandKeyboard::~WaylandKeyboard()
{
wl_keyboard_release(mKeyboard);
}

View file

@ -0,0 +1,34 @@
#pragma once
#include "Keyboard.h"
#include "wayland-client.h"
#include <xkbcommon/xkbcommon.h>
class WaylandKeyboard : public Keyboard
{
public:
WaylandKeyboard(wl_keyboard* keyboard);
~WaylandKeyboard();
std::string getKeyString(KeyCode keyCode) override { return "";};
private:
static void keyboardKeymapEvent(void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size);
static void keyboardEnterEvent(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys);
static void keyboardPressedEvent(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state);
static void keyboardModifierEvent(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group);
void onKeyboardModifier(uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group);
void onKeymapEvent(struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size);
void onEnterEvent(struct wl_array *keys);
void onPressedEvent(uint32_t key, uint32_t state);
wl_keyboard* mKeyboard{nullptr};
xkb_state* mXkbState{nullptr};
xkb_context* mXkbContext{nullptr};
xkb_keymap* mXkbKeymap{nullptr};
wl_keyboard_listener mKeyboardListener;
};

View file

@ -0,0 +1,28 @@
#pragma once
#include "wayland-client.h"
enum pointer_event_mask {
POINTER_EVENT_ENTER = 1 << 0,
POINTER_EVENT_LEAVE = 1 << 1,
POINTER_EVENT_MOTION = 1 << 2,
POINTER_EVENT_BUTTON = 1 << 3,
POINTER_EVENT_AXIS = 1 << 4,
POINTER_EVENT_AXIS_SOURCE = 1 << 5,
POINTER_EVENT_AXIS_STOP = 1 << 6,
POINTER_EVENT_AXIS_DISCRETE = 1 << 7,
};
struct WaylandPointerEvent {
uint32_t event_mask;
wl_fixed_t surface_x, surface_y;
uint32_t button, state;
uint32_t time {0};
uint32_t serial;
struct {
bool valid;
wl_fixed_t value;
int32_t discrete;
} axes[2];
uint32_t axis_source;
};

View file

@ -0,0 +1,127 @@
#include "WaylandPointerInterface.h"
#include "FileLogger.h"
static void wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value)
{
}
static void wl_pointer_axis_source(void *data, struct wl_pointer *wl_pointer, uint32_t axis_source)
{
}
static void wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis)
{
}
static void wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer, uint32_t axis, int32_t discrete)
{
}
WaylandPointerInterface::~WaylandPointerInterface()
{
wl_pointer_release(mPointer);
}
void WaylandPointerInterface::pointerFrameEvent(void *data, struct wl_pointer *wl_pointer)
{
auto thisClass = static_cast<WaylandPointerInterface*>(data);
thisClass->onPointerFrame();
}
void WaylandPointerInterface::pointerEnterEvent(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y)
{
auto thisClass = static_cast<WaylandPointerInterface*>(data);
thisClass->onPointerEnter(serial, surface, surface_x, surface_y);
}
void WaylandPointerInterface::pointerLeaveEvent(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface)
{
auto thisClass = static_cast<WaylandPointerInterface*>(data);
thisClass->onPointerLeave(serial);
}
void WaylandPointerInterface::pointerMotionEvent(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
{
auto thisClass = static_cast<WaylandPointerInterface*>(data);
thisClass->onPointerMotion(time, surface_x, surface_y);
}
void WaylandPointerInterface::pointerButtonEvent(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
{
auto thisClass = static_cast<WaylandPointerInterface*>(data);
thisClass->onPointerButton(serial, time, button, state);
}
void WaylandPointerInterface::onPointerFrame()
{
if (mWorkingPointerEvent.event_mask & POINTER_EVENT_ENTER)
{
const auto locx = wl_fixed_to_double(mWorkingPointerEvent.surface_x);
const auto locy = wl_fixed_to_double(mWorkingPointerEvent.surface_y);
}
else if (mWorkingPointerEvent.event_mask & POINTER_EVENT_LEAVE)
{
}
else if (mWorkingPointerEvent.event_mask & POINTER_EVENT_MOTION)
{
}
else if (mWorkingPointerEvent.event_mask & POINTER_EVENT_BUTTON)
{
const bool released = mWorkingPointerEvent.state == WL_POINTER_BUTTON_STATE_RELEASED;
}
mWorkingPointerEvent = WaylandPointerEvent();
}
void WaylandPointerInterface::onPointerButton(uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
{
mWorkingPointerEvent.event_mask |= POINTER_EVENT_BUTTON;
mWorkingPointerEvent.time = time;
mWorkingPointerEvent.serial = serial;
mWorkingPointerEvent.button = button;
mWorkingPointerEvent.state = state;
}
void WaylandPointerInterface::onPointerEnter(uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y)
{
mWorkingPointerEvent.event_mask |= POINTER_EVENT_ENTER;
mWorkingPointerEvent.serial = serial;
mWorkingPointerEvent.surface_x = surface_x;
mWorkingPointerEvent.surface_y = surface_y;
}
void WaylandPointerInterface::onPointerLeave(uint32_t serial)
{
mWorkingPointerEvent.event_mask |= POINTER_EVENT_LEAVE;
mWorkingPointerEvent.serial = serial;
}
void WaylandPointerInterface::onPointerMotion(uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
{
mWorkingPointerEvent.event_mask |= POINTER_EVENT_MOTION;
mWorkingPointerEvent.time = time;
mWorkingPointerEvent.surface_x = surface_x;
mWorkingPointerEvent.surface_y = surface_y;
}
WaylandPointerInterface::WaylandPointerInterface(wl_pointer* pointer)
: mPointer(pointer)
{
mPointerListener.enter = pointerEnterEvent;
mPointerListener.leave = pointerLeaveEvent;
mPointerListener.button = pointerButtonEvent;
mPointerListener.motion = pointerMotionEvent;
mPointerListener.axis = wl_pointer_axis;
mPointerListener.axis_discrete = wl_pointer_axis_discrete;
mPointerListener.axis_source = wl_pointer_axis_source;
mPointerListener.axis_stop = wl_pointer_axis_stop;
mPointerListener.frame = pointerFrameEvent;
wl_pointer_add_listener(mPointer, &mPointerListener, this);
}

View file

@ -0,0 +1,29 @@
#pragma once
#include "WaylandPointerEvent.h"
class WaylandPointerInterface
{
public:
WaylandPointerInterface(wl_pointer* pointer);
~WaylandPointerInterface();
private:
static void pointerEnterEvent(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y);
static void pointerLeaveEvent(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface);
static void pointerMotionEvent(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y);
static void pointerButtonEvent(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state);
static void pointerFrameEvent(void *data, struct wl_pointer *wl_pointer);
void onPointerButton(uint32_t serial, uint32_t time, uint32_t button, uint32_t state);
void onPointerLeave(uint32_t serial);
void onPointerEnter(uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y);
void onPointerMotion(uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y);
void onPointerFrame();
wl_pointer* mPointer{nullptr};
wl_pointer_listener mPointerListener;
WaylandPointerEvent mWorkingPointerEvent;
};

View file

@ -0,0 +1,48 @@
#include "WaylandSeatInterface.h"
#include "FileLogger.h"
void WaylandSeatInterface::seatCapabilitiesEvent(void *data, struct wl_seat *wl_seat, uint32_t capabilities)
{
auto thisClass = static_cast<WaylandSeatInterface*>(data);
thisClass->onSeatCapabilitiesEvent(capabilities);
}
void WaylandSeatInterface::onSeatCapabilitiesEvent(uint32_t capabilities)
{
const bool have_pointer = capabilities & WL_SEAT_CAPABILITY_POINTER;
if (have_pointer && mPointerInterface == nullptr)
{
auto pointer = wl_seat_get_pointer(mSeat);
mPointerInterface = std::make_unique<WaylandPointerInterface>(pointer);
}
else if (!have_pointer && mPointerInterface!= nullptr)
{
mPointerInterface.reset();
}
const bool have_keyboard = capabilities & WL_SEAT_CAPABILITY_KEYBOARD;
if (have_keyboard && mKeyboard == nullptr)
{
auto keyboard = wl_seat_get_keyboard(mSeat);
mKeyboard = std::make_unique<WaylandKeyboard>(keyboard);
}
else if (!have_keyboard && mKeyboard!= nullptr)
{
mKeyboard.reset();
}
}
WaylandSeatInterface::WaylandSeatInterface(wl_seat* seat)
: mSeat(seat)
{
mSeatListener.capabilities = seatCapabilitiesEvent;
mSeatListener.name = seatNameEvent;
wl_seat_add_listener(mSeat, &mSeatListener, this);
}
void WaylandSeatInterface::seatNameEvent(void *data, struct wl_seat *wl_seat, const char *name)
{
MLOG_INFO("seat name: " << name);
}

View file

@ -0,0 +1,27 @@
#pragma once
#include "WaylandPointerInterface.h"
#include "WaylandKeyboard.h"
#include "wayland-client.h"
#include <memory>
class WaylandSeatInterface
{
public:
WaylandSeatInterface(wl_seat* seat);
private:
static void seatCapabilitiesEvent(void *data, struct wl_seat *wl_seat, uint32_t capabilities);
static void seatNameEvent(void *data, struct wl_seat *wl_seat, const char *name);
void onSeatCapabilitiesEvent(uint32_t capabilities);
wl_seat* mSeat{nullptr};
wl_seat_listener mSeatListener;
std::unique_ptr<WaylandKeyboard> mKeyboard;
std::unique_ptr<WaylandPointerInterface> mPointerInterface;
};

View file

@ -0,0 +1,140 @@
#include "WaylandSurface.h"
#include "WaylandEglWindowInterface.h"
#include "ImagePrimitives.h"
#include "DrawingContext.h"
#include "FontsManager.h"
void WaylandSurface::add(mt::Window* window, wl_compositor* compositor, xdg_wm_base* xdg_wm_base, std::shared_ptr<WaylandBuffer> buffer, FontsManager* fontsManager, WaylandEglInterface* eglInterface)
{
auto wayland_window = std::make_unique<WaylandSurface>(window, compositor, xdg_wm_base, buffer, eglInterface);
const auto drawing_mode = eglInterface ? DrawingMode::GRAPH : DrawingMode::RASTER;
window->setPlatformWindow(std::move(wayland_window), fontsManager, drawing_mode);
}
WaylandSurface::WaylandSurface(mt::Window* window, wl_compositor* compositor, xdg_wm_base* xdg_wm_base, std::shared_ptr<WaylandBuffer> buffer, WaylandEglInterface* eglInterface)
: IPlatformWindow(window),
mCompositor(compositor),
mXdgWmBase(xdg_wm_base),
mBuffer(buffer)
{
if (eglInterface)
{
mEglWindowInterface = std::make_unique<WaylandEglWindowInterface>(eglInterface);
}
}
WaylandSurface::~WaylandSurface()
{
}
void WaylandSurface::show()
{
map();
}
void WaylandSurface::clear()
{
}
void WaylandSurface::map()
{
if (!mSurface)
{
initialize();
}
}
void WaylandSurface::initialize()
{
mSurface = wl_compositor_create_surface(mCompositor);
mXdgSurface = xdg_wm_base_get_xdg_surface(mXdgWmBase, mSurface);
auto xdg_surface_configure = [](void *data, struct xdg_surface *xdg_surface, uint32_t serial)
{
auto thisClass = static_cast<WaylandSurface*>(data);
thisClass->onConfigure(xdg_surface, serial);
};
mXdgSurfaceListener.configure = xdg_surface_configure;
xdg_surface_add_listener(mXdgSurface, &mXdgSurfaceListener, this);
mXdgTopLevel = xdg_surface_get_toplevel(mXdgSurface);
xdg_toplevel_set_title(mXdgTopLevel, "Example client");
auto region = wl_compositor_create_region(mCompositor);
wl_region_add(region, 0, 0, mWindow->getWidth(), mWindow->getHeight());
wl_surface_set_opaque_region(mSurface, region);
wl_surface_commit(mSurface);
}
void WaylandSurface::onConfigure(xdg_surface *xdg_surface, uint32_t serial)
{
xdg_surface_ack_configure(xdg_surface, serial);
beforePaint(nullptr);
}
void WaylandSurface::beforePaint(mt::Screen* screen)
{
if (mEglWindowInterface)
{
mEglWindowInterface->initialize(mSurface, mWindow->getWidth(), mWindow->getHeight());
mEglWindowInterface->beforePaint();
}
else
{
beforePaintSoftware();
}
}
void WaylandSurface::afterPaint(mt::Screen* screen)
{
if (mEglWindowInterface)
{
mEglWindowInterface->afterPaint();
}
else
{
afterPaintSoftware();
}
}
unsigned WaylandSurface::getImageBufferSize() const
{
const auto width = mWindow->getWidth();
const auto height = mWindow->getHeight();
const int stride = width * mWorkingBitDepth;
//const int numBuffers = 2; // i.e. front/back
return height * stride * mNumFrameBuffers;
}
void WaylandSurface::beforePaintSoftware()
{
const auto width = mWindow->getWidth();
const auto height = mWindow->getHeight();
const int stride = width * mWorkingBitDepth;
const int shm_pool_size = getImageBufferSize();
mBuffer->initializeSharedBuffer(shm_pool_size);
mBuffer->setUpPool(shm_pool_size, width, height, stride);
//ImagePrimitives::drawCheckerboard(mBuffer->getPoolData(), width, height, offset);
}
void WaylandSurface::afterPaintSoftware()
{
const int shm_pool_size = getImageBufferSize();
mBuffer->tearDownPool(shm_pool_size);
wl_surface_attach(mSurface, mBuffer->getWorkingBuffer(), 0, 0);
//wl_surface_damage(mSurface, 0, 0, UINT32_MAX, UINT32_MAX);
wl_surface_commit(mSurface);
}

View file

@ -0,0 +1,71 @@
#pragma once
#include "xdg-shell-client-protocol.h"
#include "wayland-client.h"
#include "Window.h"
#include "SharedMemory.h"
#include "WaylandBuffer.h"
#include "IPlatformWindow.h"
struct wl_surface;
struct xdg_surface;
struct xdg_toplevel;
class WaylandEglInterface;
class WaylandEglWindowInterface;
class FontsManager;
class WaylandSurface : public IPlatformWindow
{
public:
static void add(mt::Window* window, wl_compositor* compositor, xdg_wm_base* xdg_wm_base, std::shared_ptr<WaylandBuffer> buffer, FontsManager* fontsManager, WaylandEglInterface* eglInterface);
WaylandSurface(mt::Window* window, wl_compositor* compositor, xdg_wm_base* xdg_wm_base, std::shared_ptr<WaylandBuffer> buffer, WaylandEglInterface* eglInterface);
~WaylandSurface();
void onConfigure(xdg_surface *xdg_surface, uint32_t serial);
void show();
void map();
void clear();
void onResize(unsigned width, unsigned height)
{
}
private:
void initialize();
void beforePaint(mt::Screen* screen) override;
void afterPaint(mt::Screen* screen) override;
void beforePaintSoftware();
void afterPaintSoftware();
unsigned getImageBufferSize() const;
mt::Window* mWindow{nullptr};
wl_compositor* mCompositor{nullptr};
xdg_wm_base* mXdgWmBase{nullptr};
std::shared_ptr<WaylandBuffer> mBuffer;
std::unique_ptr<WaylandEglWindowInterface> mEglWindowInterface;
wl_surface* mSurface{nullptr};
xdg_surface* mXdgSurface{nullptr};
xdg_surface_listener mXdgSurfaceListener;
xdg_toplevel* mXdgTopLevel{nullptr};
unsigned mWorkingBitDepth{4};
unsigned mNumFrameBuffers{1};
};
using WaylandSurfacePtr = std::unique_ptr<WaylandSurface>;

View file

@ -0,0 +1,71 @@
#include "Win32UIInterface.h"
#include "DesktopManager.h"
#include "DirectXInterface.h"
#include "DirectX2dInterface.h"
#include <d3d12.h>
#include <dxgi.h>
#include <dxgi1_6.h>
#include <Windows.h>
Win32UIInterface::Win32UIInterface(DesktopManager* desktopManager, bool useHardware)
: AbstractUIInterface(desktopManager, useHardware),
mWindowInterface(std::make_unique<Win32WindowInterface>())
{
}
void Win32UIInterface::initialize()
{
if (mUseHardwareRendering)
{
initializeHardwareRendering();
}
const auto num_windows = mDesktopManager->getWindowManager()->getNumWindows();
for (std::size_t idx = 0; idx < num_windows; idx++)
{
addWindow(mDesktopManager->getWindowManager()->getWindow(idx));
}
showWindow(mDesktopManager->getWindowManager()->getMainWindow());
}
void Win32UIInterface::loop()
{
initialize();
// Run the message loop.
MSG msg = { };
while (::GetMessage(&msg, NULL, 0, 0))
{
if (msg.message == WM_QUIT)
{
break;
}
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
void Win32UIInterface::shutDown()
{
}
void Win32UIInterface::showWindow(mt::Window* window)
{
mWindowInterface->show(window);
}
void Win32UIInterface::addWindow(mt::Window* window)
{
mWindowInterface->add(window, mDesktopManager, mDxInterface.get());
}
void Win32UIInterface::initializeHardwareRendering()
{
mDxInterface = std::make_unique<DirectXInterface>();
mDxInterface->initialize();
}

View file

@ -0,0 +1,34 @@
#pragma once
#include "Window.h"
#include "Win32WindowInterface.h"
#include "AbstractUiInterface.h"
class DesktopManager;
class DirectXInterface;
using DirectXInterfacePtr = std::unique_ptr<DirectXInterface>;
class Win32UIInterface : public AbstractUIInterface
{
public:
Win32UIInterface(DesktopManager* desktopManager, bool useHardware = false);
~Win32UIInterface() = default;
void addWindow(mt::Window* window) override;
void initialize() override;
void loop() override;
void shutDown() override;
void showWindow(mt::Window* window) override;
private:
void initializeHardwareRendering() override;
Win32WindowInterfacePtr mWindowInterface;
DirectXInterfacePtr mDxInterface;
};

View file

@ -0,0 +1,268 @@
#include "Win32Window.h"
#include "Win32WindowInterface.h"
#include "DirectXInterface.h"
#include "Win32DxWindowInterface.h"
#include "FileLogger.h"
#include "UnicodeUtils.h"
#include "Widget.h"
#include "DrawingContext.h"
#include "DirectXPainter.h"
#include "KeyboardEvent.h"
#include "DesktopManager.h"
#include <WinUser.h>
#include <windowsx.h>
LRESULT CALLBACK FreeWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
Win32Window::Win32Window(mt::Window* window, DirectXInterface* dxInterface)
: IPlatformWindow(window)
{
if (dxInterface)
{
mDxInterface = std::make_unique<Win32DxWindowInterface>(window, dxInterface);
dynamic_cast<DirectXPainter*>(window->getDrawingContent()->getPainter())->setDxInterface(dxInterface);
}
}
std::unique_ptr<Win32Window> Win32Window::Create(mt::Window* window, DirectXInterface* dxInterface)
{
return std::make_unique<Win32Window>(window, dxInterface);
}
HWND Win32Window::getHandle() const
{
return mHandle;
}
void Win32Window::createNative(Win32ApplicationContext* context, DesktopManager* desktopManager)
{
mDesktopManager = desktopManager;
const char CLASS_NAME[] = "Sample Window Class";
auto hInstance = reinterpret_cast<HINSTANCE>(context->hInstance);
WNDCLASS wc = { };
wc.lpfnWndProc = FreeWindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
MLOG_INFO("Request window create");
mHandle = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class
"Notes TK", // Window text
WS_OVERLAPPEDWINDOW, // Window style
// Size and position
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
nullptr, // Parent window
nullptr, // Menu
hInstance, // Instance handle
this // Additional application data
);
if (mHandle == nullptr)
{
LPVOID lpMsgBuf;
auto dw = ::GetLastError();
::FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, dw,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL);
MLOG_INFO("Request window failed: " << dw);
LocalFree(lpMsgBuf);
}
MLOG_INFO("Request window create got handle: " << "0x" << mHandle);
}
void Win32Window::onPaintMessage()
{
mDesktopManager->onUiEvent(PaintEvent::Create());
mWindow->doPaint(nullptr);
}
void Win32Window::onMouseDownMessage(int x, int y)
{
auto event = MouseEvent::Create();
event->setClientLocation({ static_cast<unsigned>(x), static_cast<unsigned>(y) });
event->setAction(MouseEvent::Action::Pressed);
mDesktopManager->onUiEvent(std::move(event));
MLOG_INFO("Mouse down at: " << x << " , " << y);
}
void Win32Window::onMouseUpMessage(int x, int y)
{
auto event = MouseEvent::Create();
event->setClientLocation({ static_cast<unsigned>(x), static_cast<unsigned>(y) });
event->setAction(MouseEvent::Action::Released);
mDesktopManager->onUiEvent(std::move(event));
MLOG_INFO("Mouse up at: " << x << " , " << y);
}
LRESULT CALLBACK Win32Window::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
case WM_CHAR:
{
auto key_event = std::make_unique<KeyboardEvent>();
key_event->setAction(KeyboardEvent::Action::Pressed);
auto keyChar = (wchar_t)wParam;
key_event->setKeyString(UnicodeUtils::utf16ToUtf8String(std::wstring(1, keyChar)));
mDesktopManager->onUiEvent(std::move(key_event));
return 0;
}
case WM_PAINT:
{
onPaintMessage();
return 0;
}
case WM_LBUTTONDOWN :
{
const auto x = GET_X_LPARAM(lParam);
const auto y = GET_Y_LPARAM(lParam);
onMouseDownMessage(x, y);
return 0;
}
case WM_LBUTTONUP:
{
const auto x = GET_X_LPARAM(lParam);
const auto y = GET_Y_LPARAM(lParam);
onMouseUpMessage(x, y);
return 0;
}
case WM_SIZE:
{
auto width = LOWORD(lParam);
auto height = HIWORD(lParam);
MLOG_INFO("WM_SIZE: " << width << " | " << height);
mWindow->setSize(width, height, false);
if (wParam == SIZE_MINIMIZED)
{
mWindow->setDisplayState(WindowState::Display::MINIMIZED);
}
else if (wParam == SIZE_MAXIMIZED)
{
mWindow->setDisplayState(WindowState::Display::MAXIMIZED);
mWindow->onResize();
}
else if (wParam == SIZE_RESTORED)
{
if (mWindow->getDisplayState() == WindowState::Display::MINIMIZED)
{
mWindow->setDisplayState(WindowState::Display::NORMAL);
mWindow->onResize();
}
else if (mWindow->getDisplayState() == WindowState::Display::MAXIMIZED)
{
mWindow->setDisplayState(WindowState::Display::NORMAL);
mWindow->onResize();
}
else if (!mWindow->getIsSizingOnGoing())
{
mWindow->onResize();
}
}
return 0;
}
case WM_ENTERSIZEMOVE:
{
MLOG_INFO("WM_ENTERSIZEMOVE");
mWindow->setIsSizingOnGoing(true);
return 0;
}
case WM_EXITSIZEMOVE:
{
MLOG_INFO("WM_EXITSIZEMOVE");
mWindow->setIsSizingOnGoing(false);
mWindow->onResize();
return 0;
}
}
return DefWindowProc(mHandle, message, wParam, lParam);
}
static LRESULT CALLBACK FreeWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
Win32Window* window;
if (uMsg == WM_NCCREATE)
{
CREATESTRUCT* cs = (CREATESTRUCT*)lParam;
window = (Win32Window*)cs->lpCreateParams;
SetLastError(0);
if (::SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)window) == 0)
{
if (GetLastError() != 0)
{
return FALSE;
}
}
}
else
{
window = (Win32Window*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
}
if (window)
{
window->setHandle(hwnd);
return window->WindowProc(uMsg, wParam, lParam);
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
void Win32Window::beforePaint(mt::Screen* screen)
{
if (mDxInterface)
{
mDxInterface->initialize();
}
}
void Win32Window::afterPaint(mt::Screen* screen)
{
if (mDxInterface)
{
mDxInterface->onRender();
}
else
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(mHandle, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
auto text = L"Hello World";
auto val = DrawText(hdc, (LPCSTR)(&text[0]), -1, &ps.rcPaint, 0);
EndPaint(mHandle, &ps);
}
}
void Win32Window::onResize(unsigned width, unsigned height)
{
if (mDxInterface)
{
mDxInterface->onResize();
}
}

View file

@ -0,0 +1,63 @@
#pragma once
#include "IPlatformWindow.h"
#include <Windows.h>
class Win32ApplicationContext;
class Win32DxWindowInterface;
class DesktopManager;
class DirectXInterface;
class Win32Window : public IPlatformWindow
{
public:
Win32Window(mt::Window* window, DirectXInterface* dxInterface = nullptr);
virtual ~Win32Window() = default;
static std::unique_ptr<Win32Window> Create(mt::Window* window, DirectXInterface* dxInterface = nullptr);
LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
HWND getHandle() const;
void setHandle(HWND handle)
{
mHandle = handle;
}
int getCmdShow() const
{
return mCmdShow;
}
void setCmdShow(int cmdShow)
{
mCmdShow = cmdShow;
}
void createNative(Win32ApplicationContext* context, DesktopManager* desktopManager);
void show() {};
void map() {};
void clear() {};
void onResize(unsigned width, unsigned height);
void beforePaint(mt::Screen* screen);
void afterPaint(mt::Screen* screen);
private:
void onMouseDownMessage(int x, int y);
void onMouseUpMessage(int x, int y);
void onPaintMessage();
HWND mHandle{ 0 };
int mCmdShow{ 0 };
DesktopManager* mDesktopManager{ nullptr };
std::unique_ptr<Win32DxWindowInterface> mDxInterface;
};

View file

@ -0,0 +1,36 @@
#include "Win32WindowInterface.h"
#include "Win32Window.h"
#include "DesktopManager.h"
#include "DrawingContext.h"
#include "DirectXInterface.h"
#include "Widget.h"
#include "FileLogger.h"
#include <Windows.h>
Win32WindowInterface::Win32WindowInterface()
{
}
void Win32WindowInterface::show(mt::Window* window)
{
auto platformWindow = dynamic_cast<Win32Window*>(window->getPlatformWindow());
MLOG_INFO("Showing platform window: " << platformWindow->getHandle());
::ShowWindow(platformWindow->getHandle(), platformWindow->getCmdShow());
}
void Win32WindowInterface::add(mt::Window* window, DesktopManager* desktopManager, DirectXInterface* dxInterface)
{
auto context = dynamic_cast<Win32ApplicationContext*>(desktopManager->getMainApp()->GetApplicationContext());
auto win32_window = Win32Window::Create(window, dxInterface);
win32_window->createNative(context, desktopManager);
win32_window->setCmdShow(context->nCmdShow);
window->setPlatformWindow(std::move(win32_window));
window->getPlatformWindow()->beforePaint(nullptr);
}

View file

@ -0,0 +1,31 @@
#pragma once
#include "Window.h"
#include "AbstractApp.h"
#include <Windows.h>
#include <memory>
class DesktopManager;
class FontsManager;
class DirectXInterface;
class Win32ApplicationContext : public IApplicationContext
{
public:
void* hInstance{ nullptr };
int nCmdShow{ 0 };
};
class Win32WindowInterface
{
public:
Win32WindowInterface();
void add(mt::Window* window, DesktopManager* desktopManager, DirectXInterface* dxInterface = nullptr);
void show(mt::Window* window);
};
using Win32WindowInterfacePtr = std::unique_ptr<Win32WindowInterface>;

View file

@ -0,0 +1,94 @@
#include "DirectX2dIntegration.h"
#include "Window.h"
#include "Widget.h"
#include "DirectXPainter.h"
#include "DrawingContext.h"
#include "DirectXInterface.h"
#include "DirectX2dInterface.h"
#include <d3d11.h>
#include <d3d11on12.h>
#include <d2d1_3.h>
#include <d2d1_1.h>
DirectX2dIntegration::DirectX2dIntegration(mt::Window* window, DirectXInterface* dxInterface, UINT frameCount)
: mDxInterface(dxInterface),
mWindow(window),
mFrameCount(frameCount)
{
mDx2dInterface = dxInterface->getD2dInterface();
}
ID3D11Resource* const* DirectX2dIntegration::getD11on12WrappedBackBuffer() const
{
return mWrappedBackBuffers[mFrameIndex].GetAddressOf();
}
ID2D1Bitmap1* DirectX2dIntegration::getD2dRenderTarget() const
{
return mD2dRenderTargets[mFrameIndex].Get();
}
void DirectX2dIntegration::render()
{
// Acquire our wrapped render target resource for the current back buffer.
mDxInterface->get11On12Device()->AcquireWrappedResources(getD11on12WrappedBackBuffer(), 1);
// Render text directly to the back buffer.
mDx2dInterface->getContext()->SetTarget(getD2dRenderTarget());
mWindow->getDrawingContent()->getPainter()->paint();
// Release our wrapped render target resource. Releasing
// transitions the back buffer resource to the state specified
// as the OutState when the wrapped resource was created.
mDxInterface->get11On12Device()->ReleaseWrappedResources(getD11on12WrappedBackBuffer(), 1);
// Flush to submit the 11 command list to the shared command queue.
mDxInterface->getD3d11DeviceContext()->Flush();
}
void DirectX2dIntegration::clearBuffers()
{
for (auto& buffer : mWrappedBackBuffers)
{
buffer.Reset();
}
mWrappedBackBuffers.clear();
for (auto& buffer : mD2dRenderTargets)
{
buffer.Reset();
}
mD2dRenderTargets.clear();
mDx2dInterface->getContext()->SetTarget(nullptr);
mDxInterface->getD3d11DeviceContext()->Flush();
}
void DirectX2dIntegration::wrapBuffer(ID3D12Resource* renderTarget)
{
mWrappedBackBuffers.push_back(Microsoft::WRL::ComPtr<ID3D11Resource>());
D3D11_RESOURCE_FLAGS d3d11Flags = { D3D11_BIND_RENDER_TARGET };
mDxInterface->get11On12Device()->CreateWrappedResource(renderTarget, &d3d11Flags,
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT, IID_PPV_ARGS(&mWrappedBackBuffers[mWrappedBackBuffers.size()-1]));
float dpiX{ 96.0 };
float dpiY{ 96.0 };
//mDx2dInterface->getFactory()->GetDesktopDpi(&dpiX, &dpiY);
const auto pixel_format = D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED);
const auto bitmap_props = D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW, pixel_format, dpiX, dpiY);
mD2dRenderTargets.push_back(Microsoft::WRL::ComPtr<ID2D1Bitmap1>());
Microsoft::WRL::ComPtr<IDXGISurface> surface;
mWrappedBackBuffers[mWrappedBackBuffers.size() - 1].As(&surface);
mDx2dInterface->getContext()->CreateBitmapFromDxgiSurface(surface.Get(), &bitmap_props, &mD2dRenderTargets[mD2dRenderTargets.size()-1]);
}
void DirectX2dIntegration::updateBackbufferIndex(UINT idx)
{
mFrameIndex = idx;
}

View file

@ -0,0 +1,43 @@
#pragma once
#include <wrl.h>
#include <stdint.h>
#include <vector>
class DirectXInterface;
class DirectX2dInterface;
namespace mt
{
class Window;
}
struct ID3D12Resource;
struct ID3D11Resource;
struct ID2D1Bitmap1;
class DirectX2dIntegration
{
public:
DirectX2dIntegration(mt::Window* window, DirectXInterface* dxInterface, UINT frameCount);
void clearBuffers();
void render();
void updateBackbufferIndex(UINT idx);
void wrapBuffer(ID3D12Resource* referenceBuffer);
private:
ID3D11Resource* const* getD11on12WrappedBackBuffer() const;
ID2D1Bitmap1* getD2dRenderTarget() const;
DirectXInterface* mDxInterface{ nullptr };
DirectX2dInterface* mDx2dInterface{ nullptr };
mt::Window* mWindow{ nullptr };
UINT mFrameCount{ 2 };
UINT mFrameIndex{ 0 };
std::vector<Microsoft::WRL::ComPtr<ID3D11Resource> > mWrappedBackBuffers;
std::vector<Microsoft::WRL::ComPtr<ID2D1Bitmap1> > mD2dRenderTargets;
};

View file

@ -0,0 +1,109 @@
#include "DirectXBuffers.h"
#include "DirectXDescriptors.h"
#include "FileLogger.h"
#include <dxgi.h>
#include <dxgi1_6.h>
#include <d3d12.h>
#include <directx/d3dx12.h>
DirectXBuffers::DirectXBuffers(UINT frameCount)
: mFrameCount(frameCount)
{
}
void DirectXBuffers::clear()
{
for (auto& buffer : mBackBuffers)
{
auto count = buffer.Reset();
}
mBackBuffers.clear();
mDepthStencilBuffer.Reset();
mInitialized = false;
}
bool DirectXBuffers::isInitialized()
{
return mInitialized;
}
UINT DirectXBuffers::getCurrentBackBufferIndex() const
{
return mBackBufferIndex;
}
ID3D12Resource* DirectXBuffers::getCurrentBackBuffer() const
{
return mBackBuffers[mBackBufferIndex].Get();
}
ID3D12Resource* DirectXBuffers::getBackBuffer(UINT index) const
{
return mBackBuffers[index].Get();
}
ID3D12Resource* DirectXBuffers::getDepthStencilBuffer() const
{
return mDepthStencilBuffer.Get();
}
void DirectXBuffers::updateBackbufferIndex(UINT index)
{
mBackBufferIndex = index;
}
void DirectXBuffers::setupBackBuffers(ID3D12Device* device, IDXGISwapChain4* swapChain, DirectXDescriptors* descriptors)
{
CD3DX12_CPU_DESCRIPTOR_HANDLE rtv_heap_handle(descriptors->getRtvHandle());
for (UINT i = 0; i < mFrameCount; i++)
{
mBackBuffers.push_back(Microsoft::WRL::ComPtr<ID3D12Resource>());
swapChain->GetBuffer(i, IID_PPV_ARGS(&mBackBuffers[mBackBuffers.size()-1]));
device->CreateRenderTargetView(mBackBuffers[mBackBuffers.size() - 1].Get(), nullptr, rtv_heap_handle);
rtv_heap_handle.Offset(1, descriptors->getRtvDescriptorSize());
}
mInitialized = true;
}
void DirectXBuffers::setupDepthStencilHeap(ID3D12Device* device, unsigned width, unsigned height)
{
D3D12_RESOURCE_DESC depthStencilDesc;
depthStencilDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
depthStencilDesc.Alignment = 0;
depthStencilDesc.Width = width;
depthStencilDesc.Height = height;
depthStencilDesc.DepthOrArraySize = 1;
depthStencilDesc.MipLevels = 1;
depthStencilDesc.Format = DXGI_FORMAT_R24G8_TYPELESS;
depthStencilDesc.SampleDesc.Count = 1;
depthStencilDesc.SampleDesc.Quality = 0;
depthStencilDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
depthStencilDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
D3D12_CLEAR_VALUE optClear;
optClear.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
optClear.DepthStencil.Depth = 1.0f;
optClear.DepthStencil.Stencil = 0;
auto props = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);
device->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE,
&depthStencilDesc, D3D12_RESOURCE_STATE_COMMON, &optClear, IID_PPV_ARGS(mDepthStencilBuffer.GetAddressOf()));
}
void DirectXBuffers::setupDepthStencilView(ID3D12Device* device, DirectXDescriptors* descriptors)
{
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc;
dsvDesc.Flags = D3D12_DSV_FLAG_NONE;
dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
dsvDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
dsvDesc.Texture2D.MipSlice = 0;
device->CreateDepthStencilView(mDepthStencilBuffer.Get(), &dsvDesc, descriptors->getDsvHandle());
}

View file

@ -0,0 +1,42 @@
#pragma once
#include <wrl.h>
#include <vector>
class DirectXDescriptors;
struct ID3D12Resource;
struct ID3D12Device;
struct IDXGISwapChain4;
class DirectXBuffers
{
public:
DirectXBuffers(UINT frameCount);
void clear();
UINT getCurrentBackBufferIndex() const;
ID3D12Resource* getCurrentBackBuffer() const;
ID3D12Resource* getBackBuffer(UINT index) const;
ID3D12Resource* getDepthStencilBuffer() const;
bool isInitialized();
void setupBackBuffers(ID3D12Device* device, IDXGISwapChain4* swapChain, DirectXDescriptors* descriptors);
void setupDepthStencilHeap(ID3D12Device* device, unsigned width, unsigned height);
void setupDepthStencilView(ID3D12Device* device, DirectXDescriptors* descriptors);
void updateBackbufferIndex(UINT index);
private:
bool mInitialized{ false };
UINT mFrameCount{ 2 };
UINT mBackBufferIndex{ 0 };
std::vector<Microsoft::WRL::ComPtr<ID3D12Resource> > mBackBuffers;
Microsoft::WRL::ComPtr<ID3D12Resource> mDepthStencilBuffer;
};

View file

@ -0,0 +1,37 @@
#include "DirectXCommandList.h"
#include <d3d12.h>
void DirectXCommandList::close()
{
mCommandList->Close();
}
void DirectXCommandList::create(ID3D12Device* device, ID3D12PipelineState* pso)
{
device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&mCommandAllocator));
device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, mCommandAllocator.Get(), pso, IID_PPV_ARGS(&mCommandList));
mCommandList->Close();
}
ID3D12GraphicsCommandList* DirectXCommandList::get() const
{
return mCommandList.Get();
}
void DirectXCommandList::execute(ID3D12CommandQueue* queue)
{
ID3D12CommandList* ppCommandLists[] = { mCommandList.Get() };
queue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
}
void DirectXCommandList::reset(ID3D12PipelineState* pso)
{
mCommandList->Reset(mCommandAllocator.Get(), pso);
}
void DirectXCommandList::resetAllocator()
{
mCommandAllocator->Reset();
}

View file

@ -0,0 +1,29 @@
#pragma once
#include <wrl.h>
struct ID3D12CommandAllocator;
struct ID3D12GraphicsCommandList;
struct ID3D12PipelineState;
struct ID3D12CommandQueue;
struct ID3D12Device;
class DirectXCommandList
{
public:
void close();
void create(ID3D12Device* device, ID3D12PipelineState* pso);
ID3D12GraphicsCommandList* get() const;
void execute(ID3D12CommandQueue* queue);
void resetAllocator();
void reset(ID3D12PipelineState* pso);
private:
Microsoft::WRL::ComPtr<ID3D12CommandAllocator> mCommandAllocator;
Microsoft::WRL::ComPtr<ID3D12GraphicsCommandList> mCommandList;
};

View file

@ -0,0 +1,76 @@
#include "DirectXDescriptors.h"
#include <directx/d3dx12.h>
UINT DirectXDescriptors::getRtvDescriptorSize() const
{
return mRtvDescriptorSize;
}
D3D12_CPU_DESCRIPTOR_HANDLE DirectXDescriptors::getRtvHandle(int index) const
{
if (index == -1)
{
return CD3DX12_CPU_DESCRIPTOR_HANDLE(mRtvHeap->GetCPUDescriptorHandleForHeapStart());
}
else
{
return CD3DX12_CPU_DESCRIPTOR_HANDLE(mRtvHeap->GetCPUDescriptorHandleForHeapStart(), index, mRtvDescriptorSize);
}
}
D3D12_CPU_DESCRIPTOR_HANDLE DirectXDescriptors::getDsvHandle() const
{
return mDsvHeap->GetCPUDescriptorHandleForHeapStart();
}
void DirectXDescriptors::updateDescriptorSizes(ID3D12Device* device)
{
mRtvDescriptorSize = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
mDsvDescriptorSize = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
mCbvSrvDescriptorSize = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
}
void DirectXDescriptors::setupDefaultDescriptorHeaps(ID3D12Device* device, unsigned numFrames)
{
updateDescriptorSizes(device);
setupRtvDescriptorHeap(device, numFrames);
setupDsvDescriptorHeap(device);
}
void DirectXDescriptors::setupRtvDescriptorHeap(ID3D12Device* device, unsigned numFrames)
{
D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {};
rtvHeapDesc.NumDescriptors = numFrames;
rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&mRtvHeap));
}
void DirectXDescriptors::setupDsvDescriptorHeap(ID3D12Device* device)
{
D3D12_DESCRIPTOR_HEAP_DESC dsvHeapDesc = {};
dsvHeapDesc.NumDescriptors = 1;
dsvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
dsvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
dsvHeapDesc.NodeMask = 0;
device->CreateDescriptorHeap(&dsvHeapDesc, IID_PPV_ARGS(&mDsvHeap));
}
void DirectXDescriptors::setupSrvDescriptorHeap(ID3D12Device* device)
{
D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {};
srvHeapDesc.NumDescriptors = 1;
srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
device->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&mSrvHeap));
}
void DirectXDescriptors::setupCbvDescriptorHeap(ID3D12Device* device)
{
D3D12_DESCRIPTOR_HEAP_DESC cbvHeapDesc = {};
cbvHeapDesc.NumDescriptors = 1;
cbvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
cbvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
device->CreateDescriptorHeap(&cbvHeapDesc, IID_PPV_ARGS(&mCbvHeap));
}

View file

@ -0,0 +1,29 @@
#pragma once
#include <wrl.h>
#include <d3d12.h>
class DirectXDescriptors
{
public:
UINT getRtvDescriptorSize() const;
D3D12_CPU_DESCRIPTOR_HANDLE getRtvHandle(int index = -1) const;
D3D12_CPU_DESCRIPTOR_HANDLE getDsvHandle() const;
void setupDefaultDescriptorHeaps(ID3D12Device* device, unsigned numFrames = 2);
private:
void updateDescriptorSizes(ID3D12Device* device);
void setupRtvDescriptorHeap(ID3D12Device* device, unsigned numFrames);
void setupDsvDescriptorHeap(ID3D12Device* device);
void setupSrvDescriptorHeap(ID3D12Device* device);
void setupCbvDescriptorHeap(ID3D12Device* device);
UINT mRtvDescriptorSize{ 0 };
UINT mDsvDescriptorSize{ 0 };
UINT mCbvSrvDescriptorSize{ 0 };
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> mRtvHeap;
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> mDsvHeap;
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> mSrvHeap;
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> mCbvHeap;
};

View file

@ -0,0 +1,297 @@
#include "Win32DxWindowInterface.h"
#include "DirectXInterface.h"
#include "Win32Window.h"
#include "Window.h"
#include "Widget.h"
#include "FileLogger.h"
#include "DirectXDescriptors.h"
#include "DirectX2dIntegration.h"
#include "DirectXBuffers.h"
#include "DirectXCommandList.h"
#include "DrawingContext.h"
#include "DirectXPainter.h"
#include "DirectXMeshPainter.h"
#include <dxgi.h>
#include <dxgi1_6.h>
#include <d3d12sdklayers.h>
#include <D3Dcommon.h>
Win32DxWindowInterface::Win32DxWindowInterface(mt::Window* window, DirectXInterface* dxInterface)
: mWindow(window),
mDxInterface(dxInterface)
{
}
Win32DxWindowInterface::~Win32DxWindowInterface()
{
}
void Win32DxWindowInterface::destroyWindow()
{
flushCommandQueue();
::CloseHandle(mFenceEvent);
}
void Win32DxWindowInterface::onRender()
{
if (!mIsValid)
{
MLOG_INFO("Invalid state - returning");
return;
}
if (!mBuffers->isInitialized())
{
MLOG_INFO("Buffer not initialized - returning");
return;
}
updateCommandList();
mCommandList->execute(mDxInterface->getCommandQueue());
mD2dIntegration->render();
mSwapChain->Present(1, 0);
flushCommandQueue();
}
void Win32DxWindowInterface::updateCommandList()
{
// Command list allocators can only be reset when the associated
// command lists have finished execution on the GPU; apps should use
// fences to determine GPU execution progress.
mCommandList->resetAllocator();
// However, when ExecuteCommandList() is called on a particular command
// list, that command list can then be reset at any time and must be before
// re-recording.
mCommandList->reset(getPipelineState());
// Set necessary state.
auto painter = dynamic_cast<DirectXPainter*>(mWindow->getDrawingContent()->getPainter());
mCommandList->get()->SetGraphicsRootSignature(painter->getMeshPainter()->getRootSignature());
mCommandList->get()->RSSetViewports(1, &mViewport);
mCommandList->get()->RSSetScissorRects(1, &mScissorRect);
// Indicate that the back buffer will be used as a render target.
auto barrier = CD3DX12_RESOURCE_BARRIER::Transition(mBuffers->getCurrentBackBuffer(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
mCommandList->get()->ResourceBarrier(1, &barrier);
auto rtv_handle = mDescriptors->getRtvHandle(static_cast<int>(mBuffers->getCurrentBackBufferIndex()));
mCommandList->get()->OMSetRenderTargets(1, &rtv_handle, FALSE, nullptr);
painter->paintBackground(rtv_handle, mCommandList->get());
painter->paintMesh(mCommandList->get());
// Indicate that the back buffer will now be used to present. (Exclude as handled by D2D integration later)
//barrier = CD3DX12_RESOURCE_BARRIER::Transition(mBuffers->getCurrentBackBuffer(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
//mCommandList->get()->ResourceBarrier(1, &barrier);
mCommandList->close();
}
bool Win32DxWindowInterface::initialize()
{
if (mInitialized)
{
return true;
}
mInitialized = true;
MLOG_INFO("D3D Win init");
mD2dIntegration = std::make_unique<DirectX2dIntegration>(mWindow, mDxInterface, FrameCount);
mBuffers = std::make_unique<DirectXBuffers>(FrameCount);
if (!createSwapChain())
{
return false;
}
mCommandList = std::make_unique<DirectXCommandList>();
mCommandList->create(mDxInterface->getD3dDevice(), getPipelineState());
createSyncObjects();
mDescriptors = std::make_unique<DirectXDescriptors>();
mDescriptors->setupDefaultDescriptorHeaps(mDxInterface->getD3dDevice());
onResize();
if (!loadAssets())
{
return false;
}
flushCommandQueue();
mIsValid = true;
return true;
}
void Win32DxWindowInterface::onResize()
{
MLOG_INFO("On resize");
mIsValid = false;
flushCommandQueue();
mCommandList->reset(getPipelineState());
clearBuffers();
resizeSwapChain();
populateBuffers();
mCommandList->close();
mCommandList->execute(mDxInterface->getCommandQueue());
flushCommandQueue();
updateViewport();
mIsValid = true;
}
void Win32DxWindowInterface::resizeSwapChain()
{
const auto width = mWindow->getWidth();
const auto height = mWindow->getHeight();
MLOG_INFO("Resizing swap chain to: " << width << " | " << height);
mSwapChain->ResizeBuffers(FrameCount, width, height, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH);
updateBackbufferIndex(0);
}
void Win32DxWindowInterface::updateViewport()
{
const auto width = mWindow->getWidth();
const auto height = mWindow->getHeight();
mViewport = CD3DX12_VIEWPORT(0.0f, 0.0f, static_cast<float>(width), static_cast<float>(height));
mScissorRect = CD3DX12_RECT(0, 0, width, height);
}
void Win32DxWindowInterface::clearBuffers()
{
mD2dIntegration->clearBuffers();
mBuffers->clear();
}
ID3D12PipelineState* Win32DxWindowInterface::getPipelineState() const
{
auto painter = dynamic_cast<DirectXPainter*>(mWindow->getDrawingContent()->getPainter());
return painter->getMeshPainter()->getPipelineState();
}
void Win32DxWindowInterface::populateBuffers()
{
MLOG_INFO("Populating buffers");
auto d3d_device = mDxInterface->getD3dDevice();
mBuffers->setupBackBuffers(d3d_device, mSwapChain.Get(), mDescriptors.get());
for (UINT idx = 0; idx < FrameCount; idx++)
{
mD2dIntegration->wrapBuffer(mBuffers->getBackBuffer(idx));
}
const auto width = mWindow->getWidth();
const auto height = mWindow->getHeight();
if (width > 0 and height > 0)
{
mBuffers->setupDepthStencilHeap(mDxInterface->getD3dDevice(), width, height);
mBuffers->setupDepthStencilView(mDxInterface->getD3dDevice(), mDescriptors.get());
auto barrier = CD3DX12_RESOURCE_BARRIER::Transition(mBuffers->getDepthStencilBuffer(), D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_DEPTH_WRITE);
mCommandList->get()->ResourceBarrier(1, &barrier);
}
}
bool Win32DxWindowInterface::createSwapChain()
{
mSwapChain.Reset();
const auto width = mWindow->getWidth();
const auto height = mWindow->getHeight();
const auto hwnd = dynamic_cast<Win32Window*>(mWindow->getPlatformWindow())->getHandle();
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
swapChainDesc.BufferCount = FrameCount;
swapChainDesc.Width = width;
swapChainDesc.Height = height;
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
swapChainDesc.SampleDesc.Count = 1;
Microsoft::WRL::ComPtr<IDXGISwapChain1> swapChain;
if (FAILED(mDxInterface->getDxgiFactory()->CreateSwapChainForHwnd(mDxInterface->getCommandQueue(), hwnd, &swapChainDesc, nullptr, nullptr, &swapChain)))
{
MLOG_ERROR("Failed to create swap chain for hwnd: " << hwnd);
return false;
}
swapChain.As(&mSwapChain);
// Prevent fullscreen toggle
mDxInterface->getDxgiFactory()->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER);
// Update index for backbuffer
updateBackbufferIndex(mSwapChain->GetCurrentBackBufferIndex());
return true;
}
void Win32DxWindowInterface::updateBackbufferIndex(UINT index)
{
mBuffers->updateBackbufferIndex(index);
mD2dIntegration->updateBackbufferIndex(index);
}
bool Win32DxWindowInterface::loadAssets()
{
auto painter = dynamic_cast<DirectXPainter*>(mWindow->getDrawingContent()->getPainter());
painter->initializeMesh();
painter->updateMesh();
return true;
}
void Win32DxWindowInterface::createSyncObjects()
{
mDxInterface->getD3dDevice()->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&mFence));
mFenceValue = 1;
// Create an event handle to use for frame synchronization.
mFenceEvent = ::CreateEvent(nullptr, FALSE, FALSE, nullptr);
if (mFenceEvent == nullptr)
{
//ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError()));
}
// Wait for the command list to execute; we are reusing the same command
// list in our main loop but for now, we just want to wait for setup to
// complete before continuing.
flushCommandQueue();
}
void Win32DxWindowInterface::flushCommandQueue()
{
// Signal and increment the fence value.
const UINT64 fence = mFenceValue;
mDxInterface->getCommandQueue()->Signal(mFence.Get(), fence);
mFenceValue++;
// Wait until the previous frame is finished.
if (mFence->GetCompletedValue() < fence)
{
mFence->SetEventOnCompletion(fence, mFenceEvent);
::WaitForSingleObject(mFenceEvent, INFINITE);
}
updateBackbufferIndex(mSwapChain->GetCurrentBackBufferIndex());
}

View file

@ -0,0 +1,82 @@
#pragma once
#include <memory>
#include <wrl.h>
#include <d3d12.h>
#include <directx/d3dx12.h>
class DirectXInterface;
class DirectXDescriptors;
class DirectX2dIntegration;
class DirectXBuffers;
class DirectXCommandList;
namespace mt
{
class Window;
}
struct ID3D12CommandAllocator;
struct ID3D12GraphicsCommandList;
struct IDXGISwapChain4;
struct ID3D12Resource;
struct ID3D12Fence;
struct ID3D12PipelineState;
class Win32DxWindowInterface
{
public:
Win32DxWindowInterface(mt::Window* window, DirectXInterface* dxInterface);
~Win32DxWindowInterface();
bool initialize();
void onResize();
void onRender();
private:
bool loadAssets();
void updateCommandList();
void destroyWindow();
bool createSwapChain();
void resizeSwapChain();
void clearBuffers();
void populateBuffers();
void updateBackbufferIndex(UINT index);
void createSyncObjects();
void flushCommandQueue();
void updateViewport();
ID3D12PipelineState* getPipelineState() const;
DirectXInterface* mDxInterface{ nullptr };
bool mInitialized{ false };
bool mIsValid{ false };
mt::Window* mWindow{ nullptr };
CD3DX12_VIEWPORT mViewport;
CD3DX12_RECT mScissorRect;
std::unique_ptr<DirectXDescriptors> mDescriptors;
std::unique_ptr<DirectX2dIntegration> mD2dIntegration;
std::unique_ptr<DirectXBuffers> mBuffers;
std::unique_ptr<DirectXCommandList> mCommandList;
Microsoft::WRL::ComPtr<IDXGISwapChain4> mSwapChain;
static const UINT FrameCount = 2;
Microsoft::WRL::ComPtr<ID3D12Fence> mFence;
uint64_t mFenceValue = 0;
uint64_t mFrameFenceValues[FrameCount] = {};
HANDLE mFenceEvent{};
};
using XcbGlWindowInterfacePtr = std::unique_ptr<Win32DxWindowInterface>;

Some files were not shown because too many files have changed in this diff Show more