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)