source: libcaca/trunk/cucul/transform.c @ 724

Last change on this file since 724 was 724, checked in by Sam Hocevar, 15 years ago
  • Store colour information on 32 bits, for future 12-bit colour support.
  • Property svn:keywords set to Id
File size: 9.8 KB
Line 
1/*
2 *  libcucul      Canvas for ultrafast compositing of Unicode letters
3 *  Copyright (c) 2002-2006 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 Do What The Fuck You Want To
8 *  Public License, Version 2, as published by Sam Hocevar. See
9 *  http://sam.zoy.org/wtfpl/COPYING for more details.
10 */
11
12/** \file transform.c
13 *  \version \$Id: transform.c 724 2006-04-06 13:41:56Z sam $
14 *  \author Sam Hocevar <sam@zoy.org>
15 *  \brief Canvas transformation
16 *
17 *  This file contains horizontal and vertical flipping routines.
18 */
19
20#include "config.h"
21
22#if !defined(__KERNEL__)
23#endif
24
25#include "cucul.h"
26#include "cucul_internals.h"
27
28static uint32_t flipchar(uint32_t ch);
29static uint32_t flopchar(uint32_t ch);
30static uint32_t rotatechar(uint32_t ch);
31
32/** \brief Invert a canvas' colours.
33 *
34 *  This function inverts a canvas' colours (black becomes white, red
35 *  becomes cyan, etc.) without changing the characters in it.
36 *
37 *  \param qq The canvas to invert.
38 */
39void cucul_invert(cucul_t *qq)
40{
41    uint32_t *attr = qq->attr;
42    unsigned int i;
43
44    for(i = qq->height * qq->width; i--; )
45    {
46        *attr = *attr ^ 0x000f000f;
47        attr++;
48    }
49}
50
51/** \brief Flip a canvas horizontally.
52 *
53 *  This function flips a canvas horizontally, choosing characters that
54 *  look like the mirrored version wherever possible.
55 *
56 *  \param qq The canvas to flip.
57 */
58void cucul_flip(cucul_t *qq)
59{
60    unsigned int y;
61
62    for(y = 0; y < qq->height; y++)
63    {
64        uint32_t *cleft = qq->chars + y * qq->width;
65        uint32_t *cright = cleft + qq->width - 1;
66        uint32_t *aleft = qq->attr + y * qq->width;
67        uint32_t *aright = aleft + qq->width - 1;
68
69        while(cleft < cright)
70        {
71            uint32_t ch;
72            uint32_t attr;
73
74            /* Swap attributes */
75            attr = *aright; *aright = *aleft; *aleft = attr;
76
77            /* Swap characters */
78            ch = *cright; *cright = flipchar(*cleft); *cleft = flipchar(ch);
79
80            cleft++; cright--; aleft++; aright--;
81        }
82
83        if(cleft == cright)
84            *cleft = flipchar(*cleft);
85    }
86}
87
88/** \brief Flip a canvas vertically.
89 *
90 *  This function flips a canvas vertically, choosing characters that
91 *  look like the mirrored version wherever possible.
92 *
93 *  \param qq The canvas to flop.
94 */
95void cucul_flop(cucul_t *qq)
96{
97    unsigned int x;
98
99    for(x = 0; x < qq->width; x++)
100    {
101        uint32_t *ctop = qq->chars + x;
102        uint32_t *cbottom = ctop + qq->width * (qq->height - 1);
103        uint32_t *atop = qq->attr + x;
104        uint32_t *abottom = atop + qq->width * (qq->height - 1);
105
106        while(ctop < cbottom)
107        {
108            uint32_t ch;
109            uint32_t attr;
110
111            /* Swap attributes */
112            attr = *abottom; *abottom = *atop; *atop = attr;
113
114            /* Swap characters */
115            ch = *cbottom; *cbottom = flopchar(*ctop); *ctop = flopchar(ch);
116
117            ctop += qq->width; cbottom -= qq->width;
118            atop += qq->width; abottom -= qq->width;
119        }
120
121        if(ctop == cbottom)
122            *ctop = flopchar(*ctop);
123    }
124}
125
126/** \brief Rotate a canvas.
127 *
128 *  This function applies a 180 degrees transformation to a canvas,
129 *  choosing characters that look like the mirrored version wherever
130 *  possible.
131 *
132 *  \param qq The canvas to rotate.
133 */
134void cucul_rotate(cucul_t *qq)
135{
136    uint32_t *cbegin = qq->chars;
137    uint32_t *cend = cbegin + qq->width * qq->height - 1;
138    uint32_t *abegin = qq->attr;
139    uint32_t *aend = abegin + qq->width * qq->height - 1;
140
141    while(cbegin < cend)
142    {
143        uint32_t ch;
144        uint32_t attr;
145
146        /* Swap attributes */
147        attr = *aend; *aend = *abegin; *abegin = attr;
148
149        /* Swap characters */
150        ch = *cend; *cend = rotatechar(*cbegin); *cbegin = rotatechar(ch);
151
152        cbegin++; cend--; abegin++; aend--;
153    }
154
155    if(cbegin == cend)
156        *cbegin = rotatechar(*cbegin);
157}
158
159static uint32_t flipchar(uint32_t ch)
160{
161    int i;
162
163    static uint32_t const noflip[] =
164    {
165         /* ASCII */
166         (uint32_t)' ', (uint32_t)'"', (uint32_t)'#', (uint32_t)'\'',
167         (uint32_t)'-', (uint32_t)'.', (uint32_t)'*', (uint32_t)'+',
168         (uint32_t)':', (uint32_t)'=',
169         (uint32_t)'0', (uint32_t)'8', (uint32_t)'A', (uint32_t)'H',
170         (uint32_t)'I', (uint32_t)'M', (uint32_t)'O', (uint32_t)'T',
171         (uint32_t)'U', (uint32_t)'V', (uint32_t)'W', (uint32_t)'X',
172         (uint32_t)'Y', (uint32_t)'^', (uint32_t)'_', (uint32_t)'i',
173         (uint32_t)'o', (uint32_t)'v', (uint32_t)'w', (uint32_t)'x',
174         (uint32_t)'|',
175         /* Unicode */
176         0x2591, 0x2592, 0x2593, 0x2588, 0x2584, 0x2580, /* ░ ▒ ▓ █ ▄ ▀ */
177         0
178    };
179
180    static uint32_t const pairs[] =
181    {
182         /* ASCII */
183         (uint32_t)'(', (uint32_t)')', (uint32_t)'/', (uint32_t)'\\',
184         (uint32_t)'<', (uint32_t)'>', (uint32_t)'[', (uint32_t)']',
185         (uint32_t)'b', (uint32_t)'d', (uint32_t)'p', (uint32_t)'q',
186         (uint32_t)'{', (uint32_t)'}',
187         /* ASCII-Unicode */
188         (uint32_t)';', 0x204f, /* ; ⁏ */
189         (uint32_t)'`', 0x00b4, /* ` ´ */
190         (uint32_t)'E', 0x018e, /* E Ǝ */
191         (uint32_t)'N', 0x0418, /* N И */
192         (uint32_t)'R', 0x042f, /* R Я */
193         (uint32_t)'S', 0x01a7, /* S Ƨ */
194         (uint32_t)'c', 0x0254, /* c ɔ */
195         (uint32_t)'e', 0x0258, /* e ɘ */
196         /* Unicode only */
197         0x258c, 0x2590, /* ▌ ▐ */
198         0x2596, 0x2597, /* ▖ ▗ */
199         0x2598, 0x259d, /* ▘ ▝ */
200         0x2599, 0x259f, /* ▙ ▟ */
201         0x259a, 0x259e, /* ▚ ▞ */
202         0x259b, 0x259c, /* ▛ ▜ */
203         0
204    };
205
206    for(i = 0; noflip[i]; i++)
207        if(ch == noflip[i])
208            return ch;
209
210    for(i = 0; pairs[i]; i++)
211        if(ch == pairs[i])
212            return pairs[i ^ 1];
213
214    return ch;
215}
216
217static uint32_t flopchar(uint32_t ch)
218{
219    int i;
220
221    static uint32_t const noflop[] =
222    {
223         /* ASCII */
224         (uint32_t)' ', (uint32_t)'(', (uint32_t)')', (uint32_t)'*',
225         (uint32_t)'+', (uint32_t)'-',
226         (uint32_t)'0', (uint32_t)'3', (uint32_t)'8', (uint32_t)':',
227         (uint32_t)'<', (uint32_t)'=', (uint32_t)'>', (uint32_t)'B',
228         (uint32_t)'C', (uint32_t)'D', (uint32_t)'E', (uint32_t)'H',
229         (uint32_t)'I', (uint32_t)'K', (uint32_t)'O', (uint32_t)'X',
230         (uint32_t)'[', (uint32_t)']', (uint32_t)'c', (uint32_t)'o',
231         (uint32_t)'{', (uint32_t)'|', (uint32_t)'}',
232         /* Unicode */
233         0x2591, 0x2592, 0x2593, 0x2588, 0x258c, 0x2590, /* ░ ▒ ▓ █ ▌ ▐ */
234         0
235    };
236
237    static uint32_t const pairs[] =
238    {
239         /* ASCII */
240         (uint32_t)'/', (uint32_t)'\\', (uint32_t)'M', (uint32_t)'W',
241         (uint32_t)',', (uint32_t)'`', (uint32_t)'b', (uint32_t)'p',
242         (uint32_t)'d', (uint32_t)'q', (uint32_t)'p', (uint32_t)'q',
243         (uint32_t)'f', (uint32_t)'t', (uint32_t)'.', (uint32_t)'\'',
244         /* ASCII-Unicode */
245         (uint32_t)'_', 0x2594, /* _ ▔ */
246         (uint32_t)'`', 0x201a, /* ` ‚ */
247         (uint32_t)'!', 0x00a1, /* ! ¡ */
248         (uint32_t)'N', 0x0418, /* N И */
249         (uint32_t)'P', 0x042c, /* P Ь */
250         (uint32_t)'S', 0x01a7, /* S Ƨ */
251         (uint32_t)'v', 0x028c, /* v ʌ */
252         (uint32_t)'w', 0x028d, /* w ʍ */
253         /* Unicode only */
254         0x2584, 0x2580, /* ▄ ▀ */
255         0x2596, 0x2598, /* ▖ ▘ */
256         0x2597, 0x259d, /* ▗ ▝ */
257         0x2599, 0x259b, /* ▙ ▛ */
258         0x259f, 0x259c, /* ▟ ▜ */
259         0x259a, 0x259e, /* ▚ ▞ */
260         0
261    };
262
263    for(i = 0; noflop[i]; i++)
264        if(ch == noflop[i])
265            return ch;
266
267    for(i = 0; pairs[i]; i++)
268        if(ch == pairs[i])
269            return pairs[i ^ 1];
270
271    return ch;
272}
273
274static uint32_t rotatechar(uint32_t ch)
275{
276    int i;
277
278    static uint32_t const norotate[] =
279    {
280         /* ASCII - FIXME: a lot are missing */
281         (uint32_t)' ', (uint32_t)'*', (uint32_t)'+', (uint32_t)'-',
282         (uint32_t)'0', (uint32_t)'8', (uint32_t)':', (uint32_t)'=',
283         /* Unicode */
284         0x2591, 0x2592, 0x2593, 0x2588, 0x259a, 0x259e, /* ░ ▒ ▓ █ ▚ ▞ */
285         0
286    };
287
288    static uint32_t const pairs[] =
289    {
290         /* ASCII */
291         (uint32_t)'(', (uint32_t)')', (uint32_t)'<', (uint32_t)'>',
292         (uint32_t)'[', (uint32_t)']', (uint32_t)'{', (uint32_t)'}',
293         (uint32_t)'.', (uint32_t)'\'',
294         (uint32_t)'6', (uint32_t)'9',
295         (uint32_t)'M', (uint32_t)'W', (uint32_t)'b', (uint32_t)'q',
296         (uint32_t)'d', (uint32_t)'p', (uint32_t)'n', (uint32_t)'u',
297         /* ASCII-Unicode */
298         (uint32_t)'_', 0x2594, /* _ ▔ */
299         (uint32_t)',', 0x02bb, /* , ʻ */
300         (uint32_t)'!', 0x00a1, /* ! ¡ */
301         (uint32_t)'?', 0x00bf, /* ? ¿ */
302         (uint32_t)'E', 0x018e, /* E Ǝ */
303         (uint32_t)'F', 0x2132, /* F Ⅎ */
304         (uint32_t)'a', 0x0250, /* a ɐ */
305         (uint32_t)'c', 0x0254, /* c ɔ */
306         (uint32_t)'e', 0x0259, /* e ə */
307         (uint32_t)'f', 0x025f, /* f ɟ */
308         (uint32_t)'h', 0x0265, /* h ɥ */
309         (uint32_t)'k', 0x029e, /* k ʞ */
310         (uint32_t)'m', 0x026f, /* m ɯ */
311         (uint32_t)'r', 0x0279, /* r ɹ */
312         (uint32_t)'t', 0x0287, /* t ʇ */
313         (uint32_t)'v', 0x028c, /* v ʌ */
314         (uint32_t)'w', 0x028d, /* w ʍ */
315         (uint32_t)'y', 0x028e, /* y ʎ */
316         /* Unicode only */
317         0x258c, 0x2590, /* ▌ ▐ */
318         0x2584, 0x2580, /* ▄ ▀ */
319         0x2596, 0x259d, /* ▖ ▝ */
320         0x2597, 0x2598, /* ▗ ▘ */
321         0x2599, 0x259c, /* ▙ ▜ */
322         0x259f, 0x259b, /* ▟ ▛ */
323         0
324    };
325
326    for(i = 0; norotate[i]; i++)
327        if(ch == norotate[i])
328            return ch;
329
330    for(i = 0; pairs[i]; i++)
331        if(ch == pairs[i])
332            return pairs[i ^ 1];
333
334    return ch;
335}
336
Note: See TracBrowser for help on using the repository browser.