diff --git a/docs/AUTHORS.txt b/docs/AUTHORS.txt index d1d97e306..97419d826 100644 --- a/docs/AUTHORS.txt +++ b/docs/AUTHORS.txt @@ -7,7 +7,7 @@ bill@newbreedsoftware.com http://www.tuxpaint.org/ -June 17, 2002 - April 1, 2009 +June 17, 2002 - April 5, 2009 $Id$ @@ -66,6 +66,9 @@ $Id$ with modifications by Bill Kendrick and Pere Pujal i Carabantes + Math for arc used by Real Rainbow provided by + Jeff Newmiller + * Graphics @@ -84,6 +87,12 @@ $Id$ * Neko cat brushes based on XNeko by Masayuki Koba + * Real Rainbow colors/alpha based on: + http://www.flickr.com/photos/nicholas_t/281820290/ + photo by Flickr user "Nicholas_T" + Creative Commons Attribution 2.0 Generic + http://creativecommons.org/licenses/by/2.0/deed.en + * More brushes created using Inkscape by Caroline Ford (Licensed under GFDL/CC-BY-SA/GPL) diff --git a/docs/CHANGES.txt b/docs/CHANGES.txt index 643aab5ad..b5761e91a 100644 --- a/docs/CHANGES.txt +++ b/docs/CHANGES.txt @@ -8,7 +8,7 @@ http://www.tuxpaint.org/ $Id$ -2009.April.1 (0.9.21) +2009.April.5 (0.9.21) * New Starters: ------------- * Silver Frame @@ -49,6 +49,15 @@ $Id$ with modifications by Bill Kendrick and Pere Pujal i Carabantes + * Real Rainbow - Draw an arc-shaped, photorealistic rainbow. + By Bill Kendrick + with math help from Jeff Newmiller + Rainbow colors/alpha based on photo from + http://www.flickr.com/photos/nicholas_t/281820290/ + photo by Flickr user "Nicholas_T" + Creative Commons Attribution 2.0 Generic + http://creativecommons.org/licenses/by/2.0/deed.en + * String Edges - Draw string-like patters around the screen. String Corner - Draw aligned string-like patterns. String 'V' - Draw free-form string-like patterns. diff --git a/magic/icons/realrainbow-colors.png b/magic/icons/realrainbow-colors.png new file mode 100644 index 000000000..ab41c73fc Binary files /dev/null and b/magic/icons/realrainbow-colors.png differ diff --git a/magic/src/realrainbow.c b/magic/src/realrainbow.c new file mode 100644 index 000000000..3554b706f --- /dev/null +++ b/magic/src/realrainbow.c @@ -0,0 +1,322 @@ +/* + realrainbow.c + + Draws an arc with semi-transparent rainbow colors. + + by Bill Kendrick + Math assistence by Jeff Newmiller + + 2009.04.02 - 2009.04.05 +*/ + +#include +#include +#include +#include "SDL_image.h" + +#include "tp_magic_api.h" + +int realrainbow_x1, realrainbow_y1, realrainbow_x2, realrainbow_y2; +SDL_Rect realrainbow_rect; +SDL_Surface * realrainbow_colors; +Uint8 realrainbow_blendr, realrainbow_blendg, realrainbow_blendb, realrainbow_blenda; + + +void realrainbow_arc(magic_api * api, SDL_Surface * canvas, SDL_Surface * last, + int x1, int y1, int x2, int y2, + int fulldraw, SDL_Rect * update_rect); +static void realrainbow_linecb(void * ptr, int which, + SDL_Surface * canvas, SDL_Surface * last, + int x, int y); + + +Uint32 realrainbow_api_version(void) +{ + return(TP_MAGIC_API_VERSION); +} + +int realrainbow_init(magic_api * api) +{ + char fname[1024]; + + snprintf(fname, sizeof(fname), "%s/images/magic/realrainbow-colors.png", api->data_directory); + realrainbow_colors = IMG_Load(fname); + if (realrainbow_colors == NULL) + return(0); + + return(1); +} + +int realrainbow_get_tool_count(magic_api * api) +{ + return(1); +} + +SDL_Surface * realrainbow_get_icon(magic_api * api, int which) +{ + /* FIXME */ + return(NULL); +} + +char * realrainbow_get_name(magic_api * api, int which) +{ + return(strdup(gettext("Real Rainbow"))); +} + +char * realrainbow_get_description(magic_api * api, int which, int mode) +{ + return(strdup(gettext("Click where you want your rainbow to start, drag to where you want it to end, and then let go to draw a rainbow."))); +} + +int realrainbow_modes(magic_api * api, int which) +{ + return(MODE_PAINT); +} + +int realrainbow_requires_colors(magic_api * api, int which) +{ + return(0); +} + +void realrainbow_shutdown(magic_api * api) +{ + SDL_FreeSurface(realrainbow_colors); +} + +void realrainbow_set_color(magic_api * api, Uint8 r, Uint8 g, Uint8 b) +{ +} + +void realrainbow_click(magic_api * api, int which, int mode, + SDL_Surface * canvas, SDL_Surface * last, + int x, int y, + SDL_Rect * update_rect) +{ + realrainbow_x1 = x; + realrainbow_y1 = y; + + realrainbow_rect.x = x; + realrainbow_rect.y = y; + realrainbow_rect.w = 1; + realrainbow_rect.h = 1; +} + +void realrainbow_drag(magic_api * api, int which, + SDL_Surface * canvas, SDL_Surface * last, + int ox, int oy, int x, int y, + SDL_Rect * update_rect) +{ + int rx1, ry1, rx2, ry2; + SDL_Rect rect; + + realrainbow_x2 = x; + realrainbow_y2 = y; + + SDL_BlitSurface(last, &realrainbow_rect, canvas, &realrainbow_rect); + + realrainbow_arc(api, canvas, last, realrainbow_x1, realrainbow_y1, realrainbow_x2, realrainbow_y2, 0, update_rect); + + memcpy(&rect, &realrainbow_rect, sizeof(SDL_Rect)); + memcpy(&realrainbow_rect, update_rect, sizeof(SDL_Rect)); + + rx1 = update_rect->x; + ry1 = update_rect->y; + rx2 = update_rect->x + update_rect->w; + ry2 = update_rect->y + update_rect->h; + + if (rect.x < rx1) + rx1 = rect.x; + if (rect.x + rect.w > rx2) + rx2 = rect.x + rect.w; + if (rect.y < ry1) + ry1 = rect.y; + if (rect.y + rect.h > ry2) + ry2 = rect.y + rect.h; + + update_rect->x = rx1; + update_rect->y = ry1; + update_rect->w = rx2 - rx1 + 1; + update_rect->h = ry2 - ry1 + 1; +} + +void realrainbow_release(magic_api * api, int which, + SDL_Surface * canvas, SDL_Surface * last, + int x, int y, + SDL_Rect * update_rect) +{ + int rx1, ry1, rx2, ry2; + SDL_Rect rect; + + realrainbow_x2 = x; + realrainbow_y2 = y; + + SDL_BlitSurface(last, &realrainbow_rect, canvas, &realrainbow_rect); + + realrainbow_arc(api, canvas, last, realrainbow_x1, realrainbow_y1, realrainbow_x2, realrainbow_y2, 1, update_rect); + + memcpy(&rect, &realrainbow_rect, sizeof(SDL_Rect)); + memcpy(&realrainbow_rect, update_rect, sizeof(SDL_Rect)); + + rx1 = update_rect->x; + ry1 = update_rect->y; + rx2 = update_rect->x + update_rect->w; + ry2 = update_rect->y + update_rect->h; + + if (rect.x < rx1) + rx1 = rect.x; + if (rect.x + rect.w > rx2) + rx2 = rect.x + rect.w; + if (rect.y < ry1) + ry1 = rect.y; + if (rect.y + rect.h > ry2) + ry2 = rect.y + rect.h; + + update_rect->x = rx1; + update_rect->y = ry1; + update_rect->w = rx2 - rx1 + 1; + update_rect->h = ry2 - ry1 + 1; +} + +void realrainbow_switchin(magic_api * api, int which, int mode, SDL_Surface * canvas) +{ +} + +void realrainbow_switchout(magic_api * api, int which, int mode, SDL_Surface * canvas) +{ +} + + +void realrainbow_arc(magic_api * api, SDL_Surface * canvas, SDL_Surface * last, int x1, int y1, int x2, int y2, int fulldraw, SDL_Rect * update_rect) +{ + int lowx, lowy, hix, hiy, xm, ym, xc, yc, r, a1, atan2_a, atan2_b; + int a, ox, oy, nx, ny, step, thick, rr, done; + float slope, theta; + int colorindex; + + if (abs(x2 - x1) < 50) + { + if (x2 > x1) + x2 = x1 + 50; + else + x2 = x1 - 50; + } + + if (y1 == y2) + { + xc = x1 + abs(x2 - x1) / 2; + yc = y1; + r = abs(xc - x1); + + a1 = 0; + theta = -180; + } + else + { + if (y1 > y2) + { + lowx = x1; + lowy = y1; + hix = x2; + hiy = y2; + } + else + { + lowx = x2; + lowy = y2; + hix = x1; + hiy = y1; + } + + xm = (lowx + hix) / 2; + ym = (lowy + hiy) / 2; + + if (hix == lowx) + return; + + slope = (float)(hiy - lowy) / (float)(hix - lowx); + + yc = lowy; + xc = slope * (ym - yc) + xm; + + r = abs(xc - lowx); + atan2_b = hix - xc; + atan2_a = hiy - yc; + theta = atan2(atan2_a, atan2_b) * (180.0 / M_PI); + + if (slope > 0) + a1 = 0; + else + a1 = -180; + } + + if (fulldraw) + { + step = 1; + thick = (r / 5); + } + else + { + step = 10; + thick = 1; + } + + if (theta < a1) + step = -step; + done = 0; + + for (a = (a1 + step); !done; a = a + step) + { + for (rr = r - (thick / 2); rr <= r + (thick / 2); rr++) + { + ox = (rr * cos((a - step) * M_PI / 180.0)) + xc; + oy = (rr * sin((a - step) * M_PI / 180.0)) + yc; + + nx = (rr * cos(a * M_PI / 180.0)) + xc; + ny = (rr * sin(a * M_PI / 180.0)) + yc; + + if (fulldraw) + { + colorindex = realrainbow_colors->h - 1 - (((rr - r + (thick / 2)) * realrainbow_colors->h) / thick); + + SDL_GetRGBA(api->getpixel(realrainbow_colors, 0, colorindex), + realrainbow_colors->format, &realrainbow_blendr, &realrainbow_blendg, &realrainbow_blendb, &realrainbow_blenda); + + api->line((void *) api, 0, canvas, last, ox, oy, nx, ny, 1, realrainbow_linecb); + } + else + { + api->putpixel(canvas, ox, oy, + SDL_MapRGB(canvas->format, rand() % 256, rand() % 256, rand() % 256)); + } + } + + if (step > 0 && a + step > theta) + done = 1; + else if (step < 0 && a - step < theta) + done = 1; + } + + update_rect->y = yc - r - thick - 2; + update_rect->h = r + thick * 2 + 4; + update_rect->x = xc - r - thick; + update_rect->w = r * 2 + thick * 2; +} + +static void realrainbow_linecb(void * ptr, int which, + SDL_Surface * canvas, SDL_Surface * last, + int x, int y) +{ + magic_api * api = (magic_api *) ptr; + Uint8 origr, origg, origb; + Uint8 newr, newg, newb; + + SDL_GetRGB(api->getpixel(last, x, y), + last->format, &origr, &origg, &origb); + + newr = ((realrainbow_blendr * realrainbow_blenda) / 255) + ((origr * (255 - realrainbow_blenda)) / 255); + newg = ((realrainbow_blendg * realrainbow_blenda) / 255) + ((origg * (255 - realrainbow_blenda)) / 255); + newb = ((realrainbow_blendb * realrainbow_blenda) / 255) + ((origb * (255 - realrainbow_blenda)) / 255); + + api->putpixel(canvas, x, y, SDL_MapRGB(canvas->format, newr, newg, newb)); +} +