Przeglądaj źródła

* Split caca/graphics.c into driver-specific files. Resize is currently

broken, and event handling is not yet in the driver-specific files, but
    I will of course fix that later.
tags/v0.99.beta14
Sam Hocevar sam 19 lat temu
rodzic
commit
34764ae68a
11 zmienionych plików z 1854 dodań i 1450 usunięć
  1. +6
    -0
      caca/Makefile.am
  2. +41
    -246
      caca/caca.c
  3. +48
    -13
      caca/caca_internals.h
  4. +148
    -0
      caca/driver_conio.c
  5. +378
    -0
      caca/driver_gl.c
  6. +256
    -0
      caca/driver_ncurses.c
  7. +342
    -0
      caca/driver_slang.c
  8. +255
    -0
      caca/driver_win32.c
  9. +363
    -0
      caca/driver_x11.c
  10. +8
    -8
      caca/event.c
  11. +9
    -1183
      caca/graphics.c

+ 6
- 0
caca/Makefile.am Wyświetl plik

@@ -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


+ 41
- 246
caca/caca.c Wyświetl plik

@@ -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);


+ 48
- 13
caca/caca_internals.h Wyświetl plik

@@ -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__ */

+ 148
- 0
caca/driver_conio.c Wyświetl plik

@@ -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 */


+ 378
- 0
caca/driver_gl.c Wyświetl plik

@@ -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 */


+ 256
- 0
caca/driver_ncurses.c Wyświetl plik

@@ -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 */


+ 342
- 0
caca/driver_slang.c Wyświetl plik

@@ -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 */


+ 255
- 0
caca/driver_win32.c Wyświetl plik

@@ -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 */


+ 363
- 0
caca/driver_x11.c Wyświetl plik

@@ -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 */


+ 8
- 8
caca/event.c Wyświetl plik

@@ -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();



+ 9
- 1183
caca/graphics.c
Plik diff jest za duży
Wyświetl plik


Ładowanie…
Anuluj
Zapisz