broken, and event handling is not yet in the driver-specific files, but I will of course fix that later.tags/v0.99.beta14
@@ -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 | |||
@@ -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 <slang/slang.h> | |||
# else | |||
# include <slang.h> | |||
# endif | |||
#endif | |||
#if defined(USE_NCURSES) | |||
# if defined(HAVE_NCURSES_H) | |||
# include <ncurses.h> | |||
# else | |||
# include <curses.h> | |||
# endif | |||
#endif | |||
#if defined(USE_CONIO) | |||
# include <dos.h> | |||
# include <conio.h> | |||
#endif | |||
#if defined(USE_X11) | |||
# include <X11/Xlib.h> | |||
#endif | |||
#if defined(USE_WIN32) | |||
# include <windows.h> | |||
#endif | |||
#if defined(USE_GL) | |||
# include <GL/gl.h> | |||
#endif | |||
#include <stdlib.h> | |||
#include <string.h> | |||
@@ -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); | |||
@@ -20,8 +20,21 @@ | |||
#ifndef __CACA_INTERNALS_H__ | |||
#define __CACA_INTERNALS_H__ | |||
#if defined(USE_GL) | |||
# include <GL/glut.h> | |||
#endif | |||
#if defined(USE_NCURSES) | |||
# if defined(HAVE_NCURSES_H) | |||
# include <ncurses.h> | |||
# else | |||
# include <curses.h> | |||
# endif | |||
#endif | |||
#if defined(USE_WIN32) | |||
# include <windows.h> | |||
#endif | |||
#if defined(USE_X11) | |||
#include <X11/Xlib.h> | |||
# include <X11/Xlib.h> | |||
#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 <windows.h> | |||
extern HANDLE win32_hin, win32_hout; | |||
#endif | |||
#if defined(USE_GL) | |||
#include <GL/glut.h> | |||
extern unsigned int gl_width, gl_height; | |||
#endif | |||
#endif /* __CACA_INTERNALS_H__ */ |
@@ -0,0 +1,148 @@ | |||
/* | |||
* libcaca ASCII-Art library | |||
* Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org> | |||
* 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 <sam@zoy.org> | |||
* \brief Character drawing | |||
* | |||
* This file contains character and string drawing functions. | |||
*/ | |||
#include "config.h" | |||
#if defined(HAVE_INTTYPES_H) || defined(_DOXYGEN_SKIP_ME) | |||
# include <inttypes.h> | |||
#else | |||
typedef unsigned int uint32_t; | |||
typedef unsigned char uint8_t; | |||
#endif | |||
#if defined(USE_CONIO) | |||
#include <dos.h> | |||
#include <conio.h> | |||
#if defined(SCREENUPDATE_IN_PC_H) | |||
# include <pc.h> | |||
#endif | |||
#include <string.h> | |||
#include <stdlib.h> | |||
#if defined(HAVE_UNISTD_H) | |||
# include <unistd.h> | |||
#endif | |||
#include <stdarg.h> | |||
#if defined(HAVE_SYS_IOCTL_H) | |||
# include <sys/ioctl.h> | |||
#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 */ | |||
@@ -0,0 +1,378 @@ | |||
/* | |||
* libcaca ASCII-Art library | |||
* Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org> | |||
* 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 <sam@zoy.org> | |||
* \brief Character drawing | |||
* | |||
* This file contains character and string drawing functions. | |||
*/ | |||
#include "config.h" | |||
#if defined(HAVE_INTTYPES_H) || defined(_DOXYGEN_SKIP_ME) | |||
# include <inttypes.h> | |||
#else | |||
typedef unsigned int uint32_t; | |||
typedef unsigned char uint8_t; | |||
#endif | |||
#if defined(USE_GL) | |||
#include <GL/gl.h> | |||
#include <GL/glut.h> | |||
#include <GL/freeglut_ext.h> | |||
#include <stdio.h> /* BUFSIZ */ | |||
#include <string.h> | |||
#include <stdlib.h> | |||
#if defined(HAVE_UNISTD_H) | |||
# include <unistd.h> | |||
#endif | |||
#include <stdarg.h> | |||
#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 */ | |||
@@ -0,0 +1,256 @@ | |||
/* | |||
* libcaca ASCII-Art library | |||
* Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org> | |||
* 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 <sam@zoy.org> | |||
* \brief Character drawing | |||
* | |||
* This file contains character and string drawing functions. | |||
*/ | |||
#include "config.h" | |||
#if defined(HAVE_INTTYPES_H) || defined(_DOXYGEN_SKIP_ME) | |||
# include <inttypes.h> | |||
#else | |||
typedef unsigned int uint32_t; | |||
typedef unsigned char uint8_t; | |||
#endif | |||
#if defined(USE_NCURSES) | |||
#if defined(HAVE_NCURSES_H) | |||
# include <ncurses.h> | |||
#else | |||
# include <curses.h> | |||
#endif | |||
#include <stdio.h> /* BUFSIZ */ | |||
#include <string.h> | |||
#include <stdlib.h> | |||
#if defined(HAVE_UNISTD_H) | |||
# include <unistd.h> | |||
#endif | |||
#include <stdarg.h> | |||
#if defined(HAVE_SIGNAL_H) | |||
# include <signal.h> | |||
#endif | |||
#if defined(HAVE_SYS_IOCTL_H) | |||
# include <sys/ioctl.h> | |||
#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 */ | |||
@@ -0,0 +1,342 @@ | |||
/* | |||
* libcaca ASCII-Art library | |||
* Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org> | |||
* 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 <sam@zoy.org> | |||
* \brief Character drawing | |||
* | |||
* This file contains character and string drawing functions. | |||
*/ | |||
#include "config.h" | |||
#if defined(HAVE_INTTYPES_H) || defined(_DOXYGEN_SKIP_ME) | |||
# include <inttypes.h> | |||
#else | |||
typedef unsigned int uint32_t; | |||
typedef unsigned char uint8_t; | |||
#endif | |||
#if defined(USE_SLANG) | |||
#if defined(HAVE_SLANG_SLANG_H) | |||
# include <slang/slang.h> | |||
#else | |||
# include <slang.h> | |||
#endif | |||
#include <stdio.h> /* BUFSIZ */ | |||
#include <string.h> | |||
#include <stdlib.h> | |||
#if defined(HAVE_UNISTD_H) | |||
# include <unistd.h> | |||
#endif | |||
#include <stdarg.h> | |||
#if defined(HAVE_SIGNAL_H) | |||
# include <signal.h> | |||
#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 */ | |||
@@ -0,0 +1,255 @@ | |||
/* | |||
* libcaca ASCII-Art library | |||
* Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org> | |||
* 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 <sam@zoy.org> | |||
* \brief Character drawing | |||
* | |||
* This file contains character and string drawing functions. | |||
*/ | |||
#include "config.h" | |||
#if defined(HAVE_INTTYPES_H) || defined(_DOXYGEN_SKIP_ME) | |||
# include <inttypes.h> | |||
#else | |||
typedef unsigned int uint32_t; | |||
typedef unsigned char uint8_t; | |||
#endif | |||
#if defined(USE_WIN32) | |||
#include <windows.h> | |||
#include <stdio.h> /* BUFSIZ */ | |||
#include <string.h> | |||
#include <stdlib.h> | |||
#if defined(HAVE_UNISTD_H) | |||
# include <unistd.h> | |||
#endif | |||
#include <stdarg.h> | |||
#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 */ | |||
@@ -0,0 +1,363 @@ | |||
/* | |||
* libcaca ASCII-Art library | |||
* Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org> | |||
* 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 <sam@zoy.org> | |||
* \brief Character drawing | |||
* | |||
* This file contains character and string drawing functions. | |||
*/ | |||
#include "config.h" | |||
#if defined(HAVE_INTTYPES_H) || defined(_DOXYGEN_SKIP_ME) | |||
# include <inttypes.h> | |||
#else | |||
typedef unsigned int uint32_t; | |||
typedef unsigned char uint8_t; | |||
#endif | |||
#if defined(USE_X11) | |||
#include <X11/Xlib.h> | |||
#if defined(HAVE_X11_XKBLIB_H) | |||
# include <X11/XKBlib.h> | |||
#endif | |||
#include <stdio.h> /* BUFSIZ */ | |||
#include <string.h> | |||
#include <stdlib.h> | |||
#if defined(HAVE_UNISTD_H) | |||
# include <unistd.h> | |||
#endif | |||
#include <stdarg.h> | |||
#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 */ | |||
@@ -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(); | |||