Mercurial > projects > mde
comparison mde/resource/FontTexture.d @ 53:f000d6cd0f74
Changes to paths, command line arguments and font LCD rendering.
Use "./" instead of "" as default install dir on windows.
Implemented a command-line argument parser.
Changes to LCD filter/render-mode option handling after testing what actually happens.
Changed some FontTexture messages and internals.
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Thu, 05 Jun 2008 17:16:52 +0100 |
parents | 387a80724c35 |
children | 9e1f05fbbcef |
comparison
equal
deleted
inserted
replaced
51:387a80724c35 | 53:f000d6cd0f74 |
---|---|
30 import derelict.freetype.ft; | 30 import derelict.freetype.ft; |
31 import derelict.opengl.gl; | 31 import derelict.opengl.gl; |
32 | 32 |
33 import Utf = tango.text.convert.Utf; | 33 import Utf = tango.text.convert.Utf; |
34 import tango.util.log.Log : Log, Logger; | 34 import tango.util.log.Log : Log, Logger; |
35 import tango.io.Stdout; | |
36 | 35 |
37 private Logger logger; | 36 private Logger logger; |
38 static this () { | 37 static this () { |
39 logger = Log.getLogger ("mde.resource.FontTexture"); | 38 logger = Log.getLogger ("mde.resource.FontTexture"); |
40 } | 39 } |
72 * | 71 * |
73 * Recognises '\r', '\n' and "\r\n" as end-of-line markers. */ | 72 * Recognises '\r', '\n' and "\r\n" as end-of-line markers. */ |
74 void updateCache (FT_Face face, char[] str, ref TextBlock cache) | 73 void updateCache (FT_Face face, char[] str, ref TextBlock cache) |
75 { | 74 { |
76 debug scope (failure) | 75 debug scope (failure) |
77 logger.warn ("updateCache failed"); | 76 logger.error ("updateCache failed"); |
78 | 77 |
79 if (cache.cacheVer == cacheVer) // Existing cache is up-to-date | 78 if (cache.cacheVer == cacheVer) // Existing cache is up-to-date |
80 return; | 79 return; |
81 | 80 |
82 cache.cacheVer = cacheVer; | 81 cache.cacheVer = cacheVer; |
163 | 162 |
164 /** Render a block of text using a cache. Updates the cache if necessary. */ | 163 /** Render a block of text using a cache. Updates the cache if necessary. */ |
165 void drawTextCache (FT_Face face, char[] str, ref TextBlock cache, int x, int y) { | 164 void drawTextCache (FT_Face face, char[] str, ref TextBlock cache, int x, int y) { |
166 updateCache (face, str, cache); // update if necessary | 165 updateCache (face, str, cache); // update if necessary |
167 debug scope (failure) | 166 debug scope (failure) |
168 logger.warn ("drawTextCache failed"); | 167 logger.error ("drawTextCache failed"); |
169 | 168 |
170 glEnable (GL_TEXTURE_2D); | 169 glEnable (GL_TEXTURE_2D); |
171 glEnable(GL_BLEND); | 170 glEnable(GL_BLEND); |
172 glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_COLOR); | 171 glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_COLOR); |
173 | 172 |
196 glDisable(GL_BLEND); | 195 glDisable(GL_BLEND); |
197 } | 196 } |
198 | 197 |
199 void addGlyph (FT_Face face, dchar chr) { | 198 void addGlyph (FT_Face face, dchar chr) { |
200 debug scope (failure) | 199 debug scope (failure) |
201 logger.warn ("FontTexture.addGlyph failed!"); | 200 logger.error ("FontTexture.addGlyph failed!"); |
202 | 201 |
203 auto gi = FT_Get_Char_Index (face, chr); | 202 auto gi = FT_Get_Char_Index (face, chr); |
204 auto g = face.glyph; | 203 auto g = face.glyph; |
205 | 204 |
206 // Use renderMode from options, masking bits which are allowable: | 205 // Use renderMode from options, masking bits which are allowable: |
207 if (FT_Load_Glyph (face, gi, FT_LOAD_RENDER | (fontOpts.renderMode & 0xF0000))) | 206 if (FT_Load_Glyph (face, gi, FT_LOAD_RENDER | (fontOpts.renderMode & 0xF0000))) |
208 throw new fontGlyphException ("Unable to render glyph"); | 207 throw new fontGlyphException ("Unable to render glyph"); |
209 | 208 |
210 auto b = g.bitmap; | 209 auto b = g.bitmap; |
211 if (b.pitch != b.width) { | |
212 char[128] tmp; | |
213 logger.warn (logger.format (tmp, "b.pitch is {}, b.width is {}", b.pitch, b.width)); | |
214 //throw new fontGlyphException ("Unsupported freetype bitmap: b.pitch != b.width"); | |
215 } | |
216 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | 210 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); |
217 //glPixelStorei (GL_UNPACK_ROW_LENGTH, b.pitch); | 211 //glPixelStorei (GL_UNPACK_ROW_LENGTH, b.pitch); |
218 | 212 |
219 GlyphAttribs ga; | 213 GlyphAttribs ga; |
220 ga.w = b.width; | 214 ga.w = b.width; |
232 if (t.addGlyph (ga)) | 226 if (t.addGlyph (ga)) |
233 goto gotTexSpace; | 227 goto gotTexSpace; |
234 } | 228 } |
235 // if here, no existing texture had the room for the glyph so create a new texture | 229 // if here, no existing texture had the room for the glyph so create a new texture |
236 // NOTE: check if using more than one texture impacts performance due to texture switching | 230 // NOTE: check if using more than one texture impacts performance due to texture switching |
237 logger.info ("Creating a font texture."); | 231 logger.info ("Creating a new font texture."); |
238 tex ~= TexPacker.create(); | 232 tex ~= TexPacker.create(); |
239 assert (tex[$-1].addGlyph (ga), "Failed to fit glyph in a new texture but addGlyph didn't throw"); | 233 assert (tex[$-1].addGlyph (ga), "Failed to fit glyph in a new texture but addGlyph didn't throw"); |
240 | 234 |
241 gotTexSpace: | 235 gotTexSpace: |
242 glBindTexture(GL_TEXTURE_2D, ga.texID); | 236 glBindTexture(GL_TEXTURE_2D, ga.texID); |
243 GLenum format; | 237 GLenum format; |
244 ubyte[] buffer; // use our own pointer, since for LCD modes we need to perform a conversion | 238 ubyte[] buffer; // use our own pointer, since for LCD modes we need to perform a conversion |
245 if (b.pixel_mode == FT_Pixel_Mode.FT_PIXEL_MODE_GRAY && b.num_grays == 256) { | 239 if (b.pixel_mode == FT_Pixel_Mode.FT_PIXEL_MODE_GRAY && b.num_grays == 256) { |
240 assert (b.pitch == b.width, "Have assumed b.pitch == b.width for gray glyphs."); | |
246 buffer = b.buffer[0..b.pitch*b.rows]; | 241 buffer = b.buffer[0..b.pitch*b.rows]; |
247 format = GL_LUMINANCE; | 242 format = GL_LUMINANCE; |
248 } else if (b.pixel_mode == FT_Pixel_Mode.FT_PIXEL_MODE_LCD) { | 243 } else if (b.pixel_mode == FT_Pixel_Mode.FT_PIXEL_MODE_LCD) { |
249 // NOTE: Can't seem to get OpenGL to read freetype's RGB buffers properly, so convent. | 244 // NOTE: Can't seem to get OpenGL to read freetype's RGB buffers properly, so convent. |
250 /* NOTE: Sub-pixel rendering probably also needs filtering. I haven't tried, since it's | 245 /* NOTE: Sub-pixel rendering probably also needs filtering. I haven't tried, since it's |
355 * x, y, w & h is a valid subregion of the texture. */ | 350 * x, y, w & h is a valid subregion of the texture. */ |
356 bool addGlyph (ref GlyphAttribs attr) { | 351 bool addGlyph (ref GlyphAttribs attr) { |
357 if (attr.w > dimW || attr.h > dimH) | 352 if (attr.w > dimW || attr.h > dimH) |
358 throw new fontGlyphException ("Glyph too large to fit texture!"); | 353 throw new fontGlyphException ("Glyph too large to fit texture!"); |
359 | 354 |
355 attr.texID = texID; // Set now. Possibly reset if new texture is needed. | |
356 if (attr.w == 0) return true; // 0 sized glyph; x and y are unimportant. | |
357 | |
360 bool cantFitExtraLine = nextYPos + attr.h >= dimH; | 358 bool cantFitExtraLine = nextYPos + attr.h >= dimH; |
361 foreach (ref line; lines) { | 359 foreach (ref line; lines) { |
362 if (line.length + attr.w <= dimW && // if sufficient length and | 360 if (line.length + attr.w <= dimW && // if sufficient length and |
363 line.height >= attr.h && // sufficient height and | 361 line.height >= attr.h && // sufficient height and |
364 (cantFitExtraLine || // either there's not room for another line | 362 (cantFitExtraLine || // either there's not room for another line |
378 // Still room: add a new line. The new line has the largest yPos (furthest down texture), | 376 // Still room: add a new line. The new line has the largest yPos (furthest down texture), |
379 // but the lines array must remain ordered by line height (lowest to heighest). | 377 // but the lines array must remain ordered by line height (lowest to heighest). |
380 Line line; | 378 Line line; |
381 line.yPos = nextYPos; | 379 line.yPos = nextYPos; |
382 line.height = attr.h * EXTRA_H; | 380 line.height = attr.h * EXTRA_H; |
383 Stdout.format ("Creating new line of height {}", line.height).newline; | |
384 line.length = attr.w; | 381 line.length = attr.w; |
385 size_t i = 0; | 382 size_t i = 0; |
386 while (i < lines.length && lines[i].height < line.height) ++i; | 383 while (i < lines.length && lines[i].height < line.height) ++i; |
387 lines = lines[0..i] ~ line ~ lines[i..$]; // keep lines sorted by height | 384 lines = lines[0..i] ~ line ~ lines[i..$]; // keep lines sorted by height |
388 nextYPos += line.height; | 385 nextYPos += line.height; |
389 | 386 |
390 attr.x = 0; // first glyph in the line | 387 attr.x = 0; // first glyph in the line |
391 attr.y = line.yPos; | 388 attr.y = line.yPos; |
392 attr.texID = texID; | |
393 return true; | 389 return true; |
394 } | 390 } |
395 | 391 |
396 // Publically accessible data: | 392 // Publically accessible data: |
397 uint texID; // OpenGL texture identifier (for BindTexture) | 393 uint texID; // OpenGL texture identifier (for BindTexture) |