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

Last change on this file since 3952 was 3926, checked in by Jean-Yves Lamoureux, 10 years ago
  • Make caca_fill_triangle_textured use less arguments, examples/trifiller modified accordingly
  • Property svn:keywords set to Id
File size: 11.1 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 3926 2009-11-18 11:25:58Z 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/* This function actually renders the triangle,
159 * but is not exported due to sam's pedantic will. */
160static int caca_fill_triangle_textured_l(caca_canvas_t *cv,
161                                int x1, int y1,
162                                int x2, int y2,
163                                        int x3, int y3,
164                                caca_canvas_t *tex,
165                                float u1, float v1,
166                                float u2, float v2,
167                                        float u3, float v3)
168                               
169{
170    uint32_t savedattr;
171
172    #define SWAP_F(a, b) {float c = a; a = b; b = c; }
173   
174    /* (very) Naive and
175     * (very) float-based affine and
176     * (very) non-clipped and
177     * (very) non-corrected triangle mapper
178     *
179     * Accepts arbitrary texture sizes
180     * Coordinates clamped to [0.0 - 1.0] (no repeat)
181     */
182    if(!cv || !tex) return -1;
183
184    /* Bubble-sort y1 <= y2 <= y3 */
185    if(y1 > y2)
186        return caca_fill_triangle_textured_l(cv,
187                                             x2, y2, x1, y1, x3, y3,
188                                             tex,
189                                             u2, v2, u1, v1, u3, v3);
190    if(y2 > y3)
191        return caca_fill_triangle_textured_l(cv,
192                                             x1, y1, x3, y3, x2, y2,
193                                             tex,
194                                             u1, v1, u3, v3, u2, v2);
195
196    savedattr = caca_get_attr(cv, -1, -1);
197
198    /* Clip texture coordinates */
199    if(u1<0.0f) u1 = 0.0f; if(v1<0.0f) v1 = 0.0f;
200    if(u2<0.0f) u2 = 0.0f; if(v2<0.0f) v2 = 0.0f;
201    if(u3<0.0f) u3 = 0.0f; if(v3<0.0f) v3 = 0.0f;
202    if(u1>1.0f) u1 = 1.0f; if(v1>1.0f) v1 = 1.0f;
203    if(u2>1.0f) u2 = 1.0f; if(v2>1.0f) v2 = 1.0f;
204    if(u3>1.0f) u3 = 1.0f; if(v3>1.0f) v3 = 1.0f;
205   
206    /* Convert relative tex coordinates to absolute */
207    int tw = caca_get_canvas_width(tex);
208    int th = caca_get_canvas_height(tex);
209   
210    u1*=(float)tw; u2*=(float)tw; u3*=(float)tw;
211    v1*=(float)th; v2*=(float)th; v3*=(float)th;
212   
213    int x, y;
214    float y2y1 = y2-y1;
215    float y3y1 = y3-y1;
216    float y3y2 = y3-y2;
217   
218    /* Compute slopes, making sure we don't divide by zero */
219    /* (in this case, we don't need the value anyway) */
220    /* FIXME : only compute needed slopes */
221    float sl12 = ((float)x2 - x1) / (y2y1==0?1:y2y1);
222    float sl13 = ((float)x3 - x1) / (y3y1==0?1:y3y1);
223    float sl23 = ((float)x3 - x2) / (y3y2==0?1:y3y2);
224   
225    float usl12 = (u2 - u1) / (y2y1==0?1:y2y1);
226    float usl13 = (u3 - u1) / (y3y1==0?1:y3y1);
227    float usl23 = (u3 - u2) / (y3y2==0?1:y3y2);
228    float vsl12 = (v2 - v1) / (y2y1==0?1:y2y1);
229    float vsl13 = (v3 - v1) / (y3y1==0?1:y3y1);
230    float vsl23 = (v3 - v2) / (y3y2==0?1:y3y2);
231   
232    float xa = (float) x1, xb = (float) x1;
233    float ua = u1, ub = u1;
234    float va = v1, vb = v1;
235    float u, v;
236   
237    int s = 0;
238   
239    /* Top */
240    for(y = y1 ; y < y2; y++)
241    {
242       
243        if(xb < xa) {
244            SWAP_F(xb, xa);   
245            SWAP_F(sl13, sl12);
246            SWAP_F(ua, ub);
247            SWAP_F(va, vb);           
248            SWAP_F(usl13, usl12);
249            SWAP_F(vsl13, vsl12);
250            s=1;
251        }
252       
253        float tus = (ub - ua) / (xb - xa);
254        float tvs = (vb - va) / (xb - xa);
255        v = va; u = ua;
256       
257        /* scanline */
258        for(x = xa ; x < xb; x++)
259        {
260            u+=tus;
261            v+=tvs;
262            /* FIXME: use caca_get_canvas_attrs / caca_get_canvas_chars  */
263            uint32_t attr = caca_get_attr(tex, u, v);
264            uint32_t c    = caca_get_char(tex, u, v);
265            caca_set_attr(cv, attr);
266            caca_put_char(cv, x, y, c);
267        }
268       
269        xa+=sl13;
270        xb+=sl12;
271       
272        ua+=usl13; va+=vsl13;
273        ub+=usl12; vb+=vsl12;
274    }
275   
276    if(s)
277    {
278        SWAP_F(xb, xa);
279        SWAP_F(sl13, sl12);
280        SWAP_F(ua, ub);
281        SWAP_F(va, vb);
282        SWAP_F(usl13, usl12);
283        SWAP_F(vsl13, vsl12);
284    }
285   
286   
287    /* Bottom */
288    xb = (float) x2;
289
290    /* These variables are set by 'top' routine
291     * and are in an incorrect state if we only draw the bottom part
292     */
293        if(y1 == y2) {
294        ua = u1;
295        ub = u2;
296        va = v1;
297        vb = v2;
298    }
299   
300    for(y = y2 ; y < y3; y++)
301    {
302        if(xb <= xa)
303        {
304            SWAP_F(xb, xa);
305            SWAP_F(sl13, sl23);
306            SWAP_F(ua, ub);
307            SWAP_F(va, vb);
308            SWAP_F(usl13, usl23);
309            SWAP_F(vsl13, vsl23);
310        }
311       
312        float tus = (ub - ua) / ((float)xb - xa);
313        float tvs = (vb - va) / ((float)xb - xa);
314        u = ua; v = va;
315       
316        /* scanline */
317        for(x = xa ; x < xb; x++)
318        {   
319            u+=tus;
320            v+=tvs;
321            /* FIXME, can be heavily optimised  */
322            uint32_t attr = caca_get_attr(tex, u, v);
323            uint32_t c    = caca_get_char(tex, u, v);
324            caca_set_attr(cv, attr);
325            caca_put_char(cv, x, y, c);
326        }
327
328        xa+=sl13;
329        xb+=sl23;
330       
331        ua+=usl13; va+=vsl13;
332        ub+=usl23; vb+=vsl23;
333    }
334
335    caca_set_attr(cv, savedattr);
336
337    return 0;
338}
339
340/** \brief Fill a triangle on the canvas using an arbitrary-sized texture.
341 *
342 *  This function fails if one or both the canvas are missing
343 *
344 *  \param cv     The handle to the libcaca canvas.
345 *  \param coords The coordinates of the triangle (3{x,y})
346 *  \param tex    The handle of the canvas texture.
347 *  \param uv     The coordinates of the texture (3{u,v})
348 *  \return This function return 0 if ok, -1 if canvas or texture are missing.
349 */
350int caca_fill_triangle_textured(caca_canvas_t *cv,
351                                int coords[6],
352                                caca_canvas_t *tex,
353                                float uv[6]) {
354   
355    return caca_fill_triangle_textured_l(cv,
356                                         coords[0], coords[1],
357                                         coords[2], coords[3],
358                                         coords[4], coords[5],
359                                         tex,
360                                         uv[0],     uv[1],
361                                         uv[2],     uv[3],
362                                         uv[4],     uv[5]);
363}
364
365
366
367/*
368 * XXX: The following functions are aliases.
369 */
370
371int cucul_draw_triangle(cucul_canvas_t *, int, int, int, int, int,
372                      int, uint32_t) CACA_ALIAS(caca_draw_triangle);
373int cucul_draw_thin_triangle(cucul_canvas_t *, int, int, int, int,
374                             int, int) CACA_ALIAS(caca_draw_thin_triangle);
375int cucul_fill_triangle(cucul_canvas_t *, int, int, int, int, int,
376                        int, uint32_t) CACA_ALIAS(caca_fill_triangle);
377
Note: See TracBrowser for help on using the repository browser.