diff -r 2b43a7f38c34 -r 537d7c6b48a2 sdlterm/src/sdlterm.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sdlterm/src/sdlterm.cc Sat Jan 05 00:40:27 2013 +0100 @@ -0,0 +1,251 @@ +#include "sdlterm.h" + +#include + + +GlyphRenderer::GlyphRenderer() + : _font_regular(NULL), _font_bold(NULL) +{ + if (TTF_Init() == -1) + { + printf("TTF_Init: %s\n", TTF_GetError()); + throw std::exception(); + } +} + + +GlyphRenderer::~GlyphRenderer() +{ + close_font(); + TTF_Quit(); +} + + +void GlyphRenderer::open_font(const char *fname_regular, const char *fname_bold, int ptsize) +{ + close_font(); + + // open regular font + _font_regular = TTF_OpenFont(fname_regular, ptsize); + if (!_font_regular) + { + printf("TTF_OpenFont: %s\n", TTF_GetError()); + throw std::exception(); + } + + // open bold font + _font_bold = TTF_OpenFont(fname_bold, ptsize); + if (!_font_bold) + { + printf("TTF_OpenFont: %s\n", TTF_GetError()); + throw std::exception(); + } + + // update metrics for regular font + int advance; + if (TTF_GlyphMetrics(_font_regular, 'M', NULL, NULL, NULL, NULL, &advance) == -1) + { + printf("TTF_GlyphMetrics: %s\n", TTF_GetError()); + } + _cell_width = advance; + _cell_height = TTF_FontHeight(_font_regular); + + // read metrics for bold font + if (TTF_GlyphMetrics(_font_bold, 'M', NULL, NULL, NULL, NULL, &advance) == -1) + { + printf("TTF_GlyphMetrics: %s\n", TTF_GetError()); + } + if (advance > _cell_width) + { + _cell_width = advance; + } + int height = TTF_FontHeight(_font_bold); + if (height > _cell_height) + { + _cell_height = height; + } +} + + +void GlyphRenderer::close_font() +{ + if (_font_regular) + { + TTF_CloseFont(_font_regular); + _font_regular = NULL; + } + if (_font_bold) + { + TTF_CloseFont(_font_bold); + _font_bold = NULL; + } +} + + +SDL_Surface *GlyphRenderer::render_glyph(Uint16 ch) +{ + TTF_Font *font = _font_regular; + SDL_Color color={0xff,0xff,0xff}, bgcolor={0,100,100}; + if (ch != 'W') + { + bgcolor.g = 0; + bgcolor.b = 0; + } + + // create surface for whole cell and fill it with bg color + SDL_Surface *cell_surface = SDL_CreateRGBSurface(SDL_SWSURFACE, + _cell_width, _cell_height, 32, 0, 0, 0, 0); + SDL_Rect dst_rect; + dst_rect.x = 0; + dst_rect.y = 0; + dst_rect.w = _cell_width; + dst_rect.h = _cell_height; + Uint32 bgcolor_mapped = SDL_MapRGB(cell_surface->format, bgcolor.r, bgcolor.g, bgcolor.b); + SDL_FillRect(cell_surface, &dst_rect, bgcolor_mapped); + + // render glyph, blit it onto cell surface + SDL_Surface *glyph_surface = TTF_RenderGlyph_Shaded(font, ch, color, bgcolor); + int minx, maxy; + TTF_GlyphMetrics(font, ch, &minx, NULL, NULL, &maxy, NULL); + dst_rect.x = minx; + dst_rect.y = TTF_FontAscent(font) - maxy; + SDL_BlitSurface(glyph_surface, NULL, cell_surface, &dst_rect); + SDL_FreeSurface(glyph_surface); + + return cell_surface; +} + + +TerminalScreen::~TerminalScreen() +{ + if (_cells) + { + delete[] _cells; + } +} + + +void TerminalScreen::select_font(const char *fname_regular, const char *fname_bold, int ptsize) +{ + _render.open_font(fname_regular, fname_bold, ptsize); + _reset_cells(); +} + +void TerminalScreen::resize(int pxwidth, int pxheight) +{ + _screen_surface = SDL_SetVideoMode(pxwidth, pxheight, 8, SDL_SWSURFACE|SDL_ANYFORMAT|SDL_RESIZABLE); + + if (_screen_surface == NULL) + { + fprintf(stderr, "Unable to set video: %s\n", SDL_GetError()); + throw std::exception(); + } + + SDL_WM_SetCaption("terminal", NULL); + + _pixel_width = pxwidth; + _pixel_height = pxheight; + + _reset_cells(); +} + + +void TerminalScreen::erase() +{ + TerminalCell * cell = _cells; + for (int i = 0; i < _width * _height; i++) + { + cell->ch = ' '; + cell->attr = 0; + cell++; + } +} + + +void TerminalScreen::putch(int x, int y, Uint16 ch, Uint16 attr) +{ + TerminalCell &cell = _cells[y * _width + x]; + cell.ch = ch; + cell.attr = attr; +} + + +void TerminalScreen::commit() +{ + TerminalCell * cell = _cells; + SDL_Surface *glyph_surface; + SDL_Rect dst_rect; + for (int y = 0; y < _height; y++) + { + for (int x = 0; x < _width; x++) + { + dst_rect.x = x * _cell_width; + dst_rect.y = y * _cell_height; + glyph_surface = _render.render_glyph(cell->ch); + SDL_BlitSurface(glyph_surface, NULL, _screen_surface, &dst_rect); + SDL_FreeSurface(glyph_surface); + cell++; + } + } + + SDL_UpdateRect(_screen_surface, 0, 0, 0, 0); +} + + +void TerminalScreen::_reset_cells() +{ + if (_cells) + { + delete[] _cells; + _cells = NULL; + } + + _cell_width = _render.get_cell_width(); + _cell_height = _render.get_cell_height(); + _width = _pixel_width / _cell_width; + _height = _pixel_height / _cell_height; + + int num_cells = _width * _height; + _cells = new TerminalCell[num_cells]; +} + + +Terminal::Terminal() + : _screen() +{ + if (SDL_Init(SDL_INIT_VIDEO) == -1) + { + fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError()); + throw std::exception(); + } +} + + +Terminal::~Terminal() +{ + SDL_Quit(); +} + + +void Terminal::get_next_event(Event &event) +{ + SDL_Event sdl_event; + + while (SDL_WaitEvent(&sdl_event)) + { + switch (sdl_event.type) + { + case SDL_QUIT: + event.type = EventType::quit; + return; + + case SDL_KEYDOWN: + //switch(event.key.keysym.sym) + event.type = EventType::keypress; + return; + + default: + break; // continue loop + } + } +}