ObjectivelyMVC
Object oriented MVC framework for SDL3 and GNU C
Loading...
Searching...
No Matches
Font+Bitmap.c File Reference
#include <assert.h>
#include <limits.h>
#include <math.h>
#include <string.h>
#include <Objectively/String.h>
#include "Colors.h"
#include "Font.h"
#include "ImageAtlas.h"
#include "Log.h"
#include "Text.h"

Go to the source code of this file.

Data Structures

struct  RenderContext
 
struct  Token
 

Macros

#define _Class   _Font
 

Typedefs

typedef void(* TokenVisitor) (const FontBitmap *bitmap, const Token *token, int x, int y, ident data)
 Receives each drawable token with the pen position of its cell, in texels.
 

Enumerations

enum  TokenType {
  TokenEnd , TokenNewline , TokenColor , TokenGlyph ,
  TokenImage
}
 

Functions

static void blit (SDL_Surface *src, SDL_Surface *dest, const SDL_Rect *rect)
 Copies src into dest at rect, scaling if necessary, without alpha blending, so that glyph coverage lands in the sheet exactly as rasterized.
 
static Uint32 cellForCodepoint (Uint32 codepoint)
 Resolves codepoint to a cell: FONT_BITMAP_REPLACEMENT's for one outside the baked range.
 
static SDL_Point cellOrigin (const FontBitmap *bitmap, Uint32 cell)
 The top-left texel of the given cell within the grid surface.
 
void deallocBitmap (FontBitmap *bitmap)
 Releases the resources held by bitmap. Safe to call on a zeroed FontBitmap.
 
bool initBitmap (FontBitmap *bitmap, Font *font)
 Bakes FONT_BITMAP_COUNT codepoints of font, from FONT_BITMAP_FIRST, into a glyph sheet, initializing bitmap.
 
static void initGlyph (const FontBitmap *bitmap, TTF_Font *font, Uint32 codepoint, Uint32 cell)
 Rasterizes codepoint into the given cell, with its bearing baked in.
 
static void nextToken (const char **chars, const ImageAtlas *icons, Token *token)
 Advances *chars past the next token, describing it in token.
 
void renderCharactersBitmap (Font *self, const Renderer *renderer, const char *chars, SDL_Color color, int wrapWidth, const SDL_Point *origin, const ImageAtlas *icons)
 Implements Font::renderBitmapCharacters.
 
void renderDeviceWillResetBitmap (Font *self)
 Implements Font::renderDeviceWillReset.
 
static void renderToken (const FontBitmap *bitmap, const Token *token, int x, int y, ident data)
 TokenVisitor for Font::renderBitmapCharacters.
 
void sizeCharactersBitmap (const Font *self, const char *chars, int wrapWidth, const ImageAtlas *icons, int *w, int *h)
 Implements Font::sizeBitmapCharacters.
 
static int tokenAdvance (const FontBitmap *bitmap, const Token *token)
 The pen advance of the given token, in texels.
 
static void walk (const FontBitmap *bitmap, const char *chars, int wrapWidth, SDL_Color color, const ImageAtlas *icons, TokenVisitor visitor, ident data, int *w, int *h)
 Walks chars, wrapping at word boundaries when wrapWidth (in texels) is non-zero, and reports the extent of the text in texels.
 
static int wordAdvance (const FontBitmap *bitmap, const char *chars, const ImageAtlas *icons)
 The advance of the word starting at chars, up to the next space, newline or end.
 

Macro Definition Documentation

◆ _Class

#define _Class   _Font

Definition at line 31 of file Font+Bitmap.c.

Typedef Documentation

◆ TokenVisitor

typedef void(* TokenVisitor) (const FontBitmap *bitmap, const Token *token, int x, int y, ident data)

Receives each drawable token with the pen position of its cell, in texels.

Definition at line 240 of file Font+Bitmap.c.

Enumeration Type Documentation

◆ TokenType

enum TokenType
Enumerator
TokenEnd 
TokenNewline 
TokenColor 
TokenGlyph 
TokenImage 

Definition at line 106 of file Font+Bitmap.c.

106 {
107 TokenEnd,
112} TokenType;
TokenType
@ TokenColor
@ TokenImage
@ TokenEnd
@ TokenGlyph
@ TokenNewline

Function Documentation

◆ blit()

static void blit ( SDL_Surface *  src,
SDL_Surface *  dest,
const SDL_Rect *  rect 
)
static

