1 #include "ttf_manager.hpp"
8 ttf_managerst ttf_manager
;
10 bool ttf_managerst::init(int ceiling
, int tile_width
) {
11 // Reset to a known state, clear everything
12 if ((!TTF_WasInit()) && (TTF_Init() == -1)) {
13 MessageBox(NULL
, TTF_GetError(), "TTF error", MB_OK
);
16 if (font
) TTF_CloseFont(font
);
18 for (auto it
= textures
.cbegin(); it
!= textures
.cend(); ++it
)
19 SDL_FreeSurface(it
->second
);
21 this->tile_width
= tile_width
;
22 this->ceiling
= ceiling
;
23 // Try progressively smaller point sizes until we find one that fits
24 for (int sz
=20; sz
> 0; sz
--) {
25 font
= TTF_OpenFont("data/art/font.ttf", sz
);
27 if (TTF_FontHeight(font
) <= ceiling
) {
29 cout
<< "Picked font at " << sz
<< " points for ceiling " << ceiling
<< endl
;
30 // get the glyph metric for the letter 'M' in a loaded font
31 cout
<< "TTF_FontHeight " << TTF_FontHeight(font
) << endl
;
32 cout
<< "TTF_FontAscent " << TTF_FontAscent(font
) << endl
;
33 cout
<< "TTF_FontDescent " << TTF_FontDescent(font
) << endl
;
34 cout
<< "TTF_FontLineSkip " << TTF_FontLineSkip(font
) << endl
;
36 int minx
,maxx
,miny
,maxy
,advance
;
37 if (TTF_GlyphMetrics(font
, 'M', &minx
, &maxx
, &miny
, &maxy
, &advance
) == -1)
42 printf("minx : %d\n",minx
);
43 printf("maxx : %d\n",maxx
);
44 printf("miny : %d\n",miny
);
45 printf("maxy : %d\n",maxy
);
46 printf("advance : %d\n",advance
);
54 cout
<< "No font found!" << endl
;
59 static void cp437_to_unicode(const string
&text
, vector
<Uint16
> &unicode
) {
60 unicode
.resize(text
.length() + 1);
62 for (i
=0; i
< text
.size(); i
++) {
63 const int cp437
= (unsigned char)text
[i
];
64 unicode
[i
] = charmap
[cp437
];
70 int ttf_managerst::size_text(const string
&text
) {
71 vector
<Uint16
> text_unicode
;
72 cp437_to_unicode(text
, text_unicode
);
74 TTF_SizeUNICODE(font
, &text_unicode
[0], &width
, &height
);
75 return (width
+ tile_width
- 1) / tile_width
;
79 ttf_details
ttf_managerst::get_handle(const list
<ttf_id
> &text
, justification just
) {
80 // Check for an existing handle
81 handleid id
= {text
, just
};
82 auto it
= handles
.find(id
);
83 if (it
!= handles
.end()) return it
->second
;
84 // Right. Make a new one.
85 int handle
= ++max_handle
;
87 list
<ttf_id
> split_text
;
88 for (auto it
= text
.cbegin(); it
!= text
.cend(); ++it
) {
91 while ((tabpos
= it
->text
.find("\t", pos
)) != string::npos
) {
93 left
.fg
= it
->fg
; left
.bg
= it
->bg
; left
.bold
= it
->bold
;
94 left
.text
= it
->text
.substr(pos
, tabpos
- pos
);
95 split_text
.push_back(left
);
97 tabber
.fg
= tabber
.bg
= tabber
.bold
= 255;
98 split_text
.push_back(tabber
);
102 right
.fg
= it
->fg
; right
.bg
= it
->bg
; right
.bold
= it
->bold
;
103 right
.text
= it
->text
.substr(pos
);
104 split_text
.push_back(right
);
106 // Find the total width of the text
107 vector
<Uint16
> text_unicode
;
108 int ttf_width
= 0, ttf_height
= 0, text_width
= 0;
109 for (auto it
= split_text
.cbegin(); it
!= split_text
.cend(); ++it
) {
110 if (it
->fg
== 255 && it
->bg
== 255 && it
->bold
== 255) {
112 int tabstop
= tab_width
* em_width
;
113 int tab_width
= tabstop
- ((ttf_width
- 1) % tabstop
) + 1;
114 ttf_width
+= tab_width
;
117 cp437_to_unicode(it
->text
, text_unicode
);
118 int slice_width
, slice_height
;
119 TTF_SizeUNICODE(font
, &text_unicode
[0], &slice_width
, &slice_height
);
120 ttf_width
+= slice_width
;
121 text_width
+= it
->text
.size();
124 ttf_height
= ceiling
;
126 double grid_width
= double(ttf_width
) / tile_width
;
127 double offset
= just
== justify_right
? text_width
- grid_width
:
128 just
== justify_center
? (text_width
- grid_width
) / 2 :
130 if (just
== justify_center
&& text_width
% 2)
131 offset
+= 0.5; // Arbitrary fixup for approximate grid centering
132 double fraction
, integral
;
133 fraction
= modf(offset
, &integral
);
135 const int grid_offset
= int(integral
+ 0.001); // Tiles to move to the right in addst
136 const int pixel_offset
= int(fraction
* tile_width
); // Black columns to add to the left of the image
137 // const int full_grid_width = int(ceil(double(ttf_width) / double(tile_width) + fraction) + 0.1); // Total width of the image in grid units
138 const int full_grid_width
= text_width
;
139 const int pixel_width
= full_grid_width
* tile_width
; // And pixels
140 assert(pixel_width
>= ttf_width
);
142 ttf_details ret
; ret
.handle
= handle
; ret
.offset
= grid_offset
; ret
.width
= full_grid_width
;
144 // We do the actual rendering in the render thread, later on.
145 todo
.push_back(todum(handle
, split_text
, ttf_height
, pixel_offset
, pixel_width
));
149 SDL_Surface
*ttf_managerst::get_texture(int handle
) {
150 // Run any outstanding renders
152 vector
<Uint16
> text_unicode
;
153 for (auto it
= todo
.cbegin(); it
!= todo
.cend(); ++it
) {
154 const int height
= it
->height
;
155 SDL_Surface
*textimg
= SDL_CreateRGBSurface(SDL_SWSURFACE
, it
->pixel_width
, height
, 32, 0, 0, 0, 0);
157 // SDL_FillRect(textimg, NULL, SDL_MapRGBA(textimg->format, 255, 0, 0, 255));
159 // Render each of the text segments
161 int xpos
= it
->pixel_offset
;
162 for (auto seg
= it
->text
.cbegin(); seg
!= it
->text
.cend();) {
163 const ttf_id
&text
= *seg
;
166 if (text
.fg
== 255 && text
.bg
== 255 && text
.bold
== 255) {
168 int tabstop
= tab_width
* em_width
;
169 int tab_width
= tabstop
- ((xpos
- 1) % tabstop
) + 1;
173 if (text
.text
.size() <= 0)
175 cp437_to_unicode(text
.text
, text_unicode
);
176 const int fg
= (text
.fg
+ text
.bold
* 8) % 16;
177 SDL_Color fgc
= {Uint8(enabler
.ccolor
[fg
][0]*255),
178 Uint8(enabler
.ccolor
[fg
][1]*255),
179 Uint8(enabler
.ccolor
[fg
][2]*255)};
180 const int bg
= text
.bg
% 16;
181 Uint32 bgc
= SDL_MapRGB(textimg
->format
,
182 Uint8(enabler
.ccolor
[bg
][0]*255),
183 Uint8(enabler
.ccolor
[bg
][1]*255),
184 Uint8(enabler
.ccolor
[bg
][2]*255));
186 // SDL_Color white = {255,255,255};
187 // Uint32 red = SDL_MapRGB(textimg->format, 255,0,0);
192 // Fill in the left side
193 SDL_Rect left
= {0, 0, Sint16(xpos
), Sint16(height
)};
194 SDL_FillRect(textimg
, &left
, bgc
);
195 } else if (seg
== it
->text
.cend()) {
196 // Fill in the right side
197 SDL_Rect right
= {Sint16(xpos
), 0, Sint16(it
->pixel_width
), Sint16(height
)};
198 SDL_FillRect(textimg
, &right
, bgc
);
200 // Render the TTF segment
201 SDL_Surface
*textimg_seg
= TTF_RenderUNICODE_Blended(font
, &text_unicode
[0], fgc
);
202 // Fill the background color of this part of the textimg
203 SDL_Rect dest
= {Sint16(xpos
), 0, Sint16(textimg_seg
->w
), Sint16(height
)};
204 SDL_FillRect(textimg
, &dest
,
205 SDL_MapRGB(textimg
->format
,
209 Uint8(enabler
.ccolor
[bg
][0]*255),
210 Uint8(enabler
.ccolor
[bg
][1]*255),
211 Uint8(enabler
.ccolor
[bg
][2]*255)));
212 // And copy the TTF segment over.
213 SDL_Rect dest2
= {Sint16(xpos
), 0, 0, 0};
214 SDL_BlitSurface(textimg_seg
, NULL
, textimg
, &dest2
);
215 // Ready for next segment.
216 xpos
+= textimg_seg
->w
;
217 SDL_FreeSurface(textimg_seg
);
219 // ..and make the whole thing display format. Phew!
220 SDL_Surface
*textimg_2
= SDL_DisplayFormat(textimg
);
222 // cout << "Rendering \"" << text.text << "\" at height " << box2->h << endl;
223 // cout << " width " << textimg->w << " in box of " << box->w << endl;
225 SDL_FreeSurface(textimg
);
226 // Store it for later.
227 textures
[it
->handle
] = textimg_2
;
231 // Find the li'l texture
232 SDL_Surface
*tex
= textures
[handle
];
234 cout
<< "Missing/broken TTF handle: " << handle
<< endl
;
239 void ttf_managerst::gc() {
240 // Just delete everything, for now.
241 for (auto it
= textures
.begin(); it
!= textures
.end(); ++it
)
242 SDL_FreeSurface(it
->second
);