source: libcaca/trunk/caca/triangle.c @ 3909

Last change on this file since 3909 was 3909, checked in by Jean-Yves Lamoureux, 11 years ago
  • Added texture mapped triangle routine, float based, arbitrary texture size, to be optimized
  • Made compilation under MacOSX 10.6 (Snow Leopard) possible, but breaks 10.4 (Tiger), to be fixed
  • Property svn:keywords set to Id
File size: 10.8 KB
Line 
1/*
2 *  libcaca       Colour ASCII-Art library
3 *  Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  $Id: triangle.c 3909 2009-11-16 12:17:01Z jylam $
7 *
8 *  This library 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 triangle drawing functions, both filled and outline.
17 */
18
19#include "config.h"
20
21#if !defined(__KERNEL__)
22#   include <stdlib.h>
23#endif
24
25#include "caca.h"
26#include "caca_internals.h"
27
28/** \brief Draw a triangle on the canvas using the given character.
29 *
30 *  This function never fails.
31 *
32 *  \param cv The handle to the libcaca canvas.
33 *  \param x1 X coordinate of the first point.
34 *  \param y1 Y coordinate of the first point.
35 *  \param x2 X coordinate of the second point.
36 *  \param y2 Y coordinate of the second point.
37 *  \param x3 X coordinate of the third point.
38 *  \param y3 Y coordinate of the third point.
39 *  \param ch UTF-32 character to be used to draw the triangle outline.
40 *  \return This function always returns 0.
41 */
42int caca_draw_triangle(caca_canvas_t *cv, int x1, int y1, int x2, int y2,
43                        int x3, int y3, uint32_t ch)
44{
45    caca_draw_line(cv, x1, y1, x2, y2, ch);
46    caca_draw_line(cv, x2, y2, x3, y3, ch);
47    caca_draw_line(cv, x3, y3, x1, y1, ch);
48
49    return 0;
50}
51
52/** \brief Draw a thin triangle on the canvas.
53 *
54 *  This function never fails.
55 *
56 *  \param cv The handle to the libcaca canvas.
57 *  \param x1 X coordinate of the first point.
58 *  \param y1 Y coordinate of the first point.
59 *  \param x2 X coordinate of the second point.
60 *  \param y2 Y coordinate of the second point.
61 *  \param x3 X coordinate of the third point.
62 *  \param y3 Y coordinate of the third point.
63 *  \return This function always returns 0.
64 */
65int caca_draw_thin_triangle(caca_canvas_t *cv, int x1, int y1,
66                             int x2, int y2, int x3, int y3)
67{
68    caca_draw_thin_line(cv, x1, y1, x2, y2);
69    caca_draw_thin_line(cv, x2, y2, x3, y3);
70    caca_draw_thin_line(cv, x3, y3, x1, y1);
71
72    return 0;
73}
74
75/** \brief Fill a triangle on the canvas using the given character.
76 *
77 *  This function never fails.
78 *
79 *  \param cv The handle to the libcaca canvas.
80 *  \param x1 X coordinate of the first point.
81 *  \param y1 Y coordinate of the first point.
82 *  \param x2 X coordinate of the second point.
83 *  \param y2 Y coordinate of the second point.
84 *  \param x3 X coordinate of the third point.
85 *  \param y3 Y coordinate of the third point.
86 *  \param ch UTF-32 character to be used to fill the triangle.
87 *  \return This function always returns 0.
88 */
89int caca_fill_triangle(caca_canvas_t *cv, int x1, int y1, int x2, int y2,
90                        int x3, int y3, uint32_t ch)
91{
92    int x, y, xmin, xmax, ymin, ymax;
93    int xx1, xx2, xa, xb, sl21, sl31, sl32;
94
95    /* Bubble-sort y1 <= y2 <= y3 */
96    if(y1 > y2)
97        return caca_fill_triangle(cv, x2, y2, x1, y1, x3, y3, ch);
98
99    if(y2 > y3)
100        return caca_fill_triangle(cv, x1, y1, x3, y3, x2, y2, ch);
101
102    /* Compute slopes and promote precision */
103    sl21 = (y2 == y1) ? 0 : (x2 - x1) * 0x10000 / (y2 - y1);
104    sl31 = (y3 == y1) ? 0 : (x3 - x1) * 0x10000 / (y3 - y1);
105    sl32 = (y3 == y2) ? 0 : (x3 - x2) * 0x10000 / (y3 - y2);
106
107    x1 *= 0x10000;
108    x2 *= 0x10000;
109    x3 *= 0x10000;
110
111    ymin = y1 < 0 ? 0 : y1;
112    ymax = y3 + 1 < cv->height ? y3 + 1 : cv->height;
113
114    if(ymin < y2)
115    {
116        xa = x1 + sl21 * (ymin - y1);
117        xb = x1 + sl31 * (ymin - y1);
118    }
119    else if(ymin == y2)
120    {
121        xa = x2;
122        xb = (y1 == y3) ? x3 : x1 + sl31 * (ymin - y1);
123    }
124    else /* (ymin > y2) */
125    {
126        xa = x3 + sl32 * (ymin - y3);
127        xb = x3 + sl31 * (ymin - y3);
128    }
129
130    /* Rasterize our triangle */
131    for(y = ymin; y < ymax; y++)
132    {
133        /* Rescale xa and xb, recentering the division */
134        if(xa < xb)
135        {
136            xx1 = (xa + 0x800) / 0x10000;
137            xx2 = (xb + 0x801) / 0x10000;
138        }
139        else
140        {
141            xx1 = (xb + 0x800) / 0x10000;
142            xx2 = (xa + 0x801) / 0x10000;
143        }
144
145        xmin = xx1 < 0 ? 0 : xx1;
146        xmax = xx2 + 1 < cv->width ? xx2 + 1 : cv->width;
147
148        for(x = xmin; x < xmax; x++)
149            caca_put_char(cv, x, y, ch);
150
151        xa += y < y2 ? sl21 : sl32;
152        xb += sl31;
153    }
154
155    return 0;
156}
157
158/** \brief Fill a triangle on the canvas using an arbitrary-sized texture.
159 *
160 *  This function fails if one or both the canvas are missing
161 *
162 *  \param cv  The handle to the libcaca canvas.
163 *  \param x1  X coordinate of the first point.
164 *  \param y1  Y coordinate of the first point.
165 *  \param x2  X coordinate of the second point.
166 *  \param y2  Y coordinate of the second point.
167 *  \param x3  X coordinate of the third point.
168 *  \param y3  Y coordinate of the third point.
169 *  \param u1  U texture coordinate of the first point.
170 *  \param v1  V texture coordinate of the first point.
171 *  \param u2  U texture coordinate of the second point.
172 *  \param v2  V texture coordinate of the second point.
173 *  \param u3  U texture coordinate of the third point.
174 *  \param v3  V texture coordinate of the third point.
175 *  \param tex The handle of the canvas texture.
176 *  \return This function return 0 if ok, -1 if canvas or texture are missing.
177 */
178int caca_fill_triangle_textured(caca_canvas_t *cv,
179                                int x1, int y1,
180                                int x2, int y2,
181                                        int x3, int y3,
182                                float u1, float v1,
183                                float u2, float v2,
184                                        float u3, float v3,
185                                caca_canvas_t *tex)
186{
187   
188    #define SWAP_F(a, b) {float c = a; a = b; b = c; }
189   
190    /* (very) Naive and
191     * (very) float-based affine and
192     * (very) non-clipped and
193     * (very) non-corrected triangle mapper
194     *
195     * Accepts arbitrary texture sizes
196     * Coordinates clamped to [0.0 - 1.0] (no repeat)
197     */
198    if(!cv || !tex) return -1;
199
200    /* Bubble-sort y1 <= y2 <= y3 */
201    if(y1 > y2)
202        return caca_fill_triangle_textured(cv,
203                                           x2, y2, x1, y1, x3, y3,
204                                           u2, v2, u1, v1, u3, v3,
205                                           tex);
206    if(y2 > y3)
207        return caca_fill_triangle_textured(cv,
208                                           x1, y1, x3, y3, x2, y2,
209                                           u1, v1, u3, v3, u2, v2,
210                                           tex);
211   
212   
213    /* Clip texture coordinates */
214        if(u1<0.0f) u1 = 0.0f; if(v1<0.0f) v1 = 0.0f;
215    if(u2<0.0f) u2 = 0.0f; if(v2<0.0f) v2 = 0.0f;
216    if(u3<0.0f) u3 = 0.0f; if(v3<0.0f) v3 = 0.0f;
217        if(u1>1.0f) u1 = 1.0f; if(v1>1.0f) v1 = 1.0f;
218        if(u2>1.0f) u2 = 1.0f; if(v2>1.0f) v2 = 1.0f;
219        if(u3>1.0f) u3 = 1.0f; if(v3>1.0f) v3 = 1.0f;
220   
221    /* Convert relative tex coordinates to absolute */
222        int tw = caca_get_canvas_width(tex);
223    int th = caca_get_canvas_height(tex);
224   
225    u1*=(float)tw; u2*=(float)tw; u3*=(float)tw;
226    v1*=(float)th; v2*=(float)th; v3*=(float)th;
227   
228    float x = (float) x1, y = (float) y1;
229    float y2y1 = y2-y1;
230    float y3y1 = y3-y1;
231    float y3y2 = y3-y2;
232   
233    /* Compute slopes, making sure we don't divide by zero */
234    /* (in this case, we don't need the value anyway) */
235    /* FIXME : only compute needed slopes */
236    float sl12 = ((float)x2 - x1) / (y2y1==0?1:y2y1);
237    float sl13 = ((float)x3 - x1) / (y3y1==0?1:y3y1);
238    float sl23 = ((float)x3 - x2) / (y3y2==0?1:y3y2);
239   
240    float usl12 = (u2 - u1) / (y2y1==0?1:y2y1);
241    float usl13 = (u3 - u1) / (y3y1==0?1:y3y1);
242    float usl23 = (u3 - u2) / (y3y2==0?1:y3y2);
243    float vsl12 = (v2 - v1) / (y2y1==0?1:y2y1);
244    float vsl13 = (v3 - v1) / (y3y1==0?1:y3y1);
245    float vsl23 = (v3 - v2) / (y3y2==0?1:y3y2);
246   
247    float xa = (float) x1, xb = (float) x1;
248    float ua = u1, ub = u1;
249    float va = v1, vb = v1;
250    float u, v;
251   
252        int s = 0;
253   
254    /* Top */
255    for(y = y1 ; y < y2; y++)
256    {
257       
258        if(xb < xa) {
259            SWAP_F(xb, xa);   
260            SWAP_F(sl13, sl12);
261            SWAP_F(ua, ub);
262            SWAP_F(va, vb);           
263            SWAP_F(usl13, usl12);
264            SWAP_F(vsl13, vsl12);
265            s=1;
266        }
267       
268        float tus = (ub - ua) / (xb - xa);
269        float tvs = (vb - va) / (xb - xa);
270        v = va; u = ua;
271       
272        /* scanline */
273        for(x = xa ; x < xb; x++)
274        {
275            u+=tus;
276            v+=tvs;
277            /* FIXME: use caca_get_canvas_attrs / caca_get_canvas_chars  */
278                uint32_t attr = caca_get_attr(tex, u, v);
279            uint32_t c    = caca_get_char(tex, u, v);
280            caca_set_attr(cv, attr);
281            caca_put_char(cv, x, y, c);
282        }
283       
284        xa+=sl13;
285        xb+=sl12;
286       
287        ua+=usl13; va+=vsl13;
288        ub+=usl12; vb+=vsl12;
289    }
290   
291    if(s)
292    {
293        SWAP_F(xb, xa);
294        SWAP_F(sl13, sl12);
295        SWAP_F(ua, ub);
296        SWAP_F(va, vb);           
297        SWAP_F(usl13, usl12);
298        SWAP_F(vsl13, vsl12);
299    }
300   
301   
302    /* Bottom */
303    xb = (float) x2;
304
305    /* These variables are set by 'top' routine
306     * and are in an incorrect state if we only draw the bottom part
307     */
308        if(y1 == y2) {
309        ua = u1;
310        ub = u2;
311        va = v1;
312        vb = v2;
313    }
314   
315    for(y = y2 ; y < y3; y++)
316    {
317        if(xb <= xa)
318        {
319            SWAP_F(xb, xa);   
320            SWAP_F(sl13, sl23);
321            SWAP_F(ua, ub);
322            SWAP_F(va, vb); 
323            SWAP_F(usl13, usl23);
324            SWAP_F(vsl13, vsl23);
325        }
326       
327        float tus = (ub - ua) / ((float)xb - xa);
328        float tvs = (vb - va) / ((float)xb - xa);
329        u = ua; v = va;
330       
331        /* scanline */
332        for(x = xa ; x < xb; x++)
333        {   
334            u+=tus;
335            v+=tvs;
336            /* FIXME, can be heavily optimised  */
337            uint32_t attr = caca_get_attr(tex, u, v);
338            uint32_t c    = caca_get_char(tex, u, v);
339            caca_set_attr(cv, attr);   
340            caca_put_char(cv, x, y, c);   
341        }
342       
343        xa+=sl13;
344        xb+=sl23;
345       
346        ua+=usl13; va+=vsl13;
347        ub+=usl23; vb+=vsl23;
348    }
349   
350        return 0;
351}
352
353
354/*
355 * XXX: The following functions are aliases.
356 */
357
358int cucul_draw_triangle(cucul_canvas_t *, int, int, int, int, int,
359                      int, uint32_t) CACA_ALIAS(caca_draw_triangle);
360int cucul_draw_thin_triangle(cucul_canvas_t *, int, int, int, int,
361                             int, int) CACA_ALIAS(caca_draw_thin_triangle);
362int cucul_fill_triangle(cucul_canvas_t *, int, int, int, int, int,
363                        int, uint32_t) CACA_ALIAS(caca_fill_triangle);
364
Note: See TracBrowser for help on using the repository browser.