Add sdlterm prototype: extension module for SDL driver.
#include "sdlterm.h"
#include <stdexcept>
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
}
}
}