sdlterm/src/sdlterm.cc
changeset 47 537d7c6b48a2
child 48 1f00e90fd72a
equal deleted inserted replaced
46:2b43a7f38c34 47:537d7c6b48a2
       
     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 }