120 { |
121 { |
121 return cell_surface; |
122 return cell_surface; |
122 } |
123 } |
123 |
124 |
124 TTF_Font *font = _font_regular; |
125 TTF_Font *font = _font_regular; |
125 SDL_Color color={0xff,0xff,0xff}, bgcolor={0,100,100}; |
126 SDL_Color color={0xff,0xff,0xff}, bgcolor={0,0,0}; |
126 if (ch != 'W') |
|
127 { |
|
128 bgcolor.g = 0; |
|
129 bgcolor.b = 0; |
|
130 } |
|
131 |
127 |
132 // create surface for whole cell and fill it with bg color |
128 // create surface for whole cell and fill it with bg color |
133 cell_surface = SDL_CreateRGBSurface(SDL_SWSURFACE, |
129 cell_surface = SDL_CreateRGBSurface(SDL_SWSURFACE, |
134 _cell_width, _cell_height, 32, 0, 0, 0, 0); |
130 _cell_width, _cell_height, 32, 0, 0, 0, 0); |
135 SDL_Rect dst_rect; |
131 SDL_Rect dst_rect; |
139 dst_rect.h = _cell_height; |
135 dst_rect.h = _cell_height; |
140 Uint32 bgcolor_mapped = SDL_MapRGB(cell_surface->format, bgcolor.r, bgcolor.g, bgcolor.b); |
136 Uint32 bgcolor_mapped = SDL_MapRGB(cell_surface->format, bgcolor.r, bgcolor.g, bgcolor.b); |
141 SDL_FillRect(cell_surface, &dst_rect, bgcolor_mapped); |
137 SDL_FillRect(cell_surface, &dst_rect, bgcolor_mapped); |
142 |
138 |
143 // render glyph, blit it onto cell surface |
139 // render glyph, blit it onto cell surface |
144 SDL_Surface *glyph_surface = TTF_RenderGlyph_Shaded(font, ch, color, bgcolor); |
140 if (ch) |
145 int minx, maxy; |
141 { |
146 TTF_GlyphMetrics(font, ch, &minx, NULL, NULL, &maxy, NULL); |
142 SDL_Surface *glyph_surface = TTF_RenderGlyph_Shaded(font, ch, color, bgcolor); |
147 dst_rect.x = minx; |
143 int minx, maxy; |
148 dst_rect.y = TTF_FontAscent(font) - maxy; |
144 TTF_GlyphMetrics(font, ch, &minx, NULL, NULL, &maxy, NULL); |
149 SDL_BlitSurface(glyph_surface, NULL, cell_surface, &dst_rect); |
145 dst_rect.x = minx; |
150 SDL_FreeSurface(glyph_surface); |
146 dst_rect.y = TTF_FontAscent(font) - maxy; |
151 |
147 SDL_BlitSurface(glyph_surface, NULL, cell_surface, &dst_rect); |
|
148 SDL_FreeSurface(glyph_surface); |
|
149 } |
|
150 |
|
151 // convert to display format |
|
152 SDL_Surface *tmp_surface = cell_surface; |
|
153 cell_surface = SDL_DisplayFormat(tmp_surface); |
|
154 SDL_FreeSurface(tmp_surface); |
|
155 |
|
156 // put to cache |
152 _cache.put_glyph(ch, cell_surface); |
157 _cache.put_glyph(ch, cell_surface); |
|
158 |
153 return cell_surface; |
159 return cell_surface; |
154 } |
|
155 |
|
156 |
|
157 TerminalScreen::~TerminalScreen() |
|
158 { |
|
159 if (_cells) |
|
160 { |
|
161 delete[] _cells; |
|
162 } |
|
163 } |
160 } |
164 |
161 |
165 |
162 |
166 void TerminalScreen::select_font(const char *fname_regular, const char *fname_bold, int ptsize) |
163 void TerminalScreen::select_font(const char *fname_regular, const char *fname_bold, int ptsize) |
167 { |
164 { |
169 _reset_cells(); |
166 _reset_cells(); |
170 } |
167 } |
171 |
168 |
172 void TerminalScreen::resize(int pxwidth, int pxheight) |
169 void TerminalScreen::resize(int pxwidth, int pxheight) |
173 { |
170 { |
174 _screen_surface = SDL_SetVideoMode(pxwidth, pxheight, 32, SDL_HWSURFACE|SDL_RESIZABLE); |
171 _screen_surface = SDL_SetVideoMode(pxwidth, pxheight, 0, SDL_SWSURFACE|SDL_ANYFORMAT|SDL_RESIZABLE); |
175 |
172 |
176 if (_screen_surface == NULL) |
173 if (_screen_surface == NULL) |
177 { |
174 { |
178 fprintf(stderr, "Unable to set video: %s\n", SDL_GetError()); |
175 fprintf(stderr, "Unable to set video: %s\n", SDL_GetError()); |
179 throw std::exception(); |
176 throw std::exception(); |
188 } |
185 } |
189 |
186 |
190 |
187 |
191 void TerminalScreen::erase() |
188 void TerminalScreen::erase() |
192 { |
189 { |
193 TerminalCell * cell = _cells; |
190 std::fill(_cells_front.begin(), _cells_front.end(), TerminalCell()); |
194 for (int i = 0; i < _width * _height; i++) |
|
195 { |
|
196 cell->ch = ' '; |
|
197 cell->attr = 0; |
|
198 cell++; |
|
199 } |
|
200 } |
191 } |
201 |
192 |
202 |
193 |
203 void TerminalScreen::putch(int x, int y, Uint16 ch, Uint16 attr) |
194 void TerminalScreen::putch(int x, int y, Uint16 ch, Uint16 attr) |
204 { |
195 { |
205 TerminalCell &cell = _cells[y * _width + x]; |
196 TerminalCell &cell = _cells_front[y * _width + x]; |
206 cell.ch = ch; |
197 cell.ch = ch; |
207 cell.attr = attr; |
198 cell.attr = attr; |
208 } |
199 } |
209 |
200 |
210 |
201 |
211 void TerminalScreen::commit() |
202 void TerminalScreen::commit() |
212 { |
203 { |
213 TerminalCell * cell = _cells; |
204 auto front_iter = _cells_front.begin(); |
|
205 auto back_iter = _cells_back.begin(); |
214 SDL_Surface *glyph_surface; |
206 SDL_Surface *glyph_surface; |
215 SDL_Rect dst_rect; |
207 SDL_Rect dst_rect; |
216 for (int y = 0; y < _height; y++) |
208 for (int y = 0; y < _height; y++) |
217 { |
209 { |
218 for (int x = 0; x < _width; x++) |
210 for (int x = 0; x < _width; x++) |
219 { |
211 { |
220 dst_rect.x = x * _cell_width; |
212 if (*front_iter != *back_iter) |
221 dst_rect.y = y * _cell_height; |
213 { |
222 glyph_surface = _render.render_glyph(cell->ch); |
214 dst_rect.x = x * _cell_width; |
223 SDL_BlitSurface(glyph_surface, NULL, _screen_surface, &dst_rect); |
215 dst_rect.y = y * _cell_height; |
224 cell++; |
216 glyph_surface = _render.render_glyph(front_iter->ch); |
|
217 SDL_BlitSurface(glyph_surface, NULL, _screen_surface, &dst_rect); |
|
218 *back_iter = *front_iter; |
|
219 } |
|
220 front_iter++; |
|
221 back_iter++; |
225 } |
222 } |
226 } |
223 } |
227 |
224 |
228 SDL_UpdateRect(_screen_surface, 0, 0, 0, 0); |
225 SDL_UpdateRect(_screen_surface, 0, 0, 0, 0); |
229 } |
226 } |
230 |
227 |
231 |
228 |
232 void TerminalScreen::_reset_cells() |
229 void TerminalScreen::_reset_cells() |
233 { |
230 { |
234 if (_cells) |
|
235 { |
|
236 delete[] _cells; |
|
237 _cells = NULL; |
|
238 } |
|
239 |
|
240 _cell_width = _render.get_cell_width(); |
231 _cell_width = _render.get_cell_width(); |
241 _cell_height = _render.get_cell_height(); |
232 _cell_height = _render.get_cell_height(); |
242 _width = _pixel_width / _cell_width; |
233 _width = _pixel_width / _cell_width; |
243 _height = _pixel_height / _cell_height; |
234 _height = _pixel_height / _cell_height; |
244 |
235 |
245 int num_cells = _width * _height; |
236 int num_cells = _width * _height; |
246 _cells = new TerminalCell[num_cells]; |
237 _cells_front.resize(num_cells); |
|
238 _cells_back.resize(num_cells); |
247 } |
239 } |
248 |
240 |
249 |
241 |
250 Terminal::Terminal() |
242 Terminal::Terminal() |
251 : _screen() |
243 : _screen(), _mousemove_last_x(-1) |
252 { |
244 { |
253 if (SDL_Init(SDL_INIT_VIDEO) == -1) |
245 if (SDL_Init(SDL_INIT_VIDEO) == -1) |
254 { |
246 { |
255 fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError()); |
247 fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError()); |
256 throw std::exception(); |
248 throw std::exception(); |
265 } |
257 } |
266 |
258 |
267 |
259 |
268 void Terminal::get_next_event(Event &event) |
260 void Terminal::get_next_event(Event &event) |
269 { |
261 { |
270 SDL_Event sdl_event; |
262 static SDL_Event sdl_event; |
271 |
263 |
272 while (SDL_WaitEvent(&sdl_event)) |
264 while (SDL_WaitEvent(&sdl_event)) |
273 { |
265 { |
274 switch (sdl_event.type) |
266 switch (sdl_event.type) |
275 { |
267 { |
276 case SDL_QUIT: |
268 case SDL_QUIT: |
277 event.type = Event::QUIT; |
269 event.type = Event::QUIT; |
278 return; |
270 return; |
279 |
271 |
280 case SDL_KEYDOWN: |
272 case SDL_KEYDOWN: |
|
273 { |
281 //switch(event.key.keysym.sym) |
274 //switch(event.key.keysym.sym) |
282 event.type = Event::KEYPRESS; |
275 event.type = Event::KEYPRESS; |
283 event.key.unicode = sdl_event.key.keysym.unicode; |
276 const char *keyname = _translate_keyname(sdl_event.key.keysym.sym); |
284 strncpy(event.key.keyname, _translate_keyname(sdl_event.key.keysym.sym), 10); |
277 // return only keyname or unicode, never both |
|
278 if (keyname) |
|
279 { |
|
280 strncpy(event.key.keyname, keyname, 10); |
|
281 event.key.unicode = 0; |
|
282 } |
|
283 else |
|
284 { |
|
285 event.key.keyname[0] = 0; |
|
286 event.key.unicode = sdl_event.key.keysym.unicode; |
|
287 if (!event.key.unicode) |
|
288 break; // continue loop (unknown key) |
|
289 } |
285 return; |
290 return; |
|
291 } |
286 |
292 |
287 case SDL_MOUSEBUTTONDOWN: |
293 case SDL_MOUSEBUTTONDOWN: |
288 case SDL_MOUSEBUTTONUP: |
294 case SDL_MOUSEBUTTONUP: |
289 event.type = (sdl_event.type == SDL_MOUSEBUTTONDOWN) ? Event::MOUSEDOWN : Event::MOUSEUP; |
295 event.type = (sdl_event.type == SDL_MOUSEBUTTONDOWN) ? Event::MOUSEDOWN : Event::MOUSEUP; |
290 event.mouse.x = sdl_event.button.x / _screen.get_cell_width(); |
296 event.mouse.x = sdl_event.button.x / _screen.get_cell_width(); |
291 event.mouse.y = sdl_event.button.y / _screen.get_cell_height(); |
297 event.mouse.y = sdl_event.button.y / _screen.get_cell_height(); |
292 event.mouse.button = sdl_event.button.button; |
298 event.mouse.button = sdl_event.button.button; |
|
299 _mousemove_last_x = -1; |
293 return; |
300 return; |
294 |
301 |
295 case SDL_MOUSEMOTION: |
302 case SDL_MOUSEMOTION: |
296 event.type = Event::MOUSEMOVE; |
303 event.type = Event::MOUSEMOVE; |
297 event.mouse.x = sdl_event.motion.x / _screen.get_cell_width(); |
304 event.mouse.x = sdl_event.motion.x / _screen.get_cell_width(); |
298 event.mouse.y = sdl_event.motion.y / _screen.get_cell_height(); |
305 event.mouse.y = sdl_event.motion.y / _screen.get_cell_height(); |
299 return; |
306 if (_mousemove_last_x != event.mouse.x || |
|
307 _mousemove_last_y != event.mouse.y) |
|
308 { |
|
309 _mousemove_last_x = event.mouse.x; |
|
310 _mousemove_last_y = event.mouse.y; |
|
311 return; |
|
312 } |
|
313 break; // continue loop when mouse position did not change |
300 |
314 |
301 default: |
315 default: |
302 break; // continue loop |
316 break; // continue loop |
303 } |
317 } |
304 } |
318 } |