2
0
mirror of https://github.com/AxioDL/metaforce.git synced 2025-08-09 16:19:05 +00:00

various view architecture bits

This commit is contained in:
Jack Andersen 2015-11-25 21:35:43 -10:00
parent 250bfc0226
commit abb91a9d89
11 changed files with 147 additions and 50 deletions

@ -1 +1 @@
Subproject commit a073e690cda31911ade19a05f0358244b4a31151 Subproject commit a13928491e6a4da070b7767e744511203f47b59c

View File

@ -14,9 +14,11 @@ namespace Specter
class FontTag class FontTag
{ {
friend class FontCache; friend class FontCache;
uint64_t m_hash; uint64_t m_hash = 0;
FontTag(const std::string& name, bool subpixel, float points, unsigned dpi); FontTag(const std::string& name, bool subpixel, float points, unsigned dpi);
public: public:
FontTag() = default;
operator bool() const {return m_hash != 0;}
uint64_t hash() const {return m_hash;} uint64_t hash() const {return m_hash;}
bool operator==(const FontTag& other) const {return m_hash == other.m_hash;} bool operator==(const FontTag& other) const {return m_hash == other.m_hash;}
}; };
@ -56,6 +58,8 @@ class FontAtlas
FT_Face m_face; FT_Face m_face;
boo::ITextureS* m_tex; boo::ITextureS* m_tex;
uint32_t m_dpi; uint32_t m_dpi;
FT_Fixed m_ftXscale;
FT_UShort m_ftXPpem;
public: public:
struct Glyph struct Glyph
@ -113,6 +117,9 @@ public:
FontAtlas& operator=(const FontAtlas& other) = delete; FontAtlas& operator=(const FontAtlas& other) = delete;
uint32_t dpi() const {return m_dpi;} uint32_t dpi() const {return m_dpi;}
FT_Fixed FT_Xscale() const {return m_ftXscale;}
FT_UShort FT_XPPem() const {return m_ftXPpem;}
boo::ITexture* texture() const {return m_tex;}
const Glyph* lookupGlyph(atUint32 charcode) const const Glyph* lookupGlyph(atUint32 charcode) const
{ {

View File

@ -2,6 +2,7 @@
#define SPECTER_ROOTVIEW_HPP #define SPECTER_ROOTVIEW_HPP
#include "View.hpp" #include "View.hpp"
#include "TextView.hpp"
#include "FontCache.hpp" #include "FontCache.hpp"
#include <boo/boo.hpp> #include <boo/boo.hpp>
@ -12,7 +13,12 @@ class ViewSystem;
class RootView : public View, public boo::IWindowCallback class RootView : public View, public boo::IWindowCallback
{ {
boo::IWindow* m_window = nullptr; boo::IWindow* m_window = nullptr;
boo::ITextureR* m_renderTex = nullptr;
TextView m_textView;
boo::SWindowRect m_rootRect;
bool m_resizeRTDirty = false;
public:
void resized(const boo::SWindowRect& rect); void resized(const boo::SWindowRect& rect);
void mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mods); void mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mods);
void mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mods); void mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mods);

View File

