sdlterm/src/sdlterm.cc
changeset 49 1611c462c3e3
parent 48 1f00e90fd72a
child 50 c5b8b9d2da95
equal deleted inserted replaced
48:1f00e90fd72a 49:1611c462c3e3
     1 #include "sdlterm.h"
     1 #include "sdlterm.h"
     2 
     2 
     3 #include <stdexcept>
     3 #include <exception>
       
     4 #include <algorithm>
     4 
     5 
     5 
     6 
     6 SDL_Surface *GlyphCache::lookup_glyph(Uint16 ch)
     7 SDL_Surface *GlyphCache::lookup_glyph(Uint16 ch)
     7 {
     8 {
     8 	auto iter = _glyph_map.find(ch);
     9 	auto iter = _glyph_map.find(ch);
   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 	}
   335 		case SDLK_F8:			return "f8";
   349 		case SDLK_F8:			return "f8";
   336 		case SDLK_F9:			return "f9";
   350 		case SDLK_F9:			return "f9";
   337 		case SDLK_F10:			return "f10";
   351 		case SDLK_F10:			return "f10";
   338 		case SDLK_F11:			return "f11";
   352 		case SDLK_F11:			return "f11";
   339 		case SDLK_F12:			return "f12";
   353 		case SDLK_F12:			return "f12";
   340 		default: return "";
   354 		default: return NULL;
   341 	}
   355 	}
   342 }
   356 }
   343 
   357