[aseprite] 51/196: Add a basic TrueType font impl to she library using FreeType library

Tobias Hansen thansen at moszumanska.debian.org
Wed Apr 20 18:50:00 UTC 2016


This is an automated email from the git hooks/post-receive script.

thansen pushed a commit to branch master
in repository aseprite.

commit dfa6bcd16bbbbf7da30375ec345592c00f49b8a7
Author: David Capello <davidcapello at gmail.com>
Date:   Thu Mar 10 15:49:13 2016 -0300

    Add a basic TrueType font impl to she library using FreeType library
---
 src/ft/face.h                      |  26 +++++---
 src/ft/lib.h                       |   8 ++-
 src/she/CMakeLists.txt             |   6 +-
 src/she/alleg4/alleg_surface.h     |   2 +-
 src/she/common/freetype_font.cpp   |  92 ++++++++++++++++++++++++++
 src/she/common/freetype_font.h     |  43 +++++++++++++
 src/she/common/generic_surface.h   | 128 +++++++++++++++++++++++++++++++++----
 src/she/common/sprite_sheet_font.h |   4 ++
 src/she/common/system.h            |   5 ++
 src/she/font.h                     |   9 ++-
 src/she/skia/skia_surface.h        |  23 +------
 src/she/system.h                   |   1 +
 12 files changed, 300 insertions(+), 47 deletions(-)

diff --git a/src/ft/face.h b/src/ft/face.h
index 22e49d5..d42398c 100644
--- a/src/ft/face.h
+++ b/src/ft/face.h
@@ -8,7 +8,9 @@
 #define FT_FACE_H_INCLUDED
 #pragma once
 
+#include "base/disable_copying.h"
 #include "ft/freetype_headers.h"
