source: libcaca/trunk/src/caca.c @ 306

Last change on this file since 306 was 306, checked in by Sam Hocevar, 17 years ago
  • src/bitmap.c: + Fixed a minor overflow in the saturation computation. + Use a global lookup table for foreground/background colour selection

in the bitmap rendering routine. This broke dithering, sorry.

  • Property svn:keywords set to Id
File size: 13.1 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 caca.c
23 *  \version \$Id: caca.c 306 2004-01-02 18:09:29Z sam $
24 *  \author Sam Hocevar <sam@zoy.org>
25 *  \brief Main \e libcaca functions
26 *
27 *  This file contains the main functions used by \e libcaca applications to
28 *  initialise the library, get the screen properties, set the framerate and
29 *  so on.
30 */
31
32#include "config.h"
33
34#if defined(USE_SLANG)
35#   include <slang.h>
36#endif
37#if defined(USE_NCURSES)
38#   include <curses.h>
39#endif
40#if defined(USE_CONIO)
41#   include <dos.h>
42#   include <conio.h>
43#endif
44#if defined(USE_X11)
45#   include <X11/Xlib.h>
46#endif
47
48#include <stdlib.h>
49#include <string.h>
50
51#include "caca.h"
52#include "caca_internals.h"
53
54static void caca_init_driver(void);
55static void caca_init_features(void);
56static void caca_init_terminal(void);
57
58enum caca_driver _caca_driver;
59
60#if defined(USE_NCURSES)
61static mmask_t oldmask;
62#endif
63
64/** \brief Initialise \e libcaca.
65 *
66 *  This function initialises internal \e libcaca structures and the backend
67 *  that will be used for subsequent graphical operations. It must be the
68 *  first \e libcaca function to be called in a function. caca_end() should
69 *  be called at the end of the program to free all allocated resources.
70 *
71 *  \return 0 upon success, a non-zero value if an error occurs.
72 */
73int caca_init(void)
74{
75#if defined(USE_NCURSES)
76    mmask_t newmask;
77#endif
78
79    caca_init_driver();
80
81    if(_caca_driver == CACA_DRIVER_NONE)
82        return -1;
83
84    caca_init_features();
85    caca_init_terminal();
86
87#if defined(USE_SLANG)
88    if(_caca_driver == CACA_DRIVER_SLANG)
89    {
90        /* Initialise slang library */
91        SLsig_block_signals();
92        SLtt_get_terminfo();
93
94        if(SLkp_init() == -1)
95        {
96            SLsig_unblock_signals();
97            return -1;
98        }
99
100        SLang_init_tty(-1, 0, 1);
101
102        if(SLsmg_init_smg() == -1)
103        {
104            SLsig_unblock_signals();
105            return -1;
106        }
107
108        SLsig_unblock_signals();
109
110        SLsmg_cls();
111        SLtt_set_cursor_visibility(0);
112        SLkp_define_keysym("\e[M", 1001);
113        SLtt_set_mouse_mode(1, 0);
114        SLsmg_refresh();
115
116        /* Disable scrolling so that hashmap scrolling optimization code
117         * does not cause ugly refreshes due to slow terminals */
118        SLtt_Term_Cannot_Scroll = 1;
119    }
120    else
121#endif
122#if defined(USE_NCURSES)
123    if(_caca_driver == CACA_DRIVER_NCURSES)
124    {
125        initscr();
126        keypad(stdscr, TRUE);
127        nonl();
128        cbreak();
129        noecho();
130        nodelay(stdscr, TRUE);
131        curs_set(0);
132
133        /* Activate mouse */
134        newmask = ALL_MOUSE_EVENTS;
135        mousemask(newmask, &oldmask);
136    }
137    else
138#endif
139#if defined(USE_CONIO)
140    if(_caca_driver == CACA_DRIVER_CONIO)
141    {
142        _wscroll = 0;
143        _setcursortype(_NOCURSOR);
144        clrscr();
145    }
146    else
147#endif
148#if defined(USE_X11)
149    /* Nothing to do */
150#endif
151    {
152        /* Dummy */
153    }
154
155    if(_caca_init_graphics())
156        return -1;
157
158    if(_caca_init_bitmap())
159        return -1;
160
161    return 0;
162}
163
164/** \brief Get the screen width.
165 *
166 *  This function returns the current screen width, in character cells.
167 *
168 *  \return The screen width.
169 */
170unsigned int caca_get_width(void)
171{
172    return _caca_width;
173}
174
175/** \brief Get the screen height.
176 *
177 *  This function returns the current screen height, in character cells.
178 *
179 *  \return The screen height.
180 */
181unsigned int caca_get_height(void)
182{
183    return _caca_height;
184}
185
186/** \brief Translate a colour index into the colour's name.
187 *
188 *  This function translates a caca_color enum into a human-readable
189 *  description string of the associated colour.
190 *
191 *  \param color The colour value.
192 *  \return A static string containing the colour's name.
193 */
194char const *caca_get_color_name(enum caca_color color)
195{
196    static char const *color_names[] =
197    {
198        "black",
199        "blue",
200        "green",
201        "cyan",
202        "red",
203        "magenta",
204        "brown",
205        "light gray",
206        "dark gray",
207        "light blue",
208        "light green",
209        "light cyan",
210        "light red",
211        "light magenta",
212        "yellow",
213        "white",
214    };
215
216    if(color < 0 || color > 15)
217        return "unknown";
218
219    return color_names[color];
220}
221
222/** \brief Get the current value of a feature.
223 *
224 *  This function retrieves the value of an internal \e libcaca feature. A
225 *  generic feature value is expected, such as CACA_ANTIALIASING.
226 *
227 *  \param feature The requested feature.
228 *  \return The current value of the feature or CACA_UNKNOWN_FEATURE if an
229 *          error occurred..
230 */
231enum caca_feature caca_get_feature(enum caca_feature feature)
232{
233    switch(feature)
234    {
235        case CACA_BACKGROUND:
236            return _caca_background;
237        case CACA_ANTIALIASING:
238            return _caca_antialiasing;
239        case CACA_DITHERING:
240            return _caca_dithering;
241
242        default:
243            return CACA_UNKNOWN_FEATURE;
244    }
245}
246
247/** \brief Set a feature.
248 *
249 *  This function sets an internal \e libcaca feature such as the antialiasing
250 *  or dithering modes. If a specific feature such as CACA_DITHERING_RANDOM,
251 *  caca_set_feature() will set it immediately. If a generic feature is given
252 *  instead, such as CACA_DITHERING, the default value will be used instead.
253 *
254 *  \param feature The requested feature.
255 */
256void caca_set_feature(enum caca_feature feature)
257{
258    switch(feature)
259    {
260        case CACA_BACKGROUND:
261            feature = CACA_BACKGROUND_SOLID;
262        case CACA_BACKGROUND_BLACK:
263        case CACA_BACKGROUND_SOLID:
264            _caca_background = feature;
265            break;
266
267        case CACA_ANTIALIASING:
268            feature = CACA_ANTIALIASING_PREFILTER;
269        case CACA_ANTIALIASING_NONE:
270        case CACA_ANTIALIASING_PREFILTER:
271            _caca_antialiasing = feature;
272            break;
273
274        case CACA_DITHERING:
275            feature = CACA_DITHERING_ORDERED4;
276        case CACA_DITHERING_NONE:
277        case CACA_DITHERING_ORDERED2:
278        case CACA_DITHERING_ORDERED4:
279        case CACA_DITHERING_ORDERED8:
280        case CACA_DITHERING_RANDOM:
281            _caca_dithering = feature;
282            break;
283
284        case CACA_UNKNOWN_FEATURE:
285            break;
286    }
287}
288
289/** \brief Translate a feature value into the feature's name.
290 *
291 *  This function translates a caca_feature enum into a human-readable
292 *  description string of the associated feature.
293 *
294 *  \param feature The feature value.
295 *  \return A static string containing the feature's name.
296 */
297char const *caca_get_feature_name(enum caca_feature feature)
298{
299    switch(feature)
300    {
301        case CACA_BACKGROUND_BLACK: return "black background";
302        case CACA_BACKGROUND_SOLID: return "solid background";
303
304        case CACA_ANTIALIASING_NONE:      return "no antialiasing";
305        case CACA_ANTIALIASING_PREFILTER: return "prefilter antialiasing";
306
307        case CACA_DITHERING_NONE:     return "no dithering";
308        case CACA_DITHERING_ORDERED2: return "2x2 ordered dithering";
309        case CACA_DITHERING_ORDERED4: return "4x4 ordered dithering";
310        case CACA_DITHERING_ORDERED8: return "8x8 ordered dithering";
311        case CACA_DITHERING_RANDOM:   return "random dithering";
312
313        default: return "unknown";
314    }
315}
316
317/** \brief Uninitialise \e libcaca.
318 *
319 *  This function frees all resources allocated by caca_init(). After
320 *  caca_end() has been called, no other \e libcaca functions may be used
321 *  unless a new call to caca_init() is done.
322 */
323void caca_end(void)
324{
325    _caca_end_bitmap();
326    _caca_end_graphics();
327
328#if defined(USE_SLANG)
329    if(_caca_driver == CACA_DRIVER_SLANG)
330    {
331        SLtt_set_mouse_mode(0, 0);
332        SLtt_set_cursor_visibility(1);
333        SLang_reset_tty();
334        SLsmg_reset_smg();
335    }
336    else
337#endif
338#if defined(USE_NCURSES)
339    if(_caca_driver == CACA_DRIVER_NCURSES)
340    {
341        mousemask(oldmask, NULL);
342        curs_set(1);
343        endwin();
344    }
345    else
346#endif
347#if defined(USE_CONIO)
348    if(_caca_driver == CACA_DRIVER_CONIO)
349    {
350        _wscroll = 1;
351        textcolor((enum COLORS)WHITE);
352        textbackground((enum COLORS)BLACK);
353        gotoxy(_caca_width, _caca_height);
354        cputs("\r\n");
355        _setcursortype(_NORMALCURSOR);
356    }
357    else
358#endif
359#if defined(USE_X11)
360    if(_caca_driver == CACA_DRIVER_X11)
361    {
362        /* Nothing to do */
363    }
364    else
365#endif
366    {
367        /* Dummy */
368    }
369}
370
371/*
372 * XXX: The following functions are local.
373 */
374
375static void caca_init_driver(void)
376{
377#if defined(HAVE_GETENV) && defined(HAVE_STRCASECMP)
378    char *var = getenv("CACA_DRIVER");
379
380    /* If the environment variable was set, use it */
381    if(var && *var)
382    {
383#if defined(USE_CONIO)
384        if(!strcasecmp(var, "conio"))
385            _caca_driver = CACA_DRIVER_CONIO;
386        else
387#endif
388#if defined(USE_X11)
389        if(!strcasecmp(var, "x11"))
390            _caca_driver = CACA_DRIVER_X11;
391        else
392#endif
393#if defined(USE_SLANG)
394        if(!strcasecmp(var, "slang"))
395            _caca_driver = CACA_DRIVER_SLANG;
396        else
397#endif
398#if defined(USE_NCURSES)
399        if(!strcasecmp(var, "ncurses"))
400            _caca_driver = CACA_DRIVER_NCURSES;
401        else
402#endif
403            _caca_driver = CACA_DRIVER_NONE;
404
405        return;
406    }
407#endif
408
409#if defined(USE_CONIO)
410    _caca_driver = CACA_DRIVER_CONIO;
411    return;
412#endif
413#if defined(USE_X11)
414#if defined(HAVE_GETENV)
415    if(getenv("DISPLAY") && *(getenv("DISPLAY")))
416#endif
417    {
418        _caca_driver = CACA_DRIVER_X11;
419        return;
420    }
421#endif
422#if defined(USE_SLANG)
423    _caca_driver = CACA_DRIVER_SLANG;
424    return;
425#endif
426#if defined(USE_NCURSES)
427    _caca_driver = CACA_DRIVER_NCURSES;
428    return;
429#endif
430    _caca_driver = CACA_DRIVER_NONE;
431    return;
432}
433
434static void caca_init_features(void)
435{
436    /* FIXME: if strcasecmp isn't available, use strcmp */
437#if defined(HAVE_GETENV) && defined(HAVE_STRCASECMP)
438    char *var;
439#endif
440
441    caca_set_feature(CACA_BACKGROUND);
442    caca_set_feature(CACA_ANTIALIASING);
443    caca_set_feature(CACA_DITHERING);
444
445#if defined(HAVE_GETENV) && defined(HAVE_STRCASECMP)
446    if((var = getenv("CACA_BACKGROUND")) && *var)
447    {
448        if(!strcasecmp("black", var))
449            caca_set_feature(CACA_BACKGROUND_BLACK);
450        else if(!strcasecmp("solid", var))
451            caca_set_feature(CACA_BACKGROUND_SOLID);
452    }
453
454    if((var = getenv("CACA_ANTIALIASING")) && *var)
455    {
456        if(!strcasecmp("none", var))
457            caca_set_feature(CACA_ANTIALIASING_NONE);
458        else if(!strcasecmp("prefilter", var))
459            caca_set_feature(CACA_ANTIALIASING_PREFILTER);
460    }
461
462    if((var = getenv("CACA_DITHERING")) && *var)
463    {
464        if(!strcasecmp("none", var))
465            caca_set_feature(CACA_DITHERING_NONE);
466        else if(!strcasecmp("ordered2", var))
467            caca_set_feature(CACA_DITHERING_ORDERED2);
468        else if(!strcasecmp("ordered4", var))
469            caca_set_feature(CACA_DITHERING_ORDERED4);
470        else if(!strcasecmp("ordered8", var))
471            caca_set_feature(CACA_DITHERING_ORDERED8);
472        else if(!strcasecmp("random", var))
473            caca_set_feature(CACA_DITHERING_RANDOM);
474    }
475#endif
476}
477
478static void caca_init_terminal(void)
479{
480#if defined(HAVE_GETENV) && defined(HAVE_PUTENV)
481    char *term, *colorterm, *other;
482
483#if defined(USE_SLANG)
484    if(_caca_driver != CACA_DRIVER_SLANG)
485#endif
486#if defined(USE_NCURSES)
487    if(_caca_driver != CACA_DRIVER_NCURSES)
488#endif
489    return;
490
491    term = getenv("TERM");
492    colorterm = getenv("COLORTERM");
493
494    if(term && !strcmp(term, "xterm"))
495    {
496        /* If we are using gnome-terminal, it's really a 16 colour terminal */
497        if(colorterm && !strcmp(colorterm, "gnome-terminal"))
498        {
499#if defined(USE_NCURSES)
500            if(_caca_driver == CACA_DRIVER_NCURSES)
501            {
502                SCREEN *screen;
503                screen = newterm("xterm-16color", stdout, stdin);
504                if(screen == NULL)
505                    return;
506                endwin();
507            }
508#endif
509            (void)putenv("TERM=xterm-16color");
510            return;
511        }
512
513        /* Ditto if we are using Konsole */
514        other = getenv("KONSOLE_DCOP_SESSION");
515        if(other)
516        {
517#if defined(USE_NCURSES)
518            if(_caca_driver == CACA_DRIVER_NCURSES)
519            {
520                SCREEN *screen;
521                screen = newterm("xterm-16color", stdout, stdin);
522                if(screen == NULL)
523                    return;
524                endwin();
525            }
526#endif
527            (void)putenv("TERM=xterm-16color");
528            return;
529        }
530    }
531#endif
532}
533
Note: See TracBrowser for help on using the repository browser.