1 /*
2 DSFML - The Simple and Fast Multimedia Library for D
3 
4 Copyright (c) 2013 - 2015 Jeremy DeHaan (dehaan.jeremiah@gmail.com)
5 
6 This software is provided 'as-is', without any express or implied warranty.
7 In no event will the authors be held liable for any damages arising from the use of this software.
8 
9 Permission is granted to anyone to use this software for any purpose, including commercial applications,
10 and to alter it and redistribute it freely, subject to the following restrictions:
11 
12 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
13 If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
14 
15 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
16 
17 3. This notice may not be removed or altered from any source distribution
18 */
19 
20 module dsfml.graphics.font;
21 
22 import dsfml.graphics.texture;
23 import dsfml.graphics.glyph;
24 import dsfml.system.inputstream;
25 import dsfml.system.err;
26 
27 /++
28  + Class for loading and manipulating character fonts.
29  + 
30  + Fonts can be loaded from a file, from memory or from a custom stream, and supports the most common types of fonts.
31  + 
32  + See the loadFromFile function for the complete list of supported formats.
33  + 
34  + Once it is loaded, a Font instance provides three types of information about the font:
35  + - Global metrics, such as the line spacing
36  + - Per-glyph metrics, such as bounding box or kerning
37  + - Pixel representation of glyphs
38  + 
39  + Authors: Laurent Gomila, Jeremy DeHaan
40  + See_Also: http://sfml-dev.org/documentation/2.0/classsf_1_1Font.php#details
41  +/
42 class Font
43 {
44 	package sfFont* sfPtr;
45 
46 	private Texture fontTexture;
47 	private fontStream m_stream;//keeps an instance of the C++ stream stored if used
48 
49 	/// Defines an empty font
50 	this()
51 	{
52 		sfPtr = sfFont_construct();
53 		fontTexture = new Texture(sfFont_getTexturePtr(sfPtr));
54 	}
55 
56 	package this(sfFont* newFont)
57 	{
58 		sfPtr = newFont;
59 		fontTexture = new Texture(sfFont_getTexturePtr(sfPtr));
60 	}
61 	
62 	~this()
63 	{
64 		import dsfml.system.config;
65 		mixin(destructorOutput);
66 		sfFont_destroy(sfPtr);
67 	}
68 
69 	/**
70 	 * Load the font from a file.
71 	 * 
72 	 * The supported font formats are: TrueType, Type 1, CFF, OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42. Note that this function know nothing about the standard fonts installed on the user's system, thus you can't load them directly.
73 	 * 
74 	 * Params:
75 	 * 		filename	= Path of the font file to load
76 	 * 
77 	 * Returns: True if loading succeeded, false if it failed.
78 	 */
79 	bool loadFromFile(string filename)
80 	{
81 		import dsfml.system..string;
82 
83 		bool ret = sfFont_loadFromFile(sfPtr, toStringz(filename));
84 		if(!ret)
85 		{
86 			err.write(dsfml.system..string.toString(sfErr_getOutput()));
87 		}
88 		
89 		return ret;
90 	}
91 
92 	/**
93 	 * Load the font from a file in memory.
94 	 * 
95 	 * The supported font formats are: TrueType, Type 1, CFF, OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42. Warning: SFML cannot preload all the font data in this function, so the buffer pointed by data has to remain valid as long as the font is used.
96 	 * 
97 	 * Params:
98 	 * 		data	= data holding the font file
99 	 * 
100 	 * Returns: True if loading succeeded, false if it failed.
101 	 */
102 	bool loadFromMemory(const(void)[] data)
103 	{
104 		import dsfml.system..string;
105 
106 		bool ret = sfFont_loadFromMemory(sfPtr, data.ptr, data.length);
107 		if(!ret)
108 		{
109 			err.write(dsfml.system..string.toString(sfErr_getOutput()));
110 		}
111 		
112 		return ret;
113 	}
114 
115 	/**
116 	 * Load the font from a custom stream.
117 	 * 
118 	 * The supported font formats are: TrueType, Type 1, CFF, OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42. Warning: SFML cannot preload all the font data in this function, so the contents of stream have to remain valid as long as the font is used.
119 	 * 
120 	 * Params:
121 	 * 		stream	= Source stream to read from
122 	 * 
123 	 * Returns: True if loading succeeded, false if it failed.
124 	 */
125 	bool loadFromStream(InputStream stream)
126 	{
127 		import dsfml.system..string;
128 
129 		m_stream = new fontStream(stream);
130 
131 		bool ret = sfFont_loadFromStream(sfPtr, m_stream);
132 
133 		if(!ret)
134 		{
135 			err.write(dsfml.system..string.toString(sfErr_getOutput()));
136 		}
137 		
138 		return ret;
139 	}
140 
141 	/**
142 	 * Retrieve a glyph of the font.
143 	 * 
144 	 * Params:
145 	 * 		codePoint		= Unicode code point of the character ot get
146 	 * 		characterSize	= Reference character size
147 	 * 		bols			= Retrieve the bold version or the regular one?
148 	 * 
149 	 * Returns: The glyph corresponding to codePoint and characterSize
150 	 */
151 	Glyph getGlyph(dchar codePoint, uint characterSize, bool bold) const
152 	{
153 		Glyph temp;
154 
155 		sfFont_getGlyph(sfPtr, cast(uint)codePoint, characterSize,bold,&temp.advance,&temp.bounds.left,&temp.bounds.top,&temp.bounds.width,&temp.bounds.height,&temp.textureRect.left,&temp.textureRect.top,&temp.textureRect.width,&temp.textureRect.height);
156 
157 		return temp;
158 	}
159 
160 	/**
161 	 * Get the kerning offset of two glyphs.
162 	 * 
163 	 * The kerning is an extra offset (negative) to apply between two glyphs when rendering them, to make the pair look more "natural". For example, the pair "AV" have a special kerning to make them closer than other characters. Most of the glyphs pairs have a kerning offset of zero, though.
164 	 * 
165 	 * Params:
166 	 * 		first			= Unicode code point of the first character
167 	 * 		second			= Unicode code point of the second character
168 	 * 		characterSize	= Reference character size
169 	 * 
170 	 * Returns: Kerning value for first and second, in pixels
171 	 */
172 	int getKerning (dchar first, dchar second, uint characterSize) const 
173 	{
174 		return sfFont_getKerning(sfPtr, cast(uint)first, cast(uint)second, characterSize);	
175 	}
176 
177 	/**
178 	 * Get the line spacing.
179 	 * 
180 	 * The spacing is the vertical offset to apply between consecutive lines of text.
181 	 * 
182 	 * Params:
183 	 * 		characterSize	= Reference character size
184 	 * 
185 	 * Returns: Line spacing, in pixels
186 	 */
187 	int getLineSpacing (uint characterSize) const
188 	{
189 		return sfFont_getLineSpacing(sfPtr, characterSize);	
190 	}
191 
192 	/**
193 	 * Retrieve the texture containing the loaded glyphs of a certain size.
194 	 * 
195 	 * The contents of the returned texture changes as more glyphs are requested, thus it is not very relevant. It is mainly used internally by Text.
196 	 * 
197 	 * Params:
198 	 * 		characterSize	= Reference character size
199 	 * 
200 	 * Returns: Texture containing the glyphs of the requested size
201 	 */
202 	const(Texture) getTexture (uint characterSize) const
203 	{
204 		//ToDo: cache texture somehow?
205 		//Possible: cache last size used using sound method(mutable instance storage)
206 
207         import std.stdio;
208         
209         //writeln("Updating Texture");
210         
211 		sfFont_updateTexture(sfPtr, characterSize);
212 		
213 		//fontTexture.sfPtr = sfFont_getTexture(sfPtr, characterSize);
214 
215        // writeln("returning texture");
216 		return fontTexture;
217 	}
218 
219 	/**
220 	 * Performs a deep copy on the font.
221 	 * 
222 	 * Returns: The duplicated font.
223 	 */
224 	@property
225 	Font dup() const
226 	{
227 		return new Font(sfFont_copy(sfPtr));
228 	}
229 
230 }
231 
232 unittest
233 {
234 	version(DSFML_Unittest_Graphics)
235 	{
236 		import std.stdio;
237 
238 		import dsfml.graphics.text;
239 
240 		writeln("Unitest for Font");
241 
242 		auto font = new Font();
243 		assert(font.loadFromFile("res/Warenhaus-Standard.ttf"));
244 
245 		Text text;
246 		text = new Text("Sample String", font);
247 
248 
249 		//draw text or something
250 
251 		writeln();
252 	}
253 }
254 
255 
256 private:
257 private extern(C++) interface fontInputStream
258 {
259 	long read(void* data, long size);
260 	
261 	long seek(long position);
262 	
263 	long tell();
264 	
265 	long getSize();
266 }
267 
268 
269 private class fontStream:fontInputStream
270 {
271 	private InputStream myStream;
272 	
273 	this(InputStream stream)
274 	{
275 		myStream = stream;
276 	}
277 	
278 	extern(C++)long read(void* data, long size)
279 	{
280 		return myStream.read(data[0..cast(size_t)size]);
281 	}
282 	
283 	extern(C++)long seek(long position)
284 	{
285 		return myStream.seek(position);
286 	}
287 	
288 	extern(C++)long tell()
289 	{
290 		return myStream.tell();
291 	}
292 	
293 	extern(C++)long getSize()
294 	{
295 		return myStream.getSize();
296 	}
297 }
298 
299 
300 
301 package extern(C) struct sfFont;
302 
303 private extern(C):
304 
305 sfFont* sfFont_construct();
306 
307 //Create a new font from a file
308 bool sfFont_loadFromFile(sfFont* font, const(char)* filename);
309 
310 
311 //Create a new image font a file in memory
312 bool sfFont_loadFromMemory(sfFont* font, const(void)* data, size_t sizeInBytes);
313 
314 
315 //Create a new image font a custom stream
316 bool sfFont_loadFromStream(sfFont* font, fontInputStream stream);
317 
318 
319 // Copy an existing font
320 sfFont* sfFont_copy(const sfFont* font);
321 
322 
323 //Destroy an existing font
324 void sfFont_destroy(sfFont* font);
325 
326 
327 //Get a glyph in a font
328 void sfFont_getGlyph(const(sfFont)* font, uint codePoint, int characterSize, bool bold, int* glyphAdvance, int* glyphBoundsLeft, int* glyphBoundsTop, int* glyphBoundsWidth, int* glyphBoundsHeight, int* glyphTextRectLeft, int* glyphTextRectTop, int* glyphTextRectWidth, int* glyphTextRectHeight);
329 
330 
331 //Get the kerning value corresponding to a given pair of characters in a font
332 int sfFont_getKerning(const(sfFont)* font, uint first, uint second, uint characterSize);
333 
334 
335 //Get the line spacing value
336 int sfFont_getLineSpacing(const(sfFont)* font, uint characterSize);
337 
338 
339 //Get the texture pointer for a particular font
340 sfTexture* sfFont_getTexturePtr(const(sfFont)* font);
341 
342 sfTexture* sfFont_getTexture(const(sfFont)* font, uint characterSize);
343 
344 //Update the internal texture associated with the font
345 void sfFont_updateTexture(const(sfFont)* font, uint characterSize);
346 
347 
348 
349 const(char)* sfErr_getOutput();