@ -14,9 +14,12 @@ class ViewSystem;
class TextView : public View class TextView : public View
{ {
size_t m_capacity;
boo::IGraphicsBufferD* m_glyphBuf; boo::IGraphicsBufferD* m_glyphBuf;
boo::IVertexFormat* m_vtxFmt = nullptr; /* OpenGL only */
boo::IShaderDataBinding* m_shaderBinding;
const FontAtlas& m_fontAtlas; const FontAtlas& m_fontAtlas;
boo::IVertexFormat* m_bgVtxFmt = nullptr; /* OpenGL only */ int m_validSlots = 0;
public: public:
class System class System
@ -36,7 +39,7 @@ public:
#endif #endif
}; };
TextView(ViewSystem& system, FontTag font, size_t initGlyphCapacity=256); TextView(ViewSystem& system, FontTag font, size_t capacity=256);
struct RenderGlyph struct RenderGlyph
{ {
@ -45,18 +48,18 @@ public:
Zeus::CVector3f m_uv[4]; Zeus::CVector3f m_uv[4];
Zeus::CColor m_color; Zeus::CColor m_color;
RenderGlyph(int& adv, const FontAtlas::Glyph& glyph, Zeus::CColor defaultColor); RenderGlyph(int& adv, const FontAtlas::Glyph& glyph, const Zeus::CColor& defaultColor);
}; };
std::vector<RenderGlyph>& accessGlyphs() {return m_glyphs;} std::vector<RenderGlyph>& accessGlyphs() {return m_glyphs;}
void updateGlyphs() {m_validDynamicSlots = 0;} void updateGlyphs() {m_validSlots = 0;}
void typesetGlyphs(const std::string& str, void typesetGlyphs(const std::string& str,
Zeus::CColor defaultColor=Zeus::CColor::skWhite); const Zeus::CColor& defaultColor=Zeus::CColor::skWhite);
void typesetGlyphs(const std::wstring& str, void typesetGlyphs(const std::wstring& str,
Zeus::CColor defaultColor=Zeus::CColor::skWhite); const Zeus::CColor& defaultColor=Zeus::CColor::skWhite);
void colorGlyphs(Zeus::CColor newColor); void colorGlyphs(const Zeus::CColor& newColor);
void colorGlyphsTypeOn(Zeus::CColor newColor, float startInterval=0.2, float fadeTime=0.5); void colorGlyphsTypeOn(const Zeus::CColor& newColor, float startInterval=0.2, float fadeTime=0.5);
void think(); void think();
void draw(boo::IGraphicsCommandQueue* gfxQ); void draw(boo::IGraphicsCommandQueue* gfxQ);

View File

@ -23,6 +23,20 @@ class View
boo::IShaderDataBinding* m_bgShaderBinding; boo::IShaderDataBinding* m_bgShaderBinding;
Zeus::CVector3f m_bgRect[4]; Zeus::CVector3f m_bgRect[4];
Zeus::CColor m_bgColor; Zeus::CColor m_bgColor;
int m_bgValidSlots = 0;
protected:
struct VertexBlock
{
Zeus::CMatrix4f m_mv;
} m_viewVertBlock;
#define SPECTER_VIEW_VERT_BLOCK_GLSL\
"uniform SpecterViewBlock\n"\
"{\n"\
" mat4 mv;\n"\
"};\n"
boo::IGraphicsBufferD* m_viewVertBlockBuf;
public: public:
class System class System
{ {
@ -39,26 +53,12 @@ public:
#endif #endif
}; };
struct VertexBlock
{
Zeus::CMatrix4f m_mv;
};
#define SPECTER_VIEW_VERT_BLOCK_GLSL\
"uniform SpecterViewBlock\n"\
"{\n"\
" mat4 mv;\n"\
"};\n"
protected: protected:
View(ViewSystem& system); View(ViewSystem& system);
int m_validDynamicSlots = 0;
boo::IGraphicsBufferD* m_specterVertBlock;
boo::SWindowRect m_absWindowRect;
void bindScissor(boo::IGraphicsCommandQueue* gfxQ) {gfxQ->setScissor(m_absWindowRect);}
public: public:
void setBackground(Zeus::CColor color) {m_bgColor = color; m_validDynamicSlots = 0;} void setBackground(Zeus::CColor color) {m_bgColor = color; m_bgValidSlots = 0;}
virtual void resized(const boo::SWindowRect& rect);
virtual void draw(boo::IGraphicsCommandQueue* gfxQ); virtual void draw(boo::IGraphicsCommandQueue* gfxQ);
}; };

View File

@ -19,6 +19,9 @@ public:
View::System m_viewSystem; View::System m_viewSystem;
TextView::System m_textSystem; TextView::System m_textSystem;
Specter::FontTag m_mainFont;
Specter::FontTag m_monoFont;
ViewSystem() = default; ViewSystem() = default;
ViewSystem(const ViewSystem& other) = delete; ViewSystem(const ViewSystem& other) = delete;
ViewSystem(ViewSystem&& other) = default; ViewSystem(ViewSystem&& other) = default;

View File