Copies src into dest at rect, scaling if necessary, without alpha blending, so that glyph coverage lands in the sheet exactly as rasterized.

Definition at line 46 of file Font+Bitmap.c.

46 {
47
48 SDL_BlendMode blendMode;
49 SDL_GetSurfaceBlendMode(src, &blendMode);
50 SDL_SetSurfaceBlendMode(src, SDL_BLENDMODE_NONE);
51
52 if (src->w == rect->w && src->h == rect->h) {
53 SDL_BlitSurface(src, NULL, dest, rect);
54 } else {
55 SDL_BlitSurfaceScaled(src, NULL, dest, rect, SDL_SCALEMODE_LINEAR);
56 }
57
58 SDL_SetSurfaceBlendMode(src, blendMode);
59}

◆ cellForCodepoint()

static Uint32 cellForCodepoint ( Uint32  codepoint)
static

Resolves codepoint to a cell: FONT_BITMAP_REPLACEMENT's for one outside the baked range.

Definition at line 125 of file Font+Bitmap.c.

125 {
126
127 if (codepoint >= FONT_BITMAP_FIRST && codepoint < FONT_BITMAP_LAST) {
128 return codepoint - FONT_BITMAP_FIRST;
129 }
130
132}
#define FONT_BITMAP_REPLACEMENT
The codepoint drawn in place of one outside the baked range.
Definition Font+Bitmap.h:55
#define FONT_BITMAP_FIRST
The first codepoint Font bakes into its bitmap.
Definition Font+Bitmap.h:31
#define FONT_BITMAP_LAST
One past the last baked codepoint in a Font bitmap (exclusive upper bound).
Definition Font+Bitmap.h:45

◆ cellOrigin()

static SDL_Point cellOrigin ( const FontBitmap *  bitmap,
Uint32  cell 
)
static

The top-left texel of the given cell within the grid surface.

Definition at line 38 of file Font+Bitmap.c.

38 {
39 return MakePoint((cell % FONT_BITMAP_COLUMNS) * bitmap->cellSize.w, (cell / FONT_BITMAP_COLUMNS) * bitmap->cellSize.h);
40}
#define FONT_BITMAP_COLUMNS
The number of cells per row of the glyph sheet: FONT_BITMAP_COUNT cells make a square grid of this ma...
Definition Font+Bitmap.h:50
SDL_Size cellSize
The size of one cell, in texels.
Definition Font+Bitmap.h:97

◆ deallocBitmap()

void deallocBitmap ( FontBitmap *  bitmap)

Releases the resources held by bitmap. Safe to call on a zeroed FontBitmap.

Parameters
bitmapThe FontBitmap.

Definition at line 375 of file Font+Bitmap.c.

375 {
376
377 assert(bitmap);
378
379 release(bitmap->texture);
380
381 if (bitmap->surface) {
382 SDL_DestroySurface(bitmap->surface);
383 }
384}
SDL_Surface * surface
The glyph sheet: a grid of FONT_BITMAP_COLUMNS by FONT_BITMAP_COLUMNS cells of cellSize,...

◆ initBitmap()

bool initBitmap ( FontBitmap *  bitmap,
Font *  font 
)

Bakes FONT_BITMAP_COUNT codepoints of font, from FONT_BITMAP_FIRST, into a glyph sheet, initializing bitmap.

A codepoint outside the range draws FONT_BITMAP_REPLACEMENT instead.

Parameters
bitmapThe FontBitmap, zero-initialized.
fontThe Font, which MUST be fixed-width.
Returns
True if the bitmap was baked, false if font is not fixed-width or has no glyphs in the range, in which case bitmap is left zeroed.

Definition at line 322 of file Font+Bitmap.c.

