2 Font handling functions.
12 #include "SDL_gfxPrimitives.h"
13 #include "SDL_rotozoom.h"
15 /* split cannot parse gfxPrimitivesFontdata[] */
17 #define GFX_FONTDATAMAX (8*256)
19 extern unsigned char gfxPrimitivesFontdata
[GFX_FONTDATAMAX
];
21 #include "SDL_gfxPrimitives_font.h"
24 #include "../graphics.h"
25 #include "../memory.h"
30 #define GFX_FONT_WIDTH CHAR_BIT
31 #define GFX_FONT_HEIGHT (GFX_FONTDATAMAX / UCHAR_MAX)
33 static void free_font(struct xuni_t
*xuni
, struct widget_t
*widget
);
34 static void rescale_font(struct xuni_t
*xuni
, struct widget_t
*widget
);
36 static void new_font_t(struct widget_t
*widget
, const char *name
);
37 static int pick_font_point(struct xuni_t
*xuni
);
38 static SDL_Surface
*render_gfx_text(const char *text
, int r
, int g
, int b
);
40 void font_widget_event(struct xuni_t
*xuni
, struct widget_t
*widget
,
41 enum widget_event_t event
) {
43 static void (*function
[])(struct xuni_t
*xuni
, struct widget_t
*widget
)
53 call_widget_event_func(xuni
, widget
, event
, function
,
54 sizeof(function
) / sizeof(*function
));
57 void init_font(struct widget_t
*widget
, const char *name
) {
58 widget
->type
= WIDGET_FONT
;
59 new_font_t(widget
, name
);
62 static void new_font_t(struct widget_t
*widget
, const char *name
) {
63 widget
->p
.font
= xuni_memory_allocate(sizeof(*widget
->p
.font
));
65 widget
->p
.font
->name
= xuni_memory_duplicate_string(name
);
66 widget
->p
.font
->point
= 0;
67 widget
->p
.font
->ttf
= 0;
70 /*! Finds or creates a font widget with the file name \a name. In other words,
71 if a font of this name has been loaded in the past, this existing widget
72 is used. Otherwise, a new widget is created and returned. Presumably this
73 will be added to the widget tree and can be found by a later call to this
76 \param widget The structure to search through for existing font widgets.
77 (Actually, all searching is done in the first widget found called
79 \param name The name of the font to find, or if not found, to create.
81 struct widget_t
*load_font(struct widget_t
*widget
, const char *name
) {
82 struct widget_t
*fontpanel
= find_widget(widget
, "font"); /* !!! */
85 if(!fontpanel
|| !name
|| !*name
) return 0;
87 for(x
= 0; x
< fontpanel
->compose
->widgets
; x
++) {
88 if(fontpanel
->compose
->widget
[x
]->type
== WIDGET_FONT
89 && !strcmp(fontpanel
->compose
->widget
[x
]->p
.font
->name
, name
)) {
91 return fontpanel
->compose
->widget
[x
];
95 add_allocate_widget(fontpanel
, (char *)name
);
96 init_widget_pos(last_compose_widget(fontpanel
), 0, 0, 1, 1,
98 init_font(last_compose_widget(fontpanel
), name
);
100 return last_compose_widget(fontpanel
);
103 void use_font_by_name(struct xuni_t
*xuni
, size_t n
,
104 struct widget_t
*widget
) {
106 struct widget_t
**font
;
108 if(get_theme_widget(xuni
, n
)) {
109 font
= &xuni
->theme
->current
->p
.theme
->nameid
->widget
[n
].widget
;
110 free_font(xuni
, *font
);
112 xuni_memory_increment(widget
->p
.font
);
113 (*font
)->p
.font
= widget
->p
.font
;
115 else new_font_t(*font
, "");
117 widget_event(xuni
, *font
, WIDGET_EVENT_RESCALE
);
118 widget_event(xuni
, xuni
->gui
->widget
, WIDGET_EVENT_UPDATE_TEXT
);
122 static void free_font(struct xuni_t
*xuni
, struct widget_t
*widget
) {
123 if(xuni_memory_decrement(widget
->p
.font
)) {
124 if(widget
->p
.font
->ttf
) TTF_CloseFont(widget
->p
.font
->ttf
);
126 /* hack to free SDL_gfx's statically stored, dynamically allocated
127 memory for each character (glyph) */
128 gfxPrimitivesSetFont(gfxPrimitivesFontdata
,
129 GFX_FONT_WIDTH
, GFX_FONT_HEIGHT
);
132 xuni_memory_free((void *)widget
->p
.font
->name
);
134 free(widget
->p
.font
);
138 static void rescale_font(struct xuni_t
*xuni
, struct widget_t
*widget
) {
139 struct font_t
*font
= widget
->p
.font
;
141 font
->point
= pick_font_point(xuni
);
143 if(font
->ttf
) TTF_CloseFont(font
->ttf
);
144 font
->ttf
= TTF_OpenFont(font
->name
, font
->point
);
147 TTF_SetFontStyle(font
->ttf
, TTF_STYLE_NORMAL
);
150 if(!font
->name
|| *font
->name
) {
151 log_message(ERROR_TYPE_WARNING
, 0, __FILE__
, __LINE__
,
152 "Can't open font \"%s\", using built-in fixed-size %ix%i"
153 " bitmap font", font
->name
, GFX_FONT_WIDTH
, GFX_FONT_HEIGHT
);
156 gfxPrimitivesSetFont(gfxPrimitivesFontdata
,
157 GFX_FONT_WIDTH
, GFX_FONT_HEIGHT
);
161 double get_font_ratio(struct xuni_t
*xuni
) {
163 return (xuni
->smode
->screen
->w
/ (double)xuni
->smode
->screen
->h
)
167 /*! Picks a reasonable font size for the current screen resolution, according
168 to the following formula:
169 point-size = round(min(screen-width / ratio, screen-height) / 30.0)
170 \param xuni Contains information about the current screen resolution that
172 \return The right font size for the current screen resolution.
174 static int pick_font_point(struct xuni_t
*xuni
) {
175 double ratio
= get_font_ratio(xuni
);
176 int mindim
= (xuni
->smode
->width
/ ratio
< xuni
->smode
->height
177 ? xuni
->smode
->width
/ ratio
: xuni
->smode
->height
);
178 int point
= (int)(mindim
/ 30.0 + 0.5);
180 /*printf("Picking font size %i\n", (int)point);*/
182 /* restrict the font point size to a minimum of 2
183 libfreetype6 2.3.5-1+b1 often crashes with point size 1
185 if(point
<= 1) return 2;
190 int font_height(struct xuni_t
*xuni
, struct widget_t
*widget
) {
191 if(widget
&& widget
->p
.font
->ttf
) {
192 return TTF_FontHeight(widget
->p
.font
->ttf
);
194 else return GFX_FONT_HEIGHT
;
197 int font_string_width(struct xuni_t
*xuni
, struct widget_t
*widget
,
202 if(widget
&& widget
->p
.font
->ttf
) {
203 TTF_SizeText(widget
->p
.font
->ttf
, str
, &width
, 0);
205 else width
= GFX_FONT_WIDTH
* strlen(str
);
207 return (int)(width
* get_font_ratio(xuni
) + 0.5);
210 /*! Creates a new surface with text blitted to it via SDL_gfx's string*()
211 code; that is, with a built-in bitmap font. A surface is generated to make
212 this function compatible with SDL_ttf's TTF_RenderText_*() functions.
214 Uses a bit of a hack to do the transparency, because SDL_gfx's string*()
215 functions calculate their own alpha. For example, when the surface to blit
216 to has an alpha of 128, and SDL_gfx is requested to blit an alpha of 128,
217 the actual alpha in the end is (128/256)*(128/256)*256 = 64, not the
220 \param text The string to blit to the new surface.
221 \param r The red component of the colour of the new surface
222 (0 to 255 inclusive, like \a g and \a b).
223 \param g The green component of the colour of the text on the new surface.
224 \param b The blue component of the text colour, again from 0 to 255
226 \return A new SDL_Surface with the string in \a text blitted to it in the
227 colour (\a r, \a g, \a b).
229 static SDL_Surface
*render_gfx_text(const char *text
, int r
, int g
, int b
) {
230 int bg
= ((r
+ g
+ b
) / 3.0 < 128) ? 255 : 0;
232 SDL_Surface
*image
= new_surface(
233 GFX_FONT_WIDTH
* strlen(text
), GFX_FONT_HEIGHT
, 32, 0);
234 SDL_FillRect(image
, NULL
, SDL_MapRGB(image
->format
, bg
, bg
, bg
));
236 stringRGBA(image
, 0, 0, text
, r
, g
, b
, 255);
238 SDL_SetColorKey(image
, SDL_SRCCOLORKEY
,
239 SDL_MapRGB(image
->format
, bg
, bg
, bg
));
244 SDL_Surface
*render_unrescaled_text(struct widget_t
*widget
, const char *text
,
245 Uint8 r
, Uint8 g
, Uint8 b
) {
247 if(!text
|| !*text
) return NULL
;
249 if(widget
&& widget
->p
.font
->ttf
) {
256 return TTF_RenderText_Blended(widget
->p
.font
->ttf
, text
, col
);
259 return render_gfx_text(text
, r
, g
, b
);
262 SDL_Surface
*render_text(struct xuni_t
*xuni
, struct widget_t
*widget
,
263 const char *text
, Uint8 r
, Uint8 g
, Uint8 b
) {
265 SDL_Surface
*rescaled
, *unrescaled
;
266 double ratio
, xratio
, yratio
;
268 unrescaled
= render_unrescaled_text(widget
, text
, r
, g
, b
);
270 ratio
= get_font_ratio(xuni
);
272 if(!unrescaled
|| fabs(ratio
- 1.0) < 0.001) return unrescaled
;
275 xratio
= (ratio
> 1.0) ? ratio
: 1.0;
276 yratio
= (ratio
< 1.0) ? /*1.0 /*/ ratio : 1.0;
284 yratio = 1.0 / ratio;
289 rescaled = zoomSurface(unrescaled,
290 /*widget->pos->scale.w / 100.0
291 / ((double)xuni->smode->screen->w / widget->base->pos->real.w)
292 * xuni->smode->screen->w / temp->w*/ xratio
,
293 /*widget->pos->scale.h / 100.0
294 / ((double)xuni->smode->screen->h / widget->base->pos->real.h)
295 * xuni->smode->screen->h / temp->h*/ yratio
,
298 rescaled
= sge_transform_surface(unrescaled
,
299 SDL_MapRGB(xuni
->smode
->screen
->format
, 0, 0, 0),
300 0.0f
, xratio
, yratio
, 0);
302 rescaled
= zoomSurface(unrescaled
,
303 (int)(unrescaled
->w
* xratio
+ 0.5) / (double)unrescaled
->w
,
304 (int)(unrescaled
->h
* yratio
+ 0.5) / (double)unrescaled
->h
,
308 SDL_FreeSurface(unrescaled
);