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 \ | graphics.c \ | ||||
event.c \ | event.c \ | ||||
time.c \ | time.c \ | ||||
driver_conio.c \ | |||||
driver_gl.c \ | |||||
driver_ncurses.c \ | |||||
driver_slang.c \ | |||||
driver_win32.c \ | |||||
driver_x11.c \ | |||||
$(NULL) | $(NULL) | ||||
libcaca_la_CPPFLAGS = -I$(top_srcdir)/cucul | libcaca_la_CPPFLAGS = -I$(top_srcdir)/cucul | ||||
libcaca_la_LDFLAGS = -no-undefined | libcaca_la_LDFLAGS = -no-undefined | ||||
@@ -28,33 +28,6 @@ typedef unsigned int uint32_t; | |||||
typedef unsigned char uint8_t; | typedef unsigned char uint8_t; | ||||
#endif | #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 <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
@@ -63,138 +36,33 @@ typedef unsigned char uint8_t; | |||||
#include "caca.h" | #include "caca.h" | ||||
#include "caca_internals.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); | 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) | caca_t * caca_attach(cucul_t * qq) | ||||
{ | { | ||||
int ret; | |||||
caca_t *kk = malloc(sizeof(caca_t)); | 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 */ | /* Initialise events stuff */ | ||||
@@ -204,9 +72,6 @@ caca_t * caca_attach(cucul_t * qq) | |||||
kk->events.autorepeat_ticks = 0; | kk->events.autorepeat_ticks = 0; | ||||
kk->events.last_key = 0; | kk->events.last_key = 0; | ||||
qq->refcount++; | |||||
kk->qq = qq; | |||||
kk->timer.last_sec = 0; | kk->timer.last_sec = 0; | ||||
kk->timer.last_usec = 0; | kk->timer.last_usec = 0; | ||||
kk->lastticks = 0; | kk->lastticks = 0; | ||||
@@ -214,81 +79,13 @@ caca_t * caca_attach(cucul_t * qq) | |||||
kk->resize = 0; | kk->resize = 0; | ||||
kk->resize_event = 0; | kk->resize_event = 0; | ||||
if(_caca_init_graphics(kk)) | |||||
return NULL; | |||||
return kk; | return kk; | ||||
} | } | ||||
void caca_detach(caca_t *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--; | kk->qq->refcount--; | ||||
free(kk); | free(kk); | ||||
} | } | ||||
@@ -296,7 +93,7 @@ void caca_detach(caca_t *kk) | |||||
* XXX: The following functions are local. | * 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) | #if defined(HAVE_GETENV) && defined(HAVE_STRCASECMP) | ||||
char *var = getenv("CACA_DRIVER"); | char *var = getenv("CACA_DRIVER"); | ||||
@@ -306,56 +103,55 @@ static void caca_init_driver(caca_t *kk) | |||||
{ | { | ||||
#if defined(USE_WIN32) | #if defined(USE_WIN32) | ||||
if(!strcasecmp(var, "win32")) | if(!strcasecmp(var, "win32")) | ||||
kk->driver = CACA_DRIVER_WIN32; | |||||
win32_init_driver(kk); | |||||
else | else | ||||
#endif | #endif | ||||
#if defined(USE_CONIO) | #if defined(USE_CONIO) | ||||
if(!strcasecmp(var, "conio")) | if(!strcasecmp(var, "conio")) | ||||
kk->driver = CACA_DRIVER_CONIO; | |||||
conio_init_driver(kk); | |||||
else | else | ||||
#endif | #endif | ||||
#if defined(USE_X11) | #if defined(USE_X11) | ||||
if(!strcasecmp(var, "x11")) | if(!strcasecmp(var, "x11")) | ||||
kk->driver = CACA_DRIVER_X11; | |||||
x11_init_driver(kk); | |||||
else | else | ||||
#endif | #endif | ||||
#if defined(USE_GL) | #if defined(USE_GL) | ||||
if(!strcasecmp(var, "gl")) | if(!strcasecmp(var, "gl")) | ||||
kk->driver = CACA_DRIVER_GL; | |||||
gl_init_driver(kk); | |||||
else | else | ||||
#endif | #endif | ||||
#if defined(USE_SLANG) | #if defined(USE_SLANG) | ||||
if(!strcasecmp(var, "slang")) | if(!strcasecmp(var, "slang")) | ||||
kk->driver = CACA_DRIVER_SLANG; | |||||
slang_init_driver(kk); | |||||
else | else | ||||
#endif | #endif | ||||
#if defined(USE_NCURSES) | #if defined(USE_NCURSES) | ||||
if(!strcasecmp(var, "ncurses")) | if(!strcasecmp(var, "ncurses")) | ||||
kk->driver = CACA_DRIVER_NCURSES; | |||||
ncurses_init_driver(kk); | |||||
else | else | ||||
#endif | #endif | ||||
return -1; | |||||
kk->driver = CACA_DRIVER_NONE; | |||||
return; | |||||
return 0; | |||||
} | } | ||||
#endif | #endif | ||||
#if defined(USE_WIN32) | #if defined(USE_WIN32) | ||||
kk->driver = CACA_DRIVER_WIN32; | |||||
return; | |||||
win32_init_driver(kk); | |||||
return 0; | |||||
#endif | #endif | ||||
#if defined(USE_CONIO) | #if defined(USE_CONIO) | ||||
kk->driver = CACA_DRIVER_CONIO; | |||||
return; | |||||
conio_init_driver(kk); | |||||
return 0; | |||||
#endif | #endif | ||||
#if defined(USE_X11) | #if defined(USE_X11) | ||||
#if defined(HAVE_GETENV) | #if defined(HAVE_GETENV) | ||||
if(getenv("DISPLAY") && *(getenv("DISPLAY"))) | if(getenv("DISPLAY") && *(getenv("DISPLAY"))) | ||||
#endif | #endif | ||||
{ | { | ||||
kk->driver = CACA_DRIVER_X11; | |||||
return; | |||||
x11_init_driver(kk); | |||||
return 0; | |||||
} | } | ||||
#endif | #endif | ||||
#if defined(USE_GL) | #if defined(USE_GL) | ||||
@@ -363,21 +159,20 @@ static void caca_init_driver(caca_t *kk) | |||||
if(getenv("DISPLAY") && *(getenv("DISPLAY"))) | if(getenv("DISPLAY") && *(getenv("DISPLAY"))) | ||||
#endif | #endif | ||||
{ | { | ||||
kk->driver = CACA_DRIVER_GL; | |||||
return; | |||||
gl_init_driver(kk); | |||||
return 0; | |||||
} | } | ||||
#endif | #endif | ||||
#if defined(USE_SLANG) | #if defined(USE_SLANG) | ||||
kk->driver = CACA_DRIVER_SLANG; | |||||
return; | |||||
slang_init_driver(kk); | |||||
return 0; | |||||
#endif | #endif | ||||
#if defined(USE_NCURSES) | #if defined(USE_NCURSES) | ||||
kk->driver = CACA_DRIVER_NCURSES; | |||||
return; | |||||
slang_init_driver(kk); | |||||
return 0; | |||||
#endif | #endif | ||||
kk->driver = CACA_DRIVER_NONE; | |||||
return; | |||||
return -1; | |||||
} | } | ||||
static void caca_init_terminal(caca_t *kk) | static void caca_init_terminal(caca_t *kk) | ||||
@@ -388,10 +183,10 @@ static void caca_init_terminal(caca_t *kk) | |||||
#endif | #endif | ||||
#if defined(USE_SLANG) | #if defined(USE_SLANG) | ||||
if(kk->driver != CACA_DRIVER_SLANG) | |||||
if(kk->driver.driver != CACA_DRIVER_SLANG) | |||||
#endif | #endif | ||||
#if defined(USE_NCURSES) | #if defined(USE_NCURSES) | ||||
if(kk->driver != CACA_DRIVER_NCURSES) | |||||
if(kk->driver.driver != CACA_DRIVER_NCURSES) | |||||
#endif | #endif | ||||
return; | return; | ||||
@@ -406,7 +201,7 @@ static void caca_init_terminal(caca_t *kk) | |||||
if(colorterm && !strcmp(colorterm, "gnome-terminal")) | if(colorterm && !strcmp(colorterm, "gnome-terminal")) | ||||
{ | { | ||||
#if defined(USE_NCURSES) | #if defined(USE_NCURSES) | ||||
if(kk->driver == CACA_DRIVER_NCURSES) | |||||
if(kk->driver.driver == CACA_DRIVER_NCURSES) | |||||
{ | { | ||||
SCREEN *screen; | SCREEN *screen; | ||||
screen = newterm("xterm-16color", stdout, stdin); | screen = newterm("xterm-16color", stdout, stdin); | ||||
@@ -424,7 +219,7 @@ static void caca_init_terminal(caca_t *kk) | |||||
if(other) | if(other) | ||||
{ | { | ||||
#if defined(USE_NCURSES) | #if defined(USE_NCURSES) | ||||
if(kk->driver == CACA_DRIVER_NCURSES) | |||||
if(kk->driver.driver == CACA_DRIVER_NCURSES) | |||||
{ | { | ||||
SCREEN *screen; | SCREEN *screen; | ||||
screen = newterm("xterm-16color", stdout, stdin); | screen = newterm("xterm-16color", stdout, stdin); | ||||
@@ -20,8 +20,21 @@ | |||||
#ifndef __CACA_INTERNALS_H__ | #ifndef __CACA_INTERNALS_H__ | ||||
#define __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) | #if defined(USE_X11) | ||||
#include <X11/Xlib.h> | |||||
# include <X11/Xlib.h> | |||||
#endif | #endif | ||||
/* Graphics driver */ | /* Graphics driver */ | ||||
@@ -48,6 +61,26 @@ enum caca_driver | |||||
CACA_DRIVER_NONE = 0 | 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 */ | /* Timer structure */ | ||||
struct caca_timer | struct caca_timer | ||||
{ | { | ||||
@@ -59,7 +92,19 @@ struct caca_context | |||||
{ | { | ||||
cucul_t *qq; | 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; | unsigned int width, height; | ||||
int resize; | int resize; | ||||
@@ -102,6 +147,7 @@ struct caca_context | |||||
struct ncurses | struct ncurses | ||||
{ | { | ||||
int attr[16*16]; | int attr[16*16]; | ||||
mmask_t oldmask; | |||||
} ncurses; | } ncurses; | ||||
#endif | #endif | ||||
#if defined(USE_CONIO) | #if defined(USE_CONIO) | ||||
@@ -156,15 +202,4 @@ extern unsigned int _caca_height; | |||||
extern int _caca_resize; | extern int _caca_resize; | ||||
extern int _caca_resize_event; | 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__ */ | #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); | event = _lowlevel_event(kk); | ||||
#if defined(USE_SLANG) | #if defined(USE_SLANG) | ||||
if(kk->driver != CACA_DRIVER_SLANG) | |||||
if(kk->driver.driver != CACA_DRIVER_SLANG) | |||||
#endif | #endif | ||||
#if defined(USE_NCURSES) | #if defined(USE_NCURSES) | ||||
if(kk->driver != CACA_DRIVER_NCURSES) | |||||
if(kk->driver.driver != CACA_DRIVER_NCURSES) | |||||
#endif | #endif | ||||
return event; | return event; | ||||
@@ -256,7 +256,7 @@ static unsigned int _lowlevel_event(caca_t *kk) | |||||
#if defined(USE_X11) | #if defined(USE_X11) | ||||
/* The X11 event check routine */ | /* The X11 event check routine */ | ||||
if(kk->driver == CACA_DRIVER_X11) | |||||
if(kk->driver.driver == CACA_DRIVER_X11) | |||||
{ | { | ||||
XEvent xevent; | XEvent xevent; | ||||
char key; | char key; | ||||
@@ -372,7 +372,7 @@ static unsigned int _lowlevel_event(caca_t *kk) | |||||
else | else | ||||
#endif | #endif | ||||
#if defined(USE_NCURSES) | #if defined(USE_NCURSES) | ||||
if(kk->driver == CACA_DRIVER_NCURSES) | |||||
if(kk->driver.driver == CACA_DRIVER_NCURSES) | |||||
{ | { | ||||
int intkey; | int intkey; | ||||
@@ -556,7 +556,7 @@ static unsigned int _lowlevel_event(caca_t *kk) | |||||
else | else | ||||
#endif | #endif | ||||
#if defined(USE_SLANG) | #if defined(USE_SLANG) | ||||
if(kk->driver == CACA_DRIVER_SLANG) | |||||
if(kk->driver.driver == CACA_DRIVER_SLANG) | |||||
{ | { | ||||
int intkey; | int intkey; | ||||
@@ -639,7 +639,7 @@ static unsigned int _lowlevel_event(caca_t *kk) | |||||
else | else | ||||
#endif | #endif | ||||
#if defined(USE_CONIO) | #if defined(USE_CONIO) | ||||
if(kk->driver == CACA_DRIVER_CONIO) | |||||
if(kk->driver.driver == CACA_DRIVER_CONIO) | |||||
{ | { | ||||
if(!_conio_kbhit()) | if(!_conio_kbhit()) | ||||
return CACA_EVENT_NONE; | return CACA_EVENT_NONE; | ||||
@@ -651,7 +651,7 @@ static unsigned int _lowlevel_event(caca_t *kk) | |||||
else | else | ||||
#endif | #endif | ||||
#if defined(USE_WIN32) | #if defined(USE_WIN32) | ||||
if(kk->driver == CACA_DRIVER_WIN32) | |||||
if(kk->driver.driver == CACA_DRIVER_WIN32) | |||||
{ | { | ||||
INPUT_RECORD rec; | INPUT_RECORD rec; | ||||
DWORD num; | DWORD num; | ||||
@@ -725,7 +725,7 @@ static unsigned int _lowlevel_event(caca_t *kk) | |||||
else | else | ||||
#endif | #endif | ||||
#if defined(USE_GL) | #if defined(USE_GL) | ||||
if(kk->driver == CACA_DRIVER_GL) | |||||
if(kk->driver.driver == CACA_DRIVER_GL) | |||||
{ | { | ||||
glutMainLoopEvent(); | glutMainLoopEvent(); | ||||