322 {
323
324 assert(bitmap);
325 assert(font);
326
327 if (!TTF_FontIsFixedWidth(font->font)) {
328 String *name = $(font, name);
329 MVC_LogWarn("%s is not fixed-width\n", name->chars);
330 release(name);
331 return false;
332 }
333
334 int minX = INT_MAX, maxX = INT_MIN, advance = 0;
335
336 for (Uint32 codepoint = FONT_BITMAP_FIRST; codepoint < FONT_BITMAP_LAST; codepoint++) {
337
338 if (TTF_FontHasGlyph(font->font, codepoint)) {
339 int glyphMinX = 0, glyphMaxX = 0, glyphAdvance = 0;
340 if (!TTF_GetGlyphMetrics(font->font, codepoint, &glyphMinX, &glyphMaxX, NULL, NULL, &glyphAdvance)) {
341 continue;
342 }
343
344 minX = min(minX, glyphMinX);
345 maxX = max(maxX, max(glyphMaxX, glyphAdvance));
346 advance = max(advance, glyphAdvance);
347 }
348 }
349
350 if (maxX <= minX || advance == 0) {
351 String *name = $(font, name);
352 MVC_LogWarn("%s has no glyphs in U+%04X-U+%04X\n", name->chars, FONT_BITMAP_FIRST, FONT_BITMAP_LAST - 1);
353 release(name);
354 return false;
355 }
356
357 bitmap->advance = advance;
358 bitmap->bearing = minX;
359 bitmap->cellSize = MakeSize(maxX - minX, TTF_GetFontHeight(font->font));
360
361 const int rows = FONT_BITMAP_COUNT / FONT_BITMAP_COLUMNS;
362
363 bitmap->surface = SDL_CreateSurface(FONT_BITMAP_COLUMNS * bitmap->cellSize.w, rows * bitmap->cellSize.h, SDL_PIXELFORMAT_RGBA32);
364 assert(bitmap->surface);
365
366 SDL_FillSurfaceRect(bitmap->surface, NULL, 0);
367
368 for (Uint32 i = 0; i < FONT_BITMAP_COUNT; i++) {
369 initGlyph(bitmap, font->font, FONT_BITMAP_FIRST + i, i);
370 }
371
372 return true;
373}
static void initGlyph(const FontBitmap *bitmap, TTF_Font *font, Uint32 codepoint, Uint32 cell)
Rasterizes codepoint into the given cell, with its bearing baked in.
Definition Font+Bitmap.c:64
#define FONT_BITMAP_COUNT
The codepoint count Font bakes into its bitmap.
Definition Font+Bitmap.h:40
static String * name(const Font *self)
Definition Font.c:303
#define MVC_LogWarn(fmt,...)
Definition Log.h:54
static Font * font(Theme *self, const FontAttributes *attributes, float pixelDensity)
Definition Theme.c:108
int bearing
The horizontal offset from the pen to a cell's left edge, in texels.
Definition Font+Bitmap.h:92
int advance
The pen advance per glyph, in texels.
Definition Font+Bitmap.h:86
TTF_Font * font
The backing font.
Definition Font.h:122

◆ initGlyph()

static void initGlyph ( const FontBitmap *  bitmap,
TTF_Font *  font,
Uint32  codepoint,
Uint32  cell 
)
static

Rasterizes codepoint into the given cell, with its bearing baked in.

Definition at line 64 of file Font+Bitmap.c.

64 {
65
66 SDL_Surface *sheet = bitmap->surface;
67
68 if (!TTF_FontHasGlyph(font, codepoint)) {
69 return;
70 }
71
72 int minX = 0, maxX = 0;
73 if (!TTF_GetGlyphMetrics(font, codepoint, &minX, &maxX, NULL, NULL, NULL)) {
74 MVC_LogError("U+%04X: %s\n", codepoint, SDL_GetError());
75 return;
76 }
77
78 if (maxX <= minX) {
79 return;
80 }
81
82 SDL_Surface *glyph = TTF_RenderGlyph_Blended(font, codepoint, Colors.White);
83 if (glyph) {
84
85 // The glyph surface's left edge is the pen, with the glyph's own bearing already applied,
86 // except that SDL_ttf shifts a glyph with a negative bearing right so that its ink is not
87 // cut off. The cell's left edge is the pen plus the range's minimum bearing.
88 const SDL_Point origin = cellOrigin(bitmap, cell);
89 const SDL_Rect rect = MakeRect(origin.x - bitmap->bearing + min(minX, 0), origin.y, glyph->w, glyph->h);
90
91 // A glyph surface can exceed its cell, and must not overwrite its neighbours
92 const SDL_Rect clip = MakeRect(origin.x, origin.y, bitmap->cellSize.w, bitmap->cellSize.h);
93 SDL_SetSurfaceClipRect(sheet, &clip);
94
95 blit(glyph, sheet, &rect);
96
97 SDL_SetSurfaceClipRect(sheet, NULL);
98 SDL_DestroySurface(glyph);
99 } else {
100 MVC_LogDebug("U+%04X: %s\n", codepoint, SDL_GetError());
101 }
102}
static void blit(SDL_Surface *src, SDL_Surface *dest, const SDL_Rect *rect)
Copies src into dest at rect, scaling if necessary, without alpha blending, so that glyph coverage la...
Definition Font+Bitmap.c:46
static SDL_Point cellOrigin(const FontBitmap *bitmap, Uint32 cell)
The top-left texel of the given cell within the grid surface.
Definition Font+Bitmap.c:38
#define MVC_LogDebug(fmt,...)
Definition Log.h:48
#define MVC_LogError(fmt,...)
Definition Log.h:57
W3C Color constants.
Definition Colors.h:37
SDL_Color White
Definition Colors.h:185

