1// LAF OS Library
2// Copyright (C) 2019-2022 Igara Studio S.A.
3// Copyright (C) 2012-2017 David Capello
4//
5// This file is released under the terms of the MIT license.
6// Read LICENSE.txt for more information.
7
8#ifndef OS_SPRITE_SHEET_FONT_H
9#define OS_SPRITE_SHEET_FONT_H
10#pragma once
11
12#include "base/debug.h"
13#include "base/string.h"
14#include "base/utf8_decode.h"
15#include "gfx/rect.h"
16#include "os/font.h"
17#include "os/ref.h"
18#include "os/surface.h"
19
20#include <vector>
21
22namespace os {
23
24class SpriteSheetFont : public Font {
25public:
26 SpriteSheetFont() : m_sheet(nullptr) { }
27 ~SpriteSheetFont() { }
28
29 FontType type() override {
30 return FontType::SpriteSheet;
31 }
32
33 int height() const override {
34 return getCharBounds(' ').h;
35 }
36
37 int textLength(const std::string& str) const override {
38 base::utf8_decode decode(str);
39 int x = 0;
40 while (int chr = decode.next())
41 x += getCharBounds(chr).w;
42 return x;
43 }
44
45 bool isScalable() const override {
46 return false;
47 }
48
49 void setSize(int size) override {
50 // Do nothing
51 }
52
53 void setAntialias(bool antialias) override {
54 // Do nothing
55 }
56
57 bool hasCodePoint(int codepoint) const override {
58 codepoint -= (int)' ';
59 return (codepoint >= 0 && codepoint < (int)m_chars.size());
60 }
61
62 Surface* sheetSurface() const {
63 return m_sheet.get();
64 }
65
66 gfx::Rect getCharBounds(int chr) const {
67 chr -= (int)' ';
68 if (chr >= 0 && chr < (int)m_chars.size())
69 return m_chars[chr];
70 else if (chr != 128)
71 return getCharBounds(128);
72 else
73 return gfx::Rect();
74 }
75
76 static FontRef fromSurface(const SurfaceRef& sur) {
77 auto font = make_ref<SpriteSheetFont>();
78 font->m_sheet = sur;
79
80 SurfaceLock lock(sur.get());
81 gfx::Rect bounds(0, 0, 1, 1);
82
83 while (font->findChar(sur.get(), sur->width(), sur->height(), bounds)) {
84 font->m_chars.push_back(bounds);
85 bounds.x += bounds.w;
86 }
87
88 return font;
89 }
90
91private:
92
93 bool findChar(const Surface* sur, int width, int height, gfx::Rect& bounds) {
94 gfx::Color keyColor = sur->getPixel(0, 0);
95
96 while (sur->getPixel(bounds.x, bounds.y) == keyColor) {
97 bounds.x++;
98 if (bounds.x >= width) {
99 bounds.x = 0;
100 bounds.y += bounds.h;
101 bounds.h = 1;
102 if (bounds.y >= height)
103 return false;
104 }
105 }
106
107 bounds.w = 0;
108 while ((bounds.x+bounds.w < width) &&
109 (sur->getPixel(bounds.x+bounds.w, bounds.y) != keyColor)) {
110 bounds.w++;
111 }
112
113 bounds.h = 0;
114 while ((bounds.y+bounds.h < height) &&
115 (sur->getPixel(bounds.x, bounds.y+bounds.h) != keyColor)) {
116 bounds.h++;
117 }
118
119 return !bounds.isEmpty();
120 }
121
122private:
123 Ref<Surface> m_sheet;
124 std::vector<gfx::Rect> m_chars;
125};
126
127} // namespace os
128
129#endif
130