1 /*
2  Copyright (c) 2013 yvt
3 
4  This file is part of OpenSpades.
5 
6  OpenSpades is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  OpenSpades is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with OpenSpades.  If not, see <http://www.gnu.org/licenses/>.
18 
19  */
20 
21 #include "Quake3Font.h"
22 
23 #include "IRenderer.h"
24 #include <Core/Debug.h>
25 
26 namespace spades {
27 	namespace client {
Quake3Font(IRenderer * r,IImage * tex,const int * mp,int gh,float sw,bool extended)28 		Quake3Font::Quake3Font(IRenderer *r, IImage *tex, const int *mp, int gh, float sw,
29 		                       bool extended)
30 		    : IFont(r), renderer(r), tex(tex), glyphHeight(gh), spaceWidth(sw) {
31 			SPADES_MARK_FUNCTION();
32 
33 			tex->AddRef();
34 			for (int i = 0; i < (extended ? 256 : 128); i++) {
35 				int x = *(mp++);
36 				int y = *(mp++);
37 				int w = *(mp++);
38 				int adv;
39 				if (extended) {
40 					adv = *(mp++);
41 				} else {
42 					adv = w;
43 				}
44 
45 				GlyphInfo info;
46 				if (w == -1) {
47 					info.type = Invalid;
48 					glyphs.push_back(info);
49 					continue;
50 				}
51 				if (adv == PROP_SPACE_WIDTH) {
52 					info.type = Space;
53 					glyphs.push_back(info);
54 					continue;
55 				}
56 
57 				info.type = Image;
58 				info.imageRect = AABB2(x, y, w, gh);
59 				info.advance = adv;
60 
61 				glyphs.push_back(info);
62 			}
63 
64 			yMin = 0.f;
65 			yMax = (float)gh;
66 		}
67 
~Quake3Font()68 		Quake3Font::~Quake3Font() {
69 			SPADES_MARK_FUNCTION();
70 			tex->Release();
71 		}
72 
SetGlyphYRange(float yMin,float yMax)73 		void Quake3Font::SetGlyphYRange(float yMin, float yMax) {
74 			this->yMin = yMin;
75 			this->yMax = yMax;
76 		}
77 
Measure(const std::string & txt)78 		Vector2 Quake3Font::Measure(const std::string &txt) {
79 			SPADES_MARK_FUNCTION();
80 
81 			float x = 0.f, w = 0.f, h = (float)glyphHeight;
82 			for (size_t i = 0; i < txt.size();) {
83 				size_t chrLen = 0;
84 				uint32_t ch = GetCodePointFromUTF8String(txt, i, &chrLen);
85 				SPAssert(chrLen > 0);
86 				i += chrLen;
87 				if (ch >= static_cast<uint32_t>(glyphs.size())) {
88 					goto fallback;
89 				}
90 
91 				if (ch == 13 || ch == 10) {
92 					// new line
93 					x = 0.f;
94 					h += (float)glyphHeight;
95 					continue;
96 				}
97 
98 				{
99 					const GlyphInfo &info = glyphs[ch];
100 
101 					if (info.type == Invalid)
102 						goto fallback;
103 					else if (info.type == Space) {
104 						x += spaceWidth;
105 					} else if (info.type == Image) {
106 						x += info.advance;
107 					}
108 
109 					if (x > w) {
110 						w = x;
111 					}
112 				}
113 
114 				continue;
115 			fallback:
116 				x += MeasureFallback(ch, yMax - yMin);
117 				if (x > w) {
118 					w = x;
119 				}
120 			}
121 			return MakeVector2(w, h);
122 		}
123 
Draw(const std::string & txt,spades::Vector2 offset,float scale,spades::Vector4 color)124 		void Quake3Font::Draw(const std::string &txt, spades::Vector2 offset, float scale,
125 		                      spades::Vector4 color) {
126 			float x = 0.f, y = 0;
127 
128 			if (scale == 1.f) {
129 				offset.x = floorf(offset.x);
130 				offset.y = floorf(offset.y);
131 			}
132 
133 			float a = color.w;
134 			color.w = 1.f;
135 			color *= a;
136 			renderer->SetColorAlphaPremultiplied(color);
137 
138 			float invScale = 1.f / scale;
139 
140 			for (size_t i = 0; i < txt.size();) {
141 				size_t chrLen = 0;
142 				uint32_t ch = GetCodePointFromUTF8String(txt, i, &chrLen);
143 				SPAssert(chrLen > 0);
144 				i += chrLen;
145 				if (ch >= static_cast<uint32_t>(glyphs.size())) {
146 					goto fallback;
147 				}
148 
149 				if (ch == 13 || ch == 10) {
150 					// new line
151 					x = 0.f;
152 					y += (float)glyphHeight;
153 					continue;
154 				}
155 
156 				{
157 					const GlyphInfo &info = glyphs[ch];
158 
159 					if (info.type == Invalid)
160 						goto fallback;
161 					else if (info.type == Space) {
162 						x += spaceWidth;
163 					} else if (info.type == Image) {
164 						AABB2 rt(x * scale + offset.x, y * scale + offset.y,
165 						         info.imageRect.GetWidth() * scale,
166 						         info.imageRect.GetHeight() * scale);
167 						renderer->DrawImage(tex, rt, info.imageRect);
168 						x += info.advance;
169 					}
170 				}
171 				continue;
172 			fallback:
173 				DrawFallback(ch, MakeVector2(x, y + yMin) * scale + offset, (yMax - yMin) * scale,
174 				             color);
175 				x += MeasureFallback(ch, (yMax - yMin) * scale) * invScale;
176 			}
177 		}
178 	}
179 }
180