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

Last change on this file since 246 was 246, checked in by Sam Hocevar, 18 years ago
  • src/graphics.c: + Internally cache screen width and height.
  • src/bitmap.c: + Added alpha support to caca_draw_bitmap(). For now, we only treat 0%

alpha as fully transparent, and any other value as fully opaque.

+ Slightly tuned colour weights in the renderer.
+ caca_set_bitmap_palette() takes unsigned ints.

  • examples/demo.c: + Added a crap render demo.
  • examples/aafire.c: + Set a 20ms delay. + Added alpha values to the palette.
  • examples/view.c: + Draw a gray checkered grid below the image so that transparent images

look a lot nicer.

+ 'f' toggles "fullscreen" mode.

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