diff --git a/caca/Makefile.am b/caca/Makefile.am index 702a576..841a089 100644 --- a/caca/Makefile.am +++ b/caca/Makefile.am @@ -11,6 +11,12 @@ libcaca_la_SOURCES = \ graphics.c \ event.c \ time.c \ + driver_conio.c \ + driver_gl.c \ + driver_ncurses.c \ + driver_slang.c \ + driver_win32.c \ + driver_x11.c \ $(NULL) libcaca_la_CPPFLAGS = -I$(top_srcdir)/cucul libcaca_la_LDFLAGS = -no-undefined diff --git a/caca/caca.c b/caca/caca.c index abac53c..8f82124 100644 --- a/caca/caca.c +++ b/caca/caca.c @@ -28,33 +28,6 @@ typedef unsigned int uint32_t; typedef unsigned char uint8_t; #endif -#if defined(USE_SLANG) -# if defined(HAVE_SLANG_SLANG_H) -# include -# else -# include -# endif -#endif -#if defined(USE_NCURSES) -# if defined(HAVE_NCURSES_H) -# include -# else -# include -# endif -#endif -#if defined(USE_CONIO) -# include -# include -#endif -#if defined(USE_X11) -# include -#endif -#if defined(USE_WIN32) -# include -#endif -#if defined(USE_GL) -# include -#endif #include #include @@ -63,138 +36,33 @@ typedef unsigned char uint8_t; #include "caca.h" #include "caca_internals.h" -static void caca_init_driver(caca_t *kk); +static int caca_init_driver(caca_t *kk); static void caca_init_terminal(caca_t *kk); -#if defined(USE_NCURSES) -static mmask_t oldmask; -#endif - -#if defined(USE_WIN32) -static CONSOLE_CURSOR_INFO cci; -#endif - caca_t * caca_attach(cucul_t * qq) { + int ret; caca_t *kk = malloc(sizeof(caca_t)); -#if defined(USE_NCURSES) - mmask_t newmask; -#endif - - caca_init_driver(kk); - - if(kk->driver == CACA_DRIVER_NONE) - return NULL; - - caca_init_terminal(kk); - -#if defined(USE_SLANG) - if(kk->driver == CACA_DRIVER_SLANG) - { - /* Initialise slang library */ - SLsig_block_signals(); - SLtt_get_terminfo(); - - if(SLkp_init() == -1) - { - SLsig_unblock_signals(); - return NULL; - } - - SLang_init_tty(-1, 0, 1); - - if(SLsmg_init_smg() == -1) - { - SLsig_unblock_signals(); - return NULL; - } - - SLsig_unblock_signals(); + ret = caca_init_driver(kk); - SLsmg_cls(); - SLtt_set_cursor_visibility(0); - SLkp_define_keysym("\e[M", 1001); - SLtt_set_mouse_mode(1, 0); - SLsmg_refresh(); - - /* Disable scrolling so that hashmap scrolling optimization code - * does not cause ugly refreshes due to slow terminals */ - SLtt_Term_Cannot_Scroll = 1; - } - else -#endif -#if defined(USE_NCURSES) - if(kk->driver == CACA_DRIVER_NCURSES) + if(ret) { - initscr(); - keypad(stdscr, TRUE); - nonl(); - raw(); - noecho(); - nodelay(stdscr, TRUE); - curs_set(0); - - /* Activate mouse */ - newmask = REPORT_MOUSE_POSITION | ALL_MOUSE_EVENTS; - mousemask(newmask, &oldmask); - mouseinterval(-1); /* No click emulation */ - - /* Set the escape delay to a ridiculously low value */ - ESCDELAY = 10; - } - else -#endif -#if defined(USE_CONIO) - if(kk->driver == CACA_DRIVER_CONIO) - { - _wscroll = 0; - _setcursortype(_NOCURSOR); - clrscr(); - } - else -#endif -#if defined(USE_X11) - if(kk->driver == CACA_DRIVER_X11) - { - /* Nothing to do */ - kk->x11.event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask - | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask - | ExposureMask; + free(kk); + return NULL; } - else -#endif -#if defined(USE_WIN32) - if(kk->driver == CACA_DRIVER_WIN32) - { - /* This call is allowed to fail in case we already have a console */ - AllocConsole(); - kk->win32.hin = GetStdHandle(STD_INPUT_HANDLE); - kk->win32.hout = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - - if(kk->win32.hout == INVALID_HANDLE_VALUE) - return NULL; + qq->refcount++; + kk->qq = qq; - GetConsoleCursorInfo(kk->win32.hout, &cci); - cci.bVisible = FALSE; - SetConsoleCursorInfo(kk->win32.hout, &cci); + /* Only for slang and ncurses */ + caca_init_terminal(kk); - SetConsoleMode(kk->win32.hout, ENABLE_MOUSE_INPUT); - } - else -#endif -#if defined(USE_GL) - if(kk->driver == CACA_DRIVER_GL) - { - /* Nothing to do */ - } - else -#endif + if(_caca_init_graphics(kk)) { - /* Dummy */ + qq->refcount--; + free(kk); + return NULL; } /* Initialise events stuff */ @@ -204,9 +72,6 @@ caca_t * caca_attach(cucul_t * qq) kk->events.autorepeat_ticks = 0; kk->events.last_key = 0; - qq->refcount++; - kk->qq = qq; - kk->timer.last_sec = 0; kk->timer.last_usec = 0; kk->lastticks = 0; @@ -214,81 +79,13 @@ caca_t * caca_attach(cucul_t * qq) kk->resize = 0; kk->resize_event = 0; - if(_caca_init_graphics(kk)) - return NULL; - return kk; } void caca_detach(caca_t *kk) { - _caca_end_graphics(kk); - -#if defined(USE_SLANG) - if(kk->driver == CACA_DRIVER_SLANG) - { - SLtt_set_mouse_mode(0, 0); - SLtt_set_cursor_visibility(1); - SLang_reset_tty(); - SLsmg_reset_smg(); - } - else -#endif -#if defined(USE_NCURSES) - if(kk->driver == CACA_DRIVER_NCURSES) - { - mousemask(oldmask, NULL); - curs_set(1); - noraw(); - endwin(); - } - else -#endif -#if defined(USE_CONIO) - if(kk->driver == CACA_DRIVER_CONIO) - { - _wscroll = 1; - textcolor((enum COLORS)WHITE); - textbackground((enum COLORS)BLACK); - gotoxy(_caca_width, _caca_height); - cputs("\r\n"); - _setcursortype(_NORMALCURSOR); - } - else -#endif -#if defined(USE_X11) - if(kk->driver == CACA_DRIVER_X11) - { - /* Nothing to do */ - } - else -#endif -#if defined(USE_WIN32) - if(kk->driver == CACA_DRIVER_WIN32) - { - SetConsoleTextAttribute(kk->win32.hout, FOREGROUND_INTENSITY - | FOREGROUND_RED - | FOREGROUND_GREEN - | FOREGROUND_BLUE); - cci.bVisible = TRUE; - SetConsoleCursorInfo(kk->win32.hout, &cci); - CloseHandle(kk->win32.hout); - } - else -#endif -#if defined(USE_GL) - if(kk->driver == CACA_DRIVER_GL) - { - /* Nothing to do */ - } - else -#endif - { - /* Dummy */ - } - + kk->driver.end_graphics(kk); kk->qq->refcount--; - free(kk); } @@ -296,7 +93,7 @@ void caca_detach(caca_t *kk) * XXX: The following functions are local. */ -static void caca_init_driver(caca_t *kk) +static int caca_init_driver(caca_t *kk) { #if defined(HAVE_GETENV) && defined(HAVE_STRCASECMP) char *var = getenv("CACA_DRIVER"); @@ -306,56 +103,55 @@ static void caca_init_driver(caca_t *kk) { #if defined(USE_WIN32) if(!strcasecmp(var, "win32")) - kk->driver = CACA_DRIVER_WIN32; + win32_init_driver(kk); else #endif #if defined(USE_CONIO) if(!strcasecmp(var, "conio")) - kk->driver = CACA_DRIVER_CONIO; + conio_init_driver(kk); else #endif #if defined(USE_X11) if(!strcasecmp(var, "x11")) - kk->driver = CACA_DRIVER_X11; + x11_init_driver(kk); else #endif #if defined(USE_GL) if(!strcasecmp(var, "gl")) - kk->driver = CACA_DRIVER_GL; + gl_init_driver(kk); else #endif #if defined(USE_SLANG) if(!strcasecmp(var, "slang")) - kk->driver = CACA_DRIVER_SLANG; + slang_init_driver(kk); else #endif #if defined(USE_NCURSES) if(!strcasecmp(var, "ncurses")) - kk->driver = CACA_DRIVER_NCURSES; + ncurses_init_driver(kk); else #endif + return -1; - kk->driver = CACA_DRIVER_NONE; - - return; + return 0; } #endif #if defined(USE_WIN32) - kk->driver = CACA_DRIVER_WIN32; - return; + win32_init_driver(kk); + return 0; #endif #if defined(USE_CONIO) - kk->driver = CACA_DRIVER_CONIO; - return; + conio_init_driver(kk); + return 0; #endif #if defined(USE_X11) #if defined(HAVE_GETENV) if(getenv("DISPLAY") && *(getenv("DISPLAY"))) #endif { - kk->driver = CACA_DRIVER_X11; - return; + x11_init_driver(kk); + return 0; } #endif #if defined(USE_GL) @@ -363,21 +159,20 @@ static void caca_init_driver(caca_t *kk) if(getenv("DISPLAY") && *(getenv("DISPLAY"))) #endif { - kk->driver = CACA_DRIVER_GL; - return; + gl_init_driver(kk); + return 0; } #endif #if defined(USE_SLANG) - kk->driver = CACA_DRIVER_SLANG; - return; + slang_init_driver(kk); + return 0; #endif #if defined(USE_NCURSES) - kk->driver = CACA_DRIVER_NCURSES; - return; + slang_init_driver(kk); + return 0; #endif - kk->driver = CACA_DRIVER_NONE; - return; + return -1; } static void caca_init_terminal(caca_t *kk) @@ -388,10 +183,10 @@ static void caca_init_terminal(caca_t *kk) #endif #if defined(USE_SLANG) - if(kk->driver != CACA_DRIVER_SLANG) + if(kk->driver.driver != CACA_DRIVER_SLANG) #endif #if defined(USE_NCURSES) - if(kk->driver != CACA_DRIVER_NCURSES) + if(kk->driver.driver != CACA_DRIVER_NCURSES) #endif return; @@ -406,7 +201,7 @@ static void caca_init_terminal(caca_t *kk) if(colorterm && !strcmp(colorterm, "gnome-terminal")) { #if defined(USE_NCURSES) - if(kk->driver == CACA_DRIVER_NCURSES) + if(kk->driver.driver == CACA_DRIVER_NCURSES) { SCREEN *screen; screen = newterm("xterm-16color", stdout, stdin); @@ -424,7 +219,7 @@ static void caca_init_terminal(caca_t *kk) if(other) { #if defined(USE_NCURSES) - if(kk->driver == CACA_DRIVER_NCURSES) + if(kk->driver.driver == CACA_DRIVER_NCURSES) { SCREEN *screen; screen = newterm("xterm-16color", stdout, stdin); diff --git a/caca/caca_internals.h b/caca/caca_internals.h index 415bd31..a890111 100644 --- a/caca/caca_internals.h +++ b/caca/caca_internals.h @@ -20,8 +20,21 @@ #ifndef __CACA_INTERNALS_H__ #define __CACA_INTERNALS_H__ +#if defined(USE_GL) +# include +#endif +#if defined(USE_NCURSES) +# if defined(HAVE_NCURSES_H) +# include +# else +# include +# endif +#endif +#if defined(USE_WIN32) +# include +#endif #if defined(USE_X11) -#include +# include #endif /* Graphics driver */ @@ -48,6 +61,26 @@ enum caca_driver CACA_DRIVER_NONE = 0 }; +/* Available drivers */ +#if defined(USE_CONIO) +void conio_init_driver(caca_t *); +#endif +#if defined(USE_GL) +void gl_init_driver(caca_t *); +#endif +#if defined(USE_NCURSES) +void ncurses_init_driver(caca_t *); +#endif +#if defined(USE_SLANG) +void slang_init_driver(caca_t *); +#endif +#if defined(USE_WIN32) +void win32_init_driver(caca_t *); +#endif +#if defined(USE_X11) +void x11_init_driver(caca_t *); +#endif + /* Timer structure */ struct caca_timer { @@ -59,7 +92,19 @@ struct caca_context { cucul_t *qq; - enum caca_driver driver; + struct driver + { + enum caca_driver driver; + + int (* init_graphics) (caca_t *); + int (* end_graphics) (caca_t *); + int (* set_window_title) (caca_t *, char const *); + unsigned int (* get_window_width) (caca_t *); + unsigned int (* get_window_height) (caca_t *); + void (* display) (caca_t *); + void (* handle_resize) (caca_t *); + } driver; + unsigned int width, height; int resize; @@ -102,6 +147,7 @@ struct caca_context struct ncurses { int attr[16*16]; + mmask_t oldmask; } ncurses; #endif #if defined(USE_CONIO) @@ -156,15 +202,4 @@ extern unsigned int _caca_height; extern int _caca_resize; extern int _caca_resize_event; -#if defined(USE_WIN32) -#include -extern HANDLE win32_hin, win32_hout; -#endif - -#if defined(USE_GL) -#include -extern unsigned int gl_width, gl_height; -#endif - - #endif /* __CACA_INTERNALS_H__ */ diff --git a/caca/driver_conio.c b/caca/driver_conio.c new file mode 100644 index 0000000..cec6f20 --- /dev/null +++ b/caca/driver_conio.c @@ -0,0 +1,148 @@ +/* + * libcaca ASCII-Art library + * Copyright (c) 2002-2006 Sam Hocevar + * All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the Do What The Fuck You Want To + * Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +/** \file graphics.c + * \version \$Id$ + * \author Sam Hocevar + * \brief Character drawing + * + * This file contains character and string drawing functions. + */ + +#include "config.h" + +#if defined(HAVE_INTTYPES_H) || defined(_DOXYGEN_SKIP_ME) +# include +#else +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#endif + +#if defined(USE_CONIO) + +#include +#include +#if defined(SCREENUPDATE_IN_PC_H) +# include +#endif + +#include +#include +#if defined(HAVE_UNISTD_H) +# include +#endif +#include + +#if defined(HAVE_SYS_IOCTL_H) +# include +#endif + +#include "caca.h" +#include "caca_internals.h" +#include "cucul.h" +#include "cucul_internals.h" + +#if !defined(_DOXYGEN_SKIP_ME) +int conio_init_graphics(caca_t *kk) +{ + _wscroll = 0; + _setcursortype(_NOCURSOR); + clrscr(); + + gettextinfo(&kk->conio.ti); + kk->conio.screen = malloc(2 * kk->conio.ti.screenwidth + * kk->conio.ti.screenheight * sizeof(char)); + if(kk->conio.screen == NULL) + return -1; +# if defined(SCREENUPDATE_IN_PC_H) + ScreenRetrieve(kk->conio.screen); +# else + /* FIXME */ +# endif + cucul_set_size(kk->qq, kk->conio.ti.screenwidth, + kk->conio.ti.screenheight); + return 0; +} + +int conio_end_graphics(caca_t *kk) +{ + _wscroll = 1; + textcolor((enum COLORS)WHITE); + textbackground((enum COLORS)BLACK); + gotoxy(_caca_width, _caca_height); + cputs("\r\n"); + _setcursortype(_NORMALCURSOR); + + free(kk->conio.screen); + + return 0; +} +#endif /* _DOXYGEN_SKIP_ME */ + +int conio_set_window_title(caca_t *kk, char const *title) +{ + return 0; +} + +unsigned int conio_get_window_width(caca_t *kk) +{ + /* Fallback to a 6x10 font */ + return kk->qq->width * 6; +} + +unsigned int conio_get_window_height(caca_t *kk) +{ + /* Fallback to a 6x10 font */ + return kk->qq->height * 10; +} + +void conio_display(caca_t *kk) +{ + int n; + char *screen = kk->conio.screen; + uint8_t *attr = kk->qq->attr; + uint32_t *chars = kk->qq->chars; + for(n = kk->qq->height * kk->qq->width; n--; ) + { + *screen++ = *chars++ & 0x7f; + *screen++ = *attr++; + } +# if defined(SCREENUPDATE_IN_PC_H) + ScreenUpdate(kk->conio.screen); +# else + /* FIXME */ +# endif +} + +void conio_handle_resize(caca_t *kk) +{ + return; +} + +/* + * Driver initialisation + */ + +void conio_init_driver(caca_t *kk) +{ + kk->driver.driver = CACA_DRIVER_CONIO; + + kk->driver.init_graphics = conio_init_graphics; + kk->driver.end_graphics = conio_end_graphics; + kk->driver.set_window_title = conio_set_window_title; + kk->driver.get_window_width = conio_get_window_width; + kk->driver.get_window_height = conio_get_window_height; + kk->driver.display = conio_display; + kk->driver.handle_resize = conio_handle_resize; +} + +#endif /* USE_CONIO */ + diff --git a/caca/driver_gl.c b/caca/driver_gl.c new file mode 100644 index 0000000..18c9702 --- /dev/null +++ b/caca/driver_gl.c @@ -0,0 +1,378 @@ +/* + * libcaca ASCII-Art library + * Copyright (c) 2002-2006 Sam Hocevar + * All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the Do What The Fuck You Want To + * Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +/** \file graphics.c + * \version \$Id$ + * \author Sam Hocevar + * \brief Character drawing + * + * This file contains character and string drawing functions. + */ + +#include "config.h" + +#if defined(HAVE_INTTYPES_H) || defined(_DOXYGEN_SKIP_ME) +# include +#else +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#endif + +#if defined(USE_GL) + +#include +#include +#include + +#include /* BUFSIZ */ +#include +#include +#if defined(HAVE_UNISTD_H) +# include +#endif +#include + +#include "caca.h" +#include "caca_internals.h" +#include "cucul.h" +#include "cucul_internals.h" + +/* + * Global variables + */ + +/* Ok, I just suck. */ +static GLbyte const gl_bgpal[][4] = +{ + { 0x00, 0x00, 0x00, 0x7f }, + { 0x00, 0x00, 0x3f, 0x7f }, + { 0x00, 0x3f, 0x00, 0x7f }, + { 0x00, 0x3f, 0x3f, 0x7f }, + { 0x3f, 0x00, 0x00, 0x7f }, + { 0x3f, 0x00, 0x3f, 0x7f }, + { 0x3f, 0x3f, 0x00, 0x7f }, + { 0x3f, 0x3f, 0x3f, 0x7f }, + // + intensity + { 0x00, 0x00, 0x00, 0x7f }, + { 0x00, 0x00, 0x7f, 0x7f }, + { 0x00, 0x7f, 0x00, 0x7f }, + { 0x00, 0x7f, 0x7f, 0x7f }, + { 0x7f, 0x00, 0x00, 0x7f }, + { 0x7f, 0x00, 0x7f, 0x7f }, + { 0x7f, 0x7f, 0x00, 0x7f }, + { 0x7f, 0x7f, 0x7f, 0x7f } +}; + +static caca_t *gl_kk; /* FIXME: we ought to get rid of this */ + +/* + * Local functions + */ +static void gl_handle_keyboard(unsigned char, int, int); +static void gl_handle_special_key(int, int, int); +static void gl_handle_reshape(int, int); +static void gl_handle_mouse(int, int, int, int); +static void gl_handle_mouse_motion(int, int); + +int gl_init_graphics(caca_t *kk) +{ + char *empty_texture; + char const *geometry; + char *argv[2] = { "", NULL }; + unsigned int width = 0, height = 0; + int argc = 1; + int i; + + gl_kk = kk; + + geometry = getenv("CACA_GEOMETRY"); + if(geometry && *(geometry)) + sscanf(geometry, "%ux%u", &width, &height); + + if(width && height) + cucul_set_size(kk->qq, width, height); + + kk->gl.font_width = 9; + kk->gl.font_height = 15; + + kk->gl.width = kk->qq->width * kk->gl.font_width; + kk->gl.height = kk->qq->height * kk->gl.font_height; + + kk->gl.resized = 0; + kk->gl.bit = 0; + + kk->gl.mouse_changed = kk->gl.mouse_clicked = 0; + kk->gl.mouse_button = kk->gl.mouse_state = 0; + + kk->gl.key = 0; + kk->gl.special_key = 0; + + kk->gl.sw = 9.0f / 16.0f; + kk->gl.sh = 15.0f / 16.0f; + + glutInit(&argc, argv); + + glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); + glutInitWindowSize(kk->gl.width, kk->gl.height); + kk->gl.window = glutCreateWindow("caca for GL"); + + gluOrtho2D(0, kk->gl.width, kk->gl.height, 0); + + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + + glutKeyboardFunc(gl_handle_keyboard); + glutSpecialFunc(gl_handle_special_key); + glutReshapeFunc(gl_handle_reshape); + + glutMouseFunc(gl_handle_mouse); + glutMotionFunc(gl_handle_mouse_motion); + glutPassiveMotionFunc(gl_handle_mouse_motion); + + glLoadIdentity(); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + gluOrtho2D(0, kk->gl.width, kk->gl.height, 0); + + glMatrixMode(GL_MODELVIEW); + + glClear(GL_COLOR_BUFFER_BIT); + + empty_texture = malloc(16 * 16 * 4); + if(empty_texture == NULL) + return -1; + + memset(empty_texture, 0xff, 16 * 16 * 4); + glEnable(GL_TEXTURE_2D); + + for(i = 0; i < 94; i++) + { + glGenTextures(1, (GLuint*)&kk->gl.id[i]); + glBindTexture(GL_TEXTURE_2D, kk->gl.id[i]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, + 16, 16, 0, GL_RGB, GL_UNSIGNED_BYTE, empty_texture); + } + + for(i = 0; i < 94; i++) + { + glDisable(GL_TEXTURE_2D); + glClear(GL_COLOR_BUFFER_BIT); + + glColor3f(1, 1, 1); + glRasterPos2f(0, 15); + glutBitmapCharacter(GLUT_BITMAP_9_BY_15, i + 32); + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, kk->gl.id[i]); + glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, + 0, kk->gl.height - 16, 16, 16, 0); + + glutMainLoopEvent(); + glutPostRedisplay(); + } + + return 0; +} + +int gl_end_graphics(caca_t *kk) +{ + glutDestroyWindow(kk->gl.window); + return 0; +} + +int gl_set_window_title(caca_t *kk, char const *title) +{ + glutSetWindowTitle(title); + return 0; +} + +unsigned int gl_get_window_width(caca_t *kk) +{ + return kk->gl.width; +} + +unsigned int gl_get_window_height(caca_t *kk) +{ + return kk->gl.height; +} + +void gl_display(caca_t *kk) +{ + unsigned int x, y, line; + + glClear(GL_COLOR_BUFFER_BIT); + + line = 0; + for(y = 0; y < kk->gl.height; y += kk->gl.font_height) + { + uint8_t *attr = kk->qq->attr + line * kk->qq->width; + + for(x = 0; x < kk->gl.width; x += kk->gl.font_width) + { + glDisable(GL_TEXTURE_2D); + glColor4bv(gl_bgpal[attr[0] >> 4]); + glBegin(GL_QUADS); + glVertex2f(x, y); + glVertex2f(x + kk->gl.font_width, y); + glVertex2f(x + kk->gl.font_width, y + kk->gl.font_height); + glVertex2f(x, y + kk->gl.font_height); + glEnd(); + + attr++; + } + + line++; + } + + /* 2nd pass, avoids changing render state too much */ + glEnable(GL_BLEND); + glEnable(GL_TEXTURE_2D); + glBlendFunc(GL_ONE, GL_ONE); + + line = 0; + for(y = 0; y < kk->gl.height; y += kk->gl.font_height) + { + uint8_t *attr = kk->qq->attr + line * kk->qq->width; + uint32_t *chars = kk->qq->chars + line * kk->qq->width; + + for(x = 0; x < kk->gl.width; x += kk->gl.font_width) + { + if(*chars != (uint32_t)' ') + { + char ch = *chars & 0x7f; + + /* FIXME: check ch bounds */ + glBindTexture(GL_TEXTURE_2D, kk->gl.id[ch - 32]); + glColor4bv(gl_bgpal[attr[0] & 0xf]); + glBegin(GL_QUADS); + glTexCoord2f(0, kk->gl.sh); + glVertex2f(x, y); + glTexCoord2f(kk->gl.sw, kk->gl.sh); + glVertex2f(x + kk->gl.font_width, y); + glTexCoord2f(kk->gl.sw, 0); + glVertex2f(x + kk->gl.font_width, y + kk->gl.font_height); + glTexCoord2f(0, 0); + glVertex2f(x, y + kk->gl.font_height); + glEnd(); + } + + attr++; + chars++; + } + line++; + } + glDisable(GL_BLEND); + glDisable(GL_TEXTURE_2D); + + glutMainLoopEvent(); + glutSwapBuffers(); + glutPostRedisplay(); +} + +void gl_handle_resize(caca_t *kk) +{ + unsigned int new_width, new_height; + + new_width = kk->qq->width; + new_height = kk->qq->height; + + kk->gl.width = kk->gl.new_width; + kk->gl.height = kk->gl.new_height; + + new_width = kk->gl.width / kk->gl.font_width; + new_height = (kk->gl.height / kk->gl.font_height) + 1; + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + glViewport(0, 0, kk->gl.width, kk->gl.height); + gluOrtho2D(0, kk->gl.width, kk->gl.height, 0); + glMatrixMode(GL_MODELVIEW); +} + +/* + * XXX: following functions are local + */ + +static void gl_handle_keyboard(unsigned char key, int x, int y) +{ + caca_t *kk = gl_kk; + + kk->gl.key = key; +} + +static void gl_handle_special_key(int key, int x, int y) +{ + caca_t *kk = gl_kk; + + kk->gl.special_key = key; +} + +static void gl_handle_reshape(int w, int h) +{ + caca_t *kk = gl_kk; + + if(kk->gl.bit) /* Do not handle reshaping at the first time */ + { + kk->gl.new_width = w; + kk->gl.new_height = h; + + kk->gl.resized = 1; + } + else + kk->gl.bit = 1; +} + +static void gl_handle_mouse(int button, int state, int x, int y) +{ + caca_t *kk = gl_kk; + + kk->gl.mouse_clicked = 1; + kk->gl.mouse_button = button; + kk->gl.mouse_state = state; + kk->gl.mouse_x = x / kk->gl.font_width; + kk->gl.mouse_y = y / kk->gl.font_height; + kk->gl.mouse_changed = 1; +} + +static void gl_handle_mouse_motion(int x, int y) +{ + caca_t *kk = gl_kk; + + kk->gl.mouse_x = x / kk->gl.font_width; + kk->gl.mouse_y = y / kk->gl.font_height; + kk->gl.mouse_changed = 1; +} + +/* + * Driver initialisation + */ + +void gl_init_driver(caca_t *kk) +{ + kk->driver.driver = CACA_DRIVER_GL; + + kk->driver.init_graphics = gl_init_graphics; + kk->driver.end_graphics = gl_end_graphics; + kk->driver.set_window_title = gl_set_window_title; + kk->driver.get_window_width = gl_get_window_width; + kk->driver.get_window_height = gl_get_window_height; + kk->driver.display = gl_display; + kk->driver.handle_resize = gl_handle_resize; +} + +#endif /* USE_GL */ + diff --git a/caca/driver_ncurses.c b/caca/driver_ncurses.c new file mode 100644 index 0000000..ecc63e3 --- /dev/null +++ b/caca/driver_ncurses.c @@ -0,0 +1,256 @@ +/* + * libcaca ASCII-Art library + * Copyright (c) 2002-2006 Sam Hocevar + * All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the Do What The Fuck You Want To + * Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +/** \file graphics.c + * \version \$Id$ + * \author Sam Hocevar + * \brief Character drawing + * + * This file contains character and string drawing functions. + */ + +#include "config.h" + +#if defined(HAVE_INTTYPES_H) || defined(_DOXYGEN_SKIP_ME) +# include +#else +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#endif + +#if defined(USE_NCURSES) + +#if defined(HAVE_NCURSES_H) +# include +#else +# include +#endif + +#include /* BUFSIZ */ +#include +#include +#if defined(HAVE_UNISTD_H) +# include +#endif +#include + +#if defined(HAVE_SIGNAL_H) +# include +#endif +#if defined(HAVE_SYS_IOCTL_H) +# include +#endif + +#include "caca.h" +#include "caca_internals.h" +#include "cucul.h" +#include "cucul_internals.h" + +int ncurses_init_graphics(caca_t *); +int ncurses_end_graphics(caca_t *); +int ncurses_set_window_title(caca_t *, char const *); +unsigned int ncurses_get_window_width(caca_t *); +unsigned int ncurses_get_window_height(caca_t *); +void ncurses_display(caca_t *); +void ncurses_handle_resize(caca_t *); + +/* + * Local functions + */ +#if defined(HAVE_SIGNAL) +static RETSIGTYPE sigwinch_handler(int); +static caca_t *sigwinch_kk; /* FIXME: we ought to get rid of this */ +#endif + +int ncurses_init_graphics(caca_t *kk) +{ + static int curses_colors[] = + { + /* Standard curses colours */ + COLOR_BLACK, + COLOR_BLUE, + COLOR_GREEN, + COLOR_CYAN, + COLOR_RED, + COLOR_MAGENTA, + COLOR_YELLOW, + COLOR_WHITE, + /* Extra values for xterm-16color */ + COLOR_BLACK + 8, + COLOR_BLUE + 8, + COLOR_GREEN + 8, + COLOR_CYAN + 8, + COLOR_RED + 8, + COLOR_MAGENTA + 8, + COLOR_YELLOW + 8, + COLOR_WHITE + 8 + }; + + mmask_t newmask; + int fg, bg, max; + +#if defined(HAVE_SIGNAL) + sigwinch_kk = kk; + signal(SIGWINCH, sigwinch_handler); +#endif + + initscr(); + keypad(stdscr, TRUE); + nonl(); + raw(); + noecho(); + nodelay(stdscr, TRUE); + curs_set(0); + + /* Activate mouse */ + newmask = REPORT_MOUSE_POSITION | ALL_MOUSE_EVENTS; + mousemask(newmask, &kk->ncurses.oldmask); + mouseinterval(-1); /* No click emulation */ + + /* Set the escape delay to a ridiculously low value */ + ESCDELAY = 10; + + /* Activate colour */ + start_color(); + + /* If COLORS == 16, it means the terminal supports full bright colours + * using setab and setaf (will use \e[90m \e[91m etc. for colours >= 8), + * we can build 16*16 colour pairs. + * If COLORS == 8, it means the terminal does not know about bright + * colours and we need to get them through A_BOLD and A_BLINK (\e[1m + * and \e[5m). We can only build 8*8 colour pairs. */ + max = COLORS >= 16 ? 16 : 8; + + for(bg = 0; bg < max; bg++) + for(fg = 0; fg < max; fg++) + { + /* Use ((max + 7 - fg) % max) instead of fg so that colour 0 + * is light gray on black. Some terminals don't like this + * colour pair to be redefined. */ + int col = ((max + 7 - fg) % max) + max * bg; + init_pair(col, curses_colors[fg], curses_colors[bg]); + kk->ncurses.attr[fg + 16 * bg] = COLOR_PAIR(col); + + if(max == 8) + { + /* Bright fg on simple bg */ + kk->ncurses.attr[fg + 8 + 16 * bg] = A_BOLD | COLOR_PAIR(col); + /* Simple fg on bright bg */ + kk->ncurses.attr[fg + 16 * (bg + 8)] = A_BLINK + | COLOR_PAIR(col); + /* Bright fg on bright bg */ + kk->ncurses.attr[fg + 8 + 16 * (bg + 8)] = A_BLINK | A_BOLD + | COLOR_PAIR(col); + } + } + + cucul_set_size(kk->qq, COLS, LINES); + + return 0; +} + +int ncurses_end_graphics(caca_t *kk) +{ + mousemask(kk->ncurses.oldmask, NULL); + curs_set(1); + noraw(); + endwin(); + + return 0; +} + +int ncurses_set_window_title(caca_t *kk, char const *title) +{ + return 0; +} + +unsigned int ncurses_get_window_width(caca_t *kk) +{ + /* Fallback to a 6x10 font */ + return kk->qq->width * 6; +} + +unsigned int ncurses_get_window_height(caca_t *kk) +{ + /* Fallback to a 6x10 font */ + return kk->qq->height * 10; +} + +void ncurses_display(caca_t *kk) +{ + int x, y; + uint8_t *attr = kk->qq->attr; + uint32_t *chars = kk->qq->chars; + for(y = 0; y < (int)kk->qq->height; y++) + { + move(y, 0); + for(x = kk->qq->width; x--; ) + { + attrset(kk->ncurses.attr[*attr++]); + addch(*chars++ & 0x7f); + } + } + refresh(); +} + +void ncurses_handle_resize(caca_t *kk) +{ + unsigned int new_width, new_height; + struct winsize size; + + new_width = kk->qq->width; + new_height = kk->qq->height; + + if(ioctl(fileno(stdout), TIOCGWINSZ, &size) == 0) + { + new_width = size.ws_col; + new_height = size.ws_row; +#if defined(HAVE_RESIZE_TERM) + resize_term(new_height, new_width); +#else + resizeterm(new_height, new_width); +#endif + wrefresh(curscr); + } +} + +/* + * XXX: following functions are local + */ + +#if defined(HAVE_SIGNAL) +static RETSIGTYPE sigwinch_handler(int sig) +{ + sigwinch_kk->resize_event = 1; + + signal(SIGWINCH, sigwinch_handler);; +} +#endif + +/* + * Driver initialisation + */ + +void ncurses_init_driver(caca_t *kk) +{ + kk->driver.driver = CACA_DRIVER_NCURSES; + + kk->driver.init_graphics = ncurses_init_graphics; + kk->driver.end_graphics = ncurses_end_graphics; + kk->driver.set_window_title = ncurses_set_window_title; + kk->driver.get_window_width = ncurses_get_window_width; + kk->driver.get_window_height = ncurses_get_window_height; + kk->driver.display = ncurses_display; + kk->driver.handle_resize = ncurses_handle_resize; +} + +#endif /* USE_NCURSES */ + diff --git a/caca/driver_slang.c b/caca/driver_slang.c new file mode 100644 index 0000000..3d0a7ea --- /dev/null +++ b/caca/driver_slang.c @@ -0,0 +1,342 @@ +/* + * libcaca ASCII-Art library + * Copyright (c) 2002-2006 Sam Hocevar + * All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the Do What The Fuck You Want To + * Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +/** \file graphics.c + * \version \$Id$ + * \author Sam Hocevar + * \brief Character drawing + * + * This file contains character and string drawing functions. + */ + +#include "config.h" + +#if defined(HAVE_INTTYPES_H) || defined(_DOXYGEN_SKIP_ME) +# include +#else +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#endif + +#if defined(USE_SLANG) + +#if defined(HAVE_SLANG_SLANG_H) +# include +#else +# include +#endif + +#include /* BUFSIZ */ +#include +#include +#if defined(HAVE_UNISTD_H) +# include +#endif +#include + +#if defined(HAVE_SIGNAL_H) +# include +#endif + +#include "caca.h" +#include "caca_internals.h" +#include "cucul.h" +#include "cucul_internals.h" + +/* + * Global variables + */ + +/* Tables generated by test/optipal.c */ +static int const slang_palette[2*16*16] = +{ + 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, + 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 0, 8, + 8, 7, 7, 8, 15, 7, 7, 15, 15, 9, 9, 15, 1, 9, 9, 1, + 7, 9, 9, 7, 8, 1, 1, 8, 0, 1, 15, 10, 10, 15, 2, 10, + 10, 2, 7, 10, 10, 7, 8, 2, 2, 8, 0, 2, 15, 11, 11, 15, + 3, 11, 11, 3, 7, 11, 11, 7, 8, 3, 3, 8, 0, 3, 15, 12, + 12, 15, 4, 12, 12, 4, 7, 12, 12, 7, 8, 4, 4, 8, 0, 4, + 15, 13, 13, 15, 5, 13, 13, 5, 7, 13, 13, 7, 8, 5, 5, 8, + 0, 5, 15, 14, 14, 15, 6, 14, 14, 6, 7, 14, 14, 7, 8, 6, + 6, 8, 0, 6, 4, 6, 6, 4, 12, 14, 14, 12, 6, 2, 2, 6, + 14, 10, 10, 14, 2, 3, 3, 2, 10, 11, 11, 10, 3, 1, 1, 3, + 11, 9, 9, 11, 1, 5, 5, 1, 9, 13, 13, 9, 5, 4, 4, 5, + 13, 12, 12, 13, 4, 14, 6, 12, 12, 6, 14, 4, 6, 10, 2, 14, + 14, 2, 10, 6, 2, 11, 3, 10, 10, 3, 11, 2, 3, 9, 1, 11, + 11, 1, 9, 3, 1, 13, 5, 9, 9, 5, 13, 1, 5, 12, 4, 13, + 13, 4, 12, 5, 0, 7, 0, 15, 15, 8, 8, 15, 15, 1, 7, 1, + 1, 6, 2, 5, 3, 4, 4, 3, 5, 2, 6, 1, 0, 0, 1, 1, + 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 2, 2, 3, 3, + 4, 4, 5, 5, 6, 6, 7, 7, 14, 9, 1, 15, 8, 9, 8, 8, + 9, 9, 1, 7, 0, 9, 9, 8, 6, 9, 13, 10, 2, 15, 8, 10, + 7, 2, 15, 2, 2, 7, 0, 10, 10, 8, 5, 10, 12, 11, 3, 15, + 8, 11, 7, 3, 15, 3, 3, 7, 0, 11, 11, 8, 4, 11, 11, 12, + 4, 15, 8, 12, 7, 4, 15, 4, 4, 7, 0, 12, 12, 8, 3, 12, + 10, 13, 5, 15, 8, 13, 7, 5, 15, 5, 5, 7, 0, 13, 13, 8, + 2, 13, 9, 14, 6, 15, 8, 14, 7, 6, 15, 6, 6, 7, 0, 14, + 14, 8, 1, 14, 5, 6, 2, 4, 13, 14, 10, 12, 4, 2, 3, 6, + 12, 10, 11, 14, 6, 3, 1, 2, 14, 11, 9, 10, 2, 1, 5, 3, + 10, 9, 13, 11, 3, 5, 4, 1, 11, 13, 12, 9, 1, 4, 6, 5, + 9, 12, 14, 13, 5, 14, 2, 12, 13, 6, 10, 4, 4, 10, 3, 14, + 12, 2, 11, 6, 6, 11, 1, 10, 14, 3, 9, 2, 2, 9, 5, 11, + 10, 1, 13, 3, 3, 13, 4, 9, 11, 5, 12, 1, 1, 12, 6, 13, + 9, 4, 14, 5, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, +}; + +static int const slang_assoc[16*16] = +{ + 134, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 28, 135, 214, 86, 219, 91, 133, 127, 26, 23, 240, 112, 245, 117, 141, 126, + 37, 211, 142, 83, 206, 132, 78, 160, 35, 237, 32, 109, 232, 140, 104, 161, + 46, 87, 82, 143, 131, 215, 210, 169, 44, 113, 108, 41, 139, 241, 236, 170, + 55, 222, 203, 130, 144, 94, 75, 178, 53, 248, 229, 138, 50, 120, 101, 179, + 64, 90, 129, 218, 95, 145, 223, 187, 62, 116, 137, 244, 121, 59, 249, 188, + 73, 128, 79, 207, 74, 202, 146, 196, 71, 136, 105, 233, 100, 228, 68, 197, + 122, 153, 162, 171, 180, 189, 198, 147, 16, 25, 34, 43, 52, 61, 70, 18, + 15, 27, 36, 45, 54, 63, 72, 17, 151, 155, 164, 173, 182, 191, 200, 124, + 154, 22, 238, 110, 243, 115, 156, 24, 150, 152, 216, 88, 221, 93, 148, 20, + 163, 235, 31, 107, 230, 165, 102, 33, 159, 213, 250, 85, 208, 157, 80, 29, + 172, 111, 106, 40, 174, 239, 234, 42, 168, 89, 84, 251, 166, 217, 212, 38, + 181, 246, 227, 183, 49, 118, 99, 51, 177, 224, 205, 175, 252, 96, 77, 47, + 190, 114, 192, 242, 119, 58, 247, 60, 186, 92, 184, 220, 97, 253, 225, 56, + 199, 201, 103, 231, 98, 226, 67, 69, 195, 193, 81, 209, 76, 204, 254, 65, + 123, 149, 158, 167, 176, 185, 194, 19, 125, 21, 30, 39, 48, 57, 66, 255, +}; + +int slang_init_graphics(caca_t *); +int slang_end_graphics(caca_t *); +int slang_set_window_title(caca_t *, char const *); +unsigned int slang_get_window_width(caca_t *); +unsigned int slang_get_window_height(caca_t *); +void slang_display(caca_t *); +void slang_handle_resize(caca_t *); + +/* + * Local functions + */ +static void slang_init_palette(void); + +#if defined(HAVE_SIGNAL) +static RETSIGTYPE sigwinch_handler(int); +static caca_t *sigwinch_kk; /* FIXME: we ought to get rid of this */ +#endif + +#if !defined(_DOXYGEN_SKIP_ME) +int slang_init_graphics(caca_t *kk) +{ +#if defined(HAVE_SIGNAL) + sigwinch_kk = kk; + signal(SIGWINCH, sigwinch_handler); +#endif + + /* Initialise slang library */ + SLsig_block_signals(); + SLtt_get_terminfo(); + + if(SLkp_init() == -1) + { + SLsig_unblock_signals(); + return NULL; + } + + SLang_init_tty(-1, 0, 1); + + if(SLsmg_init_smg() == -1) + { + SLsig_unblock_signals(); + return NULL; + } + + SLsig_unblock_signals(); + + SLsmg_cls(); + SLtt_set_cursor_visibility(0); + SLkp_define_keysym("\e[M", 1001); + SLtt_set_mouse_mode(1, 0); + SLsmg_refresh(); + + /* Disable scrolling so that hashmap scrolling optimization code + * does not cause ugly refreshes due to slow terminals */ + SLtt_Term_Cannot_Scroll = 1; + + slang_init_palette(); + + /* Disable alt charset support so that we get a chance to have all + * 256 colour pairs */ + SLtt_Has_Alt_Charset = 0; + + cucul_set_size(kk->qq, SLtt_Screen_Cols, SLtt_Screen_Rows); + + return 0; +} + +int slang_end_graphics(caca_t *kk) +{ + SLtt_set_mouse_mode(0, 0); + SLtt_set_cursor_visibility(1); + SLang_reset_tty(); + SLsmg_reset_smg(); + + return 0; +} +#endif /* _DOXYGEN_SKIP_ME */ + +int slang_set_window_title(caca_t *kk, char const *title) +{ + return 0; +} + +unsigned int slang_get_window_width(caca_t *kk) +{ + /* Fallback to a 6x10 font */ + return kk->qq->width * 6; +} + +unsigned int slang_get_window_height(caca_t *kk) +{ + /* Fallback to a 6x10 font */ + return kk->qq->height * 10; +} + +void slang_display(caca_t *kk) +{ + int x, y; + uint8_t *attr = kk->qq->attr; + uint32_t *chars = kk->qq->chars; + for(y = 0; y < (int)kk->qq->height; y++) + { + SLsmg_gotorc(y, 0); + for(x = kk->qq->width; x--; ) + { +#if defined(OPTIMISE_SLANG_PALETTE) + /* If foreground == background, just don't use this colour + * pair, and print a space instead of the real character. */ + uint8_t fgcolor = *attr & 0xf; + uint8_t bgcolor = *attr >> 4; + if(fgcolor != bgcolor) + { + SLsmg_set_color(slang_assoc[*attr++]); + SLsmg_write_char(*chars++ & 0x7f); + } + else + { + if(fgcolor == CUCUL_COLOR_BLACK) + fgcolor = CUCUL_COLOR_WHITE; + else if(fgcolor == CUCUL_COLOR_WHITE + || fgcolor <= CUCUL_COLOR_LIGHTGRAY) + fgcolor = CUCUL_COLOR_BLACK; + else + fgcolor = CUCUL_COLOR_WHITE; + SLsmg_set_color(slang_assoc[fgcolor + 16 * bgcolor]); + SLsmg_write_char(' '); + chars++; + attr++; + } +#else + SLsmg_set_color(*attr++); + SLsmg_write_char(*chars++ & 0x7f); +#endif + } + } + SLsmg_refresh(); +} + +/* + * XXX: following functions are local + */ + +void slang_handle_resize(caca_t *kk) +{ + unsigned int new_width, new_height; + + new_width = kk->qq->width; + new_height = kk->qq->height; + + SLtt_get_screen_size(); + new_width = SLtt_Screen_Cols; + new_height = SLtt_Screen_Rows; + + if(new_width != kk->qq->width || new_height != kk->qq->height) + SLsmg_reinit_smg(); +} + +static void slang_init_palette(void) +{ + /* See SLang ref., 5.4.4. */ + static char *slang_colors[16] = + { + /* Standard colours */ + "black", + "blue", + "green", + "cyan", + "red", + "magenta", + "brown", + "lightgray", + /* Bright colours */ + "gray", + "brightblue", + "brightgreen", + "brightcyan", + "brightred", + "brightmagenta", + "yellow", + "white", + }; + +#if defined(OPTIMISE_SLANG_PALETTE) + int i; + + for(i = 0; i < 16 * 16; i++) + SLtt_set_color(i, NULL, slang_colors[slang_palette[i * 2]], + slang_colors[slang_palette[i * 2 + 1]]); +#else + int fg, bg; + + for(bg = 0; bg < 16; bg++) + for(fg = 0; fg < 16; fg++) + { + int i = fg + 16 * bg; + SLtt_set_color(i, NULL, slang_colors[fg], slang_colors[bg]); + } +#endif +} + +#if defined(HAVE_SIGNAL) +static RETSIGTYPE sigwinch_handler(int sig) +{ + sigwinch_kk->resize_event = 1; + + signal(SIGWINCH, sigwinch_handler);; +} +#endif + +/* + * Driver initialisation + */ + +void slang_init_driver(caca_t *kk) +{ + kk->driver.driver = CACA_DRIVER_SLANG; + + kk->driver.init_graphics = slang_init_graphics; + kk->driver.end_graphics = slang_end_graphics; + kk->driver.set_window_title = slang_set_window_title; + kk->driver.get_window_width = slang_get_window_width; + kk->driver.get_window_height = slang_get_window_height; + kk->driver.display = slang_display; + kk->driver.handle_resize = slang_handle_resize; +} + +#endif /* USE_SLANG */ + diff --git a/caca/driver_win32.c b/caca/driver_win32.c new file mode 100644 index 0000000..989209b --- /dev/null +++ b/caca/driver_win32.c @@ -0,0 +1,255 @@ +/* + * libcaca ASCII-Art library + * Copyright (c) 2002-2006 Sam Hocevar + * All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the Do What The Fuck You Want To + * Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +/** \file graphics.c + * \version \$Id$ + * \author Sam Hocevar + * \brief Character drawing + * + * This file contains character and string drawing functions. + */ + +#include "config.h" + +#if defined(HAVE_INTTYPES_H) || defined(_DOXYGEN_SKIP_ME) +# include +#else +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#endif + +#if defined(USE_WIN32) + +#include + +#include /* BUFSIZ */ +#include +#include +#if defined(HAVE_UNISTD_H) +# include +#endif +#include + +#include "caca.h" +#include "caca_internals.h" +#include "cucul.h" +#include "cucul_internals.h" + +/* + * Global variables + */ + +static int const win32_fg_palette[] = +{ + 0, + FOREGROUND_BLUE, + FOREGROUND_GREEN, + FOREGROUND_GREEN | FOREGROUND_BLUE, + FOREGROUND_RED, + FOREGROUND_RED | FOREGROUND_BLUE, + FOREGROUND_RED | FOREGROUND_GREEN, + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, + FOREGROUND_INTENSITY, + FOREGROUND_INTENSITY | FOREGROUND_BLUE, + FOREGROUND_INTENSITY | FOREGROUND_GREEN, + FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE, + FOREGROUND_INTENSITY | FOREGROUND_RED, + FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE, + FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN, + FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE +}; + +static int const win32_bg_palette[] = +{ + 0, + BACKGROUND_BLUE, + BACKGROUND_GREEN, + BACKGROUND_GREEN | BACKGROUND_BLUE, + BACKGROUND_RED, + BACKGROUND_RED | BACKGROUND_BLUE, + BACKGROUND_RED | BACKGROUND_GREEN, + BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE, + BACKGROUND_INTENSITY, + BACKGROUND_INTENSITY | BACKGROUND_BLUE, + BACKGROUND_INTENSITY | BACKGROUND_GREEN, + BACKGROUND_INTENSITY | BACKGROUND_GREEN | BACKGROUND_BLUE, + BACKGROUND_INTENSITY | BACKGROUND_RED, + BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_BLUE, + BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN, + BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE +}; + +int win32_init_graphics(caca_t *); +int win32_end_graphics(caca_t *); +int win32_set_window_title(caca_t *, char const *); +unsigned int win32_get_window_width(caca_t *); +unsigned int win32_get_window_height(caca_t *); +void win32_display(caca_t *); +void win32_handle_resize(caca_t *); + +int win32_init_graphics(caca_t *kk) +{ + CONSOLE_CURSOR_INFO cci; + CONSOLE_SCREEN_BUFFER_INFO csbi; + COORD size; + + /* This call is allowed to fail in case we already have a console */ + AllocConsole(); + + kk->win32.hin = GetStdHandle(STD_INPUT_HANDLE); + kk->win32.hout = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(kk->win32.hout == INVALID_HANDLE_VALUE) + return -1; + + GetConsoleCursorInfo(kk->win32.hout, &cci); + cci.bVisible = FALSE; + SetConsoleCursorInfo(kk->win32.hout, &cci); + + SetConsoleMode(kk->win32.hout, ENABLE_MOUSE_INPUT); + + kk->win32.front = + CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, + 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL); + if(!kk->win32.front || kk->win32.front == INVALID_HANDLE_VALUE) + return -1; + + kk->win32.back = + CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, + 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL); + if(!kk->win32.back || kk->win32.back == INVALID_HANDLE_VALUE) + return -1; + + if(!GetConsoleScreenBufferInfo(kk->win32.hout, &csbi)) + return -1; + + /* Sample code to get the biggest possible window */ + //size = GetLargestConsoleWindowSize(kk->win32.hout); + cucul_set_size(kk->qq, csbi.srWindow.Right - csbi.srWindow.Left + 1, + csbi.srWindow.Bottom - csbi.srWindow.Top + 1); + size.X = kk->qq->width; + size.Y = kk->qq->height; + SetConsoleScreenBufferSize(kk->win32.front, size); + SetConsoleScreenBufferSize(kk->win32.back, size); + + SetConsoleMode(kk->win32.front, 0); + SetConsoleMode(kk->win32.back, 0); + + GetConsoleCursorInfo(kk->win32.front, &cci); + cci.dwSize = 0; + cci.bVisible = FALSE; + SetConsoleCursorInfo(kk->win32.front, &cci); + SetConsoleCursorInfo(kk->win32.back, &cci); + + SetConsoleActiveScreenBuffer(kk->win32.front); + + kk->win32.buffer = malloc(kk->qq->width * kk->qq->height + * sizeof(CHAR_INFO)); + if(kk->win32.buffer == NULL) + return -1; + + return 0; +} + +int win32_end_graphics(caca_t *kk) +{ + SetConsoleActiveScreenBuffer(kk->win32.hout); + CloseHandle(kk->win32.back); + CloseHandle(kk->win32.front); + + SetConsoleTextAttribute(kk->win32.hout, FOREGROUND_INTENSITY + | FOREGROUND_RED + | FOREGROUND_GREEN + | FOREGROUND_BLUE); + cci.bVisible = TRUE; + SetConsoleCursorInfo(kk->win32.hout, &cci); + CloseHandle(kk->win32.hout); + + return 0; +} + +int win32_set_window_title(caca_t *kk, char const *title) +{ + SetConsoleTitle(title); + return 0; +} + +unsigned int win32_get_window_width(caca_t *kk) +{ + /* FIXME */ + + /* Fallback to a 6x10 font */ + return kk->qq->width * 6; +} + +unsigned int win32_get_window_height(caca_t *kk) +{ + /* FIXME */ + + /* Fallback to a 6x10 font */ + return kk->qq->height * 10; +} + +void win32_display(caca_t *kk) +{ + COORD size, pos; + SMALL_RECT rect; + unsigned int i; + + /* Render everything to our back buffer */ + for(i = 0; i < kk->qq->width * kk->qq->height; i++) + { + kk->win32.buffer[i].Char.AsciiChar = kk->qq->chars[i] & 0x7f; + kk->win32.buffer[i].Attributes = + win32_fg_palette[kk->qq->attr[i] & 0xf] + | win32_bg_palette[kk->qq->attr[i] >> 4]; + } + + /* Blit the back buffer to the front buffer */ + size.X = kk->qq->width; + size.Y = kk->qq->height; + pos.X = pos.Y = 0; + rect.Left = rect.Top = 0; + rect.Right = kk->qq->width - 1; + rect.Bottom = kk->qq->height - 1; + WriteConsoleOutput(kk->win32.front, kk->win32.buffer, size, pos, &rect); +} + +void win32_handle_resize(caca_t *kk) +{ + unsigned int new_width, new_height; + + new_width = kk->qq->width; + new_height = kk->qq->height; + + /* Nothing to do here. */ +} + +/* + * Driver initialisation + */ + +void win32_init_driver(caca_t *kk) +{ + kk->driver.driver = CACA_DRIVER_WIN32; + + kk->driver.init_graphics = win32_init_graphics; + kk->driver.end_graphics = win32_end_graphics; + kk->driver.set_window_title = win32_set_window_title; + kk->driver.get_window_width = win32_get_window_width; + kk->driver.get_window_height = win32_get_window_height; + kk->driver.display = win32_display; + kk->driver.handle_resize = win32_handle_resize; +} + +#endif /* USE_WIN32 */ + diff --git a/caca/driver_x11.c b/caca/driver_x11.c new file mode 100644 index 0000000..1330492 --- /dev/null +++ b/caca/driver_x11.c @@ -0,0 +1,363 @@ +/* + * libcaca ASCII-Art library + * Copyright (c) 2002-2006 Sam Hocevar + * All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the Do What The Fuck You Want To + * Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +/** \file graphics.c + * \version \$Id$ + * \author Sam Hocevar + * \brief Character drawing + * + * This file contains character and string drawing functions. + */ + +#include "config.h" + +#if defined(HAVE_INTTYPES_H) || defined(_DOXYGEN_SKIP_ME) +# include +#else +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#endif + +#if defined(USE_X11) + +#include +#if defined(HAVE_X11_XKBLIB_H) +# include +#endif + +#include /* BUFSIZ */ +#include +#include +#if defined(HAVE_UNISTD_H) +# include +#endif +#include + +#include "caca.h" +#include "caca_internals.h" +#include "cucul.h" +#include "cucul_internals.h" + +int x11_init_graphics(caca_t *); +int x11_end_graphics(caca_t *); +int x11_set_window_title(caca_t *, char const *); +unsigned int x11_get_window_width(caca_t *); +unsigned int x11_get_window_height(caca_t *); +void x11_display(caca_t *); +void x11_handle_resize(caca_t *); + +/* + * Local functions + */ +static int x11_error_handler(Display *, XErrorEvent *); + +#if !defined(_DOXYGEN_SKIP_ME) +int x11_init_graphics(caca_t *kk) +{ + static int const x11_palette[] = + { + /* Standard curses colours */ + 0x0, 0x0, 0x0, + 0x0, 0x0, 0x8000, + 0x0, 0x8000, 0x0, + 0x0, 0x8000, 0x8000, + 0x8000, 0x0, 0x0, + 0x8000, 0x0, 0x8000, + 0x8000, 0x8000, 0x0, + 0x8000, 0x8000, 0x8000, + /* Extra values for xterm-16color */ + 0x4000, 0x4000, 0x4000, + 0x4000, 0x4000, 0xffff, + 0x4000, 0xffff, 0x4000, + 0x4000, 0xffff, 0xffff, + 0xffff, 0x4000, 0x4000, + 0xffff, 0x4000, 0xffff, + 0xffff, 0xffff, 0x4000, + 0xffff, 0xffff, 0xffff, + }; + + Colormap colormap; + XSetWindowAttributes x11_winattr; + int (*old_error_handler)(Display *, XErrorEvent *); + char const *fonts[] = { NULL, "8x13bold", "fixed" }, **parser; + char const *geometry; + unsigned int width = 0, height = 0; + int i; + + geometry = getenv("CACA_GEOMETRY"); + if(geometry && *(geometry)) + sscanf(geometry, "%ux%u", &width, &height); + + if(width && height) + cucul_set_size(kk->qq, width, height); + + kk->x11.dpy = XOpenDisplay(NULL); + if(kk->x11.dpy == NULL) + return -1; + + fonts[0] = getenv("CACA_FONT"); + if(fonts[0] && *fonts[0]) + parser = fonts; + else + parser = fonts + 1; + + /* Ignore font errors */ + old_error_handler = XSetErrorHandler(x11_error_handler); + + /* Parse our font list */ + for( ; ; parser++) + { + if(!*parser) + { + XSetErrorHandler(old_error_handler); + XCloseDisplay(kk->x11.dpy); + return -1; + } + + kk->x11.font = XLoadFont(kk->x11.dpy, *parser); + if(!kk->x11.font) + continue; + + kk->x11.font_struct = XQueryFont(kk->x11.dpy, kk->x11.font); + if(!kk->x11.font_struct) + { + XUnloadFont(kk->x11.dpy, kk->x11.font); + continue; + } + + break; + } + + /* Reset the default X11 error handler */ + XSetErrorHandler(old_error_handler); + + kk->x11.font_width = kk->x11.font_struct->max_bounds.width; + kk->x11.font_height = kk->x11.font_struct->max_bounds.ascent + + kk->x11.font_struct->max_bounds.descent; + kk->x11.font_offset = kk->x11.font_struct->max_bounds.descent; + + colormap = DefaultColormap(kk->x11.dpy, DefaultScreen(kk->x11.dpy)); + for(i = 0; i < 16; i++) + { + XColor color; + color.red = x11_palette[i * 3]; + color.green = x11_palette[i * 3 + 1]; + color.blue = x11_palette[i * 3 + 2]; + XAllocColor(kk->x11.dpy, colormap, &color); + kk->x11.colors[i] = color.pixel; + } + + x11_winattr.backing_store = Always; + x11_winattr.background_pixel = kk->x11.colors[0]; + x11_winattr.event_mask = ExposureMask | StructureNotifyMask; + + kk->x11.window = + XCreateWindow(kk->x11.dpy, DefaultRootWindow(kk->x11.dpy), 0, 0, + kk->qq->width * kk->x11.font_width, + kk->qq->height * kk->x11.font_height, + 0, 0, InputOutput, 0, + CWBackingStore | CWBackPixel | CWEventMask, + &x11_winattr); + + XStoreName(kk->x11.dpy, kk->x11.window, "caca for X"); + + XSelectInput(kk->x11.dpy, kk->x11.window, StructureNotifyMask); + XMapWindow(kk->x11.dpy, kk->x11.window); + + kk->x11.gc = XCreateGC(kk->x11.dpy, kk->x11.window, 0, NULL); + XSetForeground(kk->x11.dpy, kk->x11.gc, kk->x11.colors[15]); + XSetFont(kk->x11.dpy, kk->x11.gc, kk->x11.font); + + for(;;) + { + XEvent event; + XNextEvent(kk->x11.dpy, &event); + if (event.type == MapNotify) + break; + } + +#if defined(HAVE_X11_XKBLIB_H) + /* Disable autorepeat */ + XkbSetDetectableAutoRepeat(kk->x11.dpy, True, &kk->x11.autorepeat); + if(!kk->x11.autorepeat) + XAutoRepeatOff(kk->x11.dpy); +#endif + + kk->x11.event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask + | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask + | ExposureMask; + + XSelectInput(kk->x11.dpy, kk->x11.window, kk->x11.event_mask); + + XSync(kk->x11.dpy, False); + + kk->x11.pixmap = XCreatePixmap(kk->x11.dpy, kk->x11.window, + kk->qq->width * kk->x11.font_width, + kk->qq->height * kk->x11.font_height, + DefaultDepth(kk->x11.dpy, + DefaultScreen(kk->x11.dpy))); + + kk->x11.new_width = kk->x11.new_height = 0; + + return 0; +} + +int x11_end_graphics(caca_t *kk) +{ + XSync(kk->x11.dpy, False); +#if defined(HAVE_X11_XKBLIB_H) + if(!kk->x11.autorepeat) + XAutoRepeatOn(kk->x11.dpy); +#endif + XFreePixmap(kk->x11.dpy, kk->x11.pixmap); + XFreeFont(kk->x11.dpy, kk->x11.font_struct); + XFreeGC(kk->x11.dpy, kk->x11.gc); + XUnmapWindow(kk->x11.dpy, kk->x11.window); + XDestroyWindow(kk->x11.dpy, kk->x11.window); + XCloseDisplay(kk->x11.dpy); + + return 0; +} +#endif /* _DOXYGEN_SKIP_ME */ + +int x11_set_window_title(caca_t *kk, char const *title) +{ + XStoreName(kk->x11.dpy, kk->x11.window, title); + return 0; +} + +unsigned int x11_get_window_width(caca_t *kk) +{ + return kk->qq->width * kk->x11.font_width; +} + +unsigned int x11_get_window_height(caca_t *kk) +{ + return kk->qq->height * kk->x11.font_height; +} + +void x11_display(caca_t *kk) +{ + unsigned int x, y, len; + + /* First draw the background colours. Splitting the process in two + * loops like this is actually slightly faster. */ + for(y = 0; y < kk->qq->height; y++) + { + for(x = 0; x < kk->qq->width; x += len) + { + uint8_t *attr = kk->qq->attr + x + y * kk->qq->width; + + len = 1; + while(x + len < kk->qq->width + && (attr[len] >> 4) == (attr[0] >> 4)) + len++; + + XSetForeground(kk->x11.dpy, kk->x11.gc, + kk->x11.colors[attr[0] >> 4]); + XFillRectangle(kk->x11.dpy, kk->x11.pixmap, kk->x11.gc, + x * kk->x11.font_width, y * kk->x11.font_height, + len * kk->x11.font_width, kk->x11.font_height); + } + } + + /* Then print the foreground characters */ + for(y = 0; y < kk->qq->height; y++) + { + for(x = 0; x < kk->qq->width; x += len) + { + char buffer[BUFSIZ]; /* FIXME: use a smaller buffer */ + uint32_t *chars = kk->qq->chars + x + y * kk->qq->width; + uint8_t *attr = kk->qq->attr + x + y * kk->qq->width; + + len = 1; + + /* Skip spaces */ + if(chars[0] == ' ') + continue; + + buffer[0] = chars[0] & 0x7f; + + while(x + len < kk->qq->width + && (attr[len] & 0xf) == (attr[0] & 0xf)) + { + buffer[len] = chars[len] & 0x7f; + len++; + } + + XSetForeground(kk->x11.dpy, kk->x11.gc, kk->x11.colors[attr[0] & 0xf]); + XDrawString(kk->x11.dpy, kk->x11.pixmap, kk->x11.gc, + x * kk->x11.font_width, + (y + 1) * kk->x11.font_height - kk->x11.font_offset, + buffer, len); + } + } + + XCopyArea(kk->x11.dpy, kk->x11.pixmap, kk->x11.window, kk->x11.gc, 0, 0, + kk->qq->width * kk->x11.font_width, + kk->qq->height * kk->x11.font_height, + 0, 0); + XFlush(kk->x11.dpy); +} + +void x11_handle_resize(caca_t *kk) +{ + unsigned int new_width, new_height; + + Pixmap new_pixmap; + + new_width = kk->qq->width; + new_height = kk->qq->height; + + new_width = kk->x11.new_width; + new_height = kk->x11.new_height; + + new_pixmap = XCreatePixmap(kk->x11.dpy, kk->x11.window, + kk->qq->width * kk->x11.font_width, + kk->qq->height * kk->x11.font_height, + DefaultDepth(kk->x11.dpy, + DefaultScreen(kk->x11.dpy))); + XCopyArea(kk->x11.dpy, kk->x11.pixmap, new_pixmap, kk->x11.gc, 0, 0, + kk->qq->width * kk->x11.font_width, + kk->qq->height * kk->x11.font_height, 0, 0); + XFreePixmap(kk->x11.dpy, kk->x11.pixmap); + kk->x11.pixmap = new_pixmap; +} + +/* + * XXX: following functions are local + */ + +static int x11_error_handler(Display *dpy, XErrorEvent *event) +{ + /* Ignore the error */ + return 0; +} + +/* + * Driver initialisation + */ + +void x11_init_driver(caca_t *kk) +{ + kk->driver.driver = CACA_DRIVER_X11; + + kk->driver.init_graphics = x11_init_graphics; + kk->driver.end_graphics = x11_end_graphics; + kk->driver.set_window_title = x11_set_window_title; + kk->driver.get_window_width = x11_get_window_width; + kk->driver.get_window_height = x11_get_window_height; + kk->driver.display = x11_display; + kk->driver.handle_resize = x11_handle_resize; +} + +#endif /* USE_X11 */ + diff --git a/caca/event.c b/caca/event.c index 6e2cc38..ade2470 100644 --- a/caca/event.c +++ b/caca/event.c @@ -187,10 +187,10 @@ static unsigned int _get_next_event(caca_t *kk) event = _lowlevel_event(kk); #if defined(USE_SLANG) - if(kk->driver != CACA_DRIVER_SLANG) + if(kk->driver.driver != CACA_DRIVER_SLANG) #endif #if defined(USE_NCURSES) - if(kk->driver != CACA_DRIVER_NCURSES) + if(kk->driver.driver != CACA_DRIVER_NCURSES) #endif return event; @@ -256,7 +256,7 @@ static unsigned int _lowlevel_event(caca_t *kk) #if defined(USE_X11) /* The X11 event check routine */ - if(kk->driver == CACA_DRIVER_X11) + if(kk->driver.driver == CACA_DRIVER_X11) { XEvent xevent; char key; @@ -372,7 +372,7 @@ static unsigned int _lowlevel_event(caca_t *kk) else #endif #if defined(USE_NCURSES) - if(kk->driver == CACA_DRIVER_NCURSES) + if(kk->driver.driver == CACA_DRIVER_NCURSES) { int intkey; @@ -556,7 +556,7 @@ static unsigned int _lowlevel_event(caca_t *kk) else #endif #if defined(USE_SLANG) - if(kk->driver == CACA_DRIVER_SLANG) + if(kk->driver.driver == CACA_DRIVER_SLANG) { int intkey; @@ -639,7 +639,7 @@ static unsigned int _lowlevel_event(caca_t *kk) else #endif #if defined(USE_CONIO) - if(kk->driver == CACA_DRIVER_CONIO) + if(kk->driver.driver == CACA_DRIVER_CONIO) { if(!_conio_kbhit()) return CACA_EVENT_NONE; @@ -651,7 +651,7 @@ static unsigned int _lowlevel_event(caca_t *kk) else #endif #if defined(USE_WIN32) - if(kk->driver == CACA_DRIVER_WIN32) + if(kk->driver.driver == CACA_DRIVER_WIN32) { INPUT_RECORD rec; DWORD num; @@ -725,7 +725,7 @@ static unsigned int _lowlevel_event(caca_t *kk) else #endif #if defined(USE_GL) - if(kk->driver == CACA_DRIVER_GL) + if(kk->driver.driver == CACA_DRIVER_GL) { glutMainLoopEvent(); diff --git a/caca/graphics.c b/caca/graphics.c index fca4808..19abec4 100644 --- a/caca/graphics.c +++ b/caca/graphics.c @@ -19,40 +19,6 @@ #include "config.h" -#if defined(USE_SLANG) -# if defined(HAVE_SLANG_SLANG_H) -# include -# else -# include -# endif -#endif -#if defined(USE_NCURSES) -# if defined(HAVE_NCURSES_H) -# include -# else -# include -# endif -#endif -#if defined(USE_CONIO) -# include -# if defined(SCREENUPDATE_IN_PC_H) -# include -# endif -#endif -#if defined(USE_X11) -# include -# if defined(HAVE_X11_XKBLIB_H) -# include -# endif -#endif -#if defined(USE_WIN32) -# include -#endif -#if defined(USE_GL) -# include -# include -# include -#endif #if defined(HAVE_INTTYPES_H) || defined(_DOXYGEN_SKIP_ME) # include #else @@ -68,581 +34,23 @@ typedef unsigned char uint8_t; #endif #include -#if defined(HAVE_SIGNAL_H) -# include -#endif -#if defined(HAVE_SYS_IOCTL_H) -# include -#endif - #include "caca.h" #include "caca_internals.h" #include "cucul.h" #include "cucul_internals.h" -/* - * Global variables - */ - -#if defined(USE_SLANG) -/* Tables generated by test/optipal.c */ -static int const slang_palette[2*16*16] = -{ - 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, - 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 0, 8, - 8, 7, 7, 8, 15, 7, 7, 15, 15, 9, 9, 15, 1, 9, 9, 1, - 7, 9, 9, 7, 8, 1, 1, 8, 0, 1, 15, 10, 10, 15, 2, 10, - 10, 2, 7, 10, 10, 7, 8, 2, 2, 8, 0, 2, 15, 11, 11, 15, - 3, 11, 11, 3, 7, 11, 11, 7, 8, 3, 3, 8, 0, 3, 15, 12, - 12, 15, 4, 12, 12, 4, 7, 12, 12, 7, 8, 4, 4, 8, 0, 4, - 15, 13, 13, 15, 5, 13, 13, 5, 7, 13, 13, 7, 8, 5, 5, 8, - 0, 5, 15, 14, 14, 15, 6, 14, 14, 6, 7, 14, 14, 7, 8, 6, - 6, 8, 0, 6, 4, 6, 6, 4, 12, 14, 14, 12, 6, 2, 2, 6, - 14, 10, 10, 14, 2, 3, 3, 2, 10, 11, 11, 10, 3, 1, 1, 3, - 11, 9, 9, 11, 1, 5, 5, 1, 9, 13, 13, 9, 5, 4, 4, 5, - 13, 12, 12, 13, 4, 14, 6, 12, 12, 6, 14, 4, 6, 10, 2, 14, - 14, 2, 10, 6, 2, 11, 3, 10, 10, 3, 11, 2, 3, 9, 1, 11, - 11, 1, 9, 3, 1, 13, 5, 9, 9, 5, 13, 1, 5, 12, 4, 13, - 13, 4, 12, 5, 0, 7, 0, 15, 15, 8, 8, 15, 15, 1, 7, 1, - 1, 6, 2, 5, 3, 4, 4, 3, 5, 2, 6, 1, 0, 0, 1, 1, - 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 2, 2, 3, 3, - 4, 4, 5, 5, 6, 6, 7, 7, 14, 9, 1, 15, 8, 9, 8, 8, - 9, 9, 1, 7, 0, 9, 9, 8, 6, 9, 13, 10, 2, 15, 8, 10, - 7, 2, 15, 2, 2, 7, 0, 10, 10, 8, 5, 10, 12, 11, 3, 15, - 8, 11, 7, 3, 15, 3, 3, 7, 0, 11, 11, 8, 4, 11, 11, 12, - 4, 15, 8, 12, 7, 4, 15, 4, 4, 7, 0, 12, 12, 8, 3, 12, - 10, 13, 5, 15, 8, 13, 7, 5, 15, 5, 5, 7, 0, 13, 13, 8, - 2, 13, 9, 14, 6, 15, 8, 14, 7, 6, 15, 6, 6, 7, 0, 14, - 14, 8, 1, 14, 5, 6, 2, 4, 13, 14, 10, 12, 4, 2, 3, 6, - 12, 10, 11, 14, 6, 3, 1, 2, 14, 11, 9, 10, 2, 1, 5, 3, - 10, 9, 13, 11, 3, 5, 4, 1, 11, 13, 12, 9, 1, 4, 6, 5, - 9, 12, 14, 13, 5, 14, 2, 12, 13, 6, 10, 4, 4, 10, 3, 14, - 12, 2, 11, 6, 6, 11, 1, 10, 14, 3, 9, 2, 2, 9, 5, 11, - 10, 1, 13, 3, 3, 13, 4, 9, 11, 5, 12, 1, 1, 12, 6, 13, - 9, 4, 14, 5, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, -}; - -static int const slang_assoc[16*16] = -{ - 134, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 28, 135, 214, 86, 219, 91, 133, 127, 26, 23, 240, 112, 245, 117, 141, 126, - 37, 211, 142, 83, 206, 132, 78, 160, 35, 237, 32, 109, 232, 140, 104, 161, - 46, 87, 82, 143, 131, 215, 210, 169, 44, 113, 108, 41, 139, 241, 236, 170, - 55, 222, 203, 130, 144, 94, 75, 178, 53, 248, 229, 138, 50, 120, 101, 179, - 64, 90, 129, 218, 95, 145, 223, 187, 62, 116, 137, 244, 121, 59, 249, 188, - 73, 128, 79, 207, 74, 202, 146, 196, 71, 136, 105, 233, 100, 228, 68, 197, - 122, 153, 162, 171, 180, 189, 198, 147, 16, 25, 34, 43, 52, 61, 70, 18, - 15, 27, 36, 45, 54, 63, 72, 17, 151, 155, 164, 173, 182, 191, 200, 124, - 154, 22, 238, 110, 243, 115, 156, 24, 150, 152, 216, 88, 221, 93, 148, 20, - 163, 235, 31, 107, 230, 165, 102, 33, 159, 213, 250, 85, 208, 157, 80, 29, - 172, 111, 106, 40, 174, 239, 234, 42, 168, 89, 84, 251, 166, 217, 212, 38, - 181, 246, 227, 183, 49, 118, 99, 51, 177, 224, 205, 175, 252, 96, 77, 47, - 190, 114, 192, 242, 119, 58, 247, 60, 186, 92, 184, 220, 97, 253, 225, 56, - 199, 201, 103, 231, 98, 226, 67, 69, 195, 193, 81, 209, 76, 204, 254, 65, - 123, 149, 158, 167, 176, 185, 194, 19, 125, 21, 30, 39, 48, 57, 66, 255, -}; -#endif - -#if defined(USE_WIN32) -static int const win32_fg_palette[] = -{ - 0, - FOREGROUND_BLUE, - FOREGROUND_GREEN, - FOREGROUND_GREEN | FOREGROUND_BLUE, - FOREGROUND_RED, - FOREGROUND_RED | FOREGROUND_BLUE, - FOREGROUND_RED | FOREGROUND_GREEN, - FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, - FOREGROUND_INTENSITY, - FOREGROUND_INTENSITY | FOREGROUND_BLUE, - FOREGROUND_INTENSITY | FOREGROUND_GREEN, - FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE, - FOREGROUND_INTENSITY | FOREGROUND_RED, - FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE, - FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN, - FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE -}; - -static int const win32_bg_palette[] = -{ - 0, - BACKGROUND_BLUE, - BACKGROUND_GREEN, - BACKGROUND_GREEN | BACKGROUND_BLUE, - BACKGROUND_RED, - BACKGROUND_RED | BACKGROUND_BLUE, - BACKGROUND_RED | BACKGROUND_GREEN, - BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE, - BACKGROUND_INTENSITY, - BACKGROUND_INTENSITY | BACKGROUND_BLUE, - BACKGROUND_INTENSITY | BACKGROUND_GREEN, - BACKGROUND_INTENSITY | BACKGROUND_GREEN | BACKGROUND_BLUE, - BACKGROUND_INTENSITY | BACKGROUND_RED, - BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_BLUE, - BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN, - BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE -}; -#endif - -#if defined(USE_GL) -/* Ok, I just suck. */ -static GLbyte const gl_bgpal[][4] = -{ - { 0x00, 0x00, 0x00, 0x7f }, - { 0x00, 0x00, 0x3f, 0x7f }, - { 0x00, 0x3f, 0x00, 0x7f }, - { 0x00, 0x3f, 0x3f, 0x7f }, - { 0x3f, 0x00, 0x00, 0x7f }, - { 0x3f, 0x00, 0x3f, 0x7f }, - { 0x3f, 0x3f, 0x00, 0x7f }, - { 0x3f, 0x3f, 0x3f, 0x7f }, - // + intensity - { 0x00, 0x00, 0x00, 0x7f }, - { 0x00, 0x00, 0x7f, 0x7f }, - { 0x00, 0x7f, 0x00, 0x7f }, - { 0x00, 0x7f, 0x7f, 0x7f }, - { 0x7f, 0x00, 0x00, 0x7f }, - { 0x7f, 0x00, 0x7f, 0x7f }, - { 0x7f, 0x7f, 0x00, 0x7f }, - { 0x7f, 0x7f, 0x7f, 0x7f } -}; - -static caca_t *gl_kk; /* FIXME: we ought to get rid of this */ -#endif - /* * Local functions */ static void caca_handle_resize(caca_t *kk); -#if defined(USE_SLANG) -static void slang_init_palette(void); -#endif - -#if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG)) -static RETSIGTYPE sigwinch_handler(int); -static caca_t *sigwinch_kk; /* FIXME: we ought to get rid of this */ -#endif - -#if defined(USE_X11) -static int x11_error_handler(Display *, XErrorEvent *); -#endif - -#if defined(USE_GL) -static void gl_handle_keyboard(unsigned char, int, int); -static void gl_handle_special_key(int, int, int); -static void gl_handle_reshape(int, int); -static void gl_handle_mouse(int, int, int, int); -static void gl_handle_mouse_motion(int, int); -#endif - #if !defined(_DOXYGEN_SKIP_ME) int _caca_init_graphics(caca_t *kk) { -#if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG)) - sigwinch_kk = kk; - signal(SIGWINCH, sigwinch_handler); -#endif - -#if defined(USE_SLANG) - if(kk->driver == CACA_DRIVER_SLANG) - { - slang_init_palette(); - - /* Disable alt charset support so that we get a chance to have all - * 256 colour pairs */ - SLtt_Has_Alt_Charset = 0; - - cucul_set_size(kk->qq, SLtt_Screen_Cols, SLtt_Screen_Rows); - } - else -#endif -#if defined(USE_NCURSES) - if(kk->driver == CACA_DRIVER_NCURSES) - { - static int curses_colors[] = - { - /* Standard curses colours */ - COLOR_BLACK, - COLOR_BLUE, - COLOR_GREEN, - COLOR_CYAN, - COLOR_RED, - COLOR_MAGENTA, - COLOR_YELLOW, - COLOR_WHITE, - /* Extra values for xterm-16color */ - COLOR_BLACK + 8, - COLOR_BLUE + 8, - COLOR_GREEN + 8, - COLOR_CYAN + 8, - COLOR_RED + 8, - COLOR_MAGENTA + 8, - COLOR_YELLOW + 8, - COLOR_WHITE + 8 - }; - - int fg, bg, max; - - /* Activate colour */ - start_color(); - - /* If COLORS == 16, it means the terminal supports full bright colours - * using setab and setaf (will use \e[90m \e[91m etc. for colours >= 8), - * we can build 16*16 colour pairs. - * If COLORS == 8, it means the terminal does not know about bright - * colours and we need to get them through A_BOLD and A_BLINK (\e[1m - * and \e[5m). We can only build 8*8 colour pairs. */ - max = COLORS >= 16 ? 16 : 8; - - for(bg = 0; bg < max; bg++) - for(fg = 0; fg < max; fg++) - { - /* Use ((max + 7 - fg) % max) instead of fg so that colour 0 - * is light gray on black. Some terminals don't like this - * colour pair to be redefined. */ - int col = ((max + 7 - fg) % max) + max * bg; - init_pair(col, curses_colors[fg], curses_colors[bg]); - kk->ncurses.attr[fg + 16 * bg] = COLOR_PAIR(col); - - if(max == 8) - { - /* Bright fg on simple bg */ - kk->ncurses.attr[fg + 8 + 16 * bg] = A_BOLD | COLOR_PAIR(col); - /* Simple fg on bright bg */ - kk->ncurses.attr[fg + 16 * (bg + 8)] = A_BLINK - | COLOR_PAIR(col); - /* Bright fg on bright bg */ - kk->ncurses.attr[fg + 8 + 16 * (bg + 8)] = A_BLINK | A_BOLD - | COLOR_PAIR(col); - } - } - - cucul_set_size(kk->qq, COLS, LINES); - } - else -#endif -#if defined(USE_CONIO) - if(kk->driver == CACA_DRIVER_CONIO) - { - gettextinfo(&kk->conio.ti); - kk->conio.screen = malloc(2 * kk->conio.ti.screenwidth - * kk->conio.ti.screenheight * sizeof(char)); - if(kk->conio.screen == NULL) - return -1; -# if defined(SCREENUPDATE_IN_PC_H) - ScreenRetrieve(kk->conio.screen); -# else - /* FIXME */ -# endif - cucul_set_size(kk->qq, kk->conio.ti.screenwidth, - kk->conio.ti.screenheight); - } - else -#endif -#if defined(USE_X11) - if(kk->driver == CACA_DRIVER_X11) - { - static int const x11_palette[] = - { - /* Standard curses colours */ - 0x0, 0x0, 0x0, - 0x0, 0x0, 0x8000, - 0x0, 0x8000, 0x0, - 0x0, 0x8000, 0x8000, - 0x8000, 0x0, 0x0, - 0x8000, 0x0, 0x8000, - 0x8000, 0x8000, 0x0, - 0x8000, 0x8000, 0x8000, - /* Extra values for xterm-16color */ - 0x4000, 0x4000, 0x4000, - 0x4000, 0x4000, 0xffff, - 0x4000, 0xffff, 0x4000, - 0x4000, 0xffff, 0xffff, - 0xffff, 0x4000, 0x4000, - 0xffff, 0x4000, 0xffff, - 0xffff, 0xffff, 0x4000, - 0xffff, 0xffff, 0xffff, - }; - - Colormap colormap; - XSetWindowAttributes x11_winattr; - int (*old_error_handler)(Display *, XErrorEvent *); - char const *fonts[] = { NULL, "8x13bold", "fixed" }, **parser; - char const *geometry; - unsigned int width = 0, height = 0; - int i; - - geometry = getenv("CACA_GEOMETRY"); - if(geometry && *(geometry)) - sscanf(geometry, "%ux%u", &width, &height); - - if(width && height) - cucul_set_size(kk->qq, width, height); - - kk->x11.dpy = XOpenDisplay(NULL); - if(kk->x11.dpy == NULL) - return -1; - - fonts[0] = getenv("CACA_FONT"); - if(fonts[0] && *fonts[0]) - parser = fonts; - else - parser = fonts + 1; - - /* Ignore font errors */ - old_error_handler = XSetErrorHandler(x11_error_handler); - - /* Parse our font list */ - for( ; ; parser++) - { - if(!*parser) - { - XSetErrorHandler(old_error_handler); - XCloseDisplay(kk->x11.dpy); - return -1; - } - - kk->x11.font = XLoadFont(kk->x11.dpy, *parser); - if(!kk->x11.font) - continue; - - kk->x11.font_struct = XQueryFont(kk->x11.dpy, kk->x11.font); - if(!kk->x11.font_struct) - { - XUnloadFont(kk->x11.dpy, kk->x11.font); - continue; - } - - break; - } - - /* Reset the default X11 error handler */ - XSetErrorHandler(old_error_handler); - - kk->x11.font_width = kk->x11.font_struct->max_bounds.width; - kk->x11.font_height = kk->x11.font_struct->max_bounds.ascent - + kk->x11.font_struct->max_bounds.descent; - kk->x11.font_offset = kk->x11.font_struct->max_bounds.descent; - - colormap = DefaultColormap(kk->x11.dpy, DefaultScreen(kk->x11.dpy)); - for(i = 0; i < 16; i++) - { - XColor color; - color.red = x11_palette[i * 3]; - color.green = x11_palette[i * 3 + 1]; - color.blue = x11_palette[i * 3 + 2]; - XAllocColor(kk->x11.dpy, colormap, &color); - kk->x11.colors[i] = color.pixel; - } - - x11_winattr.backing_store = Always; - x11_winattr.background_pixel = kk->x11.colors[0]; - x11_winattr.event_mask = ExposureMask | StructureNotifyMask; - - kk->x11.window = - XCreateWindow(kk->x11.dpy, DefaultRootWindow(kk->x11.dpy), 0, 0, - kk->qq->width * kk->x11.font_width, - kk->qq->height * kk->x11.font_height, - 0, 0, InputOutput, 0, - CWBackingStore | CWBackPixel | CWEventMask, - &x11_winattr); - - XStoreName(kk->x11.dpy, kk->x11.window, "caca for X"); - - XSelectInput(kk->x11.dpy, kk->x11.window, StructureNotifyMask); - XMapWindow(kk->x11.dpy, kk->x11.window); - - kk->x11.gc = XCreateGC(kk->x11.dpy, kk->x11.window, 0, NULL); - XSetForeground(kk->x11.dpy, kk->x11.gc, kk->x11.colors[15]); - XSetFont(kk->x11.dpy, kk->x11.gc, kk->x11.font); - - for(;;) - { - XEvent event; - XNextEvent(kk->x11.dpy, &event); - if (event.type == MapNotify) - break; - } - -#if defined(HAVE_X11_XKBLIB_H) - /* Disable autorepeat */ - XkbSetDetectableAutoRepeat(kk->x11.dpy, True, &kk->x11.autorepeat); - if(!kk->x11.autorepeat) - XAutoRepeatOff(kk->x11.dpy); -#endif - - XSelectInput(kk->x11.dpy, kk->x11.window, kk->x11.event_mask); - - XSync(kk->x11.dpy, False); - - kk->x11.pixmap = XCreatePixmap(kk->x11.dpy, kk->x11.window, - kk->qq->width * kk->x11.font_width, - kk->qq->height * kk->x11.font_height, - DefaultDepth(kk->x11.dpy, - DefaultScreen(kk->x11.dpy))); - - kk->x11.new_width = kk->x11.new_height = 0; - } - else -#endif -#if defined(USE_WIN32) - if(kk->driver == CACA_DRIVER_WIN32) - { - CONSOLE_CURSOR_INFO cci; - CONSOLE_SCREEN_BUFFER_INFO csbi; - COORD size; - - kk->win32.front = - CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, - 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL); - if(!kk->win32.front || kk->win32.front == INVALID_HANDLE_VALUE) - return -1; - - kk->win32.back = - CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, - 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL); - if(!kk->win32.back || kk->win32.back == INVALID_HANDLE_VALUE) - return -1; - - if(!GetConsoleScreenBufferInfo(kk->win32.hout, &csbi)) - return -1; - - /* Sample code to get the biggest possible window */ - //size = GetLargestConsoleWindowSize(kk->win32.hout); - cucul_set_size(kk->qq, csbi.srWindow.Right - csbi.srWindow.Left + 1, - csbi.srWindow.Bottom - csbi.srWindow.Top + 1); - size.X = kk->qq->width; - size.Y = kk->qq->height; - SetConsoleScreenBufferSize(kk->win32.front, size); - SetConsoleScreenBufferSize(kk->win32.back, size); - - SetConsoleMode(kk->win32.front, 0); - SetConsoleMode(kk->win32.back, 0); - - GetConsoleCursorInfo(kk->win32.front, &cci); - cci.dwSize = 0; - cci.bVisible = FALSE; - SetConsoleCursorInfo(kk->win32.front, &cci); - SetConsoleCursorInfo(kk->win32.back, &cci); - - SetConsoleActiveScreenBuffer(kk->win32.front); - - kk->win32.buffer = malloc(kk->qq->width * kk->qq->height - * sizeof(CHAR_INFO)); - if(kk->win32.buffer == NULL) - return -1; - } - else -#endif -#if defined(USE_GL) - if(kk->driver == CACA_DRIVER_GL) - { - char *empty_texture; - char const *geometry; - char *argv[2] = { "", NULL }; - unsigned int width = 0, height = 0; - int argc = 1; - int i; - - gl_kk = kk; - - geometry = getenv("CACA_GEOMETRY"); - if(geometry && *(geometry)) - sscanf(geometry, "%ux%u", &width, &height); - - if(width && height) - cucul_set_size(kk->qq, width, height); - - kk->gl.font_width = 9; - kk->gl.font_height = 15; - - kk->gl.width = kk->qq->width * kk->gl.font_width; - kk->gl.height = kk->qq->height * kk->gl.font_height; - - kk->gl.resized = 0; - kk->gl.bit = 0; - - kk->gl.mouse_changed = kk->gl.mouse_clicked = 0; - kk->gl.mouse_button = kk->gl.mouse_state = 0; - - kk->gl.key = 0; - kk->gl.special_key = 0; - - kk->gl.sw = 9.0f / 16.0f; - kk->gl.sh = 15.0f / 16.0f; - - glutInit(&argc, argv); - - glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); - glutInitWindowSize(kk->gl.width, kk->gl.height); - kk->gl.window = glutCreateWindow("caca for GL"); - - gluOrtho2D(0, kk->gl.width, kk->gl.height, 0); - - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - - glutKeyboardFunc(gl_handle_keyboard); - glutSpecialFunc(gl_handle_special_key); - glutReshapeFunc(gl_handle_reshape); - - glutMouseFunc(gl_handle_mouse); - glutMotionFunc(gl_handle_mouse_motion); - glutPassiveMotionFunc(gl_handle_mouse_motion); - - glLoadIdentity(); - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - gluOrtho2D(0, kk->gl.width, kk->gl.height, 0); - - glMatrixMode(GL_MODELVIEW); + int ret = kk->driver.init_graphics(kk); - glClear(GL_COLOR_BUFFER_BIT); - - empty_texture = malloc(16 * 16 * 4); - if(empty_texture == NULL) - return -1; - - memset(empty_texture, 0xff, 16 * 16 * 4); - glEnable(GL_TEXTURE_2D); - - for(i = 0; i < 94; i++) - { - glGenTextures(1, (GLuint*)&kk->gl.id[i]); - glBindTexture(GL_TEXTURE_2D, kk->gl.id[i]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, - 16, 16, 0, GL_RGB, GL_UNSIGNED_BYTE, empty_texture); - } - - for(i = 0; i < 94; i++) - { - glDisable(GL_TEXTURE_2D); - glClear(GL_COLOR_BUFFER_BIT); - - glColor3f(1, 1, 1); - glRasterPos2f(0, 15); - glutBitmapCharacter(GLUT_BITMAP_9_BY_15, i + 32); - - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, kk->gl.id[i]); - glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, - 0, kk->gl.height - 16, 16, 16, 0); - - glutMainLoopEvent(); - glutPostRedisplay(); - } - } - else -#endif - { - /* Dummy */ - } + if(!ret) + return ret; kk->delay = 0; kk->rendertime = 0; @@ -652,57 +60,7 @@ int _caca_init_graphics(caca_t *kk) int _caca_end_graphics(caca_t *kk) { -#if defined(USE_SLANG) - /* Nothing to do */ -#endif -#if defined(USE_NCURSES) - /* Nothing to do */ -#endif -#if defined(USE_CONIO) - if(kk->driver == CACA_DRIVER_CONIO) - { - free(kk->conio.screen); - } - else -#endif -#if defined(USE_X11) - if(kk->driver == CACA_DRIVER_X11) - { - XSync(kk->x11.dpy, False); -#if defined(HAVE_X11_XKBLIB_H) - if(!kk->x11.autorepeat) - XAutoRepeatOn(kk->x11.dpy); -#endif - XFreePixmap(kk->x11.dpy, kk->x11.pixmap); - XFreeFont(kk->x11.dpy, kk->x11.font_struct); - XFreeGC(kk->x11.dpy, kk->x11.gc); - XUnmapWindow(kk->x11.dpy, kk->x11.window); - XDestroyWindow(kk->x11.dpy, kk->x11.window); - XCloseDisplay(kk->x11.dpy); - } - else -#endif -#if defined(USE_WIN32) - if(kk->driver == CACA_DRIVER_WIN32) - { - SetConsoleActiveScreenBuffer(kk->win32.hout); - CloseHandle(kk->win32.back); - CloseHandle(kk->win32.front); - } - else -#endif -#if defined(USE_GL) - if(kk->driver == CACA_DRIVER_GL) - { - glutDestroyWindow(kk->gl.window); - } - else -#endif - { - /* Dummy */ - } - - return 0; + return kk->driver.end_graphics(kk); } #endif /* _DOXYGEN_SKIP_ME */ @@ -716,33 +74,7 @@ int _caca_end_graphics(caca_t *kk) */ int caca_set_window_title(caca_t *kk, char const *title) { -#if defined(USE_X11) - if(kk->driver == CACA_DRIVER_X11) - { - XStoreName(kk->x11.dpy, kk->x11.window, title); - } - else -#endif -#if defined(USE_WIN32) - if(kk->driver == CACA_DRIVER_WIN32) - { - SetConsoleTitle(title); - } - else -#endif -#if defined(USE_GL) - if(kk->driver == CACA_DRIVER_GL) - { - glutSetWindowTitle(title); - } - else -#endif - { - /* Not supported */ - return -1; - } - - return 0; + return kk->driver.set_window_title(kk, title); } /** \brief Get the window width. @@ -756,33 +88,7 @@ int caca_set_window_title(caca_t *kk, char const *title) */ unsigned int caca_get_window_width(caca_t *kk) { -#if defined(USE_X11) - if(kk->driver == CACA_DRIVER_X11) - { - return kk->qq->width * kk->x11.font_width; - } - else -#endif -#if defined(USE_WIN32) - if(kk->driver == CACA_DRIVER_WIN32) - { - /* FIXME */ - } - else -#endif -#if defined(USE_GL) - if(kk->driver == CACA_DRIVER_GL) - { - return kk->gl.width; - } - else -#endif - { - /* Dummy */ - } - - /* Fallback to a 6x10 font */ - return kk->qq->width * 6; + return kk->driver.get_window_width(kk); } /** \brief Get the window height. @@ -796,33 +102,7 @@ unsigned int caca_get_window_width(caca_t *kk) */ unsigned int caca_get_window_height(caca_t *kk) { -#if defined(USE_X11) - if(kk->driver == CACA_DRIVER_X11) - { - return kk->qq->height * kk->x11.font_height; - } - else -#endif -#if defined(USE_WIN32) - if(kk->driver == CACA_DRIVER_WIN32) - { - /* FIXME */ - } - else -#endif -#if defined(USE_GL) - if(kk->driver == CACA_DRIVER_GL) - { - return kk->gl.height; - } - else -#endif - { - /* Dummy */ - } - - /* Fallback to a 6x10 font */ - return kk->qq->height * 10; + return kk->driver.get_window_height(kk); } /** \brief Set the refresh delay. @@ -875,260 +155,7 @@ void caca_display(caca_t *kk) #endif int ticks = kk->lastticks + _caca_getticks(&kk->timer); -#if defined(USE_SLANG) - if(kk->driver == CACA_DRIVER_SLANG) - { - int x, y; - uint8_t *attr = kk->qq->attr; - uint32_t *chars = kk->qq->chars; - for(y = 0; y < (int)kk->qq->height; y++) - { - SLsmg_gotorc(y, 0); - for(x = kk->qq->width; x--; ) - { -#if defined(OPTIMISE_SLANG_PALETTE) - /* If foreground == background, just don't use this colour - * pair, and print a space instead of the real character. */ - uint8_t fgcolor = *attr & 0xf; - uint8_t bgcolor = *attr >> 4; - if(fgcolor != bgcolor) - { - SLsmg_set_color(slang_assoc[*attr++]); - SLsmg_write_char(*chars++ & 0x7f); - } - else - { - if(fgcolor == CUCUL_COLOR_BLACK) - fgcolor = CUCUL_COLOR_WHITE; - else if(fgcolor == CUCUL_COLOR_WHITE - || fgcolor <= CUCUL_COLOR_LIGHTGRAY) - fgcolor = CUCUL_COLOR_BLACK; - else - fgcolor = CUCUL_COLOR_WHITE; - SLsmg_set_color(slang_assoc[fgcolor + 16 * bgcolor]); - SLsmg_write_char(' '); - chars++; - attr++; - } -#else - SLsmg_set_color(*attr++); - SLsmg_write_char(*chars++ & 0x7f); -#endif - } - } - SLsmg_refresh(); - } - else -#endif -#if defined(USE_NCURSES) - if(kk->driver == CACA_DRIVER_NCURSES) - { - int x, y; - uint8_t *attr = kk->qq->attr; - uint32_t *chars = kk->qq->chars; - for(y = 0; y < (int)kk->qq->height; y++) - { - move(y, 0); - for(x = kk->qq->width; x--; ) - { - attrset(kk->ncurses.attr[*attr++]); - addch(*chars++ & 0x7f); - } - } - refresh(); - } - else -#endif -#if defined(USE_CONIO) - if(kk->driver == CACA_DRIVER_CONIO) - { - int n; - char *screen = kk->conio.screen; - uint8_t *attr = kk->qq->attr; - uint32_t *chars = kk->qq->chars; - for(n = kk->qq->height * kk->qq->width; n--; ) - { - *screen++ = *chars++ & 0x7f; - *screen++ = *attr++; - } -# if defined(SCREENUPDATE_IN_PC_H) - ScreenUpdate(kk->conio.screen); -# else - /* FIXME */ -# endif - } - else -#endif -#if defined(USE_X11) - if(kk->driver == CACA_DRIVER_X11) - { - unsigned int x, y, len; - - /* First draw the background colours. Splitting the process in two - * loops like this is actually slightly faster. */ - for(y = 0; y < kk->qq->height; y++) - { - for(x = 0; x < kk->qq->width; x += len) - { - uint8_t *attr = kk->qq->attr + x + y * kk->qq->width; - - len = 1; - while(x + len < kk->qq->width - && (attr[len] >> 4) == (attr[0] >> 4)) - len++; - - XSetForeground(kk->x11.dpy, kk->x11.gc, - kk->x11.colors[attr[0] >> 4]); - XFillRectangle(kk->x11.dpy, kk->x11.pixmap, kk->x11.gc, - x * kk->x11.font_width, y * kk->x11.font_height, - len * kk->x11.font_width, kk->x11.font_height); - } - } - - /* Then print the foreground characters */ - for(y = 0; y < kk->qq->height; y++) - { - for(x = 0; x < kk->qq->width; x += len) - { - char buffer[BUFSIZ]; /* FIXME: use a smaller buffer */ - uint32_t *chars = kk->qq->chars + x + y * kk->qq->width; - uint8_t *attr = kk->qq->attr + x + y * kk->qq->width; - - len = 1; - - /* Skip spaces */ - if(chars[0] == ' ') - continue; - - buffer[0] = chars[0] & 0x7f; - - while(x + len < kk->qq->width - && (attr[len] & 0xf) == (attr[0] & 0xf)) - { - buffer[len] = chars[len] & 0x7f; - len++; - } - - XSetForeground(kk->x11.dpy, kk->x11.gc, kk->x11.colors[attr[0] & 0xf]); - XDrawString(kk->x11.dpy, kk->x11.pixmap, kk->x11.gc, - x * kk->x11.font_width, - (y + 1) * kk->x11.font_height - kk->x11.font_offset, - buffer, len); - } - } - - XCopyArea(kk->x11.dpy, kk->x11.pixmap, kk->x11.window, kk->x11.gc, 0, 0, - kk->qq->width * kk->x11.font_width, kk->qq->height * kk->x11.font_height, - 0, 0); - XFlush(kk->x11.dpy); - } - else -#endif -#if defined(USE_WIN32) - if(kk->driver == CACA_DRIVER_WIN32) - { - COORD size, pos; - SMALL_RECT rect; - unsigned int i; - - /* Render everything to our back buffer */ - for(i = 0; i < kk->qq->width * kk->qq->height; i++) - { - kk->win32.buffer[i].Char.AsciiChar = kk->qq->chars[i] & 0x7f; - kk->win32.buffer[i].Attributes = - win32_fg_palette[kk->qq->attr[i] & 0xf] - | win32_bg_palette[kk->qq->attr[i] >> 4]; - } - - /* Blit the back buffer to the front buffer */ - size.X = kk->qq->width; - size.Y = kk->qq->height; - pos.X = pos.Y = 0; - rect.Left = rect.Top = 0; - rect.Right = kk->qq->width - 1; - rect.Bottom = kk->qq->height - 1; - WriteConsoleOutput(kk->win32.front, kk->win32.buffer, size, pos, &rect); - } - else -#endif -#if defined(USE_GL) - if(kk->driver == CACA_DRIVER_GL) - { - unsigned int x, y, line; - - glClear(GL_COLOR_BUFFER_BIT); - - line = 0; - for(y = 0; y < kk->gl.height; y += kk->gl.font_height) - { - uint8_t *attr = kk->qq->attr + line * kk->qq->width; - - for(x = 0; x < kk->gl.width; x += kk->gl.font_width) - { - glDisable(GL_TEXTURE_2D); - glColor4bv(gl_bgpal[attr[0] >> 4]); - glBegin(GL_QUADS); - glVertex2f(x, y); - glVertex2f(x + kk->gl.font_width, y); - glVertex2f(x + kk->gl.font_width, y + kk->gl.font_height); - glVertex2f(x, y + kk->gl.font_height); - glEnd(); - - attr++; - } - - line++; - } - - /* 2nd pass, avoids changing render state too much */ - glEnable(GL_BLEND); - glEnable(GL_TEXTURE_2D); - glBlendFunc(GL_ONE, GL_ONE); - - line = 0; - for(y = 0; y < kk->gl.height; y += kk->gl.font_height) - { - uint8_t *attr = kk->qq->attr + line * kk->qq->width; - uint32_t *chars = kk->qq->chars + line * kk->qq->width; - - for(x = 0; x < kk->gl.width; x += kk->gl.font_width) - { - if(*chars != (uint32_t)' ') - { - char ch = *chars & 0x7f; - - /* FIXME: check ch bounds */ - glBindTexture(GL_TEXTURE_2D, kk->gl.id[ch - 32]); - glColor4bv(gl_bgpal[attr[0] & 0xf]); - glBegin(GL_QUADS); - glTexCoord2f(0, kk->gl.sh); - glVertex2f(x, y); - glTexCoord2f(kk->gl.sw, kk->gl.sh); - glVertex2f(x + kk->gl.font_width, y); - glTexCoord2f(kk->gl.sw, 0); - glVertex2f(x + kk->gl.font_width, y + kk->gl.font_height); - glTexCoord2f(0, 0); - glVertex2f(x, y + kk->gl.font_height); - glEnd(); - } - - attr++; - chars++; - } - line++; - } - glDisable(GL_BLEND); - glDisable(GL_TEXTURE_2D); - - glutMainLoopEvent(); - glutSwapBuffers(); - glutPostRedisplay(); - } - else -#endif - { - /* Dummy */ - } + kk->driver.display(kk); /* FIXME handle this somewhere else */ if(kk->resize) @@ -1167,211 +194,10 @@ static void caca_handle_resize(caca_t *kk) new_width = kk->qq->width; new_height = kk->qq->height; -#if defined(USE_SLANG) - if(kk->driver == CACA_DRIVER_SLANG) - { - SLtt_get_screen_size(); - new_width = SLtt_Screen_Cols; - new_height = SLtt_Screen_Rows; - - if(new_width != kk->qq->width || new_height != kk->qq->height) - SLsmg_reinit_smg(); - } - else -#endif -#if defined(USE_NCURSES) - if(kk->driver == CACA_DRIVER_NCURSES) - { - struct winsize size; - - if(ioctl(fileno(stdout), TIOCGWINSZ, &size) == 0) - { - new_width = size.ws_col; - new_height = size.ws_row; -#if defined(HAVE_RESIZE_TERM) - resize_term(new_height, new_width); -#else - resizeterm(new_height, new_width); -#endif - wrefresh(curscr); - } - } - else -#endif -#if defined(USE_CONIO) - if(kk->driver == CACA_DRIVER_CONIO) - { - /* Nothing to do here. */ - } - else -#endif -#if defined(USE_X11) - if(kk->driver == CACA_DRIVER_X11) - { - Pixmap new_pixmap; - - new_width = kk->x11.new_width; - new_height = kk->x11.new_height; - - new_pixmap = XCreatePixmap(kk->x11.dpy, kk->x11.window, - kk->qq->width * kk->x11.font_width, - kk->qq->height * kk->x11.font_height, - DefaultDepth(kk->x11.dpy, - DefaultScreen(kk->x11.dpy))); - XCopyArea(kk->x11.dpy, kk->x11.pixmap, new_pixmap, kk->x11.gc, 0, 0, - kk->qq->width * kk->x11.font_width, - kk->qq->height * kk->x11.font_height, 0, 0); - XFreePixmap(kk->x11.dpy, kk->x11.pixmap); - kk->x11.pixmap = new_pixmap; - } - else -#endif -#if defined(USE_WIN32) - if(kk->driver == CACA_DRIVER_WIN32) - { - /* Nothing to do here. */ - } - else -#endif -#if defined(USE_GL) - if(kk->driver == CACA_DRIVER_GL) - { - kk->gl.width = kk->gl.new_width; - kk->gl.height = kk->gl.new_height; - - new_width = kk->gl.width / kk->gl.font_width; - new_height = (kk->gl.height / kk->gl.font_height) + 1; - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - - glViewport(0, 0, kk->gl.width, kk->gl.height); - gluOrtho2D(0, kk->gl.width, kk->gl.height, 0); - glMatrixMode(GL_MODELVIEW); - } - else -#endif - { - /* Dummy */ - } + kk->driver.handle_resize(kk); /* Tell libcucul we changed size */ if(new_width != kk->qq->width || new_height != kk->qq->height) cucul_set_size(kk->qq, new_width, new_height); } -#if defined(USE_SLANG) -static void slang_init_palette(void) -{ - /* See SLang ref., 5.4.4. */ - static char *slang_colors[16] = - { - /* Standard colours */ - "black", - "blue", - "green", - "cyan", - "red", - "magenta", - "brown", - "lightgray", - /* Bright colours */ - "gray", - "brightblue", - "brightgreen", - "brightcyan", - "brightred", - "brightmagenta", - "yellow", - "white", - }; - -#if defined(OPTIMISE_SLANG_PALETTE) - int i; - - for(i = 0; i < 16 * 16; i++) - SLtt_set_color(i, NULL, slang_colors[slang_palette[i * 2]], - slang_colors[slang_palette[i * 2 + 1]]); -#else - int fg, bg; - - for(bg = 0; bg < 16; bg++) - for(fg = 0; fg < 16; fg++) - { - int i = fg + 16 * bg; - SLtt_set_color(i, NULL, slang_colors[fg], slang_colors[bg]); - } -#endif -} -#endif /* USE_SLANG */ - -#if defined(USE_X11) -static int x11_error_handler(Display *dpy, XErrorEvent *event) -{ - /* Ignore the error */ - return 0; -} -#endif - -#if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG)) -static RETSIGTYPE sigwinch_handler(int sig) -{ - sigwinch_kk->resize_event = 1; - - signal(SIGWINCH, sigwinch_handler);; -} -#endif - -#if defined(USE_GL) -static void gl_handle_keyboard(unsigned char key, int x, int y) -{ - caca_t *kk = gl_kk; - - kk->gl.key = key; -} - -static void gl_handle_special_key(int key, int x, int y) -{ - caca_t *kk = gl_kk; - - kk->gl.special_key = key; -} - -static void gl_handle_reshape(int w, int h) -{ - caca_t *kk = gl_kk; - - if(kk->gl.bit) /* Do not handle reshaping at the first time */ - { - kk->gl.new_width = w; - kk->gl.new_height = h; - - kk->gl.resized = 1; - } - else - kk->gl.bit = 1; -} - -static void gl_handle_mouse(int button, int state, int x, int y) -{ - caca_t *kk = gl_kk; - - kk->gl.mouse_clicked = 1; - kk->gl.mouse_button = button; - kk->gl.mouse_state = state; - kk->gl.mouse_x = x / kk->gl.font_width; - kk->gl.mouse_y = y / kk->gl.font_height; - kk->gl.mouse_changed = 1; -} - -static void gl_handle_mouse_motion(int x, int y) -{ - caca_t *kk = gl_kk; - - kk->gl.mouse_x = x / kk->gl.font_width; - kk->gl.mouse_y = y / kk->gl.font_height; - kk->gl.mouse_changed = 1; -} -#endif -