@ -130,6 +130,8 @@ void FontAtlas::buildKernTable(FT_Face face)
if (face->driver->clazz == &tt_driver_class) if (face->driver->clazz == &tt_driver_class)
{ {
TT_Face ttface = reinterpret_cast<TT_Face>(face); TT_Face ttface = reinterpret_cast<TT_Face>(face);
if (!ttface->kern_table)
return;
Athena::io::MemoryReader r(ttface->kern_table, ttface->kern_table_size); Athena::io::MemoryReader r(ttface->kern_table, ttface->kern_table_size);
std::unordered_map<atUint16, std::vector<std::pair<atUint16, atInt16>>>::iterator it = m_kernAdjs.end(); std::unordered_map<atUint16, std::vector<std::pair<atUint16, atInt16>>>::iterator it = m_kernAdjs.end();
atUint32 nSubs = r.readUint32Big(); atUint32 nSubs = r.readUint32Big();
@ -161,7 +163,9 @@ void FontAtlas::buildKernTable(FT_Face face)
FontAtlas::FontAtlas(boo::IGraphicsDataFactory* gf, FT_Face face, uint32_t dpi, FontAtlas::FontAtlas(boo::IGraphicsDataFactory* gf, FT_Face face, uint32_t dpi,
bool subpixel, Athena::io::FileWriter& writer) bool subpixel, Athena::io::FileWriter& writer)
: m_dpi(dpi) : m_dpi(dpi),
m_ftXscale(face->size->metrics.x_scale),
m_ftXPpem(face->size->metrics.x_ppem)
{ {
FT_Int32 baseFlags = FT_LOAD_NO_BITMAP; FT_Int32 baseFlags = FT_LOAD_NO_BITMAP;
if (subpixel) if (subpixel)
@ -358,7 +362,9 @@ FontAtlas::FontAtlas(boo::IGraphicsDataFactory* gf, FT_Face face, uint32_t dpi,
FontAtlas::FontAtlas(boo::IGraphicsDataFactory* gf, FT_Face face, uint32_t dpi, FontAtlas::FontAtlas(boo::IGraphicsDataFactory* gf, FT_Face face, uint32_t dpi,
bool subpixel, Athena::io::FileReader& reader) bool subpixel, Athena::io::FileReader& reader)
: m_dpi(dpi) : m_dpi(dpi),
m_ftXscale(face->size->metrics.x_scale),
m_ftXPpem(face->size->metrics.x_ppem)
{ {
FT_Int32 baseFlags = FT_LOAD_NO_BITMAP; FT_Int32 baseFlags = FT_LOAD_NO_BITMAP;
if (subpixel) if (subpixel)

View File

@ -1,16 +1,34 @@
#include "Specter/RootView.hpp" #include "Specter/RootView.hpp"
#include "Specter/ViewSystem.hpp"
namespace Specter namespace Specter
{ {
RootView::RootView(ViewSystem& system, boo::IWindow* window) RootView::RootView(ViewSystem& system, boo::IWindow* window)
: View(system), m_window(window) : View(system), m_window(window), m_textView(system, system.m_mainFont)
{ {
boo::SWindowRect rect = window->getWindowFrame();
m_renderTex = system.m_factory->newRenderTexture(rect.size[0], rect.size[1], 1);
system.m_factory->commit();
resized(rect);
m_textView.typesetGlyphs("Hello, World!");
} }
void RootView::resized(const boo::SWindowRect& rect) void RootView::resized(const boo::SWindowRect& rect)
{ {
m_rootRect = rect;
m_rootRect.location[0] = 0;
m_rootRect.location[1] = 0;
View::resized(m_rootRect);
boo::SWindowRect textRect = m_rootRect;
textRect.location[0] = 10;
textRect.location[1] = 10;
textRect.size[0] -= 20;
if (textRect.size[0] < 0)
textRect.size[0] = 0;
textRect.size[1] = 10;
m_textView.resized(textRect);
m_resizeRTDirty = true;
} }
void RootView::mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mods) void RootView::mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mods)
@ -75,7 +93,13 @@ void RootView::modKeyUp(boo::EModifierKey mod)
void RootView::draw(boo::IGraphicsCommandQueue* gfxQ) void RootView::draw(boo::IGraphicsCommandQueue* gfxQ)
{ {
if (m_resizeRTDirty)
gfxQ->resizeRenderTexture(m_renderTex, m_rootRect.size[0], m_rootRect.size[1]);
gfxQ->setRenderTarget(m_renderTex);
gfxQ->setViewport(m_rootRect);
View::draw(gfxQ); View::draw(gfxQ);
m_textView.draw(gfxQ);
gfxQ->resolveDisplay(m_renderTex);
} }
} }

View File

@ -7,6 +7,8 @@ static LogVisor::LogModule Log("Specter");
void ViewSystem::init(boo::IGraphicsDataFactory* factory, FontCache* fcache) void ViewSystem::init(boo::IGraphicsDataFactory* factory, FontCache* fcache)
{ {
m_factory = factory; m_factory = factory;
m_mainFont = fcache->prepMainFont(factory, false, 10.0, 72);
m_monoFont = fcache->prepMonoFont(factory, false, 10.0, 72);
switch (factory->platform()) switch (factory->platform())
{ {
case boo::IGraphicsDataFactory::Platform::OGL: case boo::IGraphicsDataFactory::Platform::OGL:
@ -25,6 +27,7 @@ void ViewSystem::init(boo::IGraphicsDataFactory* factory, FontCache* fcache)
default: default:
Log.report(LogVisor::FatalError, _S("unable to init view system for %s"), factory->platformName()); Log.report(LogVisor::FatalError, _S("unable to init view system for %s"), factory->platformName());
} }
fcache->closeBuiltinFonts();
} }
} }

View File

@ -2,6 +2,9 @@
#include "Specter/ViewSystem.hpp" #include "Specter/ViewSystem.hpp"
#include "utf8proc.h" #include "utf8proc.h"
#include <freetype/internal/internal.h>
#include <freetype/internal/ftobjs.h>
namespace Specter namespace Specter
{ {
static LogVisor::LogModule Log("Specter::TextView"); static LogVisor::LogModule Log("Specter::TextView");
@ -76,13 +79,14 @@ void TextView::System::init(boo::GLDataFactory* factory, FontCache* fcache)
true, true, false); true, true, false);
} }
TextView::TextView(ViewSystem& system, FontTag font, size_t initGlyphCapacity) TextView::TextView(ViewSystem& system, FontTag font, size_t capacity)
: View(system), : View(system),
m_capacity(capacity),
m_fontAtlas(system.m_textSystem.m_fcache->lookupAtlas(font)) m_fontAtlas(system.m_textSystem.m_fcache->lookupAtlas(font))
{ {
m_glyphBuf = m_glyphBuf =
system.m_factory->newDynamicBuffer(boo::BufferUse::Vertex, system.m_factory->newDynamicBuffer(boo::BufferUse::Vertex,
sizeof(RenderGlyph), initGlyphCapacity); sizeof(RenderGlyph), capacity);
if (!system.m_textSystem.m_vtxFmt) if (!system.m_textSystem.m_vtxFmt)
{ {
@ -102,13 +106,18 @@ TextView::TextView(ViewSystem& system, FontTag font, size_t initGlyphCapacity)
{m_glyphBuf, nullptr, boo::VertexSemantic::UV4 | boo::VertexSemantic::Instanced, 3}, {m_glyphBuf, nullptr, boo::VertexSemantic::UV4 | boo::VertexSemantic::Instanced, 3},
{m_glyphBuf, nullptr, boo::VertexSemantic::Color | boo::VertexSemantic::Instanced} {m_glyphBuf, nullptr, boo::VertexSemantic::Color | boo::VertexSemantic::Instanced}
}; };
m_bgVtxFmt = system.m_factory->newVertexFormat(13, vdescs); m_vtxFmt = system.m_factory->newVertexFormat(13, vdescs);
boo::ITexture* texs[] = {m_fontAtlas.texture()};
m_shaderBinding = system.m_factory->newShaderDataBinding(system.m_textSystem.m_regular, m_vtxFmt,
nullptr, m_glyphBuf, nullptr, 1,
(boo::IGraphicsBuffer**)&m_viewVertBlockBuf,
1, texs);
} }
m_glyphs.reserve(initGlyphCapacity); m_glyphs.reserve(capacity);
} }
TextView::RenderGlyph::RenderGlyph(int& adv, const FontAtlas::Glyph& glyph, Zeus::CColor defaultColor) TextView::RenderGlyph::RenderGlyph(int& adv, const FontAtlas::Glyph& glyph, const Zeus::CColor& defaultColor)
{ {
m_pos[0].assign(adv + glyph.m_leftPadding, glyph.m_verticalOffset + glyph.m_height, 0.f); m_pos[0].assign(adv + glyph.m_leftPadding, glyph.m_verticalOffset + glyph.m_height, 0.f);
m_pos[1].assign(adv + glyph.m_leftPadding, glyph.m_verticalOffset, 0.f); m_pos[1].assign(adv + glyph.m_leftPadding, glyph.m_verticalOffset, 0.f);
@ -122,7 +131,22 @@ TextView::RenderGlyph::RenderGlyph(int& adv, const FontAtlas::Glyph& glyph, Zeus
adv += glyph.m_advance; adv += glyph.m_advance;
} }
void TextView::typesetGlyphs(const std::string& str, Zeus::CColor defaultColor) static int DoKern(FT_Pos val, const FontAtlas& atlas)
{
val = FT_MulFix(val, atlas.FT_Xscale());
FT_Pos orig_x = val;
/* we scale down kerning values for small ppem values */
/* to avoid that rounding makes them too big. */
/* `25' has been determined heuristically. */
if (atlas.FT_XPPem() < 25)
val = FT_MulDiv(orig_x, atlas.FT_XPPem(), 25);
return FT_PIX_ROUND(val);
}
void TextView::typesetGlyphs(const std::string& str, const Zeus::CColor& defaultColor)
{ {
size_t rem = str.size(); size_t rem = str.size();
const utf8proc_uint8_t* it = reinterpret_cast<const utf8proc_uint8_t*>(str.data()); const utf8proc_uint8_t* it = reinterpret_cast<const utf8proc_uint8_t*>(str.data());
@ -159,11 +183,14 @@ void TextView::typesetGlyphs(const std::string& str, Zeus::CColor defaultColor)
lCh = ch; lCh = ch;
rem -= sz; rem -= sz;
it += sz; it += sz;
if (m_glyphs.size() == m_capacity)
break;
} }
m_validDynamicSlots = 0; m_validSlots = 0;
} }
void TextView::typesetGlyphs(const std::wstring& str, Zeus::CColor defaultColor) void TextView::typesetGlyphs(const std::wstring& str, const Zeus::CColor& defaultColor)
{ {
wchar_t lCh = -1; wchar_t lCh = -1;
m_glyphs.clear(); m_glyphs.clear();
@ -181,22 +208,28 @@ void TextView::typesetGlyphs(const std::wstring& str, Zeus::CColor defaultColor)
if (lCh != -1) if (lCh != -1)
{ {
adv += m_fontAtlas.lookupKern(lCh, ch); adv += DoKern(m_fontAtlas.lookupKern(lCh, ch), m_fontAtlas);
m_glyphs.emplace_back(adv, *glyph, defaultColor); m_glyphs.emplace_back(adv, *glyph, defaultColor);
} }
else else
m_glyphs.emplace_back(adv, *glyph, defaultColor); m_glyphs.emplace_back(adv, *glyph, defaultColor);
lCh = ch; lCh = ch;
if (m_glyphs.size() == m_capacity)
break;
} }
m_validDynamicSlots = 0; m_validSlots = 0;
} }
void TextView::colorGlyphs(Zeus::CColor newColor) void TextView::colorGlyphs(const Zeus::CColor& newColor)
{ {
for (RenderGlyph& glyph : m_glyphs)
glyph.m_color = newColor;
m_validSlots = 0;
} }
void TextView::colorGlyphsTypeOn(Zeus::CColor newColor, float startInterval, float fadeTime) void TextView::colorGlyphsTypeOn(const Zeus::CColor& newColor, float startInterval, float fadeTime)
{ {
} }
void TextView::think() void TextView::think()
@ -205,13 +238,14 @@ void TextView::think()
void TextView::draw(boo::IGraphicsCommandQueue* gfxQ) void TextView::draw(boo::IGraphicsCommandQueue* gfxQ)
{ {
bindScissor(gfxQ); View::draw(gfxQ);
int pendingSlot = 1 << gfxQ->pendingDynamicSlot(); int pendingSlot = 1 << gfxQ->pendingDynamicSlot();
if ((m_validDynamicSlots & pendingSlot) == 0) if ((m_validSlots & pendingSlot) == 0)
{ {
m_glyphBuf->load(m_glyphs.data(), m_glyphs.size() * sizeof(RenderGlyph)); m_glyphBuf->load(m_glyphs.data(), m_glyphs.size() * sizeof(RenderGlyph));
m_validDynamicSlots |= pendingSlot; m_validSlots |= pendingSlot;
} }
gfxQ->setShaderDataBinding(m_shaderBinding);
gfxQ->drawInstances(0, 4, m_glyphs.size()); gfxQ->drawInstances(0, 4, m_glyphs.size());
} }

