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 	}  |