+#include "gfx/rect.h"
 
 namespace ft {
 
@@ -22,8 +24,11 @@ namespace ft {
         FT_Done_Face(m_face);
     }
 
-    operator FT_Face() {
-      return m_face;
+    operator FT_Face() { return m_face; }
+    FT_Face operator->() { return m_face; }
+
+    bool isValid() const {
+      return (m_face != nullptr);
     }
 
     bool antialias() const {
@@ -75,13 +80,14 @@ namespace ft {
     gfx::Rect calcTextBounds(Iterator first, Iterator end) {
       gfx::Rect bounds(0, 0, 0, 0);
 
-      forEachGlyph(first, end,
-              [&bounds](FT_GlyphSlot glyph, int x) {
-                bounds |= gfx::Rect(x + glyph->bitmap_left,
-                                    -glyph->bitmap_top,
-                                    (int)glyph->bitmap.width,
-                                    (int)glyph->bitmap.rows);
-              });
+      forEachGlyph(
+        first, end,
+        [&bounds](FT_GlyphSlot glyph, int x) {
+          bounds |= gfx::Rect(x + glyph->bitmap_left,
+                              -glyph->bitmap_top,
+                              (int)glyph->bitmap.width,
+                              (int)glyph->bitmap.rows);
+        });
 
       return bounds;
     }
@@ -89,6 +95,8 @@ namespace ft {
   private:
     FT_Face m_face;
     bool m_antialias;
+
+    DISABLE_COPYING(Face);
   };
 
 } // namespace ft
diff --git a/src/ft/lib.h b/src/ft/lib.h
index 91c869f..9bf35d1 100644
--- a/src/ft/lib.h
+++ b/src/ft/lib.h
@@ -8,8 +8,11 @@
 #define FT_LIB_H_INCLUDED
 #pragma once
 
+#include "base/disable_copying.h"
 #include "ft/freetype_headers.h"
 
+#include <string>
+
 namespace ft {
 
   class Lib {
@@ -19,7 +22,8 @@ namespace ft {
     }
 
     ~Lib() {
-      FT_Done_FreeType(m_ft);
+      if (m_ft)
+        FT_Done_FreeType(m_ft);
     }
 
     operator FT_Library() {
@@ -39,6 +43,8 @@ namespace ft {
 
   private:
     FT_Library m_ft;
+
+    DISABLE_COPYING(Lib);
   };
 
 } // namespace ft
diff --git a/src/she/CMakeLists.txt b/src/she/CMakeLists.txt
index 4dbd4cf..d000ee0 100644
--- a/src/she/CMakeLists.txt
+++ b/src/she/CMakeLists.txt
@@ -1,7 +1,8 @@
 # SHE
 # Copyright (C) 2012-2016  David Capello
 
-set(SHE_SOURCES)
+set(SHE_SOURCES
+  common/freetype_font.cpp)
 
 ######################################################################
 # Allegro 4 backend
@@ -197,7 +198,8 @@ add_library(she ${SHE_SOURCES})
 
 target_link_libraries(she
   gfx-lib
-  base-lib)
+  base-lib
+  ${FREETYPE_LIBRARY})
 
 if(USE_ALLEG4_BACKEND)
   target_link_libraries(she
diff --git a/src/she/alleg4/alleg_surface.h b/src/she/alleg4/alleg_surface.h
index 2636bd4..5e0e3a8 100644
--- a/src/she/alleg4/alleg_surface.h
+++ b/src/she/alleg4/alleg_surface.h
@@ -15,7 +15,7 @@
 
 namespace she {
 
-  class Alleg4Surface : public GenericSurface<Surface> {
+  class Alleg4Surface : public GenericDrawTextSurface<GenericDrawColoredRgbaSurface<Surface> > {
   public:
     enum DestroyFlag {
       None = 0,
diff --git a/src/she/common/freetype_font.cpp b/src/she/common/freetype_font.cpp
new file mode 100644
index 0000000..2e6c15d
--- /dev/null
+++ b/src/she/common/freetype_font.cpp
@@ -0,0 +1,92 @@
+// SHE library
+// Copyright (C) 2016  David Capello
+//
+// This file is released under the terms of the MIT license.
+// Read LICENSE.txt for more information.
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "she/common/freetype_font.h"
+
+#include "gfx/point.h"
+#include "gfx/size.h"
+
+namespace she {
+
+FreeTypeFont::FreeTypeFont(const char* filename, int height)
+  : m_face(m_ft.open(filename))
+{
+  ASSERT(m_face.isValid());
+  if (m_face.isValid())
+    m_face.setSize(height);
+}
+
+FreeTypeFont::~FreeTypeFont()
+{
+}
+
+bool FreeTypeFont::isValid() const
+{
+  return m_face.isValid();
+}
+
+void FreeTypeFont::dispose()
+{
+  delete this;
+}
+
+FontType FreeTypeFont::type()
+{
+  return FontType::kTrueType;
+}
+
+int FreeTypeFont::height() const
+{
+  FT_UInt glyph_index = FT_Get_Char_Index(m_face, 'A');
+
+  FT_Error err = FT_Load_Glyph(
+    m_face, glyph_index,
+    FT_LOAD_RENDER |
+    FT_LOAD_NO_BITMAP |
+    (m_face.antialias() ? FT_LOAD_TARGET_NORMAL:
+                          FT_LOAD_TARGET_MONO));
+
+  if (!err)
+    return (int)m_face->glyph->bitmap.rows;
+  else
+    return m_face->height >> 6;
+}
+
+int FreeTypeFont::charWidth(int chr) const
+{
+  return m_face.calcTextBounds(&chr, (&chr)+1).w;
+}
+
+int FreeTypeFont::textLength(const std::string& str) const
+{
+  return m_face.calcTextBounds(str.begin(), str.end()).w;
+}
+
+bool FreeTypeFont::isScalable() const
+{
+  return true;
+}
+
+void FreeTypeFont::setSize(int size)
+{
+  m_face.setSize(size);
+}
+
+FreeTypeFont* loadFreeTypeFont(const char* filename, int height)
+{
+  FreeTypeFont* font = new FreeTypeFont(filename, height);
+  if (!font->isValid()) {
+    delete font;
+    font = nullptr;
+  }
+  return font;
+}
+
+} // namespace she
diff --git a/src/she/common/freetype_font.h b/src/she/common/freetype_font.h
new file mode 100644
index 0000000..aff7d42
--- /dev/null
+++ b/src/she/common/freetype_font.h
@@ -0,0 +1,43 @@
+// SHE library
+// Copyright (C) 2016  David Capello
+//
+// This file is released under the terms of the MIT license.
+// Read LICENSE.txt for more information.
+
+#ifndef SHE_COMMON_FREETYPE_FONT_H_INCLUDED
+#define SHE_COMMON_FREETYPE_FONT_H_INCLUDED
+#pragma once
+
+#include "ft/face.h"
+#include "ft/lib.h"
+#include "she/font.h"
+
+namespace she {
+  class Font;
+
+  class FreeTypeFont : public Font {
+  public:
+    FreeTypeFont(const char* filename, int height);
+    ~FreeTypeFont();
+
+    bool isValid() const;
+    void dispose() override;
+    FontType type() override;
+    int height() const override;
+    int charWidth(int chr) const override;
+    int textLength(const std::string& str) const override;
+    bool isScalable() const override;
+    void setSize(int size) override;
+
+    ft::Face& face() { return m_face; }
+
+  private:
+    mutable ft::Lib m_ft;
+    mutable ft::Face m_face;
+  };
+
+  FreeTypeFont* loadFreeTypeFont(const char* filename, int height);
+
+} // namespace she
+
+#endif
diff --git a/src/she/common/generic_surface.h b/src/she/common/generic_surface.h
index de18e33..b7faac7 100644
--- a/src/she/common/generic_surface.h
+++ b/src/she/common/generic_surface.h
@@ -9,6 +9,7 @@
 #pragma once
 
 #include "gfx/clip.h"
+#include "she/common/freetype_font.h"
 #include "she/common/sprite_sheet_font.h"
 
 namespace she {
@@ -51,7 +52,7 @@ gfx::Color blend(const gfx::Color backdrop, gfx::Color src)
 } // anoynmous namespace
 
 template<typename Base>
-class GenericSurface : public Base {
+class GenericDrawColoredRgbaSurface : public Base {
 public:
 
   void drawColoredRgbaSurface(const Surface* src, gfx::Color fg, gfx::Color bg, const gfx::Clip& clipbase) override {
@@ -87,24 +88,127 @@ public:
       }
     }
   }
+};
+
+template<typename Base>
+class GenericDrawTextSurface : public Base {
+public:
 
   void drawChar(Font* font, gfx::Color fg, gfx::Color bg, int x, int y, int chr) override {
-    SpriteSheetFont* ssFont = static_cast<SpriteSheetFont*>(font);
+    switch (font->type()) {
+
+      case FontType::kSpriteSheet: {
+        SpriteSheetFont* ssFont = static_cast<SpriteSheetFont*>(font);
+
+        gfx::Rect charBounds = ssFont->getCharBounds(chr);
+        if (!charBounds.isEmpty()) {
+          Surface* sheet = ssFont->getSurfaceSheet();
+          SurfaceLock lock(sheet);
+          drawColoredRgbaSurface(sheet, fg, bg, gfx::Clip(x, y, charBounds));
+        }
+        break;
+      }
+
+      case FontType::kTrueType: {
+        std::string str;
+        str.push_back(chr);
+        drawString(font, fg, bg, x, y, str);
+        break;
+      }
 
-    gfx::Rect charBounds = ssFont->getCharBounds(chr);
-    if (!charBounds.isEmpty()) {
-      Surface* sheet = ssFont->getSurfaceSheet();
-      SurfaceLock lock(sheet);
-      drawColoredRgbaSurface(sheet, fg, bg, gfx::Clip(x, y, charBounds));
     }
   }
 
   void drawString(Font* font, gfx::Color fg, gfx::Color bg, int x, int y, const std::string& str) override {
-    base::utf8_const_iterator it(str.begin()), end(str.end());
-    while (it != end) {
-      drawChar(font, fg, bg, x, y, *it);
-      x += font->charWidth(*it);
-      ++it;
+    switch (font->type()) {
+
+      case FontType::kSpriteSheet: {
+        base::utf8_const_iterator it(str.begin()), end(str.end());
+        while (it != end) {
+          drawChar(font, fg, bg, x, y, *it);
+          x += font->charWidth(*it);
+          ++it;
+        }
+        break;
+      }
+
+      case FontType::kTrueType: {
+        FreeTypeFont* ttFont = static_cast<FreeTypeFont*>(font);
+        bool antialias = ttFont->face().antialias();
+        int fg_alpha = gfx::geta(fg);
+
+        gfx::Rect bounds =
+          ttFont->face().calcTextBounds(str.begin(), str.end());
+
+        she::SurfaceFormatData fd;
+        getFormat(&fd);
+
+        gfx::Rect clip = getClipBounds();
+
+        ttFont->face().forEachGlyph(
+          str.begin(), str.end(),
+          [&](FT_GlyphSlot glyph, int local_x) {
+            int t;
+
+            for (int v=0; v<(int)glyph->bitmap.rows; ++v) {
+              const uint8_t* p = glyph->bitmap.buffer + v*glyph->bitmap.pitch;
+              int bit = 0;
+              int dst_x = x + local_x - bounds.x + glyph->bitmap_left;
+              int dst_y = y - bounds.y - glyph->bitmap_top + v;
+
+              if (!clip.contains(gfx::Point(dst_x, dst_y)))
+                break;
+
+              uint32_t* dst_address = (uint32_t*)getData(dst_x, dst_y);
+
+              for (int u=0; u<(int)glyph->bitmap.width; ++u) {
+                int alpha;
+
+                if (antialias) {
+                  alpha = *(p++);
+                }
+                else {
+                  alpha = ((*p) & (1 << (7 - (bit++))) ? 255: 0);
+                  if (bit == 8) {
+                    bit = 0;
+                    ++p;
+                  }
+                }
+
+                uint32_t backdrop = *dst_address;
+                gfx::Color backdropColor =
+                  gfx::rgba(
+                    ((backdrop & fd.redMask) >> fd.redShift),
+                    ((backdrop & fd.greenMask) >> fd.greenShift),
+                    ((backdrop & fd.blueMask) >> fd.blueShift),
+                    ((backdrop & fd.alphaMask) >> fd.alphaShift));
+
+                gfx::Color output = gfx::rgba(gfx::getr(fg),
+                                              gfx::getg(fg),
+                                              gfx::getb(fg),
+                                              MUL_UN8(fg_alpha, alpha, t));
+                if (gfx::geta(bg) > 0)
+                  output = blend(blend(backdropColor, bg), output);
+                else
+                  output = blend(backdropColor, output);
+
+                *dst_address =
+                  ((gfx::getr(output) << fd.redShift  ) & fd.redMask  ) |
+                  ((gfx::getg(output) << fd.greenShift) & fd.greenMask) |
+                  ((gfx::getb(output) << fd.blueShift ) & fd.blueMask ) |
+                  ((gfx::geta(output) << fd.alphaShift) & fd.alphaMask);
+
+                ++dst_x;
+                if (dst_x >= clip.x2())
+                  break;
+
+                ++dst_address;
+              }
+            }
+          });
+        break;
+      }
+
     }
   }
 
diff --git a/src/she/common/sprite_sheet_font.h b/src/she/common/sprite_sheet_font.h
index 5f5206d..396fce0 100644
--- a/src/she/common/sprite_sheet_font.h
+++ b/src/she/common/sprite_sheet_font.h
@@ -33,6 +33,10 @@ public:
     delete this;
   }
 
+  FontType type() override {
+    return FontType::kSpriteSheet;
+  }
+
   int height() const override {
     return getCharBounds(' ').h;
   }
diff --git a/src/she/common/system.h b/src/she/common/system.h
index f23a772..b5da921 100644
--- a/src/she/common/system.h
+++ b/src/she/common/system.h
@@ -19,6 +19,7 @@
   #include "she/native_dialogs.h"
 #endif
 
+#include "she/common/freetype_font.h"
 #include "she/common/sprite_sheet_font.h"
 
 namespace she {
@@ -80,6 +81,10 @@ public:
     return font;
   }
 
+  Font* loadTrueTypeFont(const char* filename, int height) override {
+    return loadFreeTypeFont(filename, height);
+  }
+
 private:
   NativeDialogs* m_nativeDialogs;
 };
diff --git a/src/she/font.h b/src/she/font.h
index ba8f225..43a607d 100644
--- a/src/she/font.h
+++ b/src/she/font.h
@@ -1,5 +1,5 @@
 // SHE library
-// Copyright (C) 2012-2015  David Capello
+// Copyright (C) 2012-2016  David Capello
 //
 // This file is released under the terms of the MIT license.
 // Read LICENSE.txt for more information.
@@ -12,10 +12,17 @@
 
 namespace she {
 
+  enum class FontType {
+    kUnknown,
+    kSpriteSheet,
+    kTrueType,
+  };
+
   class Font {
   public:
     virtual ~Font() { }
     virtual void dispose() = 0;
+    virtual FontType type() = 0;
     virtual int height() const = 0;
     virtual int charWidth(int chr) const = 0;
     virtual int textLength(const std::string& str) const = 0;
diff --git a/src/she/skia/skia_surface.h b/src/she/skia/skia_surface.h
index e005331..5cd46d2 100644
--- a/src/she/skia/skia_surface.h
+++ b/src/she/skia/skia_surface.h
@@ -9,6 +9,7 @@
 #pragma once
 
 #include "gfx/clip.h"
+#include "she/common/generic_surface.h"
 #include "she/common/sprite_sheet_font.h"
 
 #include "SkBitmap.h"
@@ -29,7 +30,7 @@ inline SkIRect to_skia(const gfx::Rect& rc) {
   return SkIRect::MakeXYWH(rc.x, rc.y, rc.w, rc.h);
 }
 
-class SkiaSurface : public Surface {
+class SkiaSurface : public GenericDrawTextSurface<Surface> {
 public:
   SkiaSurface() : m_surface(nullptr)
                 , m_canvas(nullptr)
@@ -427,26 +428,6 @@ public:
       SkCanvas::kStrict_SrcRectConstraint);
   }
 
-  void drawChar(Font* font, gfx::Color fg, gfx::Color bg, int x, int y, int chr) override {
-    SpriteSheetFont* commonFont = static_cast<SpriteSheetFont*>(font);
-
-    gfx::Rect charBounds = commonFont->getCharBounds(chr);
-    if (!charBounds.isEmpty()) {
-      Surface* sheet = commonFont->getSurfaceSheet();
-      SurfaceLock lock(sheet);
-      drawColoredRgbaSurface(sheet, fg, bg, gfx::Clip(x, y, charBounds));
-    }
-  }
-
-  void drawString(Font* font, gfx::Color fg, gfx::Color bg, int x, int y, const std::string& str) override {
-    base::utf8_const_iterator it(str.begin()), end(str.end());
-    while (it != end) {
-      drawChar(font, fg, bg, x, y, *it);
-      x += font->charWidth(*it);
-      ++it;
-    }
-  }
-
   SkBitmap& bitmap() {
     return m_bitmap;
   }
diff --git a/src/she/system.h b/src/she/system.h
index a93c9d7..7e7f040 100644
--- a/src/she/system.h
+++ b/src/she/system.h
@@ -47,6 +47,7 @@ namespace she {
     virtual Surface* loadSurface(const char* filename) = 0;
     virtual Surface* loadRgbaSurface(const char* filename) = 0;
     virtual Font* loadSpriteSheetFont(const char* filename, int scale = 1) = 0;
+    virtual Font* loadTrueTypeFont(const char* filename, int height) = 0;
     virtual Clipboard* createClipboard() = 0;
   };
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/aseprite.git



More information about the Pkg-games-commits mailing list