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

Last change on this file since 231 was 231, checked in by Sam Hocevar, 18 years ago
  • configure.ac: + Default to ncurses, not slang, because slang only has 128 colour pairs.
  • src/caca.c: + Disable scrolling to avoid hashmap scrolling optimization code.
  • src/graphics.c: + Swap fg and bg in the colour pair indexing, so that bg is always

right.

+ Disable alt charset support to exploit my patched slang.

  • Property svn:keywords set to Id
File size: 9.2 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 231 2003-11-29 14:41:37Z 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#else
39#   error "no graphics library detected"
40#endif
41
42#ifdef HAVE_INTTYPES_H
43#   include <inttypes.h>
44#endif
45
46#include <stdio.h> /* BUFSIZ */
47#include <string.h>
48#include <stdlib.h>
49#include <unistd.h>
50#include <stdarg.h>
51#include <sys/time.h>
52#include <time.h>
53
54#include "caca.h"
55#include "caca_internals.h"
56
57static unsigned int _caca_delay;
58static unsigned int _caca_rendertime;
59
60static enum caca_color _caca_fgcolor = CACA_COLOR_LIGHTGRAY;
61static enum caca_color _caca_bgcolor = CACA_COLOR_BLACK;
62
63void caca_set_color(enum caca_color fgcolor, enum caca_color bgcolor)
64{
65    if(fgcolor < 0 || fgcolor > 15 || bgcolor < 0 || bgcolor > 15)
66        return;
67
68    _caca_fgcolor = fgcolor;
69    _caca_bgcolor = bgcolor;
70#if defined(USE_SLANG)
71    SLsmg_set_color((bgcolor + 16 * fgcolor) /*% 128*/);
72#elif defined(USE_NCURSES)
73    attrset(_caca_attr[fgcolor + 16 * bgcolor]);
74#elif defined(USE_CONIO)
75    textbackground(bgcolor);
76    textcolor(fgcolor);
77#endif
78}
79
80enum caca_color caca_get_fg_color(void)
81{
82    return _caca_fgcolor;
83}
84
85enum caca_color caca_get_bg_color(void)
86{
87    return _caca_bgcolor;
88}
89
90void caca_putchar(int x, int y, char c)
91{
92#if defined(USE_CONIO)
93    char *data;
94#endif
95    if(x < 0 || x >= (int)caca_get_width() ||
96       y < 0 || y >= (int)caca_get_height())
97        return;
98
99#if defined(USE_SLANG)
100    SLsmg_gotorc(y, x);
101    SLsmg_write_char(c);
102#elif defined(USE_NCURSES)
103    move(y, x);
104    addch(c);
105#elif defined(USE_CONIO)
106    data = _caca_screen + 2 * (x + y * caca_get_width());
107    data[0] = c;
108    data[1] = (_caca_bgcolor << 4) | _caca_fgcolor;
109//    gotoxy(x + 1, y + 1);
110//    putch(c);
111#endif
112}
113
114void caca_putstr(int x, int y, const char *s)
115{
116    unsigned int len;
117
118    if(y < 0 || y >= (int)caca_get_height() || x >= (int)caca_get_width())
119        return;
120
121    len = strlen(s);
122
123    if(x < 0)
124    {
125        len -= -x;
126        if(len < 0)
127            return;
128        s += -x;
129        x = 0;
130    }
131
132    if(x + len >= caca_get_width())
133    {
134        memcpy(_caca_scratch_line, s, caca_get_width() - x);
135        _caca_scratch_line[caca_get_width() - x] = '\0';
136        s = _caca_scratch_line;
137    }
138
139#if defined(USE_SLANG)
140    SLsmg_gotorc(y, x);
141    SLsmg_write_string((char *)(intptr_t)s);
142#elif defined(USE_NCURSES)
143    move(y, x);
144    addstr(s);
145#elif defined(USE_CONIO)
146    char *buf = _caca_screen + 2 * (x + y * caca_get_width());
147    while(*s)
148    {
149        *buf++ = *s++;
150        *buf++ = (_caca_bgcolor << 4) | _caca_fgcolor;
151    }
152//    gotoxy(x + 1, y + 1);
153//    cputs(s);
154#endif
155}
156
157void caca_printf(int x, int y, const char *format, ...)
158{
159    char tmp[BUFSIZ];
160    char *buf = tmp;
161    va_list args;
162
163    if(y < 0 || y >= (int)caca_get_height() || x >= (int)caca_get_width())
164        return;
165
166    if(caca_get_width() - x + 1 > BUFSIZ)
167        buf = malloc(caca_get_width() - x + 1);
168
169    va_start(args, format);
170#if defined(HAVE_VSNPRINTF)
171    vsnprintf(buf, caca_get_width() - x + 1, format, args);
172#else
173    vsprintf(buf, format, args);
174#endif
175    buf[caca_get_width() - x] = '\0';
176    va_end(args);
177
178    caca_putstr(x, y, buf);
179
180    if(buf != tmp)
181        free(buf);
182}
183
184void caca_clear(void)
185{
186    enum caca_color oldfg = caca_get_fg_color();
187    enum caca_color oldbg = caca_get_bg_color();
188    int y = caca_get_height();
189
190    caca_set_color(CACA_COLOR_LIGHTGRAY, CACA_COLOR_BLACK);
191
192    /* We could use SLsmg_cls() etc., but drawing empty lines is much faster */
193    while(y--)
194        caca_putstr(0, y, _caca_empty_line);
195
196    caca_set_color(oldfg, oldbg);
197}
198
199int _caca_init_graphics(void)
200{
201#if defined(USE_SLANG)
202    /* See SLang ref., 5.4.4. */
203    static char *slang_colors[16] =
204    {
205        /* Standard colours */
206        "black",
207        "blue",
208        "green",
209        "cyan",
210        "red",
211        "magenta",
212        "brown",
213        "lightgray",
214        /* Bright colours */
215        "gray",
216        "brightblue",
217        "brightgreen",
218        "brightcyan",
219        "brightred",
220        "brightmagenta",
221        "yellow",
222        "white",
223    };
224
225    int fg, bg;
226
227    for(fg = 0; fg < 16; fg++)
228        for(bg = 0; bg < 16; bg++)
229        {
230            int i = bg + 16 * fg;
231            SLtt_set_color(i, NULL, slang_colors[fg], slang_colors[bg]);
232        }
233
234    /* Disable alt charset support so that we get all 256 colour pairs */
235    SLtt_Has_Alt_Charset = 0;
236
237#elif defined(USE_NCURSES)
238    static int curses_colors[] =
239    {
240        /* Standard curses colours */
241        COLOR_BLACK,
242        COLOR_BLUE,
243        COLOR_GREEN,
244        COLOR_CYAN,
245        COLOR_RED,
246        COLOR_MAGENTA,
247        COLOR_YELLOW,
248        COLOR_WHITE,
249        /* Extra values for xterm-16color */
250        COLOR_BLACK + 8,
251        COLOR_BLUE + 8,
252        COLOR_GREEN + 8,
253        COLOR_CYAN + 8,
254        COLOR_RED + 8,
255        COLOR_MAGENTA + 8,
256        COLOR_YELLOW + 8,
257        COLOR_WHITE + 8
258    };
259
260    int fg, bg, max;
261
262    /* Activate colour */
263    start_color();
264
265    /* If COLORS == 16, it means the terminal supports full bright colours
266     * using setab and setaf (will use \e[90m \e[91m etc. for colours >= 8),
267     * we can build 16*16 colour pairs.
268     * If COLORS == 8, it means the terminal does not know about bright
269     * colours and we need to get them through A_BOLD and A_BLINK (\e[1m
270     * and \e[5m). We can only build 8*8 colour pairs. */
271    max = COLORS >= 16 ? 16 : 8;
272
273    for(bg = 0; bg < max; bg++)
274        for(fg = 0; fg < max; fg++)
275        {
276            /* Use ((max + 7 - fg) % max) instead of fg so that colour 0
277             * is light gray on black, since some terminals don't like
278             * this colour pair to be redefined. */
279            int col = ((max + 7 - fg) % max) + max * bg;
280            init_pair(col, curses_colors[fg], curses_colors[bg]);
281            _caca_attr[fg + 16 * bg] = COLOR_PAIR(col);
282
283            if(max == 8)
284            {
285                /* Bright fg on simple bg */
286                _caca_attr[fg + 8 + 16 * bg] = A_BOLD | COLOR_PAIR(col);
287                /* Simple fg on bright bg */
288                _caca_attr[fg + 16 * (bg + 8)] = A_BLINK | COLOR_PAIR(col);
289                /* Bright fg on bright bg */
290                _caca_attr[fg + 8 + 16 * (bg + 8)] = A_BLINK | A_BOLD
291                                                             | COLOR_PAIR(col);
292            }
293        }
294
295#elif defined(USE_CONIO)
296    gettextinfo(&ti);
297    _caca_screen = malloc(2 * ti.screenwidth * ti.screenheight);
298    if(_caca_screen == NULL)
299        return -1;
300#   if defined(SCREENUPDATE_IN_PC_H)
301    ScreenRetrieve(_caca_screen);
302#   else
303    /* FIXME */
304#   endif
305
306#endif
307    _caca_empty_line = malloc(caca_get_width() + 1);
308    memset(_caca_empty_line, ' ', caca_get_width());
309    _caca_empty_line[caca_get_width()] = '\0';
310
311    _caca_scratch_line = malloc(caca_get_width() + 1);
312
313    _caca_delay = 0;
314    _caca_rendertime = 0;
315
316    return 0;
317}
318
319void caca_set_delay(unsigned int usec)
320{
321    _caca_delay = usec;
322}
323
324unsigned int caca_get_rendertime(void)
325{
326    return _caca_rendertime;
327}
328
329static unsigned int _caca_getticks(void)
330{
331    static unsigned int last_sec = 0, last_usec = 0;
332
333    struct timeval tv;
334    unsigned int ticks = 0;
335
336    gettimeofday(&tv, NULL);
337
338    if(last_sec != 0)
339    {
340        ticks = (tv.tv_sec - last_sec) * 1000000 + (tv.tv_usec - last_usec);
341    }
342
343    last_sec = tv.tv_sec;
344    last_usec = tv.tv_usec;
345
346    return ticks;
347}
348
349void caca_refresh(void)
350{
351#define IDLE_USEC 10000
352    static int lastticks = 0;
353    int ticks = lastticks + _caca_getticks();
354
355#if defined(USE_SLANG)
356    SLsmg_refresh();
357#elif defined(USE_NCURSES)
358    refresh();
359#elif defined(USE_CONIO)
360#   if defined(SCREENUPDATE_IN_PC_H)
361    ScreenUpdate(_caca_screen);
362#   else
363    /* FIXME */
364#   endif
365#endif
366
367    /* Wait until _caca_delay + time of last call */
368    ticks += _caca_getticks();
369    for(; ticks + IDLE_USEC < (int)_caca_delay; ticks += _caca_getticks())
370        usleep(IDLE_USEC);
371
372    /* Update the sliding mean of the render time */
373    _caca_rendertime = (7 * _caca_rendertime + ticks) / 8;
374
375    lastticks = ticks - _caca_delay;
376
377    /* If we drifted too much, it's bad, bad, bad. */
378    if(lastticks > (int)_caca_delay)
379        lastticks = 0;
380}
381
Note: See TracBrowser for help on using the repository browser.