◆ nextToken()

static void nextToken ( const char **  chars,
const ImageAtlas *  icons,
Token *  token 
)
static

Advances *chars past the next token, describing it in token.

Definition at line 137 of file Font+Bitmap.c.

137 {
138
139 const char *p = *chars;
140
141 token->codepoint = 0;
142 token->cell = 0;
143 token->image = NULL;
144
145 while (*p == '\r') {
146 p++;
147 }
148
149 if (*p == '\0') {
150 token->type = TokenEnd;
151 *chars = p;
152 return;
153 }
154
155 if (*p == '\n') {
156 token->type = TokenNewline;
157 *chars = p + 1;
158 return;
159 }
160
161 if (p[0] == '^' && p[1] >= '0' && p[1] <= '9') {
162 token->type = TokenColor;
163 token->color = TextEscapeColors[p[1] - '0'];
164 *chars = p + 2;
165 return;
166 }
167
168 if (p[0] == '^' && p[1] == '^') {
169 token->type = TokenGlyph;
170 token->codepoint = '^';
171 token->cell = cellForCodepoint('^');
172 *chars = p + 2;
173 return;
174 }
175
176 if (*p == ':') {
177 const size_t length = MVC_IconEscapeLength(p, icons, &token->image);
178 if (length) {
179 token->type = TokenImage;
180 *chars = p + length;
181 return;
182 }
183 }
184
185 const Uint32 codepoint = SDL_StepUTF8(&p, NULL);
186
187 token->type = TokenGlyph;
188 token->codepoint = codepoint;
189 token->cell = cellForCodepoint(codepoint);
190 *chars = p;
191}
static Uint32 cellForCodepoint(Uint32 codepoint)
Resolves codepoint to a cell: FONT_BITMAP_REPLACEMENT's for one outside the baked range.
SDL_Color TextEscapeColors[]
Definition Text.c:41
size_t MVC_IconEscapeLength(const char *chars, const ImageAtlas *icons, AtlasImage **image)
Parses an icon escape at the start of chars: :name:, where name is one or more of [A-Za-z0-9_-] and u...
Definition Text.c:104
static ImageAtlas * icons(Theme *self)
Definition Theme.c:144
Uint32 codepoint
SDL_Color color
TokenType type
Uint32 cell
AtlasImage * image

◆ renderCharactersBitmap()

void renderCharactersBitmap ( Font *  self,
const Renderer *  renderer,
const char *  chars,
SDL_Color  color,
int  wrapWidth,
const SDL_Point *  origin,
const ImageAtlas *  icons 
)

Implements Font::renderBitmapCharacters.

Definition at line 452 of file Font+Bitmap.c.

452 {
453
454 assert(self);
455 assert(renderer);
456 assert(origin);
457
458 FontBitmap *bitmap = &self->bitmap;
459 assert(bitmap->surface);
460
461 if (chars == NULL) {
462 return;
463 }
464
465 if (bitmap->texture == NULL) {
466 bitmap->texture = $(renderer->device, createTextureFromSurface, bitmap->surface, SDL_GPU_TEXTUREUSAGE_SAMPLER, false);
467 assert(bitmap->texture);
468 }
469
470 RenderContext context = {
471 .renderer = renderer,
472 .device = renderer->device,
473 .texture = bitmap->texture,
474 .origin = { roundf(origin->x * self->pixelDensity), roundf(origin->y * self->pixelDensity) },
475 .scale = self->pixelDensity,
476 };
477
478 walk(bitmap, chars, (int) (wrapWidth * context.scale), color, icons, renderToken, &context, NULL, NULL);
479}
static void renderToken(const FontBitmap *bitmap, const Token *token, int x, int y, ident data)
TokenVisitor for Font::renderBitmapCharacters.
static void walk(const FontBitmap *bitmap, const char *chars, int wrapWidth, SDL_Color color, const ImageAtlas *icons, TokenVisitor visitor, ident data, int *w, int *h)
Walks chars, wrapping at word boundaries when wrapWidth (in texels) is non-zero, and reports the exte...
A fixed-width Font's glyphs, baked into one sheet, drawn as one quad per glyph.
Definition Font+Bitmap.h:82
float pixelDensity
The display pixel density scale, greater than 1.0 on high-density displays.
Definition Font.h:134
FontBitmap bitmap
The glyphs of a fixed-width Font, baked into one sheet; bitmap.surface is NULL for a proportional Fon...
Definition Font.h:107
const Renderer * renderer
RenderDevice * device
The backing RenderDevice.
Definition Renderer.h:97

