mirror of https://github.com/AxioDL/metaforce.git
355 lines
10 KiB
C++
355 lines
10 KiB
C++
#pragma once
|
|
|
|
#include <algorithm>
|
|
#include <iterator>
|
|
#include <optional>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
|
|
#include <boo/BooObject.hpp>
|
|
#include <boo/IWindow.hpp>
|
|
#include <boo/graphicsdev/IGraphicsDataFactory.hpp>
|
|
|
|
#include <hecl/UniformBufferPool.hpp>
|
|
#include <hecl/VertexBufferPool.hpp>
|
|
|
|
#include <zeus/CColor.hpp>
|
|
#include <zeus/CMatrix4f.hpp>
|
|
#include <zeus/CTransform.hpp>
|
|
#include <zeus/CVector3f.hpp>
|
|
|
|
namespace boo {
|
|
struct IGraphicsCommandQueue;
|
|
}
|
|
|
|
namespace specter {
|
|
class IThemeData;
|
|
class RootView;
|
|
class Space;
|
|
class SplitView;
|
|
class ViewResources;
|
|
|
|
extern zeus::CMatrix4f g_PlatformMatrix;
|
|
|
|
class RectangleConstraint {
|
|
public:
|
|
enum class Test { Fixed, Minimum, Maximum };
|
|
|
|
private:
|
|
int m_x, m_y;
|
|
Test m_xtest, m_ytest;
|
|
|
|
public:
|
|
RectangleConstraint(int x = -1, int y = -1, Test xtest = Test::Fixed, Test ytest = Test::Fixed)
|
|
: m_x(x), m_y(y), m_xtest(xtest), m_ytest(ytest) {}
|
|
std::pair<int, int> solve(int x, int y) const {
|
|
std::pair<int, int> ret;
|
|
|
|
if (m_x < 0)
|
|
ret.first = x;
|
|
else {
|
|
switch (m_xtest) {
|
|
case Test::Fixed:
|
|
ret.first = m_x;
|
|
break;
|
|
case Test::Minimum:
|
|
ret.first = std::max(m_x, x);
|
|
break;
|
|
case Test::Maximum:
|
|
ret.first = std::min(m_x, x);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (m_y < 0)
|
|
ret.second = y;
|
|
else {
|
|
switch (m_ytest) {
|
|
case Test::Fixed:
|
|
ret.second = m_y;
|
|
break;
|
|
case Test::Minimum:
|
|
ret.second = std::max(m_y, y);
|
|
break;
|
|
case Test::Maximum:
|
|
ret.second = std::min(m_y, y);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
};
|
|
|
|
class View {
|
|
public:
|
|
struct SolidShaderVert {
|
|
zeus::CVector3f m_pos;
|
|
zeus::CColor m_color = zeus::skClear;
|
|
};
|
|
struct TexShaderVert {
|
|
zeus::CVector3f m_pos;
|
|
zeus::CVector2f m_uv;
|
|
};
|
|
struct ViewBlock {
|
|
zeus::CMatrix4f m_mv;
|
|
zeus::CColor m_color = zeus::skWhite;
|
|
void setViewRect(const boo::SWindowRect& root, const boo::SWindowRect& sub) {
|
|
m_mv[0][0] = 2.0f / root.size[0];
|
|
m_mv[1][1] = 2.0f / root.size[1];
|
|
m_mv[3][0] = sub.location[0] * m_mv[0][0] - 1.0f;
|
|
m_mv[3][1] = sub.location[1] * m_mv[1][1] - 1.0f;
|
|
}
|
|
void finalAssign(const ViewBlock& other) {
|
|
m_mv = g_PlatformMatrix * other.m_mv;
|
|
m_color = other.m_color;
|
|
}
|
|
};
|
|
|
|
template <typename VertStruct>
|
|
struct VertexBufferBinding {
|
|
typename hecl::VertexBufferPool<VertStruct>::Token m_vertsBuf;
|
|
boo::ObjToken<boo::IShaderDataBinding> m_shaderBinding;
|
|
|
|
void load(const VertStruct* data, size_t count) {
|
|
if (m_vertsBuf) {
|
|
VertStruct* const out = m_vertsBuf.access();
|
|
std::copy(data, data + count, out);
|
|
}
|
|
}
|
|
template <typename ContiguousContainer>
|
|
void load(const ContiguousContainer& container) {
|
|
// All contiguous containers (even those that aren't containers like C arrays) are usable
|
|
// with std::begin(). Because of that, we can use it to deduce the contained type.
|
|
static_assert(std::is_same_v<std::remove_reference_t<decltype(*std::begin(std::declval<ContiguousContainer&>()))>,
|
|
VertStruct>,
|
|
"Supplied container doesn't contain same type of vertex struct");
|
|
|
|
load(std::data(container), std::size(container));
|
|
}
|
|
|
|
operator const boo::ObjToken<boo::IShaderDataBinding>&() { return m_shaderBinding; }
|
|
};
|
|
struct VertexBufferBindingSolid : VertexBufferBinding<SolidShaderVert> {
|
|
void init(boo::IGraphicsDataFactory::Context& ctx, ViewResources& res, size_t count,
|
|
const hecl::UniformBufferPool<ViewBlock>::Token& viewBlockBuf);
|
|
};
|
|
struct VertexBufferBindingTex : VertexBufferBinding<TexShaderVert> {
|
|
void init(boo::IGraphicsDataFactory::Context& ctx, ViewResources& res, size_t count,
|
|
const hecl::UniformBufferPool<ViewBlock>::Token& viewBlockBuf,
|
|
const boo::ObjToken<boo::ITexture>& texture);
|
|
};
|
|
|
|
private:
|
|
RootView& m_rootView;
|
|
View& m_parentView;
|
|
boo::SWindowRect m_subRect;
|
|
VertexBufferBindingSolid m_bgVertsBinding;
|
|
SolidShaderVert m_bgRect[4];
|
|
|
|
friend class RootView;
|
|
View(ViewResources& res);
|
|
|
|
protected:
|
|
ViewBlock m_viewVertBlock;
|
|
hecl::UniformBufferPool<ViewBlock>::Token m_viewVertBlockBuf;
|
|
|
|
public:
|
|
struct Resources {
|
|
hecl::UniformBufferPool<ViewBlock> m_bufPool;
|
|
hecl::VertexBufferPool<SolidShaderVert> m_solidPool;
|
|
hecl::VertexBufferPool<TexShaderVert> m_texPool;
|
|
|
|
void updateBuffers() {
|
|
m_bufPool.updateBuffers();
|
|
m_solidPool.updateBuffers();
|
|
m_texPool.updateBuffers();
|
|
}
|
|
|
|
boo::ObjToken<boo::IShaderPipeline> m_solidShader;
|
|
boo::ObjToken<boo::IShaderPipeline> m_texShader;
|
|
|
|
void init(boo::IGraphicsDataFactory::Context& ctx, const IThemeData& theme);
|
|
|
|
void destroy() {
|
|
m_bufPool.doDestroy();
|
|
m_solidPool.doDestroy();
|
|
m_texPool.doDestroy();
|
|
|
|
m_solidShader.reset();
|
|
m_texShader.reset();
|
|
}
|
|
};
|
|
|
|
protected:
|
|
View(ViewResources& res, View& parentView);
|
|
void buildResources(boo::IGraphicsDataFactory::Context& ctx, ViewResources& res);
|
|
void commitResources(ViewResources& res, const boo::FactoryCommitFunc& commitFunc);
|
|
|
|
public:
|
|
virtual ~View() {}
|
|
View() = delete;
|
|
View(const View& other) = delete;
|
|
View& operator=(const View& other) = delete;
|
|
|
|
View& parentView() { return m_parentView; }
|
|
RootView& rootView() { return m_rootView; }
|
|
const RootView& rootView() const { return m_rootView; }
|
|
const boo::SWindowRect& subRect() const { return m_subRect; }
|
|
int width() const { return m_subRect.size[0]; }
|
|
int height() const { return m_subRect.size[1]; }
|
|
void updateSize();
|
|
|
|
void setBackground(const zeus::CColor& color) {
|
|
for (int i = 0; i < 4; ++i)
|
|
m_bgRect[i].m_color = color;
|
|
m_bgVertsBinding.load<decltype(m_bgRect)>(m_bgRect);
|
|
}
|
|
|
|
virtual void setMultiplyColor(const zeus::CColor& color) {
|
|
m_viewVertBlock.m_color = color;
|
|
if (m_viewVertBlockBuf)
|
|
m_viewVertBlockBuf.access().finalAssign(m_viewVertBlock);
|
|
}
|
|
|
|
virtual int nominalWidth() const { return 0; }
|
|
virtual int nominalHeight() const { return 0; }
|
|
|
|
virtual void setActive(bool) {}
|
|
|
|
virtual void mouseDown(const boo::SWindowCoord&, boo::EMouseButton, boo::EModifierKey) {}
|
|
virtual void mouseUp(const boo::SWindowCoord&, boo::EMouseButton, boo::EModifierKey) {}
|
|
virtual void mouseMove(const boo::SWindowCoord&) {}
|
|
virtual void mouseEnter(const boo::SWindowCoord&) {}
|
|
virtual void mouseLeave(const boo::SWindowCoord&) {}
|
|
virtual void scroll(const boo::SWindowCoord&, const boo::SScrollDelta&) {}
|
|
virtual void touchDown(const boo::STouchCoord&, uintptr_t) {}
|
|
virtual void touchUp(const boo::STouchCoord&, uintptr_t) {}
|
|
virtual void touchMove(const boo::STouchCoord&, uintptr_t) {}
|
|
virtual void charKeyDown(unsigned long, boo::EModifierKey, bool) {}
|
|
virtual void charKeyUp(unsigned long, boo::EModifierKey) {}
|
|
virtual void specialKeyDown(boo::ESpecialKey, boo::EModifierKey, bool) {}
|
|
virtual void specialKeyUp(boo::ESpecialKey, boo::EModifierKey) {}
|
|
virtual void modKeyDown(boo::EModifierKey, bool) {}
|
|
virtual void modKeyUp(boo::EModifierKey) {}
|
|
|
|
virtual void containerResized(const boo::SWindowRect& root, const boo::SWindowRect& sub) {}
|
|
virtual void resized(const boo::SWindowRect& root, const boo::SWindowRect& sub);
|
|
virtual void resized(const ViewBlock& vb, const boo::SWindowRect& sub);
|
|
virtual void resized(const boo::SWindowRect& root, const boo::SWindowRect& sub, const boo::SWindowRect& scissor) {
|
|
resized(root, sub);
|
|
}
|
|
virtual void think() {}
|
|
virtual void draw(boo::IGraphicsCommandQueue* gfxQ);
|
|
|
|
virtual bool isSpace() const { return false; }
|
|
virtual bool isSplitView() const { return false; }
|
|
Space* castToSpace();
|
|
SplitView* castToSplitView();
|
|
};
|
|
|
|
template <class ViewPtrType>
|
|
struct ViewChild {
|
|
ViewPtrType m_view = ViewPtrType();
|
|
bool m_mouseIn = false;
|
|
int m_mouseDown = 0;
|
|
|
|
bool mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod) {
|
|
if (!m_view)
|
|
return false;
|
|
if (m_view->subRect().coordInRect(coord)) {
|
|
if ((m_mouseDown & 1 << int(button)) == 0) {
|
|
m_view->mouseDown(coord, button, mod);
|
|
m_mouseDown |= 1 << int(button);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod) {
|
|
if (!m_view)
|
|
return;
|
|
if ((m_mouseDown & 1 << int(button)) != 0) {
|
|
m_view->mouseUp(coord, button, mod);
|
|
m_mouseDown &= ~(1 << int(button));
|
|
}
|
|
}
|
|
|
|
void mouseMove(const boo::SWindowCoord& coord) {
|
|
if (!m_view)
|
|
return;
|
|
if (m_view->subRect().coordInRect(coord)) {
|
|
if (!m_mouseIn) {
|
|
m_view->mouseEnter(coord);
|
|
m_mouseIn = true;
|
|
}
|
|
m_view->mouseMove(coord);
|
|
} else {
|
|
if (m_mouseIn) {
|
|
m_view->mouseLeave(coord);
|
|
m_mouseIn = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
void mouseEnter(const boo::SWindowCoord& coord) {
|
|
if (!m_view)
|
|
return;
|
|
}
|
|
|
|
void mouseLeave(const boo::SWindowCoord& coord) {
|
|
if (!m_view)
|
|
return;
|
|
if (m_mouseIn) {
|
|
m_view->mouseLeave(coord);
|
|
m_mouseIn = false;
|
|
}
|
|
}
|
|
|
|
void scroll(const boo::SWindowCoord& coord, const boo::SScrollDelta& scroll) {
|
|
if (!m_view)
|
|
return;
|
|
if (m_mouseIn)
|
|
m_view->scroll(coord, scroll);
|
|
}
|
|
};
|
|
|
|
template <class ViewPtrType>
|
|
struct ScissorViewChild : ViewChild<ViewPtrType> {
|
|
using base = ViewChild<ViewPtrType>;
|
|
boo::SWindowRect m_scissorRect;
|
|
|
|
bool mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod) {
|
|
if (!base::m_view)
|
|
return false;
|
|
if (base::m_view->subRect().coordInRect(coord) && m_scissorRect.coordInRect(coord)) {
|
|
if ((base::m_mouseDown & 1 << int(button)) == 0) {
|
|
base::m_view->mouseDown(coord, button, mod);
|
|
base::m_mouseDown |= 1 << int(button);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void mouseMove(const boo::SWindowCoord& coord) {
|
|
if (!base::m_view)
|
|
return;
|
|
if (base::m_view->subRect().coordInRect(coord) && m_scissorRect.coordInRect(coord)) {
|
|
if (!base::m_mouseIn) {
|
|
base::m_view->mouseEnter(coord);
|
|
base::m_mouseIn = true;
|
|
}
|
|
base::m_view->mouseMove(coord);
|
|
} else {
|
|
if (base::m_mouseIn) {
|
|
base::m_view->mouseLeave(coord);
|
|
base::m_mouseIn = false;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
} // namespace specter
|