|
1 #include "sdlterm.h" |
|
2 |
|
3 #include <stdexcept> |
|
4 |
|
5 |
|
6 GlyphRenderer::GlyphRenderer() |
|
7 : _font_regular(NULL), _font_bold(NULL) |
|
8 { |
|
9 if (TTF_Init() == -1) |
|
10 { |
|
11 printf("TTF_Init: %s\n", TTF_GetError()); |
|
12 throw std::exception(); |
|
13 } |
|
14 } |
|
15 |
|
16 |
|
17 GlyphRenderer::~GlyphRenderer() |
|
18 { |
|
19 close_font(); |
|
20 TTF_Quit(); |
|
21 } |
|
22 |
|
23 |
|
24 void GlyphRenderer::open_font(const char *fname_regular, const char *fname_bold, int ptsize) |
|
25 { |
|
26 close_font(); |
|
27 |
|
28 // open regular font |
|
29 _font_regular = TTF_OpenFont(fname_regular, ptsize); |
|
30 if (!_font_regular) |
|
31 { |
|
32 printf("TTF_OpenFont: %s\n", TTF_GetError()); |
|
33 throw std::exception(); |
|
34 } |
|
35 |
|
36 // open bold font |
|
37 _font_bold = TTF_OpenFont(fname_bold, ptsize); |
|
38 if (!_font_bold) |
|
39 { |
|
40 printf("TTF_OpenFont: %s\n", TTF_GetError()); |
|
41 throw std::exception(); |
|
42 } |
|
43 |
|
44 // update metrics for regular font |
|
45 int advance; |
|
46 if (TTF_GlyphMetrics(_font_regular, 'M', NULL, NULL, NULL, NULL, &advance) == -1) |
|
47 { |
|
48 printf("TTF_GlyphMetrics: %s\n", TTF_GetError()); |
|
49 } |
|
50 _cell_width = advance; |
|
51 _cell_height = TTF_FontHeight(_font_regular); |
|
52 |
|
53 // read metrics for bold font |
|
54 if (TTF_GlyphMetrics(_font_bold, 'M', NULL, NULL, NULL, NULL, &advance) == -1) |
|
55 { |
|
56 printf("TTF_GlyphMetrics: %s\n", TTF_GetError()); |
|
57 } |
|
58 if (advance > _cell_width) |
|
59 { |
|
60 _cell_width = advance; |
|
61 } |
|
62 int height = TTF_FontHeight(_font_bold); |
|
63 if (height > _cell_height) |
|
64 { |
|
65 _cell_height = height; |
|
66 } |
|
67 } |
|
68 |
|
69 |
|
70 void GlyphRenderer::close_font() |
|
71 { |
|
72 if (_font_regular) |
|
73 { |
|
74 TTF_CloseFont(_font_regular); |
|
75 _font_regular = NULL; |
|
76 } |
|
77 if (_font_bold) |
|
78 { |
|
79 TTF_CloseFont(_font_bold); |
|
80 _font_bold = NULL; |
|
81 } |
|
82 } |
|
83 |
|
84 |
|
85 SDL_Surface *GlyphRenderer::render_glyph(Uint16 ch) |
|
86 { |
|
87 TTF_Font *font = _font_regular; |
|
88 SDL_Color color={0xff,0xff,0xff}, bgcolor={0,100,100}; |
|
89 if (ch != 'W') |
|
90 { |
|
91 bgcolor.g = 0; |
|
92 bgcolor.b = 0; |
|
93 } |
|
94 |
|
95 // create surface for whole cell and fill it with bg color |
|
96 SDL_Surface *cell_surface = SDL_CreateRGBSurface(SDL_SWSURFACE, |
|
97 _cell_width, _cell_height, 32, 0, 0, 0, 0); |
|
98 SDL_Rect dst_rect; |
|
99 dst_rect.x = 0; |
|
100 dst_rect.y = 0; |
|
101 dst_rect.w = _cell_width; |
|
102 dst_rect.h = _cell_height; |
|
103 Uint32 bgcolor_mapped = SDL_MapRGB(cell_surface->format, bgcolor.r, bgcolor.g, bgcolor.b); |
|
104 SDL_FillRect(cell_surface, &dst_rect, bgcolor_mapped); |
|
105 |
|
106 // render glyph, blit it onto cell surface |
|
107 SDL_Surface *glyph_surface = TTF_RenderGlyph_Shaded(font, ch, color, bgcolor); |
|
108 int minx, maxy; |
|
109 TTF_GlyphMetrics(font, ch, &minx, NULL, NULL, &maxy, NULL); |
|
110 dst_rect.x = minx; |
|
111 dst_rect.y = TTF_FontAscent(font) - maxy; |
|
112 SDL_BlitSurface(glyph_surface, NULL, cell_surface, &dst_rect); |
|
113 SDL_FreeSurface(glyph_surface); |
|
114 |
|
115 return cell_surface; |
|
116 } |
|
117 |
|
118 |
|
119 TerminalScreen::~TerminalScreen() |
|
120 { |
|
121 if (_cells) |
|
122 { |
|
123 delete[] _cells; |
|
124 } |
|
125 } |
|
126 |
|
127 |
|
128 void TerminalScreen::select_font(const char *fname_regular, const char *fname_bold, int ptsize) |
|
129 { |
|
130 _render.open_font(fname_regular, fname_bold, ptsize); |
|
131 _reset_cells(); |
|
132 } |
|
133 |
|
134 void TerminalScreen::resize(int pxwidth, int pxheight) |
|
135 { |
|
136 _screen_surface = SDL_SetVideoMode(pxwidth, pxheight, 8, SDL_SWSURFACE|SDL_ANYFORMAT|SDL_RESIZABLE); |
|
137 |
|
138 if (_screen_surface == NULL) |
|
139 { |
|
140 fprintf(stderr, "Unable to set video: %s\n", SDL_GetError()); |
|
141 throw std::exception(); |
|
142 } |
|
143 |
|
144 SDL_WM_SetCaption("terminal", NULL); |
|
145 |
|
146 _pixel_width = pxwidth; |
|
147 _pixel_height = pxheight; |
|
148 |
|
149 _reset_cells(); |
|
150 } |
|
151 |
|
152 |
|
153 void TerminalScreen::erase() |
|
154 { |
|
155 TerminalCell * cell = _cells; |
|
156 for (int i = 0; i < _width * _height; i++) |
|
157 { |
|
158 cell->ch = ' '; |
|
159 cell->attr = 0; |
|
160 cell++; |
|
161 } |
|
162 } |
|
163 |
|
164 |
|
165 void TerminalScreen::putch(int x, int y, Uint16 ch, Uint16 attr) |
|
166 { |
|
167 TerminalCell &cell = _cells[y * _width + x]; |
|
168 cell.ch = ch; |
|
169 cell.attr = attr; |
|
170 } |
|
171 |
|
172 |
|
173 void TerminalScreen::commit() |
|
174 { |
|
175 TerminalCell * cell = _cells; |
|
176 SDL_Surface *glyph_surface; |
|
177 SDL_Rect dst_rect; |
|
178 for (int y = 0; y < _height; y++) |
|
179 { |
|
180 for (int x = 0; x < _width; x++) |
|
181 { |
|
182 dst_rect.x = x * _cell_width; |
|
183 dst_rect.y = y * _cell_height; |
|
184 glyph_surface = _render.render_glyph(cell->ch); |
|
185 SDL_BlitSurface(glyph_surface, NULL, _screen_surface, &dst_rect); |
|
186 SDL_FreeSurface(glyph_surface); |
|
187 cell++; |
|
188 } |
|
189 } |
|
190 |
|
191 SDL_UpdateRect(_screen_surface, 0, 0, 0, 0); |
|
192 } |
|
193 |
|
194 |
|
195 void TerminalScreen::_reset_cells() |
|
196 { |
|
197 if (_cells) |
|
198 { |
|
199 delete[] _cells; |
|
200 _cells = NULL; |
|
201 } |
|
202 |
|
203 _cell_width = _render.get_cell_width(); |
|
204 _cell_height = _render.get_cell_height(); |
|
205 _width = _pixel_width / _cell_width; |
|
206 _height = _pixel_height / _cell_height; |
|
207 |
|
208 int num_cells = _width * _height; |
|
209 _cells = new TerminalCell[num_cells]; |
|
210 } |
|
211 |
|
212 |
|
213 Terminal::Terminal() |
|
214 : _screen() |
|
215 { |
|
216 if (SDL_Init(SDL_INIT_VIDEO) == -1) |
|
217 { |
|
218 fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError()); |
|
219 throw std::exception(); |
|
220 } |
|
221 } |
|
222 |
|
223 |
|
224 Terminal::~Terminal() |
|
225 { |
|
226 SDL_Quit(); |
|
227 } |
|
228 |
|
229 |
|
230 void Terminal::get_next_event(Event &event) |
|
231 { |
|
232 SDL_Event sdl_event; |
|
233 |
|
234 while (SDL_WaitEvent(&sdl_event)) |
|
235 { |
|
236 switch (sdl_event.type) |
|
237 { |
|
238 case SDL_QUIT: |
|
239 event.type = EventType::quit; |
|
240 return; |
|
241 |
|
242 case SDL_KEYDOWN: |
|
243 //switch(event.key.keysym.sym) |
|
244 event.type = EventType::keypress; |
|
245 return; |
|
246 |
|
247 default: |
|
248 break; // continue loop |
|
249 } |
|
250 } |
|
251 } |