◆ renderDeviceWillResetBitmap()

void renderDeviceWillResetBitmap ( Font *  self)

Implements Font::renderDeviceWillReset.

Definition at line 390 of file Font+Bitmap.c.

390 {
391
392 assert(self);
393
394 self->bitmap.texture = release(self->bitmap.texture);
395}

◆ renderToken()

static void renderToken ( const FontBitmap *  bitmap,
const Token *  token,
int  x,
int  y,
ident  data 
)
static

TokenVisitor for Font::renderBitmapCharacters.

Definition at line 408 of file Font+Bitmap.c.

408 {
409
410 const RenderContext *context = data;
411
412 if (token->type == TokenImage) {
413 ImageAtlas *atlas = token->image->atlas;
414 if (atlas == NULL) {
415 return;
416 }
417
418 // A square of the line height, centered in its whole-cell slot, from the icon atlas
419 const int side = bitmap->cellSize.h;
420 const int slot = tokenAdvance(bitmap, token);
421
422 const SDL_FRect dest = {
423 (context->origin.x + x + bitmap->bearing + (slot - side) / 2) / context->scale,
424 (context->origin.y + y) / context->scale,
425 side / context->scale,
426 side / context->scale
427 };
428
429 Texture *texture = $(atlas, texture, context->device);
430 $(context->renderer, drawTextureRegion, texture, &token->image->rect, &dest, &token->color);
431 return;
432 }
433
434 const SDL_Point origin = cellOrigin(bitmap, token->cell);
435 const SDL_Rect src = MakeRect(origin.x, origin.y, bitmap->cellSize.w, bitmap->cellSize.h);
436
437 // Positioned in whole texels so that the sheet is sampled 1:1, then scaled to logical
438 const SDL_FRect dest = {
439 (context->origin.x + x + bitmap->bearing) / context->scale,
440 (context->origin.y + y) / context->scale,
441 src.w / context->scale,
442 src.h / context->scale
443 };
444
445 $(context->renderer, drawTextureRegion, context->texture, &src, &dest, &token->color);
446}
static int tokenAdvance(const FontBitmap *bitmap, const Token *token)
The pen advance of the given token, in texels.
static Texture * texture(ImageAtlas *self, RenderDevice *device)
Definition ImageAtlas.c:289
static void drawTextureRegion(const Renderer *self, Texture *texture, const SDL_Rect *src, const SDL_FRect *dest, const SDL_Color *color)
Definition Renderer.c:497
SDL_Rect rect
This AtlasImage's rectangle within the atlas sheet, in texels.
Definition AtlasImage.h:66
ImageAtlas * atlas
The ImageAtlas this AtlasImage belongs to, or NULL once that atlas has been released,...
Definition AtlasImage.h:59
Packs many Images into one sheet, backed by one Texture.
Definition ImageAtlas.h:49
RenderDevice * device
SDL_FPoint origin
Texture * texture

◆ sizeCharactersBitmap()

void sizeCharactersBitmap ( const Font *  self,
const char *  chars,
int  wrapWidth,
const ImageAtlas *  icons,
int *  w,
int *  h 
)

Implements Font::sizeBitmapCharacters.

Definition at line 485 of file Font+Bitmap.c.

485 {
486
487 assert(self);
488
489 const FontBitmap *bitmap = &self->bitmap;
490 assert(bitmap->surface);
491
492 int texelsW = 0, texelsH = 0;
493
494 if (chars) {
495 walk(bitmap, chars, (int) (wrapWidth * self->pixelDensity), Colors.White, icons, NULL, NULL, &texelsW, &texelsH);
496 }
497
498 if (w) {
499 *w = (int) ceilf(texelsW / self->pixelDensity);
500 }
501 if (h) {
502 *h = (int) ceilf(texelsH / self->pixelDensity);
503 }
504}

