23#include <Objectively/String.h>
33#pragma mark - Glyph blitting
46static void blit(SDL_Surface *src, SDL_Surface *dest,
const SDL_Rect *rect) {
48 SDL_BlendMode blendMode;
49 SDL_GetSurfaceBlendMode(src, &blendMode);
50 SDL_SetSurfaceBlendMode(src, SDL_BLENDMODE_NONE);
52 if (src->w == rect->w && src->h == rect->h) {
53 SDL_BlitSurface(src, NULL, dest, rect);
55 SDL_BlitSurfaceScaled(src, NULL, dest, rect, SDL_SCALEMODE_LINEAR);
58 SDL_SetSurfaceBlendMode(src, blendMode);
66 SDL_Surface *sheet = bitmap->
surface;
68 if (!TTF_FontHasGlyph(
font, codepoint)) {
72 int minX = 0, maxX = 0;
73 if (!TTF_GetGlyphMetrics(
font, codepoint, &minX, &maxX, NULL, NULL, NULL)) {
82 SDL_Surface *glyph = TTF_RenderGlyph_Blended(
font, codepoint,
Colors.
White);
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);
92 const SDL_Rect clip = MakeRect(origin.x, origin.y, bitmap->
cellSize.w, bitmap->
cellSize.h);
93 SDL_SetSurfaceClipRect(sheet, &clip);
95 blit(glyph, sheet, &rect);
97 SDL_SetSurfaceClipRect(sheet, NULL);
98 SDL_DestroySurface(glyph);
100 MVC_LogDebug(
"U+%04X: %s\n", codepoint, SDL_GetError());
104#pragma mark - Walking
139 const char *p = *chars;
161 if (p[0] ==
'^' && p[1] >=
'0' && p[1] <=
'9') {
168 if (p[0] ==
'^' && p[1] ==
'^') {
185 const Uint32 codepoint = SDL_StepUTF8(&p, NULL);
198 switch (token->
type) {
217 const char *next = chars;
249 int x = 0, y = 0, maxX = 0;
250 bool lineHasContent =
false;
266 lineHasContent =
false;
279 lineHasContent =
false;
286 if (wrapWidth && x > 0 && x + advance > wrapWidth) {
289 lineHasContent =
false;
294 visitor(bitmap, &token, x, y, data);
298 lineHasContent =
true;
305 const int side = bitmap->
cellSize.h;
306 extent = max(0, bitmap->
bearing + (advance - side) / 2 + side - advance);
309 maxX = max(maxX, x + extent);
316 *h = y + (lineHasContent ? bitmap->
cellSize.h : 0);
320#pragma mark - FontBitmap
327 if (!TTF_FontIsFixedWidth(
font->
font)) {
334 int minX = INT_MAX, maxX = INT_MIN, advance = 0;
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)) {
344 minX = min(minX, glyphMinX);
345 maxX = max(maxX, max(glyphMaxX, glyphAdvance));
346 advance = max(advance, glyphAdvance);
350 if (maxX <= minX || advance == 0) {
366 SDL_FillSurfaceRect(bitmap->
surface, NULL, 0);
379 release(bitmap->texture);
382 SDL_DestroySurface(bitmap->
surface);
419 const int side = bitmap->
cellSize.h;
422 const SDL_FRect dest = {
425 side / context->
scale,
426 side / context->
scale
435 const SDL_Rect src = MakeRect(origin.x, origin.y, bitmap->
cellSize.w, bitmap->
cellSize.h);
438 const SDL_FRect dest = {
441 src.w / context->
scale,
442 src.h / context->
scale
465 if (bitmap->texture == NULL) {
466 bitmap->texture = $(renderer->
device, createTextureFromSurface, bitmap->
surface, SDL_GPU_TEXTUREUSAGE_SAMPLER,
false);
467 assert(bitmap->texture);
473 .texture = bitmap->texture,
492 int texelsW = 0, texelsH = 0;
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...
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 initGlyph(const FontBitmap *bitmap, TTF_Font *font, Uint32 codepoint, Uint32 cell)
Rasterizes codepoint into the given cell, with its bearing baked in.
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(* 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.
void deallocBitmap(FontBitmap *bitmap)
Releases the resources held by bitmap. Safe to call on a zeroed FontBitmap.
static void renderToken(const FontBitmap *bitmap, const Token *token, int x, int y, ident data)
TokenVisitor for Font::renderBitmapCharacters.
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 exte...
static SDL_Point cellOrigin(const FontBitmap *bitmap, Uint32 cell)
The top-left texel of the given cell within the grid surface.
void renderDeviceWillResetBitmap(Font *self)
Implements Font::renderDeviceWillReset.
void sizeCharactersBitmap(const Font *self, const char *chars, int wrapWidth, const ImageAtlas *icons, int *w, int *h)
Implements Font::sizeBitmapCharacters.
static void nextToken(const char **chars, const ImageAtlas *icons, Token *token)
Advances *chars past the next token, describing it in token.
bool initBitmap(FontBitmap *bitmap, Font *font)
Bakes FONT_BITMAP_COUNT codepoints of font, from FONT_BITMAP_FIRST, into a glyph sheet,...
static Uint32 cellForCodepoint(Uint32 codepoint)
Resolves codepoint to a cell: FONT_BITMAP_REPLACEMENT's for one outside the baked range.
#define FONT_BITMAP_REPLACEMENT
The codepoint drawn in place of one outside the baked range.
#define FONT_BITMAP_COUNT
The codepoint count Font bakes into its bitmap.
#define FONT_BITMAP_FIRST
The first codepoint Font bakes into its bitmap.
#define FONT_BITMAP_LAST
One past the last baked codepoint in a Font bitmap (exclusive upper bound).
#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...
static String * name(const Font *self)
static Texture * texture(ImageAtlas *self, RenderDevice *device)
Packs many Images into one sheet, backed by one Texture.
View logging facilities via SDL_Log.
#define MVC_LogWarn(fmt,...)
#define MVC_LogDebug(fmt,...)
#define MVC_LogError(fmt,...)
static void drawTextureRegion(const Renderer *self, Texture *texture, const SDL_Rect *src, const SDL_FRect *dest, const SDL_Color *color)
SDL_Color TextEscapeColors[]
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...
Text rendered with TrueType fonts.
static ImageAtlas * icons(Theme *self)
static Font * font(Theme *self, const FontAttributes *attributes, float pixelDensity)
An Image packed into an ImageAtlas.
SDL_Rect rect
This AtlasImage's rectangle within the atlas sheet, in texels.
ImageAtlas * atlas
The ImageAtlas this AtlasImage belongs to, or NULL once that atlas has been released,...
A fixed-width Font's glyphs, baked into one sheet, drawn as one quad per glyph.
int bearing
The horizontal offset from the pen to a cell's left edge, in texels.
SDL_Size cellSize
The size of one cell, in texels.
int advance
The pen advance per glyph, in texels.
SDL_Surface * surface
The glyph sheet: a grid of FONT_BITMAP_COLUMNS by FONT_BITMAP_COLUMNS cells of cellSize,...
float pixelDensity
The display pixel density scale, greater than 1.0 on high-density displays.
FontBitmap bitmap
The glyphs of a fixed-width Font, baked into one sheet; bitmap.surface is NULL for a proportional Fon...
TTF_Font * font
The backing font.
Packs many Images into one sheet, backed by one Texture.
const Renderer * renderer
Renderer extends Object with ObjectivelyMVC's UI rendering layer.
RenderDevice * device
The backing RenderDevice.