diff --git a/specter/CMakeLists.txt b/specter/CMakeLists.txt index 9604dd28a..80e2a3017 100644 --- a/specter/CMakeLists.txt +++ b/specter/CMakeLists.txt @@ -27,10 +27,11 @@ 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/DeferredWindowEvents.hpp include/Specter/ViewSystem.hpp include/Specter/View.hpp include/Specter/RootView.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 909b40aba..99aa325ef 100644 --- a/specter/include/Specter/RootView.hpp +++ b/specter/include/Specter/RootView.hpp @@ -4,27 +4,29 @@ #include "View.hpp" #include "MultiLineTextView.hpp" #include "FontCache.hpp" +#include "DeferredWindowEvents.hpp" #include namespace Specter { class ViewSystem; -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(ViewSystem& system, 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); @@ -44,6 +46,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/RootView.cpp b/specter/lib/RootView.cpp index 9b5a07d7f..134496142 100644 --- a/specter/lib/RootView.cpp +++ b/specter/lib/RootView.cpp @@ -6,9 +6,9 @@ namespace Specter static LogVisor::LogModule Log("Specter::RootView"); RootView::RootView(ViewSystem& system, boo::IWindow* window) -: View(system, *this), m_window(window) +: View(system, *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); @@ -17,7 +17,7 @@ RootView::RootView(ViewSystem& system, boo::IWindow* window) MultiLineTextView* textView2 = new MultiLineTextView(system, *this, system.m_mainFont); 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) @@ -152,17 +149,17 @@ RootView::SplitView::SplitView(ViewSystem& system, View& parentView, Axis axis) boo::IGraphicsBuffer* bufs[] = {m_splitBlockBuf}; boo::ITexture* texs[] = {system.m_splitViewSystem.m_shadingTex}; m_splitShaderBinding = system.m_factory->newShaderDataBinding(system.m_viewSystem.m_texShader, - m_splitVtxFmt, m_splitVertsBuf, nullptr, - nullptr, 1, bufs, 1, texs); + m_splitVtxFmt, m_splitVertsBuf, nullptr, + nullptr, 1, bufs, 1, texs); } else { boo::IGraphicsBuffer* bufs[] = {m_splitBlockBuf}; boo::ITexture* texs[] = {system.m_splitViewSystem.m_shadingTex}; m_splitShaderBinding = system.m_factory->newShaderDataBinding(system.m_viewSystem.m_texShader, - system.m_viewSystem.m_texVtxFmt, - m_splitVertsBuf, nullptr, - nullptr, 1, bufs, 1, texs); + system.m_viewSystem.m_texVtxFmt, + m_splitVertsBuf, nullptr, + nullptr, 1, bufs, 1, texs); } commitResources(system); diff --git a/specter/lib/Specter.cpp b/specter/lib/Specter.cpp index ca64581a5..1cf8fa691 100644 --- a/specter/lib/Specter.cpp +++ b/specter/lib/Specter.cpp @@ -7,7 +7,7 @@ static LogVisor::LogModule Log("Specter"); void ViewSystem::init(boo::IGraphicsDataFactory* factory, FontCache* fcache) { m_factory = factory; - m_mainFont = fcache->prepMainFont(factory, FontCache::DefaultCharFilter, false, 10.0, 72); + m_mainFont = fcache->prepMainFont(factory, FontCache::DefaultCharFilter, true, 10.0, 72); m_monoFont = fcache->prepMonoFont(factory, FontCache::DefaultCharFilter, false, 10.0, 72); switch (factory->platform()) { diff --git a/specter/lib/TextView.cpp b/specter/lib/TextView.cpp index d8f902a91..643c05dec 100644 --- a/specter/lib/TextView.cpp +++ b/specter/lib/TextView.cpp @@ -429,16 +429,18 @@ void TextView::think() void TextView::draw(boo::IGraphicsCommandQueue* gfxQ) { View::draw(gfxQ); - 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); if (m_glyphs.size()) + { + 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()); + } } diff --git a/specter/lib/View.cpp b/specter/lib/View.cpp index e905ee1fd..5484d1fb7 100644 --- a/specter/lib/View.cpp +++ b/specter/lib/View.cpp @@ -169,9 +169,9 @@ void View::System::init(boo::ID3DDataFactory* factory) 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