home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / gimpressionist / brush.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-16  |  14.4 KB  |  501 lines

  1. #ifdef HAVE_CONFIG_H
  2. #include "config.h"
  3. #else
  4. #define HAVE_DIRENT_H
  5. #define HAVE_UNISTD_H
  6. #endif
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <gtk/gtk.h>
  11. #ifdef HAVE_UNISTD_H
  12. #include <unistd.h>
  13. #endif
  14. #include <libgimp/gimp.h>
  15. #include <libgimp/gimpui.h>
  16. #include <libgimp/stdplugins-intl.h>
  17. #include <math.h>
  18. #include "gimpressionist.h"
  19. #include "ppmtool.h"
  20.  
  21.  
  22. GtkWidget *brushlist = NULL;
  23. GtkWidget *brushprev = NULL;
  24. GtkObject *brushreliefadjust = NULL;
  25. GtkObject *brushaspectadjust = NULL;
  26. GtkObject *brushgammaadjust = NULL;
  27.  
  28. GtkWidget *brushdrawablemenu = NULL;
  29. GtkWidget *brushemptyitem;
  30.  
  31. gint32 brushdrawableid;
  32.  
  33. int brushfile = 2;
  34.  
  35. struct ppm brushppm = {0,0,NULL};
  36.  
  37. void updatebrushprev(char *fn);
  38.  
  39. int colorfile(char *fn)
  40. {
  41.   if(!fn) return 0;
  42.   if(strstr(fn, ".ppm")) return 1;
  43.   return 0;
  44. }
  45.  
  46. void brushdmenuselect(gint32 id, gpointer data)
  47. {
  48.   GimpPixelRgn src_rgn;
  49.   guchar *src_row;
  50.   guchar *src;
  51.   gint alpha, has_alpha, bpp;
  52.   gint x, y;
  53.   struct ppm *p;
  54.   gint x1, y1, x2, y2;
  55.   gint row, col;
  56.   GimpDrawable *drawable;
  57.   int rowstride;
  58.  
  59.   if(brushfile == 2) return; /* Not finished GUI-building yet */
  60.  
  61.   if(brushfile) {
  62.     unselectall(brushlist);
  63.     if(GTK_IS_WIDGET(presetsavebutton))
  64.       gtk_widget_set_sensitive(GTK_WIDGET(presetsavebutton), FALSE);
  65.   }
  66.  
  67.   gtk_adjustment_set_value(GTK_ADJUSTMENT(brushgammaadjust), 1.0);
  68.   gtk_adjustment_set_value(GTK_ADJUSTMENT(brushaspectadjust), 0.0);
  69.  
  70.   drawable = gimp_drawable_get(id);
  71.  
  72.   gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
  73.   
  74.   bpp = gimp_drawable_bpp (drawable->id);
  75.   has_alpha = gimp_drawable_has_alpha (drawable->id);
  76.   alpha = (has_alpha) ? bpp - 1 : bpp;
  77.  
  78.   if(brushppm.col)
  79.     killppm(&brushppm);
  80.   newppm(&brushppm, x2-x1, y2-y1);
  81.   p = &brushppm;
  82.  
  83.   rowstride = p->width * 3;
  84.  
  85.   src_row = g_new (guchar, (x2 - x1) * bpp);
  86.  
  87.   gimp_pixel_rgn_init (&src_rgn, drawable, 0, 0, x2-x1, y2-y1, FALSE, FALSE);
  88.  
  89.   if(bpp == 3) { /* RGB */
  90.     int bpr = (x2-x1) * 3;
  91.     for(row = 0, y = y1; y < y2; row++, y++) {
  92.       gimp_pixel_rgn_get_row (&src_rgn, src_row, x1, y, (x2 - x1));
  93.       memcpy(p->col + row*rowstride, src_row, bpr);
  94.     }
  95.   } else if(bpp > 3) { /* RGBA */
  96.     for(row = 0, y = y1; y < y2; row++, y++) {
  97.       guchar *tmprow = p->col + row * rowstride;
  98.       gimp_pixel_rgn_get_row (&src_rgn, src_row, x1, y, (x2 - x1));
  99.       src = src_row;
  100.       for (col = 0, x = x1; x < x2; col++, x++) {
  101.     int k = col * 3;
  102.     tmprow[k+0] = src[0];
  103.     tmprow[k+1] = src[1];
  104.     tmprow[k+2] = src[2];
  105.     src += src_rgn.bpp;
  106.       }
  107.     }  
  108.   } else if(bpp == 2) { /* GrayA */
  109.     for(row = 0, y = y1; y < y2; row++, y++) {
  110.     guchar *tmprow = p->col + row * rowstride;
  111.       gimp_pixel_rgn_get_row (&src_rgn, src_row, x1, y, (x2 - x1));
  112.       src = src_row;
  113.       for (col = 0, x = x1; x < x2; col++, x++) {
  114.     int k = col * 3;
  115.     tmprow[k+0] = src[0];
  116.     tmprow[k+1] = src[0];
  117.     tmprow[k+2] = src[0];
  118.     src += src_rgn.bpp;
  119.       }
  120.     }  
  121.   } else { /* Gray */
  122.     for(row = 0, y = y1; y < y2; row++, y++) {
  123.       guchar *tmprow = p->col + row * rowstride;
  124.       gimp_pixel_rgn_get_row (&src_rgn, src_row, x1, y, (x2 - x1));
  125.       src = src_row;
  126.       for (col = 0, x = x1; x < x2; col++, x++) {
  127.     int k = col * 3;
  128.     tmprow[k+0] = src[0];
  129.     tmprow[k+1] = src[0];
  130.     tmprow[k+2] = src[0];
  131.     src += src_rgn.bpp;
  132.       }
  133.     }  
  134.   }  
  135.   g_free (src_row);
  136.  
  137.   if(bpp >= 3) pcvals.colorbrushes = 1;
  138.   else pcvals.colorbrushes = 0;
  139.  
  140.   brushfile = 0;
  141.   updatebrushprev(NULL);
  142. }
  143.  
  144. void dummybrushdmenuselect(GtkWidget *w, gpointer data)
  145. {
  146.   if(brushppm.col)
  147.     killppm(&brushppm);
  148.   newppm(&brushppm, 10,10);
  149.   brushfile = 0;
  150.   updatebrushprev(NULL);
  151. }
  152.  
  153. void destroy_window (GtkWidget *widget, GtkWidget **window)
  154. {
  155.   *window = NULL;
  156. }
  157.  
  158. void brushlistrefresh(void)
  159. {
  160.   GtkWidget *list = brushlist;
  161.   int n = g_list_length(GTK_LIST(list)->children);
  162.   gtk_list_clear_items(GTK_LIST(list), 0, n);
  163.   readdirintolist("Brushes", list, NULL);
  164. }
  165.  
  166. void savebrush_ok(GtkWidget *w, GtkFileSelection *fs, gpointer data)
  167. {
  168.   char *fn;
  169.   fn = gtk_file_selection_get_filename (GTK_FILE_SELECTION(fs));
  170.  
  171.   saveppm(&brushppm, fn);
  172.  
  173.   gtk_widget_destroy(GTK_WIDGET(fs));
  174.   brushlistrefresh();
  175. }
  176.  
  177. void savebrush(GtkWidget *wg, gpointer data)
  178. {
  179.   static GtkWidget *window = NULL;
  180.   GList *thispath = parsepath();
  181.   char path[200];
  182.  
  183.   if(!brushppm.col) {
  184.     g_message( _("GIMPressionist: Can only save drawables!\n"));
  185.     return;
  186.   }
  187.  
  188.   sprintf(path, "%s/Brushes/", (char *)thispath->data);
  189.  
  190.   window = gtk_file_selection_new( _("Save brush"));
  191.   gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE);
  192.  
  193.   gtk_file_selection_set_filename(GTK_FILE_SELECTION(window), path);
  194.  
  195.   gtk_signal_connect (GTK_OBJECT(window), "destroy",
  196.                       (GtkSignalFunc) destroy_window, &window);
  197.   
  198.   gtk_signal_connect (GTK_OBJECT(GTK_FILE_SELECTION(window)->ok_button),
  199.                       "clicked", (GtkSignalFunc)savebrush_ok,(gpointer)window);
  200.  
  201.   gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(window)->cancel_button),
  202.                             "clicked", (GtkSignalFunc) gtk_widget_destroy,
  203.                 GTK_OBJECT(window));
  204.   gtk_widget_show(window);
  205.  
  206.   return;
  207. }
  208.  
  209. gint validdrawable(gint32 imageid, gint32 drawableid, gpointer data)
  210. {
  211.   if(drawableid == -1) return TRUE;
  212.   return (gimp_drawable_is_rgb(drawableid) || gimp_drawable_is_gray(drawableid));
  213. }
  214.  
  215. void reloadbrush(char *fn, struct ppm *p)
  216. {
  217.   static char lastfn[200] = "";
  218.   static struct ppm cache = {0,0,NULL};
  219.  
  220.   if(strcmp(fn, lastfn)) {
  221.     strncpy(lastfn, fn, 199);
  222.     loadppm(fn, &cache);
  223.   }
  224.   copyppm(&cache, p);
  225.   pcvals.colorbrushes = colorfile(fn);
  226. }
  227.  
  228. void padbrush(struct ppm *p, int width, int height)
  229. {
  230.   guchar black[3] = {0,0,0};
  231.   int left = (width - p->width) / 2;
  232.   int right = (width - p->width) - left;
  233.   int top = (height - p->height) / 2;
  234.   int bottom = (height - p->height) - top;
  235.   pad(p, left, right, top, bottom, black);
  236. }
  237.  
  238. void updatebrushprev(char *fn)
  239. {
  240.   int i, j;
  241.   char buf[100];
  242.  
  243.   if(fn)
  244.     brushfile = 1;
  245.  
  246.   if(!fn && brushfile) {
  247.     memset(buf, 0, 100);
  248.     for(i = 0; i < 100; i++) {
  249.       gtk_preview_draw_row (GTK_PREVIEW (brushprev), buf, 0, i, 100);
  250.     }
  251.   } else {
  252.     double sc;
  253.     struct ppm p = {0,0,NULL};
  254.     guchar gammatable[256];
  255.     int newheight;
  256.  
  257.     if(brushfile)
  258.       reloadbrush(fn, &p);
  259.     else if(brushppm.col)
  260.       copyppm(&brushppm, &p);
  261.  
  262.     pcvals.colorbrushes = colorfile(fn);
  263.  
  264.     sc = GTK_ADJUSTMENT(brushgammaadjust)->value;
  265.     if(sc != 1.0)
  266.       for(i = 0; i < 256; i++)
  267.     gammatable[i] = pow(i / 255.0, sc) * 255; 
  268.     else
  269.       for(i = 0; i < 256; i++)
  270.     gammatable[i] = i;
  271.  
  272.     newheight = p.height*pow(10,GTK_ADJUSTMENT(brushaspectadjust)->value);
  273.     sc = p.width > newheight ? p.width : newheight;
  274.     sc = 100.0 / sc;
  275.     resize_fast(&p, p.width*sc,newheight*sc);
  276.     padbrush(&p,100,100);
  277.     for(i = 0; i < 100; i++) {
  278.       int k = i * p.width * 3;
  279.       memset(buf,0,100);
  280.       if(i < p.height)
  281.     for(j = 0; j < p.width; j++)
  282.       buf[j] = gammatable[p.col[k + j * 3]];
  283.       gtk_preview_draw_row (GTK_PREVIEW (brushprev), buf, 0, i, 100);
  284.     }
  285.     killppm(&p);
  286.   }
  287.   gtk_widget_draw (brushprev, NULL);
  288. }
  289.  
  290. int brushdontupdate = 0;
  291.  
  292. void selectbrush(GtkWidget *wg, GtkWidget *p)
  293. {
  294.   GList *h;
  295.   GtkWidget *tmpw;
  296.   char *l;
  297.   static char *oldl = NULL;
  298.   static char fname[200];
  299.  
  300.   if(brushdontupdate) return;
  301.  
  302.   if(brushfile == 0) {
  303.     updatebrushprev(NULL);
  304.     return;
  305.   }
  306.  
  307.   /* Argh! Doesn't work! WHY!? :-( */
  308.   /*
  309.   gtk_menu_set_active(GTK_MENU(brushdrawablemenu),0);
  310.   gtk_menu_item_select(GTK_MENU_ITEM(brushemptyitem));
  311.   gtk_widget_draw_default(brushdrawablemenu);
  312.   gtk_widget_bite_me(brushdrawablemenu);
  313.   */
  314.  
  315.   if(!p) return;
  316.   h = GTK_LIST(p)->selection;
  317.   if(!h) return;
  318.   tmpw = h->data;
  319.   if(!tmpw) return;
  320.   gtk_label_get(GTK_LABEL(GTK_BIN(tmpw)->child), &l);
  321.  
  322.   if(oldl) if(strcmp(oldl, l)) {
  323.     brushdontupdate = 1;
  324.     gtk_adjustment_set_value(GTK_ADJUSTMENT(brushgammaadjust), 1.0);
  325.     gtk_adjustment_set_value(GTK_ADJUSTMENT(brushaspectadjust), 0.0);
  326.     brushdontupdate = 0;
  327.   }
  328.   oldl = l;
  329.  
  330.   sprintf(fname, "Brushes/%s", l);
  331.   strcpy(pcvals.selectedbrush, fname);
  332.  
  333.   updatebrushprev(fname);
  334. }
  335.  
  336. void selectbrushfile(GtkWidget *wg, GtkWidget *p)
  337. {
  338.   brushfile = 1;
  339.   if(GTK_IS_WIDGET(presetsavebutton))
  340.     gtk_widget_set_sensitive(GTK_WIDGET(presetsavebutton), TRUE);
  341.   selectbrush(wg,p);
  342. }
  343.  
  344. void create_brushpage(GtkNotebook *notebook)
  345. {
  346.   GtkWidget *box1, *box2, *box3, *thispage;
  347.   GtkWidget *labelbox, *menubox;
  348.   GtkWidget *scrolled_win, *list;
  349.   GtkWidget *tmpw;
  350.   GtkWidget *dmenu;
  351.  
  352.   labelbox = gtk_hbox_new (FALSE, 0);
  353.   tmpw = gtk_label_new (_("Brush"));
  354.   gtk_box_pack_start(GTK_BOX(labelbox), tmpw, FALSE, FALSE, 0);
  355.   gtk_widget_show_all(labelbox);
  356.  
  357.   menubox = gtk_hbox_new (FALSE, 0);
  358.   tmpw = gtk_label_new (_("Brush"));
  359.   gtk_box_pack_start(GTK_BOX(menubox), tmpw, FALSE, FALSE, 0);
  360.   gtk_widget_show_all(menubox);
  361.  
  362.   thispage = gtk_vbox_new(FALSE, 0);
  363.   gtk_container_set_border_width (GTK_CONTAINER (thispage), 5);
  364.   gtk_widget_show(thispage);
  365.  
  366.   box1 = gtk_hbox_new (FALSE, 0);
  367.   gtk_box_pack_start(GTK_BOX(thispage), box1, TRUE,TRUE,0);
  368.   gtk_widget_show (box1);
  369.  
  370.   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
  371.   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
  372.                   GTK_POLICY_AUTOMATIC, 
  373.                   GTK_POLICY_AUTOMATIC);
  374.   gtk_box_pack_start (GTK_BOX (box1), scrolled_win, FALSE, FALSE, 0);
  375.   gtk_widget_show (scrolled_win);
  376.   gtk_widget_set_usize(scrolled_win, 150,-1);
  377.  
  378.   brushlist = list = gtk_list_new ();
  379.   gtk_list_set_selection_mode (GTK_LIST (list), GTK_SELECTION_BROWSE);
  380. #if GTK_MINOR_VERSION > 0
  381.   gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_win), list);
  382. #else
  383.   gtk_container_add (GTK_CONTAINER (scrolled_win), list);
  384. #endif
  385.   gtk_widget_show (list);
  386.  
  387.   readdirintolist("Brushes", list, pcvals.selectedbrush);
  388.  
  389.   box2 = gtk_vbox_new (FALSE, 0);
  390.   gtk_box_pack_start(GTK_BOX(box1), box2,FALSE,FALSE,0);
  391.   gtk_widget_show (box2);
  392.   gtk_container_set_border_width (GTK_CONTAINER (box2), 5);
  393.  
  394.   tmpw = gtk_label_new( _("Brush Preview:"));
  395.   gtk_box_pack_start(GTK_BOX(box2), tmpw,FALSE,FALSE,0);
  396.   gtk_widget_show (tmpw);
  397.  
  398.   brushprev = tmpw = gtk_preview_new (GTK_PREVIEW_GRAYSCALE);
  399.   gtk_preview_size(GTK_PREVIEW (tmpw), 100, 100);
  400.   gtk_box_pack_start(GTK_BOX (box2), tmpw, FALSE, FALSE, 5);
  401.   gtk_widget_show(tmpw);
  402.  
  403.   tmpw = gtk_label_new( _("Gamma:"));
  404.   gtk_box_pack_start(GTK_BOX(box2), tmpw,FALSE,FALSE,0);
  405.   gtk_widget_show (tmpw);
  406.  
  407.   brushgammaadjust = gtk_adjustment_new(pcvals.brushgamma, 0.5, 3.0, 0.1, 0.1, 1.0);
  408.   tmpw = gtk_hscale_new(GTK_ADJUSTMENT(brushgammaadjust));
  409.   gtk_widget_set_usize (GTK_WIDGET(tmpw), 100, 30);
  410.   gtk_scale_set_draw_value (GTK_SCALE (tmpw), FALSE);
  411.   gtk_scale_set_digits(GTK_SCALE (tmpw), 2);
  412.   gtk_box_pack_start (GTK_BOX (box2), tmpw, FALSE, FALSE, 0);
  413.   gtk_widget_show (tmpw);
  414.   gtk_signal_connect(GTK_OBJECT(brushgammaadjust), "value_changed",
  415.              (GtkSignalFunc)selectbrush, list);
  416.   gtk_tooltips_set_tip(GTK_TOOLTIPS(tooltips), tmpw, _("Changes the gamma (brightness) of the selected brush"), NULL);
  417.  
  418.   box1 = gtk_hbox_new (FALSE, 0);
  419.   gtk_box_pack_start(GTK_BOX(thispage), box1,FALSE,FALSE,5);
  420.   gtk_widget_show (box1);
  421.  
  422.  
  423.   box2 = gtk_vbox_new (TRUE, 0);
  424.   gtk_box_pack_start(GTK_BOX(box1), box2,FALSE,FALSE,0);
  425.   gtk_widget_show (box2);
  426.  
  427.   if(!standalone) {
  428.     tmpw = gtk_label_new( _("Select:"));
  429.     gtk_box_pack_start(GTK_BOX(box2), tmpw,FALSE,FALSE,0);
  430.     gtk_widget_show (tmpw);
  431.   }
  432.  
  433.   tmpw = gtk_label_new( _("Aspect ratio:"));
  434.   gtk_box_pack_start(GTK_BOX(box2), tmpw,FALSE,FALSE,0);
  435.   gtk_widget_show (tmpw);
  436.  
  437.   tmpw = gtk_label_new( _("Relief:"));
  438.   gtk_box_pack_start(GTK_BOX(box2), tmpw,FALSE,FALSE,0);
  439.   gtk_widget_show (tmpw);
  440.  
  441.   box2 = gtk_vbox_new (TRUE, 0);
  442.   gtk_box_pack_start(GTK_BOX(box1), box2,FALSE,FALSE,10);
  443.   gtk_widget_show (box2);
  444.  
  445.   if(!standalone) {
  446.     GtkWidget *emptyitem;
  447.  
  448.     box3 = gtk_hbox_new(FALSE,0);
  449.     gtk_box_pack_start(GTK_BOX(box2),box3, FALSE, FALSE, 0);
  450.     gtk_widget_show(box3);
  451.  
  452.     brushemptyitem = emptyitem = gtk_menu_item_new_with_label( _("(None)"));
  453.     gtk_signal_connect (GTK_OBJECT(emptyitem), "activate",
  454.             (GtkSignalFunc)dummybrushdmenuselect, NULL);
  455.     gtk_widget_show(emptyitem);
  456.  
  457.     tmpw = gtk_option_menu_new();
  458.     gtk_box_pack_start(GTK_BOX(box3),tmpw, FALSE, FALSE, 0);
  459.     gtk_widget_show(tmpw);
  460.  
  461.     brushdrawablemenu = dmenu = gimp_drawable_menu_new(validdrawable, brushdmenuselect, NULL, -1);
  462.     gtk_menu_prepend(GTK_MENU(dmenu), emptyitem);
  463.     gtk_option_menu_set_menu(GTK_OPTION_MENU(tmpw), dmenu);
  464.  
  465.     tmpw = gtk_button_new_with_label( _("Save..."));
  466.     gtk_box_pack_start(GTK_BOX(box3),tmpw, FALSE, FALSE, 0);
  467.     gtk_signal_connect (GTK_OBJECT(tmpw), "clicked",
  468.             GTK_SIGNAL_FUNC(savebrush), NULL);
  469.     gtk_widget_show(tmpw);
  470.   }
  471.  
  472.   brushaspectadjust = gtk_adjustment_new(pcvals.brushaspect, -1.0, 2.0, 0.1, 0.1, 1.0);
  473.   tmpw = gtk_hscale_new(GTK_ADJUSTMENT(brushaspectadjust));
  474.   gtk_widget_set_usize (GTK_WIDGET(tmpw), 150, 30);
  475.   gtk_scale_set_draw_value (GTK_SCALE (tmpw), TRUE);
  476.   gtk_scale_set_digits(GTK_SCALE (tmpw), 2);
  477.   gtk_box_pack_start (GTK_BOX (box2), tmpw, FALSE, FALSE, 0);
  478.   gtk_widget_show (tmpw);
  479.   gtk_tooltips_set_tip(GTK_TOOLTIPS(tooltips), tmpw, _("Specifies the aspect ratio of the brush"), NULL);
  480.   gtk_signal_connect(GTK_OBJECT(brushaspectadjust), "value_changed",
  481.              (GtkSignalFunc)selectbrush, list);
  482.  
  483.   brushreliefadjust = gtk_adjustment_new(pcvals.brushrelief, 0.0, 101.0, 1.0, 1.0, 1.0);
  484.   tmpw = gtk_hscale_new(GTK_ADJUSTMENT(brushreliefadjust));
  485.   gtk_widget_set_usize (GTK_WIDGET(tmpw), 150, 30);
  486.   gtk_scale_set_draw_value (GTK_SCALE (tmpw), TRUE);
  487.   gtk_scale_set_digits(GTK_SCALE (tmpw), 2);
  488.   gtk_box_pack_start (GTK_BOX (box2), tmpw, FALSE, FALSE, 0);
  489.   gtk_widget_show (tmpw);
  490.   gtk_tooltips_set_tip(GTK_TOOLTIPS(tooltips), tmpw, _("Specifies the amount of embossing to apply to each brush stroke"), NULL);
  491.  
  492.   gtk_signal_connect (GTK_OBJECT(list), "selection_changed",
  493.               GTK_SIGNAL_FUNC(selectbrushfile),
  494.               list);
  495.   if(!GTK_LIST(list)->selection)
  496.     gtk_list_select_item(GTK_LIST(list), 0);
  497.   selectbrush(NULL, list);
  498.  
  499.   gtk_notebook_append_page_menu (notebook, thispage, labelbox, menubox);
  500. }
  501.