View File

@ -52,7 +52,7 @@ View::View(ViewSystem& system)
system.m_factory->newDynamicBuffer(boo::BufferUse::Vertex, system.m_factory->newDynamicBuffer(boo::BufferUse::Vertex,
sizeof(Zeus::CColor), 1); sizeof(Zeus::CColor), 1);
m_specterVertBlock = m_viewVertBlockBuf =
system.m_factory->newDynamicBuffer(boo::BufferUse::Uniform, system.m_factory->newDynamicBuffer(boo::BufferUse::Uniform,
sizeof(VertexBlock), 1); sizeof(VertexBlock), 1);
@ -67,22 +67,33 @@ View::View(ViewSystem& system)
m_bgShaderBinding = m_bgShaderBinding =
system.m_factory->newShaderDataBinding(system.m_viewSystem.m_solidShader, m_bgVtxFmt, system.m_factory->newShaderDataBinding(system.m_viewSystem.m_solidShader, m_bgVtxFmt,
m_bgVertBuf, m_bgInstBuf, nullptr, 1, m_bgVertBuf, m_bgInstBuf, nullptr, 1,
(boo::IGraphicsBuffer**)&m_specterVertBlock, (boo::IGraphicsBuffer**)&m_viewVertBlockBuf,
0, nullptr); 0, nullptr);
} }
} }
void View::resized(const boo::SWindowRect& rect)
{
m_viewVertBlock.m_mv[3].assign(rect.location[0], rect.location[1], 0.f, 1.f);
m_bgRect[0].assign(0.f, rect.size[1], 0.f);
m_bgRect[1].assign(0.f, rect.size[1], 0.f);
m_bgRect[2].assign(0.f, rect.size[1], 0.f);
m_bgRect[3].assign(0.f, rect.size[1], 0.f);
m_bgValidSlots = 0;
}
void View::draw(boo::IGraphicsCommandQueue* gfxQ) void View::draw(boo::IGraphicsCommandQueue* gfxQ)
{ {
bindScissor(gfxQ);
int pendingSlot = 1 << gfxQ->pendingDynamicSlot(); int pendingSlot = 1 << gfxQ->pendingDynamicSlot();
if ((m_validDynamicSlots & pendingSlot) == 0) if ((m_bgValidSlots & pendingSlot) == 0)
{ {
m_viewVertBlockBuf->load(&m_viewVertBlock, sizeof(VertexBlock));
m_bgVertBuf->load(m_bgRect, sizeof(Zeus::CVector3f) * 4); m_bgVertBuf->load(m_bgRect, sizeof(Zeus::CVector3f) * 4);
m_bgInstBuf->load(&m_bgColor, sizeof(Zeus::CColor)); m_bgInstBuf->load(&m_bgColor, sizeof(Zeus::CColor));
m_validDynamicSlots |= pendingSlot; m_bgValidSlots |= pendingSlot;
} }
gfxQ->setShaderDataBinding(m_bgShaderBinding);
gfxQ->draw(0, 4); gfxQ->draw(0, 4);
} }