Text system updates

This commit is contained in:
Jack Andersen 2015-11-28 16:55:30 -10:00
parent 4ede0d6858
commit b4ffb13903
14 changed files with 272 additions and 17 deletions

View File

@ -34,7 +34,9 @@ list(APPEND SPECTER_HEADERS
include/Specter/ViewSystem.hpp include/Specter/ViewSystem.hpp
include/Specter/View.hpp include/Specter/View.hpp
include/Specter/RootView.hpp include/Specter/RootView.hpp
include/Specter/ScrollView.hpp
include/Specter/TextView.hpp include/Specter/TextView.hpp
include/Specter/MultiLineTextView.hpp
include/Specter/Space.hpp include/Specter/Space.hpp
include/Specter/Table.hpp include/Specter/Table.hpp
include/Specter/Outliner.hpp include/Specter/Outliner.hpp
@ -54,7 +56,9 @@ list(APPEND SPECTER_SOURCES
lib/Specter.cpp lib/Specter.cpp
lib/View.cpp lib/View.cpp
lib/RootView.cpp lib/RootView.cpp
lib/ScrollView.cpp
lib/TextView.cpp lib/TextView.cpp
lib/MultiLineTextView.cpp
lib/Space.cpp lib/Space.cpp
lib/Table.cpp lib/Table.cpp
lib/Outliner.cpp lib/Outliner.cpp

@ -1 +1 @@
Subproject commit f075c38a4cb65ce4d1e812a308de45b41cb88eb8 Subproject commit 9885d34420ec70ba52d8270b4e0a9ddc22663dea

View File

@ -62,6 +62,8 @@ class FontAtlas
uint32_t m_dpi; uint32_t m_dpi;
FT_Fixed m_ftXscale; FT_Fixed m_ftXscale;
FT_UShort m_ftXPpem; FT_UShort m_ftXPpem;
FT_Pos m_lineHeight;
bool m_subpixel;
public: public:
struct Glyph struct Glyph
@ -120,7 +122,9 @@ public:
uint32_t dpi() const {return m_dpi;} uint32_t dpi() const {return m_dpi;}
FT_Fixed FT_Xscale() const {return m_ftXscale;} FT_Fixed FT_Xscale() const {return m_ftXscale;}
FT_UShort FT_XPPem() const {return m_ftXPpem;} FT_UShort FT_XPPem() const {return m_ftXPpem;}
FT_Pos FT_LineHeight() const {return m_lineHeight;}
boo::ITexture* texture() const {return m_tex;} boo::ITexture* texture() const {return m_tex;}
bool subpixel() const {return m_subpixel;}
const Glyph* lookupGlyph(atUint32 charcode) const const Glyph* lookupGlyph(atUint32 charcode) const
{ {

View File

@ -0,0 +1,33 @@
#ifndef SPECTER_MULTILINETEXTVIEW_HPP
#define SPECTER_MULTILINETEXTVIEW_HPP
#include "View.hpp"
#include "TextView.hpp"
#include "FontCache.hpp"
namespace Specter
{
class MultiLineTextView : public View
{
ViewSystem& m_viewSystem;
std::vector<TextView> m_lines;
const FontAtlas& m_fontAtlas;
size_t m_lineCapacity;
float m_lineHeight;
public:
MultiLineTextView(ViewSystem& system, View& parentView, const FontAtlas& font, size_t lineCapacity=256, float lineHeight=1.0);
MultiLineTextView(ViewSystem& system, View& parentView, FontTag font, size_t lineCapacity=256, float lineHeight=1.0);
void typesetGlyphs(const std::string& str,
const Zeus::CColor& defaultColor=Zeus::CColor::skWhite);
void typesetGlyphs(const std::wstring& str,
const Zeus::CColor& defaultColor=Zeus::CColor::skWhite);
void resized(const boo::SWindowRect& root, const boo::SWindowRect& sub);
void draw(boo::IGraphicsCommandQueue* gfxQ);
};
}
#endif // SPECTER_MULTILINETEXTVIEW_HPP

View File

@ -2,7 +2,7 @@
#define SPECTER_ROOTVIEW_HPP #define SPECTER_ROOTVIEW_HPP
#include "View.hpp" #include "View.hpp"
#include "TextView.hpp" #include "MultiLineTextView.hpp"
#include "FontCache.hpp" #include "FontCache.hpp"
#include <boo/boo.hpp> #include <boo/boo.hpp>
@ -14,7 +14,7 @@ class RootView : public View, public boo::IWindowCallback
{ {
boo::IWindow* m_window = nullptr; boo::IWindow* m_window = nullptr;
boo::ITextureR* m_renderTex = nullptr; boo::ITextureR* m_renderTex = nullptr;
TextView m_textView; MultiLineTextView m_textView;
boo::SWindowRect m_rootRect; boo::SWindowRect m_rootRect;
bool m_resizeRTDirty = false; bool m_resizeRTDirty = false;
bool m_destroyed = false; bool m_destroyed = false;
@ -46,6 +46,8 @@ public:
void draw(boo::IGraphicsCommandQueue* gfxQ); void draw(boo::IGraphicsCommandQueue* gfxQ);
RootView(ViewSystem& system, boo::IWindow* window); RootView(ViewSystem& system, boo::IWindow* window);
const boo::SWindowRect& rootRect() const {return m_rootRect;}
}; };
} }

View File

@ -0,0 +1,19 @@
#ifndef SPECTER_SCROLLVIEW_HPP
#define SPECTER_SCROLLVIEW_HPP
#include "View.hpp"
namespace Specter
{
class ViewSystem;
class ScrollView : public View
{
View& m_contentView;
public:
ScrollView(ViewSystem& system, View& parentView, View& contentView);
};
}
#endif // SPECTER_SCROLLVIEW_HPP

View File

@ -26,6 +26,7 @@ public:
{ {
friend class ViewSystem; friend class ViewSystem;
friend class TextView; friend class TextView;
friend class MultiLineTextView;
FontCache* m_fcache = nullptr; FontCache* m_fcache = nullptr;
boo::IShaderPipeline* m_regular = nullptr; boo::IShaderPipeline* m_regular = nullptr;
boo::IShaderPipeline* m_subpixel = nullptr; boo::IShaderPipeline* m_subpixel = nullptr;
@ -39,7 +40,8 @@ public:
#endif #endif
}; };
TextView(ViewSystem& system, FontTag font, size_t capacity=256); TextView(ViewSystem& system, View& parentView, const FontAtlas& font, size_t capacity=256);
TextView(ViewSystem& system, View& parentView, FontTag font, size_t capacity=256);
struct RenderGlyph struct RenderGlyph
{ {

View File

@ -14,9 +14,13 @@
namespace Specter namespace Specter
{ {
class ViewSystem; class ViewSystem;
class RootView;
class View class View
{ {
RootView& m_rootView;
View& m_parentView;
boo::SWindowRect m_subRect;
boo::IGraphicsBufferD* m_bgVertBuf; boo::IGraphicsBufferD* m_bgVertBuf;
boo::IGraphicsBufferD* m_bgInstBuf; boo::IGraphicsBufferD* m_bgInstBuf;
boo::IVertexFormat* m_bgVtxFmt = nullptr; /* OpenGL only */ boo::IVertexFormat* m_bgVtxFmt = nullptr; /* OpenGL only */
@ -25,6 +29,10 @@ class View
Zeus::CColor m_bgColor; Zeus::CColor m_bgColor;
int m_bgValidSlots = 0; int m_bgValidSlots = 0;
friend class RootView;
void buildResources(ViewSystem& system);
View(ViewSystem& system, RootView& parentView);
protected: protected:
struct VertexBlock struct VertexBlock
{ {
@ -71,10 +79,15 @@ public:
}; };
protected: protected:
View(ViewSystem& system); View(ViewSystem& system, View& parentView);
public: public:
View() = delete; View() = delete;
View& parent() {return m_parentView;}
RootView& root() {return m_rootView;}
void updateSize();
void setBackground(Zeus::CColor color) {m_bgColor = color; m_bgValidSlots = 0;} void setBackground(Zeus::CColor color) {m_bgColor = color; m_bgValidSlots = 0;}
virtual void resized(const boo::SWindowRect &root, const boo::SWindowRect& sub); virtual void resized(const boo::SWindowRect &root, const boo::SWindowRect& sub);
virtual void draw(boo::IGraphicsCommandQueue* gfxQ); virtual void draw(boo::IGraphicsCommandQueue* gfxQ);

View File

@ -221,7 +221,9 @@ FontAtlas::FontAtlas(boo::IGraphicsDataFactory* gf, FT_Face face, uint32_t dpi,
bool subpixel, FCharFilter& filter, Athena::io::FileWriter& writer) bool subpixel, FCharFilter& filter, Athena::io::FileWriter& writer)
: m_dpi(dpi), : m_dpi(dpi),
m_ftXscale(face->size->metrics.x_scale), m_ftXscale(face->size->metrics.x_scale),
m_ftXPpem(face->size->metrics.x_ppem) m_ftXPpem(face->size->metrics.x_ppem),
m_lineHeight(face->size->metrics.height),
m_subpixel(subpixel)
{ {
FT_Int32 baseFlags = FT_LOAD_NO_BITMAP; FT_Int32 baseFlags = FT_LOAD_NO_BITMAP;
if (subpixel) if (subpixel)
@ -433,7 +435,9 @@ FontAtlas::FontAtlas(boo::IGraphicsDataFactory* gf, FT_Face face, uint32_t dpi,
bool subpixel, FCharFilter& filter, Athena::io::FileReader& reader) bool subpixel, FCharFilter& filter, Athena::io::FileReader& reader)
: m_dpi(dpi), : m_dpi(dpi),
m_ftXscale(face->size->metrics.x_scale), m_ftXscale(face->size->metrics.x_scale),
m_ftXPpem(face->size->metrics.x_ppem) m_ftXPpem(face->size->metrics.x_ppem),
m_lineHeight(face->size->metrics.height),
m_subpixel(subpixel)
{ {
FT_Int32 baseFlags = FT_LOAD_NO_BITMAP; FT_Int32 baseFlags = FT_LOAD_NO_BITMAP;
if (subpixel) if (subpixel)

View File

@ -0,0 +1,130 @@
#include "Specter/MultiLineTextView.hpp"
#include "Specter/ViewSystem.hpp"
namespace Specter
{
static LogVisor::LogModule Log("Specter::MultiLineTextView");
MultiLineTextView::MultiLineTextView(ViewSystem& system,
View& parentView,
const FontAtlas& font,
size_t lineCapacity,
float lineHeight)
: View(system, parentView),
m_viewSystem(system),
m_fontAtlas(font),
m_lineCapacity(lineCapacity),
m_lineHeight(lineHeight) {}
MultiLineTextView::MultiLineTextView(ViewSystem& system,
View& parentView,
FontTag font,
size_t lineCapacity,
float lineHeight)
: MultiLineTextView(system,
parentView,
system.m_textSystem.m_fcache->lookupAtlas(font),
lineCapacity,
lineHeight) {}
void MultiLineTextView::typesetGlyphs(const std::string& str,
const Zeus::CColor& defaultColor)
{
m_lines.clear();
size_t rem = str.size() + 1;
const utf8proc_uint8_t* it = reinterpret_cast<const utf8proc_uint8_t*>(str.data());
size_t lineCount = 0;
while (rem)
{
utf8proc_int32_t ch;
utf8proc_ssize_t sz = utf8proc_iterate(it, -1, &ch);
if (sz < 0)
Log.report(LogVisor::FatalError, "invalid UTF-8 char");
if (ch == '\n' || ch == '\0')
++lineCount;
rem -= sz;
it += sz;
}
m_lines.reserve(lineCount);
rem = str.size() + 1;
it = reinterpret_cast<const utf8proc_uint8_t*>(str.data());
const utf8proc_uint8_t* beginIt = it;
while (rem)
{
utf8proc_int32_t ch;
utf8proc_ssize_t sz = utf8proc_iterate(it, -1, &ch);
if (ch == '\n' || ch == '\0')
{
m_lines.emplace_back(m_viewSystem, *this, m_fontAtlas, m_lineCapacity);
m_lines.back().typesetGlyphs(std::string((char*)beginIt, it - beginIt), defaultColor);
beginIt = it + 1;
}
rem -= sz;
it += sz;
}
updateSize();
}
void MultiLineTextView::typesetGlyphs(const std::wstring& str,
const Zeus::CColor& defaultColor)
{
m_lines.clear();
size_t rem = str.size() + 1;
auto it = str.cbegin();
size_t lineCount = 0;
while (rem)
{
if (*it == L'\n' || *it == L'\0')
++lineCount;
--rem;
++it;
}
m_lines.reserve(lineCount);
rem = str.size() + 1;
it = str.cbegin();
auto beginIt = it;
while (rem)
{
if (*it == L'\n' || *it == L'\0')
{
m_lines.emplace_back(m_viewSystem, *this, m_fontAtlas, m_lineCapacity);
m_lines.back().typesetGlyphs(std::wstring(beginIt, it), defaultColor);
beginIt = it + 1;
}
--rem;
++it;
}
updateSize();
}
void MultiLineTextView::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub)
{
View::resized(root, sub);
unsigned lHeight = unsigned(m_lineHeight * m_fontAtlas.FT_LineHeight()) >> 6;
unsigned decumHeight = lHeight * m_lines.size();
boo::SWindowRect tsub = sub;
tsub.location[1] += decumHeight;
tsub.size[1] = 10;
for (TextView& tv : m_lines)
{
tsub.location[1] -= lHeight;
tv.resized(root, tsub);
}
}
void MultiLineTextView::draw(boo::IGraphicsCommandQueue* gfxQ)
{
View::draw(gfxQ);
for (TextView& tv : m_lines)
tv.draw(gfxQ);
}
}

View File

@ -5,17 +5,17 @@ namespace Specter
{ {
RootView::RootView(ViewSystem& system, boo::IWindow* window) RootView::RootView(ViewSystem& system, boo::IWindow* window)
: View(system), m_window(window), m_textView(system, system.m_mainFont) : View(system, *this), m_window(window), m_textView(system, *this, system.m_mainFont)
{ {
window->setCallback(this); window->setCallback(this);
boo::SWindowRect rect = window->getWindowFrame(); boo::SWindowRect rect = window->getWindowFrame();
m_renderTex = system.m_factory->newRenderTexture(rect.size[0], rect.size[1], 1); m_renderTex = system.m_factory->newRenderTexture(rect.size[0], rect.size[1], 1);
system.m_factory->commit(); system.m_factory->commit();
resized(rect); resized(rect);
m_textView.typesetGlyphs("Hello, World! — こんにちは世界!", Zeus::CColor::skGreen); m_textView.typesetGlyphs("Hello, World!\nこんにちは世界!\n\n", Zeus::CColor::skWhite);
Zeus::CColor transBlack(0.f, 0.f, 0.f, 0.5f); Zeus::CColor transBlack(0.f, 0.f, 0.f, 0.5f);
m_textView.setBackground(transBlack); m_textView.setBackground(transBlack);
setBackground(Zeus::CColor::skBlue); setBackground(Zeus::CColor::skGrey);
} }
void RootView::destroyed() void RootView::destroyed()
@ -34,14 +34,16 @@ void RootView::resized(const boo::SWindowRect& root, const boo::SWindowRect&)
m_rootRect.location[0] = 0; m_rootRect.location[0] = 0;
m_rootRect.location[1] = 0; m_rootRect.location[1] = 0;
View::resized(m_rootRect, m_rootRect); View::resized(m_rootRect, m_rootRect);
boo::SWindowRect textRect = m_rootRect; boo::SWindowRect textRect = m_rootRect;
textRect.location[0] = 10; textRect.location[0] = 10;
textRect.location[1] = 10; textRect.location[1] = 10;
textRect.size[0] -= 20; textRect.size[0] -= 20;
if (textRect.size[0] < 0) if (textRect.size[0] < 0)
textRect.size[0] = 0; textRect.size[0] = 0;
textRect.size[1] = 10; textRect.size[1] = 100;
m_textView.resized(m_rootRect, textRect); m_textView.resized(m_rootRect, textRect);
m_resizeRTDirty = true; m_resizeRTDirty = true;
} }

View File

@ -0,0 +1,11 @@
#include "Specter/ScrollView.hpp"
namespace Specter
{
ScrollView::ScrollView(ViewSystem& system, View& parentView, View& contentView)
: View(system, parentView), m_contentView(contentView)
{
}
}

View File

@ -259,15 +259,21 @@ void TextView::System::init(boo::MetalDataFactory* factory, FontCache* fcache)
#endif #endif
TextView::TextView(ViewSystem& system, FontTag font, size_t capacity) TextView::TextView(ViewSystem& system, View& parentView, const FontAtlas& font, size_t capacity)
: View(system), : View(system, parentView),
m_capacity(capacity), m_capacity(capacity),
m_fontAtlas(system.m_textSystem.m_fcache->lookupAtlas(font)) m_fontAtlas(font)
{ {
m_glyphBuf = m_glyphBuf =
system.m_factory->newDynamicBuffer(boo::BufferUse::Vertex, system.m_factory->newDynamicBuffer(boo::BufferUse::Vertex,
sizeof(RenderGlyph), capacity); sizeof(RenderGlyph), capacity);
boo::IShaderPipeline* shader;
if (font.subpixel())
shader = system.m_textSystem.m_subpixel;
else
shader = system.m_textSystem.m_regular;
if (!system.m_textSystem.m_vtxFmt) if (!system.m_textSystem.m_vtxFmt)
{ {
boo::VertexElementDescriptor vdescs[] = boo::VertexElementDescriptor vdescs[] =
@ -288,7 +294,7 @@ TextView::TextView(ViewSystem& system, FontTag font, size_t capacity)
}; };
m_vtxFmt = system.m_factory->newVertexFormat(13, vdescs); m_vtxFmt = system.m_factory->newVertexFormat(13, vdescs);
boo::ITexture* texs[] = {m_fontAtlas.texture()}; boo::ITexture* texs[] = {m_fontAtlas.texture()};
m_shaderBinding = system.m_factory->newShaderDataBinding(system.m_textSystem.m_regular, m_vtxFmt, m_shaderBinding = system.m_factory->newShaderDataBinding(shader, m_vtxFmt,
nullptr, m_glyphBuf, nullptr, 1, nullptr, m_glyphBuf, nullptr, 1,
(boo::IGraphicsBuffer**)&m_viewVertBlockBuf, (boo::IGraphicsBuffer**)&m_viewVertBlockBuf,
1, texs); 1, texs);
@ -296,7 +302,7 @@ TextView::TextView(ViewSystem& system, FontTag font, size_t capacity)
else else
{ {
boo::ITexture* texs[] = {m_fontAtlas.texture()}; boo::ITexture* texs[] = {m_fontAtlas.texture()};
m_shaderBinding = system.m_factory->newShaderDataBinding(system.m_textSystem.m_regular, system.m_textSystem.m_vtxFmt, m_shaderBinding = system.m_factory->newShaderDataBinding(shader, system.m_textSystem.m_vtxFmt,
nullptr, m_glyphBuf, nullptr, 1, nullptr, m_glyphBuf, nullptr, 1,
(boo::IGraphicsBuffer**)&m_viewVertBlockBuf, (boo::IGraphicsBuffer**)&m_viewVertBlockBuf,
1, texs); 1, texs);
@ -305,6 +311,9 @@ TextView::TextView(ViewSystem& system, FontTag font, size_t capacity)
m_glyphs.reserve(capacity); m_glyphs.reserve(capacity);
} }
TextView::TextView(ViewSystem& system, View& parentView, FontTag font, size_t capacity)
: TextView(system, parentView, system.m_textSystem.m_fcache->lookupAtlas(font), capacity) {}
TextView::RenderGlyph::RenderGlyph(int& adv, const FontAtlas::Glyph& glyph, const 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);

View File

@ -1,5 +1,6 @@
#include "Specter/View.hpp" #include "Specter/View.hpp"
#include "Specter/ViewSystem.hpp" #include "Specter/ViewSystem.hpp"
#include "Specter/RootView.hpp"
namespace Specter namespace Specter
{ {
@ -145,8 +146,10 @@ void View::System::init(boo::MetalDataFactory* factory)
#endif #endif
View::View(ViewSystem& system) void View::buildResources(ViewSystem& system)
{ {
m_bgColor = Zeus::CColor::skClear;
m_bgVertBuf = m_bgVertBuf =
system.m_factory->newDynamicBuffer(boo::BufferUse::Vertex, system.m_factory->newDynamicBuffer(boo::BufferUse::Vertex,
sizeof(Zeus::CVector3f), 4); sizeof(Zeus::CVector3f), 4);
@ -181,11 +184,30 @@ View::View(ViewSystem& system)
(boo::IGraphicsBuffer**)&m_viewVertBlockBuf, (boo::IGraphicsBuffer**)&m_viewVertBlockBuf,
0, nullptr); 0, nullptr);
} }
}
View::View(ViewSystem& system, RootView& rootView)
: m_rootView(rootView),
m_parentView(rootView)
{
buildResources(system);
}
View::View(ViewSystem& system, View& parentView)
: m_rootView(parentView.root()),
m_parentView(parentView)
{
buildResources(system);
}
void View::updateSize()
{
resized(m_rootView.rootRect(), m_subRect);
} }
void View::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub) void View::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub)
{ {
m_subRect = sub;
m_viewVertBlock.setViewRect(root, sub); m_viewVertBlock.setViewRect(root, sub);
m_bgRect[0].assign(0.f, sub.size[1], 0.f); m_bgRect[0].assign(0.f, sub.size[1], 0.f);
m_bgRect[1].assign(0.f, 0.f, 0.f); m_bgRect[1].assign(0.f, 0.f, 0.f);