diff --git a/ChangeLog b/ChangeLog index f4c23ed249..553d0f8b49 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Wed Apr 8 00:04:31 PDT 1998 Manish Singh + + * app/batch.c: fixup for script-fu in batch mode from + Christian Maegaard + + * added pagecurl plug-in + Wed Apr 8 01:40:45 EDT 1998 Matthew Wilson * app/by_color_select.c: Don't destroy tool. diff --git a/app/batch.c b/app/batch.c index 9cb6cb4f81..e749ec9a90 100644 --- a/app/batch.c +++ b/app/batch.c @@ -84,24 +84,111 @@ batch_is_cmd (char *cmd) return (paren_level == 0); } +char * +get_tok(char **rest) +{ + char *tok_start, *tok; + int i,j,len,escapes; + + /* Skip delimiters */ + while((**rest != 0) && + (**rest == ' ' || **rest == '\t')) + (*rest)++; + + /* token starts here */ + tok_start = *rest; + + if(**rest == '"'){ + /* Handle string */ + + /* Skip quote */ + (*rest)++; + tok_start++; + len = 0; + escapes = 0; + + /* Scan to end while skipping escaped quotes */ + while((**rest != 0) && + (**rest != '"')){ + if(**rest == '\\'){ + (*rest)++; + escapes++; + } + (*rest)++; + len++; + } + if(**rest == '"'){ + (*rest)++; + tok = g_malloc(len+1); + } + else{ + g_print("String not properly terminated."); + return NULL; + } + + /* Copy the string while converting the escaped characters. */ + /* Only double quote and backspace is accepted other escapes are ignored. */ + j = 0; + for (i=0;i < len + escapes;i++){ + if(tok_start[i] != '\\') + tok[j++] = tok_start[i]; + else{ + i++; + if(tok_start[i] == '"' || tok_start[i] == '\\') + tok[j++] = tok_start[i]; + } + } + tok[j] = 0; + } + else{ + /* Handle number or identifier */ + while((**rest != 0) && + ((**rest >= 'a' && **rest <= 'z') || + (**rest >= 'A' && **rest <= 'Z') || + (**rest >= '0' && **rest <= '9') || + (**rest == '-') || + (**rest == '_'))) + (*rest)++; + if (*rest != tok_start){ + len = *rest - tok_start; + tok = g_malloc(len+1); + strncpy(tok,tok_start,len); + tok[len]=0; + } + else{ + if(**rest == 0){ + g_print("Unexpected end of command argument."); + return NULL; + } + /* One character token - normally "(" or ")" */ + tok = g_malloc(2); + tok[0] = *rest[0]; + tok[1] = 0; + (*rest)++; + } + } + return tok; +} + static void batch_run_cmd (char *cmd) { ProcRecord *proc; Argument *args; Argument *vals; + char *rest; char *cmdname; char *t; int i; - cmd = strchr (cmd, '('); - if (!cmd) + rest = cmd; + t = get_tok(&rest); + if (!t || t[0] != '(') return; - cmd += 1; + g_free(t); - cmdname = cmd; - cmd = strtok (cmd, " )"); - if (!cmd) + cmdname = get_tok (&rest); + if (!cmdname) return; t = cmdname; @@ -131,25 +218,28 @@ batch_run_cmd (char *cmd) case PDB_INT32: case PDB_INT16: case PDB_INT8: - cmd = strtok (NULL, " \t)"); - if (!cmd) + t = get_tok (&rest); + if (!t) goto error; - args[i].value.pdb_int = atoi (cmd); + args[i].value.pdb_int = atoi (t); + g_free(t); break; case PDB_FLOAT: - cmd = strtok (NULL, " \t)"); - if (!cmd) + t = get_tok (&rest); + if (!t) goto error; - args[i].value.pdb_float = atof (cmd); + args[i].value.pdb_float = atof (t); + g_free(t); break; case PDB_STRING: - cmd = strtok (NULL, "\""); - if (!cmd) + t = get_tok (&rest); + if (!t) goto error; - args[i].value.pdb_pointer = g_strdup (cmd); + args[i].value.pdb_pointer = g_strdup (t); + g_free(t); break; case PDB_INT32ARRAY: case PDB_INT16ARRAY: @@ -221,10 +311,12 @@ batch_run_cmd (char *cmd) break; } + g_free(cmdname); return; error: g_print ("Unable to run batch command: %s because of bad arguments.\n", cmdname); + g_free(cmdname); } static void diff --git a/configure.in b/configure.in index 7e5a7fe29d..405d5718db 100644 --- a/configure.in +++ b/configure.in @@ -484,6 +484,7 @@ plug-ins/pnm/Makefile plug-ins/plasma/Makefile plug-ins/pixelize/Makefile plug-ins/pcx/Makefile +plug-ins/pagecurl/Makefile plug-ins/pat/Makefile plug-ins/blinds/Makefile plug-ins/autostretch_hsv/Makefile diff --git a/plug-ins/Makefile.am b/plug-ins/Makefile.am index 4b04279dc2..ee053383d6 100644 --- a/plug-ins/Makefile.am +++ b/plug-ins/Makefile.am @@ -82,6 +82,7 @@ SUBDIRS = \ normalize \ nova \ oilify \ + pagecurl \ palette \ papertile \ pat \ diff --git a/plug-ins/pagecurl/.cvsignore b/plug-ins/pagecurl/.cvsignore new file mode 100644 index 0000000000..5ca869bef7 --- /dev/null +++ b/plug-ins/pagecurl/.cvsignore @@ -0,0 +1,6 @@ +Makefile.in +Makefile +.deps +_libs +.libs +pagecurl diff --git a/plug-ins/pagecurl/Makefile.am b/plug-ins/pagecurl/Makefile.am new file mode 100644 index 0000000000..a3620f07a3 --- /dev/null +++ b/plug-ins/pagecurl/Makefile.am @@ -0,0 +1,38 @@ +## Process this file with automake to produce Makefile.in + +pluginlibdir = $(gimpplugindir)/plug-ins + +pluginlib_PROGRAMS = pagecurl + +pagecurl_SOURCES = \ + pagecurl.c curl0.xpm curl1.xpm curl2.xpm curl3.xpm curl4.xpm curl5.xpm curl6.xpm curl7.xpm + +INCLUDES = \ + $(X_CFLAGS) \ + -I$(top_srcdir) \ + -I$(includedir) + +LDADD = \ + $(top_builddir)/libgimp/libgimpui.la \ + $(top_builddir)/libgimp/libgimp.la \ + $(X_LIBS) \ + -lc + +DEPS = \ + $(top_builddir)/libgimp/libgimpui.la \ + $(top_builddir)/libgimp/libgimp.la + +pagecurl_DEPENDENCIES = $(DEPS) + +.PHONY: files + +files: + @files=`ls $(DISTFILES) 2> /dev/null`; for p in $$files; do \ + echo $$p; \ + done + @for subdir in $(SUBDIRS); do \ + files=`cd $$subdir; $(MAKE) files | grep -v "make\[[1-9]\]"`; \ + for file in $$files; do \ + echo $$subdir/$$file; \ + done; \ + done diff --git a/plug-ins/pagecurl/curl0.xpm b/plug-ins/pagecurl/curl0.xpm new file mode 100644 index 0000000000..54a45aaab6 --- /dev/null +++ b/plug-ins/pagecurl/curl0.xpm @@ -0,0 +1,43 @@ +/* XPM */ +static char * curl0_xpm[] = { +"33 33 7 1", +" c None", +". c #000000", +"+ c #FFFFFF", +"@ c #333333", +"# c #666666", +"$ c #CCCCCC", +"% c #999999", +".................................", +".++++++++++++++++++++++++++++++.@", +".+++++++++++++++++++++++++++++..#", +".++++++++++++++++++++++++++++.$@$", +".+++++++++++++++++++++++++++.$@$$", +".++++++++++++++++++++++++++.$$@$$", +".+++++++++++++++++++++++++.%+.###", +".++++++++++++++++++++++++.%+%.###", +".+++++++++++++++++++++++.#+$.$###", +".++++++++++++++++++++++.#$+#@#$$$", +".+++++++++++++++++++++.#$+%.##$$$", +".++++++++++++++++++++.@$+$@@##$$$", +".+++++++++++++++++++.@%++%.$$$###", +".++++++++++++++++++.@%++$@#$$$###", +".+++++++++++++++++.@%$+$#.#$$$###", +".++++++++++++++++.@%$++%@$$###$$$", +".+++++++++++++++.@#$++$#.$$###$$$", +".++++++++++++++.@#$++$%.$$$###$$$", +".+++++++++++++.@#%+++%@.###$$$###", +".++++++++++++..#%$++$#.$###$$$###", +".+++++++++++..#%$++$%@$$###$$$###", +".++++++++++..@@$+++%#.##$$$###$$$", +".+++++++++.+$$$@++$#@###$$$###$$$", +".++++++++.+$$$%%@$%@.###$$$###$$$", +".+++++++++$$$%%##@#@#$$$###$$$###", +".++++++++$$$%%###@@.#$$$###$$$###", +".+++++++$$$%%%##@@.##$$$###$$$###", +".+++++++$$%%%##@@..$$###$$$###$$$", +".++++++$$$%%###@@.$$$###$$$###$$$", +".+++++$$$%%###@@..$$$###$$$###$$$", +".++++$$$%%%##@@@.$###$$$###$$$###", +".+++$$$%%%###@@.$$###$$$###$$$###", +"...............$$$###$$$###$$$###"}; diff --git a/plug-ins/pagecurl/curl1.xpm b/plug-ins/pagecurl/curl1.xpm new file mode 100644 index 0000000000..153b898716 --- /dev/null +++ b/plug-ins/pagecurl/curl1.xpm @@ -0,0 +1,43 @@ +/* XPM */ +static char * curl1_xpm[] = { +"33 33 7 1", +" c None", +". c #000000", +"+ c #333333", +"@ c #FFFFFF", +"# c #666666", +"$ c #CCCCCC", +"% c #999999", +".................................", +"+.@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.", +"#..@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.", +"$+$.@@@@@@@@@@@@@@@@@@@@@@@@@@@@.", +"$$+$.@@@@@@@@@@@@@@@@@@@@@@@@@@@.", +"$$+$$.@@@@@@@@@@@@@@@@@@@@@@@@@@.", +"###.@%.@@@@@@@@@@@@@@@@@@@@@@@@@.", +"###.%@%.@@@@@@@@@@@@@@@@@@@@@@@@.", +"###$.$@#.@@@@@@@@@@@@@@@@@@@@@@@.", +"$$$#+#@$#.@@@@@@@@@@@@@@@@@@@@@@.", +"$$$##.%@$#.@@@@@@@@@@@@@@@@@@@@@.", +"$$$##++$@$+.@@@@@@@@@@@@@@@@@@@@.", +"###$$$.%@@%+.@@@@@@@@@@@@@@@@@@@.", +"###$$$#+$@@%+.@@@@@@@@@@@@@@@@@@.", +"###$$$#.#$@$%+.@@@@@@@@@@@@@@@@@.", +"$$$###$$+%@@$%+.@@@@@@@@@@@@@@@@.", +"$$$###$$.#$@@$#+.@@@@@@@@@@@@@@@.", +"$$$###$$$.%$@@$#+.@@@@@@@@@@@@@@.", +"###$$$###.+%@@@%#+.@@@@@@@@@@@@@.", +"###$$$###$.#$@@$%#..@@@@@@@@@@@@.", +"###$$$###$$+%$@@$%#..@@@@@@@@@@@.", +"$$$###$$$##.#%@@@$++..@@@@@@@@@@.", +"$$$###$$$###+#$@@+$$$@.@@@@@@@@@.", +"$$$###$$$###.+%$+%%$$$@.@@@@@@@@.", +"###$$$###$$$#+#+##%%$$$@@@@@@@@@.", +"###$$$###$$$#.++###%%$$$@@@@@@@@.", +"###$$$###$$$##.++##%%%$$$@@@@@@@.", +"$$$###$$$###$$..++##%%%$$@@@@@@@.", +"$$$###$$$###$$$.++###%%$$$@@@@@@.", +"$$$###$$$###$$$..++###%%$$$@@@@@.", +"###$$$###$$$###$.+++##%%%$$$@@@@.", +"###$$$###$$$###$$.++###%%%$$$@@@.", +"###$$$###$$$###$$$..............."}; diff --git a/plug-ins/pagecurl/curl2.xpm b/plug-ins/pagecurl/curl2.xpm new file mode 100644 index 0000000000..b2ae438bcb --- /dev/null +++ b/plug-ins/pagecurl/curl2.xpm @@ -0,0 +1,43 @@ +/* XPM */ +static char * curl2_xpm[] = { +"33 33 7 1", +" c None", +". c #000000", +"+ c #CCCCCC", +"@ c #666666", +"# c #FFFFFF", +"$ c #999999", +"% c #333333", +"...............+++@@@+++@@@+++@@@", +".###+++$$$@@@%%.++@@@+++@@@+++@@@", +".####+++$$$@@%%%.+@@@+++@@@+++@@@", +".#####+++$$@@@%%..+++@@@+++@@@+++", +".######+++$$@@@%%.+++@@@+++@@@+++", +".#######++$$$@@%%..++@@@+++@@@+++", +".#######+++$$$@@%%.@@+++@@@+++@@@", +".########+++$$@@@%%.@+++@@@+++@@@", +".#########+++$$@@%@%@+++@@@+++@@@", +".########.#+++$$%+$%.@@@+++@@@+++", +".#########.#+++%##+@%@@@+++@@@+++", +".##########..%%+###$@.@@+++@@@+++", +".###########..@$+##+$%++@@@+++@@@", +".############..@$+##+@.+@@@+++@@@", +".#############.%@$###$%.@@@+++@@@", +".##############.%@+##+$.+++@@@+++", +".###############.%@+##+@.++@@@+++", +".################.%$+##$%++@@@+++", +".#################.%$+#+@.@+++@@@", +".##################.%$##+%@+++@@@", +".###################.%$##$.+++@@@", +".####################.%+#+%%@@+++", +".#####################.@+#$.@@+++", +".######################.@+#@%@+++", +".#######################.@#+.+@@@", +".########################.$#$.@@@", +".#########################.$#.@@@", +".##########################.++%++", +".###########################.+%++", +".############################.+%+", +".#############################..@", +".##############################.%", +"................................."}; diff --git a/plug-ins/pagecurl/curl3.xpm b/plug-ins/pagecurl/curl3.xpm new file mode 100644 index 0000000000..3d6fa59a93 --- /dev/null +++ b/plug-ins/pagecurl/curl3.xpm @@ -0,0 +1,43 @@ +/* XPM */ +static char * curl3_xpm[] = { +"33 33 7 1", +" c None", +". c #666666", +"+ c #CCCCCC", +"@ c #000000", +"# c #333333", +"$ c #999999", +"% c #FFFFFF", +"...+++...+++...+++@@@@@@@@@@@@@@@", +"...+++...+++...++@##...$$$+++%%%@", +"...+++...+++...+@###..$$$+++%%%%@", +"+++...+++...+++@@##...$$+++%%%%%@", +"+++...+++...+++@##...$$+++%%%%%%@", +"+++...+++...++@@##..$$$++%%%%%%%@", +"...+++...+++..@##..$$$+++%%%%%%%@", +"...+++...+++.@##...$$+++%%%%%%%%@", +"...+++...+++.#.#..$$+++%%%%%%%%%@", +"+++...+++...@#$+#$$+++%@%%%%%%%%@", +"+++...+++...#.+%%#+++%@%%%%%%%%%@", +"+++...+++..@.$%%%+##@@%%%%%%%%%%@", +"...+++...++#$+%%+$.@@%%%%%%%%%%%@", +"...+++...+@.+%%+$.@@%%%%%%%%%%%%@", +"...+++...@#$%%%$.#@%%%%%%%%%%%%%@", +"+++...+++@$+%%+.#@%%%%%%%%%%%%%%@", +"+++...++@.+%%+.#@%%%%%%%%%%%%%%%@", +"+++...++#$%%+$#@%%%%%%%%%%%%%%%%@", +"...+++.@.+%+$#@%%%%%%%%%%%%%%%%%@", +"...+++.#+%%$#@%%%%%%%%%%%%%%%%%%@", +"...+++@$%%$#@%%%%%%%%%%%%%%%%%%%@", +"+++..##+%+#@%%%%%%%%%%%%%%%%%%%%@", +"+++..@$%+.@%%%%%%%%%%%%%%%%%%%%%@", +"+++.#.%+.@%%%%%%%%%%%%%%%%%%%%%%@", +"...+@+%.@%%%%%%%%%%%%%%%%%%%%%%%@", +"...@$%$@%%%%%%%%%%%%%%%%%%%%%%%%@", +"...@%$@%%%%%%%%%%%%%%%%%%%%%%%%%@", +"++#++@%%%%%%%%%%%%%%%%%%%%%%%%%%@", +"++#+@%%%%%%%%%%%%%%%%%%%%%%%%%%%@", +"+#+@%%%%%%%%%%%%%%%%%%%%%%%%%%%%@", +".@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@", +"#@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@", +"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"}; diff --git a/plug-ins/pagecurl/curl4.xpm b/plug-ins/pagecurl/curl4.xpm new file mode 100644 index 0000000000..45643a24de --- /dev/null +++ b/plug-ins/pagecurl/curl4.xpm @@ -0,0 +1,43 @@ +/* XPM */ +static char * curl4_xpm[] = { +"33 33 7 1", +" c None", +". c #000000", +"+ c #FFFFFF", +"@ c #CCCCCC", +"# c #999999", +"$ c #666666", +"% c #333333", +".................................", +".+++++++++++++++++++++++++++++++.", +".+++++++++++++++++++++++++++++++.", +".+++++++++++++++++++++++++++++++.", +".++++++++++++++++++++++++++++++@.", +".+++++++++++++++++++++++++++++@@.", +".++++++++++++++++++++++++++++@@@.", +".+++++++++++++++++++++++++++@@@#.", +".+++++++++++++++++++++++++@@@@##.", +".++++++++++++++++++++++.+@@@@###.", +".+++++++++++++++++++++.+@@@####$.", +".++++++++++++++++++++.+@@@###$$$.", +".+++++++++++++++++++..@@@###$$$$.", +".++++++++++++++++++..%@@###$$$%%.", +".+++++++++++++++++..$%@##$$$$%%%.", +".++++++++++++++++.%$#@%#$$$%%%%.@", +".+++++++++++++++.%$#@++%$$%%%..@@", +".++++++++++++++.%$#@+++@%%%...@@@", +".+++++++++++++.%$@++++@#$%..@@$$$", +".++++++++++++.%#@+++@#$%%.$@@@$$$", +".+++++++++++.%#@+++@#$%.$$$@@@$$$", +".++++++++++.%#@++@#$%.$$@@@$$$@@@", +".+++++++++.%#+++@#%.@$$$@@@$$$@@@", +".++++++++.$@++@#$..@@$$$@@@$$$@@@", +".+++++++.$@++@$%.@$$$@@@$$$@@@$$$", +".++++++.$@+@#%.@@@$$$@@@$$$@@@$$$", +".+++++.#++#%.$$@@@$$$@@@$$$@@@$$$", +".++++.#+@$.%@@@$$$@@@$$$@@@$$$@@@", +".+++.@+#.%$$@@@$$$@@@$$$@@@$$$@@@", +".++.@@..@$$$@@@$$$@@@$$$@@@$$$@@@", +".+.@%%$$$@@@$$$@@@$$$@@@$$$@@@$$$", +"...%@@$$$@@@$$$@@@$$$@@@$$$@@@$$$", +".%$@@@$$$@@@$$$@@@$$$@@@$$$@@@$$$"}; diff --git a/plug-ins/pagecurl/curl5.xpm b/plug-ins/pagecurl/curl5.xpm new file mode 100644 index 0000000000..7333b37284 --- /dev/null +++ b/plug-ins/pagecurl/curl5.xpm @@ -0,0 +1,43 @@ +/* XPM */ +static char * curl5_xpm[] = { +"33 33 7 1", +" c None", +". c #000000", +"+ c #FFFFFF", +"@ c #CCCCCC", +"# c #999999", +"$ c #666666", +"% c #333333", +".................................", +".+++++++++++++++++++++++++++++++.", +".+++++++++++++++++++++++++++++++.", +".+++++++++++++++++++++++++++++++.", +".@++++++++++++++++++++++++++++++.", +".@@+++++++++++++++++++++++++++++.", +".@@@++++++++++++++++++++++++++++.", +".#@@@+++++++++++++++++++++++++++.", +".##@@@@+++++++++++++++++++++++++.", +".###@@@@+.++++++++++++++++++++++.", +".$####@@@+.+++++++++++++++++++++.", +".$$$###@@@+.++++++++++++++++++++.", +".$$$$###@@@..+++++++++++++++++++.", +".%%$$$###@@%..++++++++++++++++++.", +".%%%$$$$##@%$..+++++++++++++++++.", +"@.%%%%$$$#%@#$%.++++++++++++++++.", +"@@..%%%$$%++@#$%.+++++++++++++++.", +"@@@...%%%@+++@#$%.++++++++++++++.", +"$$$@@..%$#@++++@$%.+++++++++++++.", +"$$$@@@$.%%$#@+++@#%.++++++++++++.", +"$$$@@@$$$.%$#@+++@#%.+++++++++++.", +"@@@$$$@@@$$.%$#@++@#%.++++++++++.", +"@@@$$$@@@$$$@.%#@+++#%.+++++++++.", +"@@@$$$@@@$$$@@..$#@++@$.++++++++.", +"$$$@@@$$$@@@$$$@.%$@++@$.+++++++.", +"$$$@@@$$$@@@$$$@@@.%#@+@$.++++++.", +"$$$@@@$$$@@@$$$@@@$$.%#++#.+++++.", +"@@@$$$@@@$$$@@@$$$@@@%.$@+#.++++.", +"@@@$$$@@@$$$@@@$$$@@@$$%.#+@.+++.", +"@@@$$$@@@$$$@@@$$$@@@$$$@..@@.++.", +"$$$@@@$$$@@@$$$@@@$$$@@@$$$%%@.+.", +"$$$@@@$$$@@@$$$@@@$$$@@@$$$@@%...", +"$$$@@@$$$@@@$$$@@@$$$@@@$$$@@@$%."}; diff --git a/plug-ins/pagecurl/curl6.xpm b/plug-ins/pagecurl/curl6.xpm new file mode 100644 index 0000000000..8d95f9f8ee --- /dev/null +++ b/plug-ins/pagecurl/curl6.xpm @@ -0,0 +1,43 @@ +/* XPM */ +static char * curl6_xpm[] = { +"33 33 7 1", +" c None", +". c #000000", +"+ c #333333", +"@ c #666666", +"# c #CCCCCC", +"$ c #FFFFFF", +"% c #999999", +".+@###@@@###@@@###@@@###@@@###@@@", +"...+##@@@###@@@###@@@###@@@###@@@", +".$.#++@@@###@@@###@@@###@@@###@@@", +".$$.##..#@@@###@@@###@@@###@@@###", +".$$$.#$%.+@@###@@@###@@@###@@@###", +".$$$$.%$#@.+###@@@###@@@###@@@###", +".$$$$$.%$$%+.@@###@@@###@@@###@@@", +".$$$$$$.@#$#%+.###@@@###@@@###@@@", +".$$$$$$$.@#$$#@+.#@@@###@@@###@@@", +".$$$$$$$$.@#$$#%@..##@@@###@@@###", +".$$$$$$$$$.+%$$$#%+.#@@@###@@@###", +".$$$$$$$$$$.+%#$$#%@+.@@###@@@###", +".$$$$$$$$$$$.+%#$$$#%@+.@@@###@@@", +".$$$$$$$$$$$$.+%#$$$#%@++.@###@@@", +".$$$$$$$$$$$$$.+@#$$$$#%@+..##@@@", +".$$$$$$$$$$$$$$.+@%#$$$#+++...###", +".$$$$$$$$$$$$$$$.+@%#$$+@@+++..##", +".$$$$$$$$$$$$$$$$.+@%#+%@@@++++.#", +".$$$$$$$$$$$$$$$$$..@+#%%@@@@+++.", +".$$$$$$$$$$$$$$$$$$..+##%%%@@@++.", +".$$$$$$$$$$$$$$$$$$$..###%%%@@@@.", +".$$$$$$$$$$$$$$$$$$$$.$###%%%@@@.", +".$$$$$$$$$$$$$$$$$$$$$.$###%%%%@.", +".$$$$$$$$$$$$$$$$$$$$$$.$####%%%.", +".$$$$$$$$$$$$$$$$$$$$$$$$$####%%.", +".$$$$$$$$$$$$$$$$$$$$$$$$$$$###%.", +".$$$$$$$$$$$$$$$$$$$$$$$$$$$$###.", +".$$$$$$$$$$$$$$$$$$$$$$$$$$$$$##.", +".$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$#.", +".$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$.", +".$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$.", +".$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$.", +"................................."}; diff --git a/plug-ins/pagecurl/curl7.xpm b/plug-ins/pagecurl/curl7.xpm new file mode 100644 index 0000000000..0730e7b19d --- /dev/null +++ b/plug-ins/pagecurl/curl7.xpm @@ -0,0 +1,43 @@ +/* XPM */ +static char * curl7_xpm[] = { +"33 33 7 1", +" c None", +". c #666666", +"+ c #CCCCCC", +"@ c #333333", +"# c #000000", +"$ c #FFFFFF", +"% c #999999", +"...+++...+++...+++...+++...+++.@#", +"...+++...+++...+++...+++...++@###", +"...+++...+++...+++...+++...@@+#$#", +"+++...+++...+++...+++...+##++#$$#", +"+++...+++...+++...+++..@#%$+#$$$#", +"+++...+++...+++...+++@#.+$%#$$$$#", +"...+++...+++...+++..#@%$$%#$$$$$#", +"...+++...+++...+++#@%+$+.#$$$$$$#", +"...+++...+++...+#@.+$$+.#$$$$$$$#", +"+++...+++...++##.%+$$+.#$$$$$$$$#", +"+++...+++...+#@%+$$$%@#$$$$$$$$$#", +"+++...+++..#@.%+$$+%@#$$$$$$$$$$#", +"...+++...#@.%+$$$+%@#$$$$$$$$$$$#", +"...+++.#@@.%+$$$+%@#$$$$$$$$$$$$#", +"...++##@.%+$$$$+.@#$$$$$$$$$$$$$#", +"+++###@@@+$$$+%.@#$$$$$$$$$$$$$$#", +"++##@@@..@$$+%.@#$$$$$$$$$$$$$$$#", +"+#@@@@...%@+%.@#$$$$$$$$$$$$$$$$#", +"#@@@....%%+@.##$$$$$$$$$$$$$$$$$#", +"#@@...%%%++@##$$$$$$$$$$$$$$$$$$#", +"#....%%%+++##$$$$$$$$$$$$$$$$$$$#", +"#...%%%+++$#$$$$$$$$$$$$$$$$$$$$#", +"#.%%%%+++$#$$$$$$$$$$$$$$$$$$$$$#", +"#%%%++++$#$$$$$$$$$$$$$$$$$$$$$$#", +"#%%++++$$$$$$$$$$$$$$$$$$$$$$$$$#", +"#%+++$$$$$$$$$$$$$$$$$$$$$$$$$$$#", +"#+++$$$$$$$$$$$$$$$$$$$$$$$$$$$$#", +"#++$$$$$$$$$$$$$$$$$$$$$$$$$$$$$#", +"#+$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$#", +"#$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$#", +"#$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$#", +"#$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$#", +"#################################"}; diff --git a/plug-ins/pagecurl/pagecurl.c b/plug-ins/pagecurl/pagecurl.c new file mode 100644 index 0000000000..7f9d5cb370 --- /dev/null +++ b/plug-ins/pagecurl/pagecurl.c @@ -0,0 +1,942 @@ +/* Page Curl 0.8 --- image filter plug-in for The Gimp + * Copyright (C) 1996 Federico Mena Quintero + * Ported to Gimp 1.0 1998 by Simon Budig + * + * You can contact me at quartic@polloux.fciencias.unam.mx + * You can contact the original The Gimp authors at gimp@xcf.berkeley.edu + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* TODO for v0.5 - in 0.8 still to do... + * As of version 0.5 alpha, the only thing that is not yet implemented + * is the "Warp curl" option. Everything else seems to be working + * just fine. Please email me if you find any bugs. I know that the + * calculation code is horrible, but you don't want to tweak it anyway ;) + */ + +/* + * Ported to the 0.99.x architecture by Simon Budig, Simon.Budig@unix-ag.org + * *** Why does gimp_drawable_add_alpha cause the plugin to produce an + * ** WARNING **: received tile info did not match computed tile info + * ** WARNING **: expected tile ack and received: 0 + */ + +#include +#include +#include + +#include +#include +#include "curl0.xpm" +#include "curl1.xpm" +#include "curl2.xpm" +#include "curl3.xpm" +#include "curl4.xpm" +#include "curl5.xpm" +#include "curl6.xpm" +#include "curl7.xpm" +#include + +#define PLUG_IN_NAME "plug_in_pagecurl" +#define PLUG_IN_VERSION "Mar 1998, 0.8" + +/***** Macros *****/ + +/* Convert color to Gray ala Gimp... */ +#define INTENSITY(r,g,b) (r * 0.30 + g * 0.59 + b * 0.11 + 0.001) + + +/***** Types *****/ + +typedef struct { + double x, y; +} vector_t; + +typedef struct { + gint do_curl_shade; + gint do_curl_warp; /* Not yet supported... */ + + double do_curl_opacity; + gint do_shade_under; + + gint do_upper_left; + gint do_upper_right; + gint do_lower_left; + gint do_lower_right; + + gint do_vertical; + gint do_horizontal; +} CurlParams; + +/***** Prototypes *****/ + +static void set_default_params (void); + +static void dialog_close_callback (GtkWidget *, gpointer); +static void dialog_ok_callback (GtkWidget *, gpointer); +static void dialog_cancel_callback (GtkWidget *, gpointer); +static void dialog_toggle_update (GtkWidget *, gint); +static void dialog_scale_update (GtkAdjustment *, double *); + +static void query (void); +static void run (gchar * name, + gint nparams, + GParam * param, + gint * nreturn_vals, + GParam ** return_vals); + +static int do_dialog (void); + +static void v_set (vector_t * v, double x, double y); +static void v_add (vector_t * v, vector_t a, vector_t b); +static void v_sub (vector_t * v, vector_t a, vector_t b); +static double v_mag (vector_t v); +static double v_dot (vector_t a, vector_t b); + +static void init_calculation (); + +static int left_of_diagl (double x, double y); +static int right_of_diagr (double x, double y); +static int below_diagb (double x, double y); +static int right_of_diagm (double x, double y); +static int inside_circle (double x, double y); + +static void do_curl_effect (void); +static void clear_curled_region (void); +static void page_curl (void); + +/***** Variables *****/ + +GPlugInInfo PLUG_IN_INFO = { + NULL, /* init_proc */ + NULL, /* quit_proc */ + query, /* query_proc */ + run /* run_proc */ +}; /* PLUG_IN_INFO */ + +static CurlParams curl; + +/* Image parameters */ + +gint32 image_id; +GDrawable *curl_layer; +GDrawable *drawable; +GDrawable *layer_mask; + +typedef GdkPixmap *GdkPmP; +GdkPmP gdk_curl_pixmaps[8]; + +typedef GdkBitmap *GdkBmP; +GdkBmP gdk_curl_masks[8]; + +GtkWidget *curl_pixmap_widget; + +gint sel_x1, sel_y1, sel_x2, sel_y2; +gint true_sel_width, true_sel_height; +gint sel_width, sel_height; +gint drawable_position; +static gint curl_run = FALSE; + +/* Center and radius of circle */ + +vector_t center; +double radius; + +/* Useful points to keep around */ + +vector_t left_tangent; +vector_t right_tangent; + +/* Slopes --- these are *not* in the usual geometric sense! */ + +double diagl_slope; +double diagr_slope; +double diagb_slope; +double diagm_slope; + +/* User-configured parameters */ + +guchar fore_color[3]; +guchar back_color[3]; + + +/***** Functions *****/ + +/****/ +MAIN (); +/****/ + +/*************************/ +/* Some Vector-functions */ + +static void v_set (vector_t * v, double x, double y) { + v->x = x; + v->y = y; +} /* v_set */ + +static void v_add (vector_t * v, vector_t a, vector_t b) { + v->x = a.x + b.x; + v->y = a.y + b.y; +} /* v_add */ + +static void v_sub (vector_t * v, vector_t a, vector_t b) { + v->x = a.x - b.x; + v->y = a.y - b.y; +} /* v_sub */ + +static double v_mag (vector_t v) { + return sqrt (v.x * v.x + v.y * v.y); +} /* v_mag */ + +static double v_dot (vector_t a, vector_t b) { + return a.x * b.x + a.y * b.y; +} /* v_dot */ + + +/***************************************************** + * Functions to locate the current point in the curl. + * The following functions assume an curl in the + * lower right corner. + * diagb crosses the two tangential points from the + * circle with diagl and diagr. + * + * +------------------------------------------------+ + * | __-- /| + * | __-- _/ | + * | __-- / | + * | __-- _/ | + * | __-- / | + * | __--____ _/ | + * | __----~~ \ _/ | + * | __-- | _/ | + * | diagl __-- _/| _/diagr | + * | __-- diagm_/ |/ | + * | __-- /___/ | + * +-------------------------+----------------------+ + */ + +static int left_of_diagl (double x, double y) { + return (x < (sel_width + (y - sel_height) * diagl_slope)); +} /* left_of_diagl */ + +static int right_of_diagr (double x, double y) { + return (x > (sel_width + (y - sel_height) * diagr_slope)); +} /* right_of_diagr */ + +static int below_diagb (double x, double y) { + return (y < (right_tangent.y + (x - right_tangent.x) * diagb_slope)); +} /* below_diagb */ + +static int right_of_diagm (double x, double y) { + return (x > (sel_width + (y - sel_height) * diagm_slope)); +} /* right_of_diagm */ + +static int inside_circle (double x, double y) { + double dx, dy; + dx = x - center.x; + dy = y - center.y; + return (sqrt (dx * dx + dy * dy) <= radius); +} /* inside_circle */ + + +/*****/ + +static void query (void) { + static GParamDef args[] = { + {PARAM_INT32, "run_mode", "Interactive (0) , non-interactive (1)"}, + {PARAM_IMAGE, "image", "Input image"}, + {PARAM_DRAWABLE, "drawable", "Input drawable"}, + {PARAM_INT32, "edge", "Edge to curl (1-4, clockwise, starting in the lower right edge)"}, + {PARAM_INT32, "type", "vertical (0), horizontal (1)"}, + {PARAM_INT32, "shade", "Shade the region under the curl (1) or not (0)"}, + }; /* args */ + + static GParamDef *return_vals = NULL; + static int nargs = sizeof (args) / sizeof (args[0]); + static int nreturn_vals = 0; + + gimp_install_procedure (PLUG_IN_NAME, + "Pagecurl effect", + "This plug-in creates an pagecurl-effect.", + "Federico Mena Quintero and Simon Budig", + "Federico Mena Quintero and Simon Budig", + PLUG_IN_VERSION, + "/Filters/Distorts/Pagecurl", + "RGBA*, GRAYA*", + PROC_PLUG_IN, + nargs, + nreturn_vals, + args, + return_vals); +} /* query */ + +static void run (gchar * name, + gint nparams, + GParam * param, + gint * nreturn_vals, + GParam ** return_vals) { + static GParam values[1]; + GRunModeType run_mode; + GStatusType status = STATUS_SUCCESS; + + run_mode = param[0].data.d_int32; + + set_default_params (); + + /* Possibly retrieve data */ + gimp_get_data (PLUG_IN_NAME, &curl); + + *nreturn_vals = 1; + *return_vals = values; + + values[0].type = PARAM_STATUS; + values[0].data.d_status = status; + + /* Get the specified drawable */ + drawable = gimp_drawable_get (param[2].data.d_drawable); + image_id = param[1].data.d_image; + + if ((gimp_drawable_color (drawable->id) + || gimp_drawable_gray (drawable->id)) + && gimp_drawable_has_alpha (drawable->id)) { + + switch (run_mode) { + case RUN_INTERACTIVE: + /* First acquire information with a dialog */ + if (!do_dialog ()) + return; + break; + + case RUN_NONINTERACTIVE: + /* Make sure all the arguments are there! */ + if (nparams != 6) + status = STATUS_CALLING_ERROR; + if (status == STATUS_SUCCESS) { + switch (param[3].data.d_int32) { + case 1: + curl.do_upper_left = 0; + curl.do_upper_right = 0; + curl.do_lower_left = 0; + curl.do_lower_right = 1; + break; + case 2: + curl.do_upper_left = 0; + curl.do_upper_right = 0; + curl.do_lower_left = 1; + curl.do_lower_right = 0; + break; + case 3: + curl.do_upper_left = 1; + curl.do_upper_right = 0; + curl.do_lower_left = 0; + curl.do_lower_right = 0; + break; + case 4: + curl.do_upper_left = 0; + curl.do_upper_right = 1; + curl.do_lower_left = 0; + curl.do_lower_right = 0; + break; + default: + break; + } + curl.do_vertical = (param[4].data.d_int32) ? 0 : 1; + curl.do_horizontal = 1 - curl.do_vertical; + curl.do_shade_under = (param[5].data.d_int32) ? 1 : 0; + } + break; + + case RUN_WITH_LAST_VALS: + break; + + default: + break; + } + + if (status == STATUS_SUCCESS) { + page_curl (); + if (run_mode != RUN_NONINTERACTIVE) + gimp_displays_flush (); + if (run_mode == RUN_INTERACTIVE) + gimp_set_data (PLUG_IN_NAME, &curl, sizeof (CurlParams)); + } + } else + /* Sorry - no indexed/noalpha images */ + status = STATUS_EXECUTION_ERROR; + + values[0].data.d_status = status; +} /* run */ + + +/*****/ + +static void set_default_params (void) { + curl.do_curl_shade = 1; + curl.do_curl_warp = 0; /* Not yet supported... */ + + curl.do_curl_opacity = 1.0; + curl.do_shade_under = 1; + + curl.do_upper_left = 0; + curl.do_upper_right = 0; + curl.do_lower_left = 0; + curl.do_lower_right = 1; + + curl.do_vertical = 1; + curl.do_horizontal = 0; +} /* set_default_params */ + + + +/********************************************************************/ +/* dialog callbacks */ +/********************************************************************/ + +static void dialog_close_callback (GtkWidget * widget, gpointer data) { + gtk_main_quit (); +} + +static void dialog_ok_callback (GtkWidget * widget, gpointer data) { + curl_run = TRUE; + gtk_widget_destroy (GTK_WIDGET (data)); +} + +static void dialog_cancel_callback (GtkWidget * widget, gpointer data) { + gtk_widget_destroy (GTK_WIDGET (data)); +} + +static void dialog_scale_update (GtkAdjustment * adjustment, double *value) { + *value = ((double) adjustment->value) / 100.0; +} + +static void dialog_toggle_update (GtkWidget * widget, gint32 value) { + gint pixmapindex = 0; + + switch (value) { + case 0: + curl.do_upper_left = (GTK_TOGGLE_BUTTON (widget)->active) ? 1 : 0; + break; + case 1: + curl.do_upper_right = (GTK_TOGGLE_BUTTON (widget)->active) ? 1 : 0; + break; + case 2: + curl.do_lower_left = (GTK_TOGGLE_BUTTON (widget)->active) ? 1 : 0; + break; + case 3: + curl.do_lower_right = (GTK_TOGGLE_BUTTON (widget)->active) ? 1 : 0; + break; + case 5: + curl.do_horizontal = (GTK_TOGGLE_BUTTON (widget)->active) ? 1 : 0; + break; + case 6: + curl.do_vertical = (GTK_TOGGLE_BUTTON (widget)->active) ? 1 : 0; + break; + case 8: + curl.do_shade_under = (GTK_TOGGLE_BUTTON (widget)->active) ? 1 : 0; + return; + break; + default: + break; + } + + if (curl.do_upper_left + curl.do_upper_right + curl.do_lower_left + curl.do_lower_right == 1 && + curl.do_horizontal + curl.do_vertical == 1) { + pixmapindex = curl.do_lower_left + curl.do_upper_right * 2 + + curl.do_upper_left * 3 + curl.do_horizontal * 4; + if (pixmapindex < 0 || pixmapindex > 7) + pixmapindex = 0; + gtk_pixmap_set (GTK_PIXMAP (curl_pixmap_widget), + gdk_curl_pixmaps[pixmapindex], + gdk_curl_masks[pixmapindex]); + } +} + +/*********/ + +static int do_dialog (void) { + + /* Missing options: Color-dialogs? / own curl layer ? / transparency + to original drawable / Warp-curl (unsupported yet) */ + + GtkWidget *dialog; + GtkWidget *orhbox1, *orhbox2, *vbox, *ivbox, *corner_frame, *orient_frame; + GtkWidget *shade_button, *button, *label, *scale; + GtkStyle *style; + GtkObject *adjustment; + gint pixmapindex; + + gint argc; + gchar **argv; + + argc = 1; + argv = g_new (gchar *, 1); + argv[0] = g_strdup ("pagecurl"); + + gtk_init (&argc, &argv); + gtk_rc_parse (gimp_gtkrc ()); + gdk_set_use_xshm (gimp_use_xshm ()); + + dialog = gtk_dialog_new (); + gtk_window_set_title (GTK_WINDOW (dialog), "Pagecurl effect"); + gtk_container_border_width (GTK_CONTAINER (dialog), 0); + gtk_widget_realize (dialog); + gtk_signal_connect (GTK_OBJECT (dialog), "destroy", + (GtkSignalFunc) dialog_close_callback, + NULL); + + button = gtk_button_new_with_label ("OK"); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) dialog_ok_callback, + dialog); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Cancel"); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) dialog_cancel_callback, + dialog); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (vbox), 5); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), + vbox, FALSE, FALSE, 0); + +/*****/ + + orhbox1 = gtk_hbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (orhbox1), 0); + gtk_container_add (GTK_CONTAINER (vbox), orhbox1); + + style = gtk_widget_get_style (dialog); + gdk_curl_pixmaps[0] = gdk_pixmap_create_from_xpm_d (dialog->window, + &(gdk_curl_masks[0]), &style->bg[GTK_STATE_NORMAL], curl0_xpm); + gdk_curl_pixmaps[1] = gdk_pixmap_create_from_xpm_d (dialog->window, + &(gdk_curl_masks[1]), &style->bg[GTK_STATE_NORMAL], curl1_xpm); + gdk_curl_pixmaps[2] = gdk_pixmap_create_from_xpm_d (dialog->window, + &(gdk_curl_masks[2]), &style->bg[GTK_STATE_NORMAL], curl2_xpm); + gdk_curl_pixmaps[3] = gdk_pixmap_create_from_xpm_d (dialog->window, + &(gdk_curl_masks[3]), &style->bg[GTK_STATE_NORMAL], curl3_xpm); + gdk_curl_pixmaps[4] = gdk_pixmap_create_from_xpm_d (dialog->window, + &(gdk_curl_masks[4]), &style->bg[GTK_STATE_NORMAL], curl4_xpm); + gdk_curl_pixmaps[5] = gdk_pixmap_create_from_xpm_d (dialog->window, + &(gdk_curl_masks[5]), &style->bg[GTK_STATE_NORMAL], curl5_xpm); + gdk_curl_pixmaps[6] = gdk_pixmap_create_from_xpm_d (dialog->window, + &(gdk_curl_masks[6]), &style->bg[GTK_STATE_NORMAL], curl6_xpm); + gdk_curl_pixmaps[7] = gdk_pixmap_create_from_xpm_d (dialog->window, + &(gdk_curl_masks[7]), &style->bg[GTK_STATE_NORMAL], curl7_xpm); + + pixmapindex = curl.do_lower_left + curl.do_upper_right * 2 + + curl.do_upper_left * 3 + curl.do_horizontal * 4; + if (pixmapindex < 0 || pixmapindex > 7) + pixmapindex = 0; + curl_pixmap_widget = gtk_pixmap_new (gdk_curl_pixmaps[pixmapindex], + gdk_curl_masks[pixmapindex]); + gtk_box_pack_start (GTK_BOX (orhbox1), + curl_pixmap_widget, TRUE, TRUE, 0); + gtk_widget_show (curl_pixmap_widget); + + corner_frame = gtk_frame_new ("Curl location"); + gtk_frame_set_shadow_type (GTK_FRAME (corner_frame), GTK_SHADOW_ETCHED_IN); + gtk_box_pack_start (GTK_BOX (orhbox1), + corner_frame, TRUE, TRUE, 0); + + ivbox = gtk_vbox_new (FALSE, 0); + gtk_container_border_width (GTK_CONTAINER (ivbox), 5); + gtk_container_add (GTK_CONTAINER (corner_frame), ivbox); + + { + int i; + char *name[4] = + {"Upper left", "Upper right", "Lower left", "Lower right"}; + + button = NULL; + for (i = 0; i < 4; i++) { + button = gtk_radio_button_new_with_label ( + (button == NULL) ? NULL : gtk_radio_button_group (GTK_RADIO_BUTTON (button)), + name[i]); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), + (i == 0 ? curl.do_upper_left : i == 1 ? curl.do_upper_right : + i == 2 ? curl.do_lower_left : curl.do_lower_right)); + + gtk_signal_connect (GTK_OBJECT (button), "toggled", + (GtkSignalFunc) dialog_toggle_update, + (gpointer) i); + + gtk_box_pack_start (GTK_BOX (ivbox), button, FALSE, FALSE, 0); + gtk_widget_show (button); + } + } + + gtk_widget_show (ivbox); + gtk_widget_show (corner_frame); + gtk_widget_show (orhbox1); + +/*****/ + + orient_frame = gtk_frame_new ("Curl orientation"); + gtk_frame_set_shadow_type (GTK_FRAME (orient_frame), GTK_SHADOW_ETCHED_IN); + gtk_box_pack_start (GTK_BOX (vbox), + orient_frame, FALSE, FALSE, 0); + + orhbox2 = gtk_hbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (orhbox2), 5); + gtk_container_add (GTK_CONTAINER (orient_frame), orhbox2); + + { + int i; + char *name[2] = + {"horizontal", "vertical"}; + + button = NULL; + for (i = 0; i < 2; i++) { + button = gtk_radio_button_new_with_label ( + (button == NULL) ? NULL : gtk_radio_button_group (GTK_RADIO_BUTTON (button)), + name[i]); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), + (i == 0 ? curl.do_horizontal : curl.do_vertical)); + + gtk_signal_connect (GTK_OBJECT (button), "toggled", + (GtkSignalFunc) dialog_toggle_update, + (gpointer) i + 5); + + gtk_box_pack_start (GTK_BOX (orhbox2), button, TRUE, FALSE, 0); + gtk_widget_show (button); + } + } + + gtk_widget_show (orhbox2); + gtk_widget_show (orient_frame); + + shade_button = gtk_toggle_button_new_with_label ("Shade under curl"); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (shade_button), + curl.do_shade_under ? TRUE : FALSE); + gtk_signal_connect (GTK_OBJECT (shade_button), "toggled", + (GtkSignalFunc) dialog_toggle_update, (gpointer) 8); + gtk_box_pack_start (GTK_BOX (vbox), shade_button, TRUE, FALSE, 0); + gtk_widget_show (shade_button); + + + label = gtk_label_new ("Curl opacity"); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, FALSE, 0); + gtk_widget_show (label); + + adjustment = gtk_adjustment_new (curl.do_curl_opacity * 100, 0.0, 100.0, + 1.0, 1.0, 1.0); + gtk_signal_connect (adjustment, "value_changed", + (GtkSignalFunc) dialog_scale_update, + &(curl.do_curl_opacity)); + + scale = gtk_hscale_new (GTK_ADJUSTMENT (adjustment)); + gtk_widget_set_usize (GTK_WIDGET (scale), 150, 30); + gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED); + gtk_scale_set_digits (GTK_SCALE (scale), 0); + gtk_scale_set_draw_value (GTK_SCALE (scale), TRUE); + gtk_box_pack_start (GTK_BOX (vbox), scale, TRUE, FALSE, 0); + gtk_widget_show (scale); + +/*****/ + + gtk_widget_show (vbox); + + gtk_widget_show (dialog); + + gtk_main (); + gdk_flush (); + + return curl_run; +} /* do_dialog */ + +/*****/ + +static void init_calculation () { + double k; + double alpha, beta; + double angle; + vector_t v1, v2; + gint32 *image_layers, nlayers; + + + gimp_layer_add_alpha (drawable->id); + + /* Image parameters */ + + /* Determine Position of original Layer in the Layer stack. */ + + image_layers = gimp_image_get_layers (image_id, &nlayers); + drawable_position = 0; + while (drawable_position < nlayers && + image_layers[drawable_position] != drawable->id) + drawable_position++; + if (drawable_position >= nlayers) { + fprintf (stderr, "Fatal error: drawable not found in layer stack.\n"); + drawable_position = 0; + } + /* Get the bounds of the active selection */ + gimp_drawable_mask_bounds (drawable->id, &sel_x1, &sel_y1, &sel_x2, &sel_y2); + + true_sel_width = sel_x2 - sel_x1; + true_sel_height = sel_y2 - sel_y1; + if (curl.do_vertical) { + sel_width = true_sel_width; + sel_height = true_sel_height; + } else { + sel_width = true_sel_height; + sel_height = true_sel_width; + } /* else */ + + + /* Circle parameters */ + + alpha = atan ((double) sel_height / sel_width); + beta = alpha / 2.0; + k = sel_width / ((M_PI + alpha) * sin (beta) + cos (beta)); + v_set (¢er, k * cos (beta), k * sin (beta)); + radius = center.y; + + /* left_tangent */ + + v_set (&left_tangent, radius * -sin (alpha), radius * cos (alpha)); + v_add (&left_tangent, left_tangent, center); + + /* right_tangent */ + + v_sub (&v1, left_tangent, center); + v_set (&v2, sel_width - center.x, sel_height - center.y); + angle = -2.0 * acos (v_dot (v1, v2) / (v_mag (v1) * v_mag (v2))); + v_set (&right_tangent, + v1.x * cos (angle) + v1.y * -sin (angle), + v1.x * sin (angle) + v1.y * cos (angle)); + v_add (&right_tangent, right_tangent, center); + + /* Slopes */ + + diagl_slope = (double) sel_width / sel_height; + diagr_slope = (sel_width - right_tangent.x) / (sel_height - right_tangent.y); + diagb_slope = (right_tangent.y - left_tangent.y) / (right_tangent.x - left_tangent.x); + diagm_slope = (sel_width - center.x) / sel_height; + + /* Colors */ + + gimp_palette_get_foreground (&fore_color[0], &fore_color[1], &fore_color[2]); + gimp_palette_get_background (&back_color[0], &back_color[1], &back_color[2]); +} /* init_calculation */ + +/*****/ + +static void do_curl_effect (void) { + gint x, y, color_image; + guint x1, y1, k; + guint alpha_pos, progress, max_progress; + gdouble intensity, alpha; + vector_t v, dl, dr; + gdouble dl_mag, dr_mag, angle, factor; + guchar *pp, *dest, fore_grayval, back_grayval; + GPixelRgn dest_rgn; + gpointer pr; + + color_image = gimp_drawable_color (drawable->id); + curl_layer = + gimp_drawable_get (gimp_layer_new (image_id, + "Curl layer", + true_sel_width, + true_sel_height, + color_image ? RGBA_IMAGE : GRAYA_IMAGE, + 100, NORMAL_MODE)); + gimp_image_add_layer (image_id, curl_layer->id, drawable_position); + + gimp_drawable_offsets (drawable->id, &x1, &y1); + gimp_layer_set_offsets (curl_layer->id, sel_x1 + x1, sel_y1 + y1); + gimp_tile_cache_ntiles (2 * (curl_layer->width / gimp_tile_width () + 1)); + + /* Clear the newly created layer */ + gimp_pixel_rgn_init (&dest_rgn, curl_layer, 0, 0, true_sel_width, true_sel_height, TRUE, FALSE); + for (pr = gimp_pixel_rgns_register (1, &dest_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr)) { + dest = dest_rgn.data; + for (y1 = dest_rgn.y; y1 < dest_rgn.y + dest_rgn.h; y1++) { + pp = dest; + for (x1 = dest_rgn.x; x1 < dest_rgn.x + dest_rgn.w; x1++) { + for (k = 0; k < dest_rgn.bpp; k++) + pp[k] = 0; + pp += dest_rgn.bpp; + } + dest += dest_rgn.rowstride; + } + } + gimp_drawable_flush (curl_layer); + gimp_drawable_update (curl_layer->id, 0, 0, curl_layer->width, curl_layer->height); + + gimp_pixel_rgn_init (&dest_rgn, curl_layer, 0, 0, true_sel_width, true_sel_height, TRUE, TRUE); + + /* Init shade_under */ + v_set (&dl, -sel_width, -sel_height); + dl_mag = v_mag (dl); + v_set (&dr, -(sel_width - right_tangent.x), -(sel_height - right_tangent.y)); + dr_mag = v_mag (dr); + alpha = acos (v_dot (dl, dr) / (dl_mag * dr_mag)); + + /* Init shade_curl */ + + fore_grayval = INTENSITY (fore_color[0], fore_color[1], fore_color[2]); + back_grayval = INTENSITY (back_color[0], back_color[1], back_color[2]); + + max_progress = 2 * sel_width * sel_height; + progress = 0; + + alpha_pos = dest_rgn.bpp - 1; + + /* Main loop */ + for (pr = gimp_pixel_rgns_register (1, &dest_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr)) { + + dest = dest_rgn.data; + + for (y1 = dest_rgn.y; y1 < dest_rgn.y + dest_rgn.h; y1++) { + pp = dest; + for (x1 = dest_rgn.x; x1 < dest_rgn.x + dest_rgn.w; x1++) { + /* Map coordinates to get the curl correct... */ + if (curl.do_horizontal) { + x = (curl.do_lower_right || curl.do_lower_left) ? y1 : sel_width - 1 - y1; + y = (curl.do_upper_left || curl.do_lower_left) ? x1 : sel_height - 1 - x1; + } else { + x = (curl.do_upper_right || curl.do_lower_right) ? x1 : sel_width - 1 - x1; + y = (curl.do_upper_left || curl.do_upper_right) ? y1 : sel_height - 1 - y1; + } + if (left_of_diagl (x, y)) { /* uncurled region */ + for (k = 0; k <= alpha_pos; k++) + pp[k] = 0; + } else if (right_of_diagr (x, y) || (right_of_diagm (x, y) + && below_diagb (x, y) && !inside_circle (x, y))) { + /* curled region */ + for (k = 0; k <= alpha_pos; k++) + pp[k] = 0; + } else { + v.x = -(sel_width - x); + v.y = -(sel_height - y); + angle = acos (v_dot (v, dl) / (v_mag (v) * dl_mag)); + + if (inside_circle (x, y) || below_diagb (x, y)) { + /* Below the curl. */ + factor = angle / alpha; + for (k = 0; k < alpha_pos; k++) + pp[k] = 0; + pp[alpha_pos] = curl.do_shade_under ? (guchar) ((float) 255 * (float) factor) : 0; + + } else { + /* On the curl */ + intensity = pow (sin (M_PI * angle / alpha), 1.5); + if (color_image) { + pp[0] = (intensity * fore_color[0] + (1 - intensity) * back_color[0]); + pp[1] = (intensity * fore_color[1] + (1 - intensity) * back_color[1]); + pp[2] = (intensity * fore_color[2] + (1 - intensity) * back_color[2]); + } else + pp[0] = (intensity * fore_grayval + (1 - intensity) * back_grayval); + pp[alpha_pos] = (guchar) ((double) 255 * (1 - intensity*(1-curl.do_curl_opacity))); + } + } + pp += dest_rgn.bpp; + } /* for y1 */ + dest += dest_rgn.rowstride; + } /* for x1 */ + progress += dest_rgn.w * dest_rgn.h; + gimp_progress_update ((double) progress / (double) max_progress); + } /* Pixel Regions loop end */ + + gimp_drawable_flush (curl_layer); + gimp_drawable_merge_shadow (curl_layer->id, FALSE); + gimp_drawable_update (curl_layer->id, 0, 0, curl_layer->width, curl_layer->height); + gimp_drawable_detach (curl_layer); +} + +/************************************************/ + +static void clear_curled_region () { + GPixelRgn src_rgn, dest_rgn; + gpointer pr; + gint x, y; + guint x1, y1, i; + guchar *dest, *src, *pp, *sp; + guint alpha_pos, progress, max_progress; + + max_progress = 2 * sel_width * sel_height; + progress = max_progress / 2; + + gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1)); + gimp_pixel_rgn_init (&src_rgn, drawable, sel_x1, sel_y1, true_sel_width, true_sel_height, FALSE, FALSE); + gimp_pixel_rgn_init (&dest_rgn, drawable, sel_x1, sel_y1, true_sel_width, true_sel_height, TRUE, TRUE); + alpha_pos = dest_rgn.bpp - 1; + if (dest_rgn.bpp != src_rgn.bpp) + fprintf (stderr, "WARNING: src_rgn.bpp != dest_rgn.bpp!\n"); + for (pr = gimp_pixel_rgns_register (2, &dest_rgn, &src_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr)) { + dest = dest_rgn.data; + src = src_rgn.data; + for (y1 = dest_rgn.y; y1 < dest_rgn.y + dest_rgn.h; y1++) { + sp = src; + pp = dest; + for (x1 = dest_rgn.x; x1 < dest_rgn.x + dest_rgn.w; x1++) { + /* Map coordinates to get the curl correct... */ + if (curl.do_horizontal) { + x = (curl.do_lower_right || curl.do_lower_left) ? y1 - sel_y1 : sel_width - 1 - (y1 - sel_y1); + y = (curl.do_upper_left || curl.do_lower_left) ? x1 - sel_x1 : sel_height - 1 - (x1 - sel_x1); + } else { + x = (curl.do_upper_right || curl.do_lower_right) ? x1 - sel_x1 : sel_width - 1 - (x1 - sel_x1); + y = (curl.do_upper_left || curl.do_upper_right) ? y1 - sel_y1 : sel_height - 1 - (y1 - sel_y1); + } + for (i = 0; i < alpha_pos; i++) + pp[i] = sp[i]; + if (right_of_diagr (x, y) || (right_of_diagm (x, y) && below_diagb (x, y) && !inside_circle (x, y))) { + /* Right of the curl */ + pp[alpha_pos] = 0; + } else { + pp[alpha_pos] = sp[alpha_pos]; + } + pp += dest_rgn.bpp; + sp += src_rgn.bpp; + } + src += src_rgn.rowstride; + dest += dest_rgn.rowstride; + } + progress += dest_rgn.w * dest_rgn.h; + gimp_progress_update ((double) progress / (double) max_progress); + } + gimp_drawable_flush (drawable); + gimp_drawable_merge_shadow (drawable->id, TRUE); + gimp_drawable_update (drawable->id, sel_x1, sel_y1, true_sel_width, true_sel_height); + gimp_drawable_detach (drawable); +} + +/*****/ + +static void page_curl () { + int nreturn_vals; + gimp_run_procedure ("gimp_undo_push_group_start", &nreturn_vals, + PARAM_IMAGE, image_id, + PARAM_END); + + gimp_progress_init ("Page Curl"); + init_calculation (); + do_curl_effect (); + clear_curled_region (); + gimp_run_procedure ("gimp_undo_push_group_end", &nreturn_vals, + PARAM_IMAGE, image_id, + PARAM_END); +} /* page_curl */ +