diff --git a/caca/caca.h b/caca/caca.h index b6abb02..baf82e6 100644 --- a/caca/caca.h +++ b/caca/caca.h @@ -338,6 +338,14 @@ __extern int caca_draw_thin_triangle(caca_canvas_t *, int, int, int, int, int, int); __extern int caca_fill_triangle(caca_canvas_t *, int, int, int, int, int, int, uint32_t); +__extern int caca_fill_triangle_textured(caca_canvas_t *, + int , int , + int , int , + int , int , + float , float , + float , float , + float , float , + caca_canvas_t *); /* @} */ /** \defgroup caca_frame libcaca canvas frame handling diff --git a/caca/triangle.c b/caca/triangle.c index 5045e15..008df8d 100644 --- a/caca/triangle.c +++ b/caca/triangle.c @@ -155,6 +155,202 @@ int caca_fill_triangle(caca_canvas_t *cv, int x1, int y1, int x2, int y2, return 0; } +/** \brief Fill a triangle on the canvas using an arbitrary-sized texture. + * + * This function fails if one or both the canvas are missing + * + * \param cv The handle to the libcaca canvas. + * \param x1 X coordinate of the first point. + * \param y1 Y coordinate of the first point. + * \param x2 X coordinate of the second point. + * \param y2 Y coordinate of the second point. + * \param x3 X coordinate of the third point. + * \param y3 Y coordinate of the third point. + * \param u1 U texture coordinate of the first point. + * \param v1 V texture coordinate of the first point. + * \param u2 U texture coordinate of the second point. + * \param v2 V texture coordinate of the second point. + * \param u3 U texture coordinate of the third point. + * \param v3 V texture coordinate of the third point. + * \param tex The handle of the canvas texture. + * \return This function return 0 if ok, -1 if canvas or texture are missing. + */ +int caca_fill_triangle_textured(caca_canvas_t *cv, + int x1, int y1, + int x2, int y2, + int x3, int y3, + float u1, float v1, + float u2, float v2, + float u3, float v3, + caca_canvas_t *tex) +{ + + #define SWAP_F(a, b) {float c = a; a = b; b = c; } + + /* (very) Naive and + * (very) float-based affine and + * (very) non-clipped and + * (very) non-corrected triangle mapper + * + * Accepts arbitrary texture sizes + * Coordinates clamped to [0.0 - 1.0] (no repeat) + */ + if(!cv || !tex) return -1; + + /* Bubble-sort y1 <= y2 <= y3 */ + if(y1 > y2) + return caca_fill_triangle_textured(cv, + x2, y2, x1, y1, x3, y3, + u2, v2, u1, v1, u3, v3, + tex); + if(y2 > y3) + return caca_fill_triangle_textured(cv, + x1, y1, x3, y3, x2, y2, + u1, v1, u3, v3, u2, v2, + tex); + + + /* Clip texture coordinates */ + if(u1<0.0f) u1 = 0.0f; if(v1<0.0f) v1 = 0.0f; + if(u2<0.0f) u2 = 0.0f; if(v2<0.0f) v2 = 0.0f; + if(u3<0.0f) u3 = 0.0f; if(v3<0.0f) v3 = 0.0f; + if(u1>1.0f) u1 = 1.0f; if(v1>1.0f) v1 = 1.0f; + if(u2>1.0f) u2 = 1.0f; if(v2>1.0f) v2 = 1.0f; + if(u3>1.0f) u3 = 1.0f; if(v3>1.0f) v3 = 1.0f; + + /* Convert relative tex coordinates to absolute */ + int tw = caca_get_canvas_width(tex); + int th = caca_get_canvas_height(tex); + + u1*=(float)tw; u2*=(float)tw; u3*=(float)tw; + v1*=(float)th; v2*=(float)th; v3*=(float)th; + + float x = (float) x1, y = (float) y1; + float y2y1 = y2-y1; + float y3y1 = y3-y1; + float y3y2 = y3-y2; + + /* Compute slopes, making sure we don't divide by zero */ + /* (in this case, we don't need the value anyway) */ + /* FIXME : only compute needed slopes */ + float sl12 = ((float)x2 - x1) / (y2y1==0?1:y2y1); + float sl13 = ((float)x3 - x1) / (y3y1==0?1:y3y1); + float sl23 = ((float)x3 - x2) / (y3y2==0?1:y3y2); + + float usl12 = (u2 - u1) / (y2y1==0?1:y2y1); + float usl13 = (u3 - u1) / (y3y1==0?1:y3y1); + float usl23 = (u3 - u2) / (y3y2==0?1:y3y2); + float vsl12 = (v2 - v1) / (y2y1==0?1:y2y1); + float vsl13 = (v3 - v1) / (y3y1==0?1:y3y1); + float vsl23 = (v3 - v2) / (y3y2==0?1:y3y2); + + float xa = (float) x1, xb = (float) x1; + float ua = u1, ub = u1; + float va = v1, vb = v1; + float u, v; + + int s = 0; + + /* Top */ + for(y = y1 ; y < y2; y++) + { + + if(xb < xa) { + SWAP_F(xb, xa); + SWAP_F(sl13, sl12); + SWAP_F(ua, ub); + SWAP_F(va, vb); + SWAP_F(usl13, usl12); + SWAP_F(vsl13, vsl12); + s=1; + } + + float tus = (ub - ua) / (xb - xa); + float tvs = (vb - va) / (xb - xa); + v = va; u = ua; + + /* scanline */ + for(x = xa ; x < xb; x++) + { + u+=tus; + v+=tvs; + /* FIXME: use caca_get_canvas_attrs / caca_get_canvas_chars */ + uint32_t attr = caca_get_attr(tex, u, v); + uint32_t c = caca_get_char(tex, u, v); + caca_set_attr(cv, attr); + caca_put_char(cv, x, y, c); + } + + xa+=sl13; + xb+=sl12; + + ua+=usl13; va+=vsl13; + ub+=usl12; vb+=vsl12; + } + + if(s) + { + SWAP_F(xb, xa); + SWAP_F(sl13, sl12); + SWAP_F(ua, ub); + SWAP_F(va, vb); + SWAP_F(usl13, usl12); + SWAP_F(vsl13, vsl12); + } + + + /* Bottom */ + xb = (float) x2; + + /* These variables are set by 'top' routine + * and are in an incorrect state if we only draw the bottom part + */ + if(y1 == y2) { + ua = u1; + ub = u2; + va = v1; + vb = v2; + } + + for(y = y2 ; y < y3; y++) + { + if(xb <= xa) + { + SWAP_F(xb, xa); + SWAP_F(sl13, sl23); + SWAP_F(ua, ub); + SWAP_F(va, vb); + SWAP_F(usl13, usl23); + SWAP_F(vsl13, vsl23); + } + + float tus = (ub - ua) / ((float)xb - xa); + float tvs = (vb - va) / ((float)xb - xa); + u = ua; v = va; + + /* scanline */ + for(x = xa ; x < xb; x++) + { + u+=tus; + v+=tvs; + /* FIXME, can be heavily optimised */ + uint32_t attr = caca_get_attr(tex, u, v); + uint32_t c = caca_get_char(tex, u, v); + caca_set_attr(cv, attr); + caca_put_char(cv, x, y, c); + } + + xa+=sl13; + xb+=sl23; + + ua+=usl13; va+=vsl13; + ub+=usl23; vb+=vsl23; + } + + return 0; +} + + /* * XXX: The following functions are aliases. */ diff --git a/configure.ac b/configure.ac index 5bce1f8..e4312b2 100644 --- a/configure.ac +++ b/configure.ac @@ -258,7 +258,7 @@ if test "${enable_cocoa}" != "no"; then MACOSX_SDK_CXXFLAGS="${MACOSX_SDK_CXXFLAGS:-${MACOSX_SDK_CFLAGS}}" ;; x*86*darwin*) - MACOSX_SDK="${MACOSX_SDK:-/Developer/SDKs/MacOSX10.4u.sdk}" + MACOSX_SDK="${MACOSX_SDK:-/Developer/SDKs/MacOSX10.6.sdk}" GCC_VERSION="${GCC_VERSION:-4.0}" ARCH="${ARCH:--arch i386}" MACOSX_SDK_CFLAGS="${MACOSX_SDK_CFLAGS:--isysroot ${MACOSX_SDK}}" diff --git a/examples/Makefile.am b/examples/Makefile.am index 35372f9..ebf7d56 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -2,12 +2,15 @@ AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/caca -I$(top_builddir)/caca -noinst_PROGRAMS = blit canvas colors conio $(conio_snake) demo demo0 dithering driver event export figfont font font2tga frames fullwidth gamma hsv input spritedit swallow text transform truecolor unicode import +noinst_PROGRAMS = trifiller blit canvas colors conio $(conio_snake) demo demo0 dithering driver event export figfont font font2tga frames fullwidth gamma hsv input spritedit swallow text transform truecolor unicode import if USE_CXX conio_snake = conio-snake endif +trifiller_SOURCES = trifiller.c ../src/common-image.c +trifiller_LDADD = ../caca/libcaca.la + blit_SOURCES = blit.c blit_LDADD = ../caca/libcaca.la diff --git a/examples/trifiller.c b/examples/trifiller.c new file mode 100644 index 0000000..3b1de73 --- /dev/null +++ b/examples/trifiller.c @@ -0,0 +1,239 @@ +/* + * trifiller texture mapping features + * Copyright (c) 2009 Jean-Yves Lamoureux + * All Rights Reserved + * + * $Id: trifiller.c 2821 2008-09-27 13:12:46Z sam $ + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + + +#include "config.h" + +#if !defined(__KERNEL__) +# include +# include +#endif + +/* libcaca header */ +#include "caca.h" + +/* Image loading functions */ +#include "../src/common-image.h" + +/* M_PI / cos / sin */ +#include + + +#define SQUARE_SIZE 20 + +int main(int argc, char *argv[]) +{ + + /* libcaca/libcaca contexts */ + caca_canvas_t *cv; caca_display_t *dp; + caca_canvas_t *tex; + + /* cached canvas size */ + int ww, wh, tw, th; + + /* logic */ + int quit = 0; + int update = 1; + int px, py; + float angle = 0; + + + float square[4][2] = { + {-SQUARE_SIZE, -SQUARE_SIZE}, + { SQUARE_SIZE, -SQUARE_SIZE}, + { SQUARE_SIZE, SQUARE_SIZE}, + {-SQUARE_SIZE, SQUARE_SIZE}, + }; + + float rotated[4][2]; + + /* Create displayed canvas */ + cv = caca_create_canvas(0, 0); + if(!cv) + { + fprintf(stderr, "%s: unable to initialise libcaca\n", argv[0]); + return 1; + } + + /* Create texture holding canvas */ + tex = caca_create_canvas(16, 16); + if(!tex) + { + fprintf(stderr, "%s: unable to initialise libcaca\n", argv[0]); + return 1; + } + + /* Open window */ + dp = caca_create_display(cv); + if(!dp) + { + fprintf(stderr, "%s: unable to initialise libcaca\n", argv[0]); + return 1; + } + + + + /* Set the window title */ + caca_set_display_title(dp, "trifiller"); + + /* Frame duration */ + caca_set_display_time(dp, 10000); + + /* Get displayed canvas size */ + ww = caca_get_canvas_width(cv); + wh = caca_get_canvas_height(cv); + + /* Texture size */ + tw = caca_get_canvas_width(tex); + th = caca_get_canvas_height(tex); + + /* Load texture if any */ + if(argc == 2) + { + struct image *im = load_image(argv[1]); + if(!im) + { + fprintf(stderr, "%s: unable to load image '%s'\n", argv[0], argv[1]); + return 1; + } + + caca_set_dither_algorithm(im->dither, + caca_get_dither_algorithm_list(NULL)[4]); + caca_dither_bitmap(tex, + 0, 0, + tw, th, + im->dither, im->pixels); + unload_image(im); + } + /* or generate one */ + else + { + + int i; + for(i = 0; i < 16; i ++) + { + caca_set_color_ansi(tex, (i+1)%0xF, i); + caca_put_str(tex, 0, i, "123456789ABCDEF"); + } + } + + + px = 0; + py = 0; + + while(!quit) + { + caca_event_t ev; + unsigned int const event_mask = CACA_EVENT_KEY_PRESS + | CACA_EVENT_RESIZE + | CACA_EVENT_QUIT; + int event; + + if(update) + event = caca_get_event(dp, event_mask, &ev, 0); + else + event = caca_get_event(dp, event_mask, &ev, -1); + + while(event) + { + if(caca_get_event_type(&ev) & CACA_EVENT_KEY_PRESS) + switch(caca_get_event_key_ch(&ev)) + { + case 'q': + case 'Q': + case CACA_KEY_ESCAPE: + quit = 1; + break; + case CACA_KEY_UP: + py--; + break; + case CACA_KEY_DOWN: + py++; + break; + case CACA_KEY_LEFT: + px--; + break; + case CACA_KEY_RIGHT: + px++; + break; + case 'a': + angle+=1.0f; + break; + case 's': + angle-=1.0f; + break; + } + else if(caca_get_event_type(&ev) == CACA_EVENT_RESIZE) + { + caca_refresh_display(dp); + ww = caca_get_event_resize_width(&ev); + wh = caca_get_event_resize_height(&ev); + update = 1; + } + else if(caca_get_event_type(&ev) & CACA_EVENT_QUIT) + quit = 1; + + event = caca_get_event(dp, CACA_EVENT_KEY_PRESS, &ev, 0); + } + + + + /* 2D Rotation around screen center */ + int p; + for(p=0; p<4; p++) + { + rotated[p][0] = square[p][0] * cos(angle*M_PI/180.0f) - square[p][1] * sin(angle*M_PI/180.0f); + rotated[p][1] = square[p][0] * sin(angle*M_PI/180.0f) + square[p][1] * cos(angle*M_PI/180.0f); + + rotated[p][0] += ww/2 + px; + rotated[p][1] += wh/2 + py; + } + + angle+=1.0f; + + /* Display two triangles */ + caca_fill_triangle_textured(cv, + /* triangle screen coordinates */ + rotated[0][0], rotated[0][1], + rotated[1][0], rotated[1][1], + rotated[2][0], rotated[2][1], + /* texture coordinates */ + 0, 0, + 1, 0, + 1, 1, + tex); + + caca_fill_triangle_textured(cv, + /* triangle screen coordinates */ + rotated[0][0], rotated[0][1], + rotated[2][0], rotated[2][1], + rotated[3][0], rotated[3][1], + /* texture coordinates */ + 0, 0, + 1, 1, + 0, 1, + tex); + + /* Refresh display and clear for next frame */ + caca_refresh_display(dp); + caca_clear_canvas(cv); + + } + + caca_free_display(dp); + caca_free_canvas(cv); + caca_free_canvas(tex); + + return 0; +} \ No newline at end of file