source: toilet/trunk/src/filter.c @ 2988

Last change on this file since 2988 was 2988, checked in by sam, 6 years ago

Port toilet to the unified libcaca 0.99.beta15 API.

  • Property svn:keywords set to Id
File size: 5.6 KB
Line 
1/*
2 *  TOIlet        The Other Implementation’s letters
3 *  Copyright (c) 2006 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  $Id: filter.c 2988 2008-10-18 21:36:17Z sam $
7 *
8 *  This program is free software. It comes without any warranty, to
9 *  the extent permitted by applicable law. You can redistribute it
10 *  and/or modify it under the terms of the Do What The Fuck You Want
11 *  To Public License, Version 2, as published by Sam Hocevar. See
12 *  http://sam.zoy.org/wtfpl/COPYING for more details.
13 */
14
15/*
16 * This file contains post-processing filter functions.
17 */
18
19#include "config.h"
20
21#if defined(HAVE_INTTYPES_H)
22#   include <inttypes.h>
23#endif
24#include <string.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <caca.h>
28
29#include "toilet.h"
30#include "filter.h"
31
32static void filter_crop(context_t *);
33static void filter_gay(context_t *);
34static void filter_metal(context_t *);
35static void filter_flip(context_t *);
36static void filter_flop(context_t *);
37static void filter_180(context_t *);
38static void filter_left(context_t *);
39static void filter_right(context_t *);
40
41struct
42{
43    char const *name;
44    void (*function)(context_t *);
45    char const *description;
46}
47const lookup[] =
48{
49    { "crop", filter_crop, "crop unused blanks" },
50    { "gay", filter_gay, "add a rainbow colour effect" },
51    { "metal", filter_metal, "add a metallic colour effect" },
52    { "flip", filter_flip, "flip horizontally" },
53    { "flop", filter_flop, "flip vertically" },
54    { "rotate", filter_180, NULL }, /* backwards compatibility */
55    { "180", filter_180, "rotate 180 degrees" },
56    { "left", filter_left, "rotate 90 degrees counterclockwise" },
57    { "right", filter_right, "rotate 90 degrees clockwise" },
58};
59
60int filter_list(void)
61{
62    unsigned int i;
63
64    printf("Available filters:\n");
65    for(i = 0; i < sizeof(lookup) / sizeof(lookup[0]); i++)
66        if(lookup[i].description)
67            printf("\"%s\": %s\n", lookup[i].name, lookup[i].description);
68
69    return 0;
70}
71
72int filter_add(context_t *cx, char const *filter)
73{
74    unsigned int n;
75    int i;
76
77    for(;;)
78    {
79        while(*filter == ':')
80            filter++;
81
82        if(*filter == '\0')
83            break;
84
85        for(i = sizeof(lookup) / sizeof(lookup[0]); i--; )
86            if(!strncmp(filter, lookup[i].name, strlen(lookup[i].name)))
87            {
88                n = strlen(lookup[i].name);
89                break;
90            }
91
92        if(i == -1 || (filter[n] != ':' && filter[n] != '\0'))
93        {
94            fprintf(stderr, "unknown filter near `%s'\n", filter);
95            return -1;
96        }
97
98        if((cx->nfilters % 16) == 0)
99            cx->filters = realloc(cx->filters, (cx->nfilters + 16)
100                                                 * sizeof(lookup[0].function));
101        cx->filters[cx->nfilters] = lookup[i].function;
102        cx->nfilters++;
103
104        filter += n;
105    }
106
107    return 0;
108}
109
110int filter_do(context_t *cx)
111{
112    unsigned int i;
113
114    for(i = 0; i < cx->nfilters; i++)
115        cx->filters[i](cx);
116
117    return 0;
118}
119
120int filter_end(context_t *cx)
121{
122    free(cx->filters);
123
124    return 0;
125}
126
127static void filter_crop(context_t *cx)
128{
129    unsigned int x, y, w, h;
130    unsigned int xmin, xmax, ymin, ymax;
131
132    xmin = w = caca_get_canvas_width(cx->torender);
133    xmax = 0;
134    ymin = h = caca_get_canvas_height(cx->torender);
135    ymax = 0;
136
137    for(y = 0; y < h; y++)
138        for(x = 0; x < w; x++)
139    {
140        unsigned long int ch = caca_get_char(cx->torender, x, y);
141        if(ch != (unsigned char)' ')
142        {
143            if(x < xmin)
144                xmin = x;
145            if(x > xmax)
146                xmax = x;
147            if(y < ymin)
148                ymin = y;
149            if(y > ymax)
150                ymax = y;
151        }
152    }
153
154    if(xmax < xmin || ymax < ymin)
155        return;
156
157    caca_set_canvas_boundaries(cx->torender, xmin, ymin,
158                                xmax - xmin + 1, ymax - ymin + 1);
159}
160
161static void filter_metal(context_t *cx)
162{
163    static unsigned char const palette[] =
164    {
165        CACA_LIGHTBLUE, CACA_BLUE, CACA_LIGHTGRAY, CACA_DARKGRAY,
166    };
167
168    unsigned int x, y, w, h;
169
170    w = caca_get_canvas_width(cx->torender);
171    h = caca_get_canvas_height(cx->torender);
172
173    for(y = 0; y < h; y++)
174        for(x = 0; x < w; x++)
175    {
176        unsigned long int ch = caca_get_char(cx->torender, x, y);
177        int i;
178
179        if(ch == (unsigned char)' ')
180            continue;
181
182        i = ((cx->lines + y + x / 8) / 2) % 4;
183        caca_set_color_ansi(cx->torender, palette[i], CACA_TRANSPARENT);
184        caca_put_char(cx->torender, x, y, ch);
185    }
186}
187
188static void filter_gay(context_t *cx)
189{
190    static unsigned char const rainbow[] =
191    {
192        CACA_LIGHTMAGENTA, CACA_LIGHTRED, CACA_YELLOW,
193        CACA_LIGHTGREEN, CACA_LIGHTCYAN, CACA_LIGHTBLUE,
194    };
195    unsigned int x, y, w, h;
196
197    w = caca_get_canvas_width(cx->torender);
198    h = caca_get_canvas_height(cx->torender);
199
200    for(y = 0; y < h; y++)
201        for(x = 0; x < w; x++)
202    {
203        unsigned long int ch = caca_get_char(cx->torender, x, y);
204        if(ch != (unsigned char)' ')
205        {
206            caca_set_color_ansi(cx->torender,
207                                 rainbow[(x / 2 + y + cx->lines) % 6],
208                                 CACA_TRANSPARENT);
209            caca_put_char(cx->torender, x, y, ch);
210        }
211    }
212}
213
214static void filter_flip(context_t *cx)
215{
216    caca_flip(cx->torender);
217}
218
219static void filter_flop(context_t *cx)
220{
221    caca_flop(cx->torender);
222}
223
224static void filter_180(context_t *cx)
225{
226    caca_rotate_180(cx->torender);
227}
228
229static void filter_left(context_t *cx)
230{
231    caca_rotate_left(cx->torender);
232}
233
234static void filter_right(context_t *cx)
235{
236    caca_rotate_right(cx->torender);
237}
238
Note: See TracBrowser for help on using the repository browser.