From 609a8d5104be2ed5b24b58ae9151d3f08b5c3c05 Mon Sep 17 00:00:00 2001 From: William Kendrick Date: Mon, 4 Sep 2006 06:26:12 +0000 Subject: [PATCH] Added support for animated brushes. --- data/brushes/vine.dat | 2 +- docs/CHANGES.txt | 10 ++++- docs/EXTENDING.txt | 33 +++++++++++++-- docs/html/EXTENDING.html | 40 +++++++++++++++++-- src/tuxpaint.c | 86 +++++++++++++++++++++++++++++----------- 5 files changed, 139 insertions(+), 32 deletions(-) diff --git a/data/brushes/vine.dat b/data/brushes/vine.dat index ff0527314..db0bb6e0a 100644 --- a/data/brushes/vine.dat +++ b/data/brushes/vine.dat @@ -1 +1 @@ -frames=7 +frames=6 diff --git a/docs/CHANGES.txt b/docs/CHANGES.txt index a4cbd6896..cbff03141 100644 --- a/docs/CHANGES.txt +++ b/docs/CHANGES.txt @@ -9,7 +9,7 @@ http://www.newbreedsoftware.com/tuxpaint/ $Id$ -2006.September.2 (0.9.16) +2006.September.3 (0.9.16) * Interface improvements: ----------------------- * New slideshow tool! ("Slides", available in "Open" dialog.) @@ -68,6 +68,14 @@ $Id$ * Round erasers added. + * Brushes may be animated. + (Create an image (W*N) x H in size (where N is number of frames), + then create a ".dat" file for the brush containing "frames=N". + + * New Brushes: + ------------ + * Vines (animated) + * New Starter Images: ------------------- * Shipwreck diff --git a/docs/EXTENDING.txt b/docs/EXTENDING.txt index e83ced88d..2e5d4dd02 100644 --- a/docs/EXTENDING.txt +++ b/docs/EXTENDING.txt @@ -8,7 +8,7 @@ bill@newbreedsoftware.com http://www.newbreedsoftware.com/tuxpaint/ - June 14, 2002 - March 12, 2006 + June 14, 2002 - September 3, 2006 -------------------------------------------------------------------------- @@ -119,16 +119,43 @@ Where Files Go Brushes The brushes used for drawing with the 'Brush' and 'Lines' tools in - Tux Paint are simply greyscale PNG images. + Tux Paint are simply PNG image files. The alpha (transparency) of the PNG image is used to determine the shape of the brush, which means that the shape can be 'anti-aliased' and even partially-transparent! + Greyscale pixels in the brush PNG will be drawn using the + currently-selected color in Tux Paint. Color pixels will be tinted. + Brush images should be no wider than 40 pixels across and no taller than 40 pixels high. (i.e., the maximum size can be 40 x 40.) - Just place them in the "brushes" directory. + Brush Options + + Aside from a graphical shape, brushes can also be given other + attributes. To do this, you need to create a 'data file' for the + brush. + + A brush data file is simply a text file containing the options. + + The file has the same name as the PNG image, but a ".dat" extension. + (e.g., "brush.png"'s data file is the text file "brush.dat" in the + same directory.) + + Animated Brushes + + As of Tux Paint version 0.9.16, you may now create animated brushes. + As the brush is drawn, each frame of the animation is displayed. + + Lay each frame out across a wide PNG image. For example, if your + brush is 30x30 and you have 5 frames, the image should be 150x30. + + Add a line containing the line "frames=N" to the brush's data file, + where N is the number of frames in the brush. + + Place the brush image PNGs (and any data text files) in the "brushes" + directory. Note: If your new brushes all come out as solid squares or rectangles, it's because you forgot to use alpha transparency! See the documentation diff --git a/docs/html/EXTENDING.html b/docs/html/EXTENDING.html index a805fede7..ae66e1383 100644 --- a/docs/html/EXTENDING.html +++ b/docs/html/EXTENDING.html @@ -23,7 +23,7 @@ New Breed Software

bill@newbreedsoftware.com
http://www.newbreedsoftware.com/tuxpaint/

-

