diff --git a/specter/CMakeLists.txt b/specter/CMakeLists.txt index c2b022c9f..f0684e98c 100644 --- a/specter/CMakeLists.txt +++ b/specter/CMakeLists.txt @@ -27,11 +27,12 @@ add_subdirectory(resources/fonts) include_directories(include ${HECL_INCLUDE_DIR} ${BOO_INCLUDE_DIR} ${LOG_VISOR_INCLUDE_DIR} ${ATHENA_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/freetype2/include - ${MATHLIB_INCLUDE_DIR}) + ${MATHLIB_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR}) list(APPEND SPECTER_HEADERS include/Specter/Specter.hpp include/Specter/ViewResources.hpp + include/Specter/DeferredWindowEvents.hpp include/Specter/View.hpp include/Specter/RootView.hpp include/Specter/SplitView.hpp diff --git a/specter/include/Specter/DeferredWindowEvents.hpp b/specter/include/Specter/DeferredWindowEvents.hpp new file mode 100644 index 000000000..e46eec8d8 --- /dev/null +++ b/specter/include/Specter/DeferredWindowEvents.hpp @@ -0,0 +1,262 @@ +#ifndef SPECTER_DEFERREDWINDOWEVENTS_HPP +#define SPECTER_DEFERREDWINDOWEVENTS_HPP + +#include + +namespace Specter +{ + +template +struct DeferredWindowEvents : public boo::IWindowCallback +{ + Receiver& m_rec; + std::mutex m_mt; + DeferredWindowEvents(Receiver& rec) : m_rec(rec) {} + + bool m_destroyed = false; + void destroyed() + { + m_destroyed = true; + } + + bool m_hasResize = false; + boo::SWindowRect m_latestResize; + void resized(const boo::SWindowRect& rect) + { + std::unique_lock lk(m_mt); + m_latestResize = rect; + m_hasResize = true; + } + + struct Command + { + enum class Type + { + MouseDown, + MouseUp, + MouseMove, + MouseEnter, + MouseLeave, + Scroll, + TouchDown, + TouchUp, + TouchMove, + CharKeyDown, + CharKeyUp, + SpecialKeyDown, + SpecialKeyUp, + ModKeyDown, + ModKeyUp + } m_type; + + boo::SWindowCoord m_coord; + boo::EMouseButton m_button; + boo::EModifierKey m_mods; + boo::SScrollDelta m_scroll; + boo::STouchCoord m_tCoord; + uintptr_t m_tid; + unsigned long m_charcode; + boo::ESpecialKey m_special; + bool m_isRepeat; + + void dispatch(Receiver& rec) const + { + switch (m_type) + { + case Type::MouseDown: + rec.mouseDown(m_coord, m_button, m_mods); + break; + case Type::MouseUp: + rec.mouseUp(m_coord, m_button, m_mods); + break; + case Type::MouseMove: + rec.mouseMove(m_coord); + break; + case Type::MouseEnter: + rec.mouseEnter(m_coord); + break; + case Type::MouseLeave: + rec.mouseLeave(m_coord); + break; + case Type::Scroll: + rec.scroll(m_coord, m_scroll); + break; + case Type::TouchDown: + rec.touchDown(m_tCoord, m_tid); + break; + case Type::TouchUp: + rec.touchUp(m_tCoord, m_tid); + break; + case Type::TouchMove: + rec.touchMove(m_tCoord, m_tid); + break; + case Type::CharKeyDown: + rec.charKeyDown(m_charcode, m_mods, m_isRepeat); + break; + case Type::CharKeyUp: + rec.charKeyUp(m_charcode, m_mods); + break; + case Type::SpecialKeyDown: + rec.specialKeyDown(m_special, m_mods, m_isRepeat); + break; + case Type::SpecialKeyUp: + rec.specialKeyUp(m_special, m_mods); + break; + case Type::ModKeyDown: + rec.modKeyDown(m_mods, m_isRepeat); + break; + case Type::ModKeyUp: + rec.modKeyUp(m_mods); + break; + default: break; + } + } + + Command(Type tp) : m_type(tp) {} + }; + std::vector m_cmds; + + void mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mods) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::MouseDown); + m_cmds.back().m_coord = coord; + m_cmds.back().m_button = button; + m_cmds.back().m_mods = mods; + } + + void mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mods) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::MouseUp); + m_cmds.back().m_coord = coord; + m_cmds.back().m_button = button; + m_cmds.back().m_mods = mods; + } + + void mouseMove(const boo::SWindowCoord& coord) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::MouseMove); + m_cmds.back().m_coord = coord; + } + + void mouseEnter(const boo::SWindowCoord& coord) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::MouseEnter); + m_cmds.back().m_coord = coord; + } + + void mouseLeave(const boo::SWindowCoord& coord) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::MouseLeave); + m_cmds.back().m_coord = coord; + } + + void scroll(const boo::SWindowCoord& coord, const boo::SScrollDelta& scroll) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::Scroll); + m_cmds.back().m_coord = coord; + m_cmds.back().m_scroll = scroll; + } + + void touchDown(const boo::STouchCoord& coord, uintptr_t tid) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::TouchDown); + m_cmds.back().m_tCoord = coord; + m_cmds.back().m_tid = tid; + } + + void touchUp(const boo::STouchCoord& coord, uintptr_t tid) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::TouchUp); + m_cmds.back().m_tCoord = coord; + m_cmds.back().m_tid = tid; + } + + void touchMove(const boo::STouchCoord& coord, uintptr_t tid) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::TouchMove); + m_cmds.back().m_tCoord = coord; + m_cmds.back().m_tid = tid; + } + + void charKeyDown(unsigned long charCode, boo::EModifierKey mods, bool isRepeat) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::CharKeyDown); + m_cmds.back().m_charcode = charCode; + m_cmds.back().m_mods = mods; + m_cmds.back().m_isRepeat = isRepeat; + } + + void charKeyUp(unsigned long charCode, boo::EModifierKey mods) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::CharKeyUp); + m_cmds.back().m_charcode = charCode; + m_cmds.back().m_mods = mods; + } + + void specialKeyDown(boo::ESpecialKey key, boo::EModifierKey mods, bool isRepeat) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::SpecialKeyDown); + m_cmds.back().m_special = key; + m_cmds.back().m_mods = mods; + m_cmds.back().m_isRepeat = isRepeat; + } + + void specialKeyUp(boo::ESpecialKey key, boo::EModifierKey mods) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::SpecialKeyUp); + m_cmds.back().m_special = key; + m_cmds.back().m_mods = mods; + } + + void modKeyDown(boo::EModifierKey mod, bool isRepeat) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::ModKeyDown); + m_cmds.back().m_mods = mod; + m_cmds.back().m_isRepeat = isRepeat; + } + + void modKeyUp(boo::EModifierKey mod) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::ModKeyUp); + m_cmds.back().m_mods = mod; + } + + void dispatchEvents() + { + std::unique_lock lk(m_mt); + if (m_destroyed) + { + m_rec.destroyed(); + return; + } + + if (m_hasResize) + { + m_rec.resized(m_latestResize, m_latestResize); + m_hasResize = false; + } + + for (const Command& cmd : m_cmds) + cmd.dispatch(m_rec); + m_cmds.clear(); + } +}; + +} + +#endif // SPECTER_DEFERREDWINDOWEVENTS_HPP diff --git a/specter/include/Specter/RootView.hpp b/specter/include/Specter/RootView.hpp index 5776ec1b5..485d4996b 100644 --- a/specter/include/Specter/RootView.hpp +++ b/specter/include/Specter/RootView.hpp @@ -5,27 +5,29 @@ #include "MultiLineTextView.hpp" #include "SplitView.hpp" #include "FontCache.hpp" +#include "DeferredWindowEvents.hpp" #include namespace Specter { class ViewResources; -class RootView : public View, public boo::IWindowCallback +class RootView : public View { boo::IWindow* m_window = nullptr; boo::ITextureR* m_renderTex = nullptr; - boo::SWindowRect m_rootRect; + boo::SWindowRect m_rootRect = {}; bool m_resizeRTDirty = false; bool m_destroyed = false; + DeferredWindowEvents m_events; + public: RootView(ViewResources& res, boo::IWindow* window); void destroyed(); bool isDestroyed() const {return m_destroyed;} - void resized(const boo::SWindowRect& rect); void resized(const boo::SWindowRect& root, const boo::SWindowRect& sub); void mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mods); void mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mods); @@ -45,6 +47,7 @@ public: void modKeyDown(boo::EModifierKey mod, bool isRepeat); void modKeyUp(boo::EModifierKey mod); + void dispatchEvents() {m_events.dispatchEvents();} void draw(boo::IGraphicsCommandQueue* gfxQ); const boo::SWindowRect& rootRect() const {return m_rootRect;} diff --git a/specter/lib/FontCache.cpp b/specter/lib/FontCache.cpp index 641d1509c..9b97fed72 100644 --- a/specter/lib/FontCache.cpp +++ b/specter/lib/FontCache.cpp @@ -218,10 +218,7 @@ static bool ReadDecompressed(Athena::io::FileReader& reader, atUint8* data, size } inflateEnd(&z); - - if (adler32 != z.adler) - return false; - return true; + return adler32 == z.adler; } FontAtlas::FontAtlas(boo::IGraphicsDataFactory* gf, FT_Face face, uint32_t dpi, @@ -300,7 +297,7 @@ FontAtlas::FontAtlas(boo::IGraphicsDataFactory* gf, FT_Face face, uint32_t dpi, else { size_t count = TEXMAP_DIM * totalHeight; - texmap.reset(new RgbaPixel[TEXMAP_DIM * totalHeight]); + texmap.reset(new RgbaPixel[count]); bufSz = count * sizeof(RgbaPixel); memset(texmap.get(), 0, bufSz); } @@ -375,7 +372,7 @@ FontAtlas::FontAtlas(boo::IGraphicsDataFactory* gf, FT_Face face, uint32_t dpi, else { size_t count = TEXMAP_DIM * totalHeight; - texmap.reset(new GreyPixel[TEXMAP_DIM * totalHeight]); + texmap.reset(new GreyPixel[count]); bufSz = count * sizeof(GreyPixel); memset(texmap.get(), 0, bufSz); } diff --git a/specter/lib/RootView.cpp b/specter/lib/RootView.cpp index 41c9ccf04..2297b115d 100644 --- a/specter/lib/RootView.cpp +++ b/specter/lib/RootView.cpp @@ -5,19 +5,19 @@ namespace Specter { static LogVisor::LogModule Log("Specter::RootView"); -RootView::RootView(ViewResources& system, boo::IWindow* window) -: View(system, *this), m_window(window) +RootView::RootView(ViewResources& res, boo::IWindow* window) +: View(res, *this), m_window(window), m_events(*this) { - window->setCallback(this); + window->setCallback(&m_events); boo::SWindowRect rect = window->getWindowFrame(); - m_renderTex = system.m_factory->newRenderTexture(rect.size[0], rect.size[1], 1); - commitResources(system); - m_splitView.reset(new SplitView(system, *this, SplitView::Axis::Horizontal)); - MultiLineTextView* textView1 = new MultiLineTextView(system, *this, system.m_heading18); - MultiLineTextView* textView2 = new MultiLineTextView(system, *this, system.m_heading18); + m_renderTex = res.m_factory->newRenderTexture(rect.size[0], rect.size[1], 1); + commitResources(res); + m_splitView.reset(new SplitView(res, *this, SplitView::Axis::Horizontal)); + MultiLineTextView* textView1 = new MultiLineTextView(res, *this, res.m_heading18); + MultiLineTextView* textView2 = new MultiLineTextView(res, *this, res.m_heading18); m_splitView->setContentView(0, std::unique_ptr(textView1)); m_splitView->setContentView(1, std::unique_ptr(textView2)); - resized(rect); + resized(rect, rect); textView1->typesetGlyphs("Hello, World!\n\n", Zeus::CColor::skWhite); textView2->typesetGlyphs("こんにちは世界!\n\n", Zeus::CColor::skWhite); Zeus::CColor transBlack(0.f, 0.f, 0.f, 0.5f); @@ -31,19 +31,16 @@ void RootView::destroyed() m_destroyed = true; } -void RootView::resized(const boo::SWindowRect& rect) -{ - resized(rect, rect); -} - void RootView::resized(const boo::SWindowRect& root, const boo::SWindowRect&) { + boo::SWindowRect old = m_rootRect; m_rootRect = root; m_rootRect.location[0] = 0; m_rootRect.location[1] = 0; View::resized(m_rootRect, m_rootRect); m_splitView->resized(m_rootRect, m_rootRect); - m_resizeRTDirty = true; + if (old != m_rootRect) + m_resizeRTDirty = true; } void RootView::mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mods) diff --git a/specter/lib/TextView.cpp b/specter/lib/TextView.cpp index c46c1a30a..87ba746a7 100644 --- a/specter/lib/TextView.cpp +++ b/specter/lib/TextView.cpp @@ -429,15 +429,18 @@ void TextView::think() void TextView::draw(boo::IGraphicsCommandQueue* gfxQ) { View::draw(gfxQ); - int pendingSlot = 1 << gfxQ->pendingDynamicSlot(); - if ((m_validSlots & pendingSlot) == 0) + if (m_glyphs.size()) { - m_glyphBuf->load(m_glyphs.data(), m_glyphs.size() * sizeof(RenderGlyph)); - m_validSlots |= pendingSlot; + int pendingSlot = 1 << gfxQ->pendingDynamicSlot(); + if ((m_validSlots & pendingSlot) == 0) + { + m_glyphBuf->load(m_glyphs.data(), m_glyphs.size() * sizeof(RenderGlyph)); + m_validSlots |= pendingSlot; + } + gfxQ->setShaderDataBinding(m_shaderBinding); + gfxQ->setDrawPrimitive(boo::Primitive::TriStrips); + gfxQ->drawInstances(0, 4, m_glyphs.size()); } - gfxQ->setShaderDataBinding(m_shaderBinding); - gfxQ->setDrawPrimitive(boo::Primitive::TriStrips); - gfxQ->drawInstances(0, 4, m_glyphs.size()); } diff --git a/specter/lib/View.cpp b/specter/lib/View.cpp index 267395cce..a06e11abb 100644 --- a/specter/lib/View.cpp +++ b/specter/lib/View.cpp @@ -145,12 +145,12 @@ void View::System::init(boo::ID3DDataFactory* factory) " return tex.Sample(samp, vtf.uv);\n" "}\n"; - boo::VertexElementDescriptor vdescs[] = + boo::VertexElementDescriptor solidvdescs[] = { {nullptr, nullptr, boo::VertexSemantic::Position4}, {nullptr, nullptr, boo::VertexSemantic::Color | boo::VertexSemantic::Instanced} }; - m_solidVtxFmt = factory->newVertexFormat(2, vdescs); + m_solidVtxFmt = factory->newVertexFormat(2, solidvdescs); ComPtr vertBlob; ComPtr fragBlob; @@ -159,19 +159,19 @@ void View::System::init(boo::ID3DDataFactory* factory) boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha, false, false, false); - boo::VertexElementDescriptor vdescs[] = + boo::VertexElementDescriptor texvdescs[] = { {nullptr, nullptr, boo::VertexSemantic::Position4}, {nullptr, nullptr, boo::VertexSemantic::UV4} }; - m_texVtxFmt = factory->newVertexFormat(2, vdescs); + m_texVtxFmt = factory->newVertexFormat(2, texvdescs); vertBlob.Reset(); fragBlob.Reset(); pipeBlob.Reset(); - m_solidShader = factory->newShaderPipeline(TexVS, TexFS, vertBlob, fragBlob, pipeBlob, m_texVtxFmt, - boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha, - false, false, false); + m_texShader = factory->newShaderPipeline(TexVS, TexFS, vertBlob, fragBlob, pipeBlob, m_texVtxFmt, + boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha, + false, false, false); } #elif BOO_HAS_METAL @@ -249,23 +249,23 @@ void View::System::init(boo::MetalDataFactory* factory) " return tex.sample(samp, vtf.uv);\n" "}\n"; - boo::VertexElementDescriptor vdescs[] = + boo::VertexElementDescriptor solidvdescs[] = { {nullptr, nullptr, boo::VertexSemantic::Position4}, {nullptr, nullptr, boo::VertexSemantic::Color | boo::VertexSemantic::Instanced} }; - m_solidVtxFmt = factory->newVertexFormat(2, vdescs); + m_solidVtxFmt = factory->newVertexFormat(2, solidvdescs); m_solidShader = factory->newShaderPipeline(SolidVS, SolidFS, m_solidVtxFmt, 1, boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha, false, false, false); - boo::VertexElementDescriptor vdescs[] = + boo::VertexElementDescriptor texvdescs[] = { {nullptr, nullptr, boo::VertexSemantic::Position4}, {nullptr, nullptr, boo::VertexSemantic::UV4} }; - m_texVtxFmt = factory->newVertexFormat(2, vdescs); + m_texVtxFmt = factory->newVertexFormat(2, texvdescs); m_texShader = factory->newShaderPipeline(TexVS, TexFS, m_texVtxFmt, 1, boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha,