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

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