June 14, 2002 - March 12, 2006

+

June 14, 2002 - September 3, 2006


@@ -187,7 +187,7 @@ effect.

Brushes

The brushes used for drawing with the 'Brush' and 'Lines' tools in - Tux Paint are simply greyscale PNG images.

+ Tux Paint are simply PNG image files.

@@ -195,11 +195,45 @@ effect.

of the brush, which means that the shape can be 'anti-aliased' and even partially-transparent!

+

Greyscale pixels in the brush PNG will be drawn using the + currently-selected color in Tux Paint. Color pixels will be + tinted.

+

Brush images should be no wider than 40 pixels across and no taller than 40 pixels high. (i.e., the maximum size can be 40 x 40.)

-

Just place them in the "brushes" directory.

+ +

Brush Options

+
+

Aside from a graphical shape, brushes can also be given other + attributes. To do this, you need to create a 'data file' + for the brush.

+ +

A brush data file is simply a text file containing the options.

+ +

The file has the same name as the PNG image, but a ".dat" + extension. (e.g., "brush.png"'s data file is the text + file "brush.dat" in the same directory.)

+ +

Animated Brushes

+
+

As of Tux Paint version 0.9.16, you may now create animated + brushes. As the brush is drawn, each frame of the animation is + displayed.

+ +

Lay each frame out across a wide PNG image. For example, + if your brush is 30x30 and you have 5 frames, the image should + be 150x30.

+ +

Add a line containing the line "frames=N" + to the brush's data file, where N is the number of frames + in the brush.

+
+
+ +

Place the brush image PNGs (and any data text files) in the + "brushes" directory.

Note: If your new brushes all come out as solid squares or rectangles, it's because you forgot to use alpha transparency! See the documentation diff --git a/src/tuxpaint.c b/src/tuxpaint.c index 8382bdfa9..5b7361c17 100644 --- a/src/tuxpaint.c +++ b/src/tuxpaint.c @@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (See COPYING.txt) - June 14, 2002 - August 28, 2006 + June 14, 2002 - September 3, 2006 $Id$ */ @@ -972,7 +972,8 @@ static SDL_Surface *img_color_btn_off; static int colors_are_selectable; static SDL_Surface *img_cur_brush; -static int brush_counter, rainbow_color; +int img_cur_brush_w, img_cur_brush_h, img_cur_brush_frames; +static int brush_counter, rainbow_color, brush_frame; #define NUM_ERASERS 12 /* How many sizes of erasers (from ERASER_MIN to _MAX as squares, then again @@ -1070,6 +1071,9 @@ static void rect_xor(int x1, int y1, int x2, int y2); static void draw_blinking_cursor(void); static void hide_blinking_cursor(void); +void reset_brush_counter_and_frame(void); +void reset_brush_counter(void); + #ifdef LOW_QUALITY_STAMP_OUTLINE #define stamp_xor(x,y) rect_xor( \ (x) - (CUR_STAMP_W+1)/2, \ @@ -2635,10 +2639,10 @@ static void mainloop(void) rec_undo_buffer(); /* (Arbitrarily large, so we draw once now) */ - brush_counter = 999; + reset_brush_counter(); brush_draw(old_x, old_y, old_x, old_y, 1); - playsound(screen, 0, SND_PAINT1 + (img_cur_brush->w) / 12, 1, + playsound(screen, 0, SND_PAINT1 + (img_cur_brush_w) / 12, 1, event.button.x, SNDDIST_NEAR); } else if (cur_tool == TOOL_STAMP) @@ -2667,7 +2671,7 @@ static void mainloop(void) line_start_y = old_y; /* (Arbitrarily large, so we draw once now) */ - brush_counter = 999; + reset_brush_counter(); brush_draw(old_x, old_y, old_x, old_y, 1); @@ -2697,7 +2701,7 @@ static void mainloop(void) /* Draw the shape with the brush! */ /* (Arbitrarily large...) */ - brush_counter = 999; + reset_brush_counter(); playsound(screen, 1, SND_LINE_END, 1, event.button.x, SNDDIST_NEAR); @@ -2728,7 +2732,7 @@ static void mainloop(void) /* (Arbitrarily large, so we draw once now) */ - brush_counter = 999; + reset_brush_counter(); if (cur_magic != MAGIC_FILL) { @@ -2975,7 +2979,7 @@ static void mainloop(void) if (cur_tool == TOOL_LINES) { /* (Arbitrarily large, so we draw once now) */ - brush_counter = 999; + reset_brush_counter(); brush_draw(line_start_x, line_start_y, event.button.x - r_canvas.x, @@ -3028,7 +3032,7 @@ static void mainloop(void) } else { - brush_counter = 999; /* arbitrarily large... */ + reset_brush_counter(); playsound(screen, 1, SND_LINE_END, 1, event.button.x, @@ -3191,7 +3195,7 @@ static void mainloop(void) brush_draw(old_x, old_y, new_x, new_y, 1); - playsound(screen, 0, SND_PAINT1 + (img_cur_brush->w) / 12, 0, + playsound(screen, 0, SND_PAINT1 + (img_cur_brush_w) / 12, 0, event.button.x, SNDDIST_NEAR); } else if (cur_tool == TOOL_LINES) @@ -3483,23 +3487,43 @@ static void brush_draw(int x1, int y1, int x2, int y2, int update) } } +void reset_brush_counter_and_frame(void) +{ + brush_counter = 999; + brush_frame = 0; +} + +void reset_brush_counter(void) +{ + brush_counter = 999; +} + /* Draw the current brush in the current color: */ static void blit_brush(int x, int y) { - SDL_Rect dest; + SDL_Rect src, dest; brush_counter++; - if (brush_counter >= (img_cur_brush->h / 4)) + if (brush_counter >= (img_cur_brush_h / 4)) { brush_counter = 0; + brush_frame++; + if (brush_frame > img_cur_brush_frames) + brush_frame = 0; + dest.x = x; dest.y = y; - SDL_BlitSurface(img_cur_brush, NULL, canvas, &dest); + src.x = brush_frame * img_cur_brush_w; + src.y = 0; + src.w = img_cur_brush_w; + src.h = img_cur_brush_h; + + SDL_BlitSurface(img_cur_brush, &src, canvas, &dest); } } @@ -5165,14 +5189,13 @@ static void loadbrush_callback(SDL_Surface * screen, /* Load brush metadata, if any: */ + brushes_frames[num_brushes] = 1; + brushes_directional[num_brushes] = 0; + strcpy(strcasestr(fname, ".png"), ".dat"); fi = fopen(fname, "r"); - if (fi == NULL) - { - brushes_frames[num_brushes] = 1; - brushes_directional[num_brushes] = 0; - } - else + + if (fi != NULL) { do { @@ -8533,17 +8556,32 @@ static void render_brush(void) SDL_GetRGBA(getpixel_brush(img_brushes[cur_brush], x, y), img_brushes[cur_brush]->format, &r, &g, &b, &a); - putpixel_brush(img_cur_brush, x, y, - SDL_MapRGBA(img_cur_brush->format, - color_hexes[cur_color][0], - color_hexes[cur_color][1], - color_hexes[cur_color][2], a)); + if (r == g && g == b) + { + putpixel_brush(img_cur_brush, x, y, + SDL_MapRGBA(img_cur_brush->format, + color_hexes[cur_color][0], + color_hexes[cur_color][1], + color_hexes[cur_color][2], a)); + } + else + { + putpixel_brush(img_cur_brush, x, y, + SDL_MapRGBA(img_cur_brush->format, + (r + color_hexes[cur_color][0]) >> 1, + (g + color_hexes[cur_color][1]) >> 1, + (b + color_hexes[cur_color][2]) >> 1, a)); + } } } SDL_UnlockSurface(img_cur_brush); SDL_UnlockSurface(img_brushes[cur_brush]); + img_cur_brush_w = img_cur_brush->w / brushes_frames[cur_brush]; + img_cur_brush_h = img_cur_brush->h / (brushes_directional[cur_brush] ? 3 : 1); + img_cur_brush_frames = brushes_frames[cur_brush]; + brush_counter = 0; }