source: libcaca/trunk/src/graphics.c @ 251

Last change on this file since 251 was 251, checked in by Sam Hocevar, 19 years ago
  • src/graphics.c src/io.c: + Beginning of an X11 driver. Currently we merely open the window and

check keyboard events.

  • Property svn:keywords set to Id
File size: 11.4 KB
Line 
1/*
2 *   libcaca       ASCII-Art library
3 *   Copyright (c) 2002, 2003 Sam Hocevar <sam@zoy.org>
4 *                 All Rights Reserved
5 *
6 *   This library is free software; you can redistribute it and/or
7 *   modify it under the terms of the GNU Lesser General Public
8 *   License as published by the Free Software Foundation; either
9 *   version 2 of the License, or (at your option) any later version.
10 *
11 *   This library is distributed in the hope that it will be useful,
12 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 *   Lesser General Public License for more details.
15 *
16 *   You should have received a copy of the GNU Lesser General Public
17 *   License along with this library; if not, write to the Free Software
18 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 *   02111-1307  USA
20 */
21
22/**  \file graphics.c
23 *   \version \$Id: graphics.c 251 2003-12-15 10:38:03Z sam $
24 *   \author Sam Hocevar <sam@zoy.org>
25 *   \brief Character drawing functions
26 *
27 *   This file contains character and string drawing functions.
28 */
29
30#include "config.h"
31
32#if defined(USE_SLANG)
33#   include <slang.h>
34#elif defined(USE_NCURSES)
35#   include <curses.h>
36#elif defined(USE_CONIO)
37#   include <conio.h>
38#   if defined(SCREENUPDATE_IN_PC_H)
39#       include <pc.h>
40#   endif
41#elif defined(USE_X11)
42#   include <X11/Xlib.h>
43#else
44#   error "no graphics library detected"
45#endif
46
47#ifdef HAVE_INTTYPES_H
48#   include <inttypes.h>
49#endif
50
51#include <stdio.h> /* BUFSIZ */
52#include <string.h>
53#include <stdlib.h>
54#include <unistd.h>
55#include <stdarg.h>
56#include <sys/time.h>
57#include <time.h>
58
59#include "caca.h"
60#include "caca_internals.h"
61
62/*
63 * Global variables
64 */
65unsigned int _caca_width;
66unsigned int _caca_height;
67
68/*
69 * Local variables
70 */
71#if defined(USE_NCURSES)
72static int _caca_attr[16*16];
73#endif
74
75#if defined(USE_CONIO)
76static struct text_info ti;
77static char *_caca_screen;
78#endif
79
80#if defined(USE_X11)
81Display *_caca_dpy;
82Window _caca_window;
83GC _caca_gc;
84#endif
85
86static char *_caca_empty_line;
87static char *_caca_scratch_line;
88
89static unsigned int _caca_delay;
90static unsigned int _caca_rendertime;
91
92static enum caca_color _caca_fgcolor = CACA_COLOR_LIGHTGRAY;
93static enum caca_color _caca_bgcolor = CACA_COLOR_BLACK;
94
95void caca_set_color(enum caca_color fgcolor, enum caca_color bgcolor)
96{
97    if(fgcolor < 0 || fgcolor > 15 || bgcolor < 0 || bgcolor > 15)
98        return;
99
100    _caca_fgcolor = fgcolor;
101    _caca_bgcolor = bgcolor;
102#if defined(USE_SLANG)
103    SLsmg_set_color((bgcolor + 16 * fgcolor) /*% 128*/);
104#elif defined(USE_NCURSES)
105    attrset(_caca_attr[fgcolor + 16 * bgcolor]);
106#elif defined(USE_CONIO)
107    textbackground(bgcolor);
108    textcolor(fgcolor);
109#elif defined(USE_X11)
110    /* FIXME */
111#endif
112}
113
114enum caca_color caca_get_fg_color(void)
115{
116    return _caca_fgcolor;
117}
118
119enum caca_color caca_get_bg_color(void)
120{
121    return _caca_bgcolor;
122}
123
124void caca_putchar(int x, int y, char c)
125{
126#if defined(USE_CONIO)
127    char *data;
128#endif
129    if(x < 0 || x >= (int)_caca_width ||
130       y < 0 || y >= (int)_caca_height)
131        return;
132
133#if defined(USE_SLANG)
134    SLsmg_gotorc(y, x);
135    SLsmg_write_char(c);
136#elif defined(USE_NCURSES)
137    move(y, x);
138    addch(c);
139#elif defined(USE_CONIO)
140    data = _caca_screen + 2 * (x + y * _caca_width);
141    data[0] = c;
142    data[1] = (_caca_bgcolor << 4) | _caca_fgcolor;
143//    gotoxy(x + 1, y + 1);
144//    putch(c);
145#elif defined(USE_X11)
146    /* FIXME */
147#endif
148}
149
150void caca_putstr(int x, int y, const char *s)
151{
152    unsigned int len;
153
154    if(y < 0 || y >= (int)_caca_height || x >= (int)_caca_width)
155        return;
156
157    len = strlen(s);
158
159    if(x < 0)
160    {
161        len -= -x;
162        if(len < 0)
163            return;
164        s += -x;
165        x = 0;
166    }
167
168    if(x + len >= _caca_width)
169    {
170        memcpy(_caca_scratch_line, s, _caca_width - x);
171        _caca_scratch_line[_caca_width - x] = '\0';
172        s = _caca_scratch_line;
173    }
174
175#if defined(USE_SLANG)
176    SLsmg_gotorc(y, x);
177    SLsmg_write_string((char *)(intptr_t)s);
178#elif defined(USE_NCURSES)
179    move(y, x);
180    addstr(s);
181#elif defined(USE_CONIO)
182    char *buf = _caca_screen + 2 * (x + y * _caca_width);
183    while(*s)
184    {
185        *buf++ = *s++;
186        *buf++ = (_caca_bgcolor << 4) | _caca_fgcolor;
187    }
188//    gotoxy(x + 1, y + 1);
189//    cputs(s);
190#elif defined(USE_X11)
191    /* FIXME */
192#endif
193}
194
195void caca_printf(int x, int y, const char *format, ...)
196{
197    char tmp[BUFSIZ];
198    char *buf = tmp;
199    va_list args;
200
201    if(y < 0 || y >= (int)_caca_height || x >= (int)_caca_width)
202        return;
203
204    if(_caca_width - x + 1 > BUFSIZ)
205        buf = malloc(_caca_width - x + 1);
206
207    va_start(args, format);
208#if defined(HAVE_VSNPRINTF)
209    vsnprintf(buf, _caca_width - x + 1, format, args);
210#else
211    vsprintf(buf, format, args);
212#endif
213    buf[_caca_width - x] = '\0';
214    va_end(args);
215
216    caca_putstr(x, y, buf);
217
218    if(buf != tmp)
219        free(buf);
220}
221
222void caca_clear(void)
223{
224    enum caca_color oldfg = caca_get_fg_color();
225    enum caca_color oldbg = caca_get_bg_color();
226    int y = _caca_height;
227
228    caca_set_color(CACA_COLOR_LIGHTGRAY, CACA_COLOR_BLACK);
229
230    /* We could use SLsmg_cls() etc., but drawing empty lines is much faster */
231    while(y--)
232        caca_putstr(0, y, _caca_empty_line);
233
234    caca_set_color(oldfg, oldbg);
235}
236
237int _caca_init_graphics(void)
238{
239#if defined(USE_SLANG)
240    /* See SLang ref., 5.4.4. */
241    static char *slang_colors[16] =
242    {
243        /* Standard colours */
244        "black",
245        "blue",
246        "green",
247        "cyan",
248        "red",
249        "magenta",
250        "brown",
251        "lightgray",
252        /* Bright colours */
253        "gray",
254        "brightblue",
255        "brightgreen",
256        "brightcyan",
257        "brightred",
258        "brightmagenta",
259        "yellow",
260        "white",
261    };
262
263    int fg, bg;
264
265    for(fg = 0; fg < 16; fg++)
266        for(bg = 0; bg < 16; bg++)
267        {
268            int i = bg + 16 * fg;
269            SLtt_set_color(i, NULL, slang_colors[fg], slang_colors[bg]);
270        }
271
272    /* Disable alt charset support so that we get all 256 colour pairs */
273    SLtt_Has_Alt_Charset = 0;
274
275    _caca_width = SLtt_Screen_Cols;
276    _caca_height = SLtt_Screen_Rows;
277
278#elif defined(USE_NCURSES)
279    static int curses_colors[] =
280    {
281        /* Standard curses colours */
282        COLOR_BLACK,
283        COLOR_BLUE,
284        COLOR_GREEN,
285        COLOR_CYAN,
286        COLOR_RED,
287        COLOR_MAGENTA,
288        COLOR_YELLOW,
289        COLOR_WHITE,
290        /* Extra values for xterm-16color */
291        COLOR_BLACK + 8,
292        COLOR_BLUE + 8,
293        COLOR_GREEN + 8,
294        COLOR_CYAN + 8,
295        COLOR_RED + 8,
296        COLOR_MAGENTA + 8,
297        COLOR_YELLOW + 8,
298        COLOR_WHITE + 8
299    };
300
301    int fg, bg, max;
302
303    /* Activate colour */
304    start_color();
305
306    /* If COLORS == 16, it means the terminal supports full bright colours
307     * using setab and setaf (will use \e[90m \e[91m etc. for colours >= 8),
308     * we can build 16*16 colour pairs.
309     * If COLORS == 8, it means the terminal does not know about bright
310     * colours and we need to get them through A_BOLD and A_BLINK (\e[1m
311     * and \e[5m). We can only build 8*8 colour pairs. */
312    max = COLORS >= 16 ? 16 : 8;
313
314    for(bg = 0; bg < max; bg++)
315        for(fg = 0; fg < max; fg++)
316        {
317            /* Use ((max + 7 - fg) % max) instead of fg so that colour 0
318             * is light gray on black, since some terminals don't like
319             * this colour pair to be redefined. */
320            int col = ((max + 7 - fg) % max) + max * bg;
321            init_pair(col, curses_colors[fg], curses_colors[bg]);
322            _caca_attr[fg + 16 * bg] = COLOR_PAIR(col);
323
324            if(max == 8)
325            {
326                /* Bright fg on simple bg */
327                _caca_attr[fg + 8 + 16 * bg] = A_BOLD | COLOR_PAIR(col);
328                /* Simple fg on bright bg */
329                _caca_attr[fg + 16 * (bg + 8)] = A_BLINK | COLOR_PAIR(col);
330                /* Bright fg on bright bg */
331                _caca_attr[fg + 8 + 16 * (bg + 8)] = A_BLINK | A_BOLD
332                                                             | COLOR_PAIR(col);
333            }
334        }
335
336    _caca_width = COLS;
337    _caca_height = LINES;
338
339#elif defined(USE_CONIO)
340    gettextinfo(&ti);
341    _caca_screen = malloc(2 * ti.screenwidth * ti.screenheight);
342    if(_caca_screen == NULL)
343        return -1;
344#   if defined(SCREENUPDATE_IN_PC_H)
345    ScreenRetrieve(_caca_screen);
346#   else
347    /* FIXME */
348#   endif
349    _caca_width = ti.screenwidth;
350    _caca_height = ti.screenheight;
351
352#elif defined(USE_X11)
353    int black_color;
354    int white_color;
355
356    _caca_dpy = XOpenDisplay(NULL);
357    if(_caca_dpy == NULL)
358        return -1;
359
360    black_color = BlackPixel(_caca_dpy, DefaultScreen(_caca_dpy));
361    white_color = WhitePixel(_caca_dpy, DefaultScreen(_caca_dpy));
362
363    _caca_window = XCreateSimpleWindow(_caca_dpy, DefaultRootWindow(_caca_dpy),
364                                       0, 0, 400, 300, 0,
365                                       black_color, black_color);
366    XSelectInput(_caca_dpy, _caca_window, StructureNotifyMask);
367    XMapWindow(_caca_dpy, _caca_window);
368
369    _caca_gc = XCreateGC(_caca_dpy, _caca_window, 0, NULL);
370    XSetForeground(_caca_dpy, _caca_gc, white_color);
371
372    for(;;)
373    {
374        XEvent event;
375        XNextEvent(_caca_dpy, &event);
376        if (event.type == MapNotify)
377            break;
378    }
379
380    XSelectInput(_caca_dpy, _caca_window, KeyPressMask);
381
382    /* FIXME */
383    _caca_width = 80;
384    _caca_height = 24;
385
386    XSync(_caca_dpy, False);
387
388#endif
389    _caca_empty_line = malloc(_caca_width + 1);
390    memset(_caca_empty_line, ' ', _caca_width);
391    _caca_empty_line[_caca_width] = '\0';
392
393    _caca_scratch_line = malloc(_caca_width + 1);
394
395    _caca_delay = 0;
396    _caca_rendertime = 0;
397
398    return 0;
399}
400
401int _caca_end_graphics(void)
402{
403#if defined(USE_SLANG)
404    /* Nothing to do */
405#elif defined(USE_NCURSES)
406    /* Nothing to do */
407#elif defined(USE_CONIO)
408    free(_caca_screen);
409#elif defined(USE_X11)
410    XSync(_caca_dpy, False);
411    XFreeGC(_caca_dpy, _caca_gc);
412    XUnmapWindow(_caca_dpy, _caca_window);
413    XDestroyWindow(_caca_dpy, _caca_window);
414    XCloseDisplay(_caca_dpy);
415#endif
416    free(_caca_empty_line);
417
418    return 0;
419}
420
421void caca_set_delay(unsigned int usec)
422{
423    _caca_delay = usec;
424}
425
426unsigned int caca_get_rendertime(void)
427{
428    return _caca_rendertime;
429}
430
431static unsigned int _caca_getticks(void)
432{
433    static unsigned int last_sec = 0, last_usec = 0;
434
435    struct timeval tv;
436    unsigned int ticks = 0;
437
438    gettimeofday(&tv, NULL);
439
440    if(last_sec != 0)
441    {
442        ticks = (tv.tv_sec - last_sec) * 1000000 + (tv.tv_usec - last_usec);
443    }
444
445    last_sec = tv.tv_sec;
446    last_usec = tv.tv_usec;
447
448    return ticks;
449}
450
451void caca_refresh(void)
452{
453#define IDLE_USEC 10000
454    static int lastticks = 0;
455    int ticks = lastticks + _caca_getticks();
456
457#if defined(USE_SLANG)
458    SLsmg_refresh();
459#elif defined(USE_NCURSES)
460    refresh();
461#elif defined(USE_CONIO)
462#   if defined(SCREENUPDATE_IN_PC_H)
463    ScreenUpdate(_caca_screen);
464#   else
465    /* FIXME */
466#   endif
467#elif defined(USE_X11)
468    /* FIXME */
469    XFlush(_caca_dpy);
470#endif
471
472    /* Wait until _caca_delay + time of last call */
473    ticks += _caca_getticks();
474    for(; ticks + IDLE_USEC < (int)_caca_delay; ticks += _caca_getticks())
475        usleep(IDLE_USEC);
476
477    /* Update the sliding mean of the render time */
478    _caca_rendertime = (7 * _caca_rendertime + ticks) / 8;
479
480    lastticks = ticks - _caca_delay;
481
482    /* If we drifted too much, it's bad, bad, bad. */
483    if(lastticks > (int)_caca_delay)
484        lastticks = 0;
485}
486
Note: See TracBrowser for help on using the repository browser.