◆ tokenAdvance()

static int tokenAdvance ( const FontBitmap *  bitmap,
const Token *  token 
)
static

The pen advance of the given token, in texels.

Definition at line 196 of file Font+Bitmap.c.

196 {
197
198 switch (token->type) {
199 case TokenGlyph:
200 return bitmap->advance;
201 case TokenImage:
202 // A square of the line height, in whole cells, so that the grid stays aligned
203 return ((bitmap->cellSize.h + bitmap->advance - 1) / bitmap->advance) * bitmap->advance;
204 default:
205 return 0;
206 }
207}

◆ walk()

static void walk ( const FontBitmap *  bitmap,
const char *  chars,
int  wrapWidth,
SDL_Color  color,
const ImageAtlas *  icons,
TokenVisitor  visitor,
ident  data,
int *  w,
int *  h 
)
static

Walks chars, wrapping at word boundaries when wrapWidth (in texels) is non-zero, and reports the extent of the text in texels.

Definition at line 246 of file Font+Bitmap.c.

247 {
248
249 int x = 0, y = 0, maxX = 0;
250 bool lineHasContent = false;
251
252 const int overhang = max(0, bitmap->bearing + bitmap->cellSize.w - bitmap->advance);
253
254 Token token = { .type = TokenEnd, .color = color };
255
256 while (true) {
257 nextToken(&chars, icons, &token);
258
259 if (token.type == TokenEnd) {
260 break;
261 }
262
263 if (token.type == TokenNewline) {
264 x = 0;
265 y += bitmap->cellSize.h;
266 lineHasContent = false;
267 continue;
268 }
269
270 if (token.type == TokenColor) {
271 color = token.color;
272 continue;
273 }
274
275 if (wrapWidth && token.type == TokenGlyph && token.codepoint == ' ' && x > 0) {
276 if (x + bitmap->advance + wordAdvance(bitmap, chars, icons) > wrapWidth) {
277 x = 0;
278 y += bitmap->cellSize.h;
279 lineHasContent = false;
280 continue;
281 }
282 }
283
284 const int advance = tokenAdvance(bitmap, &token);
285
286 if (wrapWidth && x > 0 && x + advance > wrapWidth) {
287 x = 0;
288 y += bitmap->cellSize.h;
289 lineHasContent = false;
290 }
291
292 if (visitor) {
293 token.color = token.type == TokenImage ? Colors.White : color;
294 visitor(bitmap, &token, x, y, data);
295 }
296
297 x += advance;
298 lineHasContent = true;
299 // Ink past the pen: a glyph's cell overhang, or the bearing an icon shares with the glyph
300 // column, less what centering in its slot gives back
301 int extent = 0;
302 if (token.type == TokenGlyph) {
303 extent = overhang;
304 } else if (token.type == TokenImage) {
305 const int side = bitmap->cellSize.h;
306 extent = max(0, bitmap->bearing + (advance - side) / 2 + side - advance);
307 }
308
309 maxX = max(maxX, x + extent);
310 }
311
312 if (w) {
313 *w = maxX;
314 }
315 if (h) {
316 *h = y + (lineHasContent ? bitmap->cellSize.h : 0);
317 }
318}
static int wordAdvance(const FontBitmap *bitmap, const char *chars, const ImageAtlas *icons)
The advance of the word starting at chars, up to the next space, newline or end.
static void nextToken(const char **chars, const ImageAtlas *icons, Token *token)
Advances *chars past the next token, describing it in token.

◆ wordAdvance()

static int wordAdvance ( const FontBitmap *  bitmap,
const char *  chars,
const ImageAtlas *  icons 
)
static

The advance of the word starting at chars, up to the next space, newline or end.

Definition at line 212 of file Font+Bitmap.c.

212 {
213
214 int advance = 0;
215
216 while (true) {
217 const char *next = chars;
218
219 Token token;
220 nextToken(&next, icons, &token);
221
222 if (token.type == TokenEnd || token.type == TokenNewline) {
223 break;
224 }
225
226 if (token.type == TokenGlyph && token.codepoint == ' ') {
227 break;
228 }
229
230 advance += tokenAdvance(bitmap, &token);
231 chars = next;
232 }
233
234 return advance;
235}