#ifdef HAVE_CONFIG_H #include "config.h" #else #define HAVE_DIRENT_H #define HAVE_UNISTD_H #endif #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include "gimpressionist.h" #include "ppmtool.h" #include gimpressionist_vals_t runningvals; void prepbrush(struct ppm *p) { int x, y; int rowstride = p->width * 3; for(y = 0; y< p->height; y++) { for(x = 0; x < p->width; x++) { p->col[y*rowstride+x*3+1] = 0; } } for(y = 1; y< p->height; y++) { for(x = 1; x < p->width; x++) { int v = p->col[y*rowstride+x*3] - p->col[(y-1)*rowstride+(x-1)*3]; if(v < 0) v = 0; p->col[y*rowstride+x*3+1] = v; } } } double sumbrush(struct ppm *p) { double sum = 0; int i; for(i = 0; i < p->width*3*p->height; i += 3) sum += p->col[i]; return sum; } int gethue(guchar *rgb) { double h, v, temp, diff; if((rgb[0] == rgb[1]) && (rgb[0] == rgb[2])) /* Gray */ return 0; v = (rgb[0] > rgb[1] ? rgb[0] : rgb[1]); /* v = strste verdi */ if(rgb[2] > v) v = rgb[2]; temp = (rgb[0] > rgb[1] ? rgb[1] : rgb[0] ); /* temp = minste */ if(rgb[2] < temp) temp = rgb[2]; diff = v - temp; if(v == rgb[0]) h = ((double)rgb[1] - rgb[2]) / diff; else if(v == rgb[1]) h = ((double)rgb[2] - rgb[0]) / diff + 2; else /* v == rgb[2] */ h = ((double)rgb[0] - rgb[1]) / diff + 4; if(h < 0) h += 6; return h * 255.0 / 6.0; } int bestbrush(struct ppm *p, struct ppm *a, int tx, int ty, struct ppm *brushes, int numbrush, double *brushsum, int start, int step) { double dev, thissum; double bestdev = 0.0; double r, g, b; int best = -1; int x, y, h; long i; GList *brlist = NULL; for(i = start; i < numbrush; i += step) { struct ppm *brush = &brushes[i]; /* thissum = 0.0; */ thissum = brushsum[i]; r = g = b = 0.0; for(y = 0; y < brush->height; y++) { guchar *row = p->col + (ty+y)*p->width*3; for(x = 0; x < brush->width; x++) { int k = (tx+x)*3; double v; if((h = brush->col[(y*brush->width*3)+x*3])) { /* thissum += h; */ v = h / 255.0; r += row[k+0] * v; g += row[k+1] * v; b += row[k+2] * v; } } } r = r * 255.0 / thissum; g = g * 255.0 / thissum; b = b * 255.0 / thissum; dev = 0.0; for(y = 0; y < brush->height; y++) { guchar *row = p->col + (ty+y)*p->width*3; for(x = 0; x < brush->width; x++) { int k = (tx+x)*3; double v; if((h = brush->col[(y*brush->width*3)+x*3])) { v = h / 255.0; dev += abs(row[k+0] - r) * v; dev += abs(row[k+1] - g) * v; dev += abs(row[k+2] - b) * v; if(img_has_alpha) dev += a->col[(ty+y)*a->width*3+(tx+x)*3] * v; } } } dev /= thissum; if((best == -1) || (dev < bestdev)) { if(brlist) g_list_free(brlist); brlist = NULL; } if(dev <= bestdev || best < 0) { best = i; bestdev = dev; brlist = g_list_append(brlist, (void *)i); } if(dev < runningvals.devthresh) break; } if(!brlist) { fprintf(stderr, "What!? No brushes?!\n"); return 0; } i = RAND_FUNC() % g_list_length(brlist); best = (long)((g_list_nth(brlist,i))->data); g_list_free(brlist); return best; } void applybrush(struct ppm *brush, struct ppm *shadow, struct ppm *p, struct ppm *a, int tx, int ty, int r, int g, int b) { struct ppm tmp; struct ppm atmp; double v, h; int x, y; double edgedarken = 1.0 - runningvals.generaldarkedge; double relief = runningvals.brushrelief / 100.0; int shadowdepth = pcvals.generalshadowdepth; int shadowblur = pcvals.generalshadowblur; /* if((tx < 0) || (ty < 0)) { fprintf(stderr, "applybrush: Huh!? tx=%d ty=%d\n",tx,ty); return; } */ memcpy(&tmp, p, sizeof(struct ppm)); if(img_has_alpha) memcpy(&atmp, a, sizeof(struct ppm)); if(shadow) { int sx = tx + shadowdepth - shadowblur*2; int sy = ty + shadowdepth - shadowblur*2; for(y = 0; y < shadow->height; y++) { guchar *row, *arow = NULL; if((sy + y) < 0) continue; if((sy + y) >= tmp.height) break; row = tmp.col + (sy+y) * tmp.width * 3; if(img_has_alpha) arow = atmp.col + (sy+y) * atmp.width * 3; for(x = 0; x < shadow->width; x++) { int k = (sx + x) * 3; if((sx + x) < 0) continue; if((sx + x) >= tmp.width) break; h = shadow->col[y*shadow->width*3+x*3+2]; if(!h) continue; v = 1.0 - (h / 255.0 * runningvals.generalshadowdarkness / 100.0); row[k+0] *= v; row[k+1] *= v; row[k+2] *= v; if(img_has_alpha) arow[k] *= v; } } } for(y = 0; y < brush->height; y++) { guchar *row = tmp.col + (ty+y)*tmp.width*3; guchar *arow = NULL; if(img_has_alpha) arow = atmp.col + (ty+y)*atmp.width*3; for(x = 0; x < brush->width; x++) { int k = (tx + x) * 3; h = brush->col[y*brush->width*3+x*3]; if(!h) continue; if(runningvals.colorbrushes) { v = 1.0 - brush->col[y*brush->width*3+x*3+2] / 255.0; row[k+0] *= v; row[k+1] *= v; row[k+2] *= v; if(img_has_alpha) arow[(tx+x)*3] *= v; } v = (1.0 - h / 255.0) * edgedarken; row[k+0] *= v; row[k+1] *= v; row[k+2] *= v; if(img_has_alpha) arow[k] *= v; v = h / 255.0; row[k+0] += r * v; row[k+1] += g * v; row[k+2] += b * v; } } if(relief > 0.001) { for(y = 1; y < brush->height; y++) { guchar *row = tmp.col + (ty+y)*tmp.width*3; for(x = 1; x < brush->width; x++) { int k = (tx + x) * 3; h = brush->col[y*brush->width*3+x*3+1] * relief; if(h < 0.001) continue; if(h > 255) h = 255; row[k+0] = (row[k+0] * (255-h) + 255 * h) / 255; row[k+1] = (row[k+1] * (255-h) + 255 * h) / 255; row[k+2] = (row[k+2] * (255-h) + 255 * h) / 255; } } } } void repaint(struct ppm *p, struct ppm *a) { int x, y; int tx = 0, ty = 0; struct ppm tmp = {0,0,NULL}; struct ppm atmp = {0,0,NULL}; int r, g, b, n, h, i, j, on, sn; int numbrush, maxbrushwidth, maxbrushheight; guchar back[3] = {0,0,0}; struct ppm *brushes, *shadows; struct ppm *brush, *shadow = NULL; double *brushsum; int cx, cy, maxdist; double scale, relief, startangle, anglespan, density, bgamma; double thissum; int max_progress; struct ppm paperppm = {0,0,NULL}; struct ppm dirmap = {0,0,NULL}; struct ppm sizmap = {0,0,NULL}; int *xpos = NULL, *ypos = NULL; int step = 1; int progstep; static int running = 0; int dropshadow = pcvals.generaldropshadow; int shadowblur = pcvals.generalshadowblur; if(running) return; running++; memcpy(&runningvals, &pcvals, sizeof(pcvals)); /* Shouldn't be necessary, but... */ if(img_has_alpha) if((p->width != a->width) || (p->height != a->height)) { fprintf(stderr, "Huh? Image size != alpha size?\n"); return; } SRAND_FUNC(time(NULL)); numbrush = runningvals.orientnum * runningvals.sizenum; startangle = runningvals.orientfirst; anglespan = runningvals.orientlast; density = runningvals.brushdensity; if(runningvals.placetype == 1) density /= 3.0; bgamma = runningvals.brushgamma; brushes = g_malloc (numbrush * sizeof(struct ppm)); brushsum = g_malloc (numbrush * sizeof(double)); if(dropshadow) shadows = g_malloc (numbrush * sizeof(struct ppm)); else shadows = NULL; brushes[0].col = NULL; if(brushfile) reloadbrush(runningvals.selectedbrush, &brushes[0]); else copyppm(&brushppm, &brushes[0]); resize(&brushes[0], brushes[0].width, brushes[0].height * pow(10,runningvals.brushaspect)); scale = runningvals.sizelast / MAX(brushes[0].width, brushes[0].height); if(bgamma != 1.0) ppmgamma(&brushes[0], 1.0/bgamma, 1,1,1); resize(&brushes[0], brushes[0].width * scale, brushes[0].height * scale); i = 1 + sqrt(brushes[0].width * brushes[0].width + brushes[0].height * brushes[0].height); pad(&brushes[0], i-brushes[0].width, i-brushes[0].width, i-brushes[0].height, i-brushes[0].height, back); for(i = 1; i < numbrush; i++) { brushes[i].col = NULL; copyppm(&brushes[0], &brushes[i]); } for(i = 0; i < runningvals.sizenum; i++) { double sv; if(runningvals.sizenum > 1) sv = i / (runningvals.sizenum - 1.0); else sv = 1.0; for(j = 0; j < runningvals.orientnum; j++) { h = j + i * runningvals.orientnum; freerotate(&brushes[h], startangle + j * anglespan / runningvals.orientnum); rescale(&brushes[h], (sv * runningvals.sizefirst + (1.0-sv) * runningvals.sizelast) / runningvals.sizelast); autocrop(&brushes[h],1); } } /* Brush-debugging */ /* for(i = 0; i < numbrush; i++) { char tmp[1000]; sprintf(tmp, "/tmp/_brush%03d.ppm", i); saveppm(&brushes[i], tmp); } */ for(i = 0; i < numbrush; i++) { if(!runningvals.colorbrushes) prepbrush(&brushes[i]); brushsum[i] = sumbrush(&brushes[i]); } brush = &brushes[0]; thissum = brushsum[0]; maxbrushwidth = maxbrushheight = 0; for(i = 0; i < numbrush; i++) { if(brushes[i].width > maxbrushwidth) maxbrushwidth = brushes[i].width; if(brushes[i].height > maxbrushheight) maxbrushheight = brushes[i].height; } for(i = 0; i < numbrush; i++) { int xp, yp; guchar blk[3] = {0,0,0}; xp = maxbrushwidth - brushes[i].width; yp = maxbrushheight - brushes[i].height; if(xp || yp) pad(&brushes[i], xp/2, xp-xp/2, yp/2, yp-yp/2, blk); } if(dropshadow) { for(i = 0; i < numbrush; i++) { shadows[i].col = NULL; copyppm(&brushes[i], &shadows[i]); ppmgamma(&shadows[i], 0, 1,1,0); pad(&shadows[i], shadowblur*2, shadowblur*2, shadowblur*2, shadowblur*2, back); for(j = 0; j < shadowblur; j++) blur(&shadows[i], 2, 2); /* autocrop(&shadows[i],1); */ } /* maxbrushwidth += shadowdepth*3; maxbrushheight += shadowdepth*3; */ } /* For extra annoying debugging :-) */ /* saveppm(brushes, "/tmp/__brush.ppm"); if(shadows) saveppm(shadows, "/tmp/__shadow.ppm"); system("xv /tmp/__brush.ppm & xv /tmp/__shadow.ppm & "); */ if(runningvals.generalpaintedges) { edgepad(p, maxbrushwidth, maxbrushwidth, maxbrushheight, maxbrushheight); if(img_has_alpha) edgepad(a, maxbrushwidth, maxbrushwidth, maxbrushheight, maxbrushheight); } if(img_has_alpha) { /* Initially fully transparent */ if(runningvals.generalbgtype == 3) { guchar tmpcol[3] = {255,255,255}; newppm(&atmp, a->width, a->height); fill(&atmp, tmpcol); } else { copyppm(a, &atmp); } } if(runningvals.generalbgtype == 0) { guchar tmpcol[3]; newppm(&tmp, p->width, p->height); memcpy(&tmpcol, runningvals.color, 3); fill(&tmp, tmpcol); } else if(runningvals.generalbgtype == 1) { copyppm(p, &tmp); } else { scale = runningvals.paperscale / 100.0; newppm(&tmp, p->width, p->height); loadppm(runningvals.selectedpaper, &paperppm); resize(&paperppm, paperppm.width * scale, paperppm.height * scale); if(runningvals.paperinvert) ppmgamma(&paperppm, -1.0, 1, 1, 1); for(x = 0; x < tmp.width; x++) { int rx = x % paperppm.width; for(y = 0; y < tmp.height; y++) { int ry = y % paperppm.height; memcpy(&tmp.col[y*tmp.width*3+x*3], &paperppm.col[ry*paperppm.width*3+rx*3], 3); } } } cx = p->width / 2; cy = p->height / 2; maxdist = sqrt(cx*cx+cy*cy); if(runningvals.orienttype == 0) { /* Value */ newppm(&dirmap, p->width, p->height); for(y = 0; y < dirmap.height; y++) { guchar *dstrow = &dirmap.col[y*dirmap.width*3]; guchar *srcrow = &p->col[y*p->width*3]; for(x = 0; x < dirmap.width; x++) { dstrow[x*3] = (srcrow[x*3] + srcrow[x*3+1] + srcrow[x*3+2]) / 3; } } } else if(runningvals.orienttype == 1) { /* Radius */ newppm(&dirmap, p->width, p->height); for(y = 0; y < dirmap.height; y++) { guchar *dstrow = &dirmap.col[y*dirmap.width*3]; double ysqr = (cy-y)*(cy-y); for(x = 0; x < dirmap.width; x++) { dstrow[x*3] = sqrt((cx-x)*(cx-x)+ysqr) * 255 / maxdist; } } } else if(runningvals.orienttype == 3) { /* Radial */ newppm(&dirmap, p->width, p->height); for(y = 0; y < dirmap.height; y++) { guchar *dstrow = &dirmap.col[y*dirmap.width*3]; for(x = 0; x < dirmap.width; x++) { dstrow[x*3] = (G_PI + atan2(cy-y, cx-x)) * 255.0 / (G_PI*2); } } } else if(runningvals.orienttype == 4) { /* Flowing */ newppm(&dirmap, p->width / 6 + 5, p->height / 6 + 5); mkgrayplasma(&dirmap, 15); blur(&dirmap, 2, 2); blur(&dirmap, 2, 2); resize(&dirmap, p->width, p->height); blur(&dirmap, 2, 2); if(runningvals.generalpaintedges) edgepad(&dirmap, maxbrushwidth, maxbrushheight,maxbrushwidth, maxbrushheight); } else if(runningvals.orienttype == 5) { /* Hue */ newppm(&dirmap, p->width, p->height); for(y = 0; y < dirmap.height; y++) { guchar *dstrow = &dirmap.col[y*dirmap.width*3]; guchar *srcrow = &p->col[y*p->width*3]; for(x = 0; x < dirmap.width; x++) { dstrow[x*3] = gethue(&srcrow[x*3]); } } } else if(runningvals.orienttype == 6) { guchar tmpcol[3] = {0,0,0}; newppm(&dirmap, p->width, p->height); fill(&dirmap, tmpcol); } else if(runningvals.orienttype == 7) { /* Manual */ newppm(&dirmap, p->width-maxbrushwidth*2, p->height-maxbrushheight*2); for(y = 0; y < dirmap.height; y++) { guchar *dstrow = &dirmap.col[y*dirmap.width*3]; double tmpy = y / (double)dirmap.height; for(x = 0; x < dirmap.width; x++) { dstrow[x*3] = pixval(90-getdir(x / (double)dirmap.width, tmpy, 1)); } } edgepad(&dirmap, maxbrushwidth, maxbrushwidth, maxbrushheight, maxbrushheight); } if(runningvals.sizetype == 0) { /* Value */ newppm(&sizmap, p->width, p->height); for(y = 0; y < sizmap.height; y++) { guchar *dstrow = &sizmap.col[y*sizmap.width*3]; guchar *srcrow = &p->col[y*p->width*3]; for(x = 0; x < sizmap.width; x++) { dstrow[x*3] = (srcrow[x*3] + srcrow[x*3+1] + srcrow[x*3+2]) / 3; } } } else if(runningvals.sizetype == 1) { /* Radius */ newppm(&sizmap, p->width, p->height); for(y = 0; y < sizmap.height; y++) { guchar *dstrow = &sizmap.col[y*sizmap.width*3]; double ysqr = (cy-y)*(cy-y); for(x = 0; x < sizmap.width; x++) { dstrow[x*3] = sqrt((cx-x)*(cx-x)+ysqr) * 255 / maxdist; } } } else if(runningvals.sizetype == 3) { /* Radial */ newppm(&sizmap, p->width, p->height); for(y = 0; y < sizmap.height; y++) { guchar *dstrow = &sizmap.col[y*sizmap.width*3]; for(x = 0; x < sizmap.width; x++) { dstrow[x*3] = (G_PI + atan2(cy-y, cx-x)) * 255.0 / (G_PI*2); } } } else if(runningvals.sizetype == 4) { /* Flowing */ newppm(&sizmap, p->width / 6 + 5, p->height / 6 + 5); mkgrayplasma(&sizmap, 15); blur(&sizmap, 2, 2); blur(&sizmap, 2, 2); resize(&sizmap, p->width, p->height); blur(&sizmap, 2, 2); if(runningvals.generalpaintedges) edgepad(&sizmap, maxbrushwidth, maxbrushheight,maxbrushwidth, maxbrushheight); } else if(runningvals.sizetype == 5) { /* Hue */ newppm(&sizmap, p->width, p->height); for(y = 0; y < sizmap.height; y++) { guchar *dstrow = &sizmap.col[y*sizmap.width*3]; guchar *srcrow = &p->col[y*p->width*3]; for(x = 0; x < sizmap.width; x++) { dstrow[x*3] = gethue(&srcrow[x*3]); } } } else if(runningvals.sizetype == 6) { guchar tmpcol[3] = {0,0,0}; newppm(&sizmap, p->width, p->height); fill(&sizmap, tmpcol); } else if(runningvals.sizetype == 7) { /* Manual */ newppm(&sizmap, p->width-maxbrushwidth*2, p->height-maxbrushheight*2); for(y = 0; y < sizmap.height; y++) { guchar *dstrow = &sizmap.col[y*sizmap.width*3]; double tmpy = y / (double)sizmap.height; for(x = 0; x < sizmap.width; x++) { dstrow[x*3] = 255 * (1.0 - getsiz(x / (double)sizmap.width, tmpy, 1)); } } edgepad(&sizmap, maxbrushwidth, maxbrushwidth, maxbrushheight, maxbrushheight); } /* saveppm(&sizmap, "/tmp/_sizmap.ppm"); */ if(runningvals.placetype == 0) { i = tmp.width * tmp.height / (maxbrushwidth * maxbrushheight); i *= density; } else if(runningvals.placetype == 1) { i = (int)(tmp.width * density / maxbrushwidth) * (int)(tmp.height * density / maxbrushheight); step = i; /* fprintf(stderr, "step=%d i=%d\n", step, i); */ } if(i < 1) i = 1; max_progress = i; progstep = max_progress / 30; if(progstep < 10) progstep = 10; if(runningvals.placetype == 1) { int j; xpos = g_new (int, i); ypos = g_new (int, i); for(j = 0; j < i; j++) { int factor = (int)(tmp.width * density / maxbrushwidth + 0.5); if(factor < 1) factor = 1; xpos[j] = maxbrushwidth/2 + (j % factor) * maxbrushwidth / density; ypos[j] = maxbrushheight/2 + (j / factor) * maxbrushheight / density; } for(j = 0; j < i; j++) { int a, b; a = RAND_FUNC() % i; b = xpos[j]; xpos[j] = xpos[a]; xpos[a] = b; b = ypos[j]; ypos[j] = ypos[a]; ypos[a] = b; } } for(; i; i--) { if(i % progstep == 0) { if(runningvals.run) { if(!standalone) gimp_progress_update(0.8 - 0.8*((double)i / max_progress)); else { fprintf(stderr, "."); fflush(stderr); } } else { char tmps[40]; sprintf(tmps, "%.1f %%", 100 * (1.0 - ((double)i / max_progress))); gtk_label_set_text(GTK_LABEL(GTK_BIN(previewbutton)->child), tmps); while(gtk_events_pending()) gtk_main_iteration(); } } if(runningvals.placetype == 0) { tx = RAND_FUNC() % (tmp.width - maxbrushwidth) + maxbrushwidth/2; ty = RAND_FUNC() % (tmp.height - maxbrushheight) + maxbrushheight/2; } else if(runningvals.placetype == 1) { tx = xpos[i-1]; ty = ypos[i-1]; } if(runningvals.placecenter) { double z = RAND_FUNC() * 0.75 / G_MAXRAND; tx = tx * (1.0-z) + tmp.width/2 * z; ty = ty * (1.0-z) + tmp.height/2 * z; } if((tx < maxbrushwidth/2) || (ty < maxbrushwidth/2) || (tx + maxbrushwidth/2 >= p->width) || (ty + maxbrushheight/2 >= p->height)) { /* fprintf(stderr, "Internal Error; invalid coords: (%d,%d) i=%d\n", tx, ty, i); */ continue; } if(img_has_alpha) { if(a->col[ty*a->width*3+tx*3] > 128) continue; } n = sn = on = 0; switch(runningvals.orienttype) { case 2: /* Random */ on = RAND_FUNC() % runningvals.orientnum; break; case 0: /* Value */ case 1: /* Radius */ case 3: /* Radial */ case 4: /* Flowing */ case 5: /* Hue */ case 7: /* Manual */ on = runningvals.orientnum * dirmap.col[ty*dirmap.width*3+tx*3] / 256; break; case 6: /* Adaptive */ break; /* Handled below */ default: fprintf(stderr, "Internal error; Unknown orientationtype\n"); on = 0; break; } switch(runningvals.sizetype) { case 2: /* Random */ sn = RAND_FUNC() % runningvals.sizenum; break; case 0: /* Value */ case 1: /* Radius */ case 3: /* Radial */ case 4: /* Flowing */ case 5: /* Hue */ case 7: /* Manual */ sn = runningvals.sizenum * sizmap.col[ty*sizmap.width*3+tx*3] / 256; break; case 6: /* Adaptive */ break; /* Handled below */ default: fprintf(stderr, "Internal error; Unknown sizetype\n"); sn = 0; break; } /* Handle Adaptive selections */ if((runningvals.orienttype == 6) && (runningvals.sizetype == 6)) { n = bestbrush(p, a, tx-maxbrushwidth/2, ty-maxbrushheight/2, brushes, numbrush, brushsum, 0, 1); } else if(runningvals.orienttype == 6) { int st = sn * runningvals.orientnum; n = bestbrush(p, a, tx-maxbrushwidth/2, ty-maxbrushheight/2, brushes, st+runningvals.orientnum, brushsum, st, 1); } else if(runningvals.sizetype == 6) { n = bestbrush(p, a, tx-maxbrushwidth/2, ty-maxbrushheight/2, brushes, numbrush, brushsum, on, runningvals.orientnum); } else { n = sn * runningvals.orientnum + on; } /* Should never happen, but hey... */ if(n < 0) n = 0; else if(n >= numbrush) n = numbrush - 1; tx -= maxbrushwidth/2; ty -= maxbrushheight/2; brush = &brushes[n]; if(dropshadow) shadow = &shadows[n]; thissum = brushsum[n]; /* Calculate color - avg. of in-brush pixels */ if(runningvals.colortype == 0) { r = g = b = 0; for(y = 0; y < brush->height; y++) { guchar *row = &p->col[(ty+y)*p->width*3]; for(x = 0; x < brush->width; x++) { int k = (tx+x) * 3; double v; if((h = brush->col[y*brush->width*3+x*3])) { v = h / 255.0; r += row[k+0] * v; g += row[k+1] * v; b += row[k+2] * v; } } } r = r * 255.0 / thissum; g = g * 255.0 / thissum; b = b * 255.0 / thissum; } else if(runningvals.colortype == 1) { guchar *pixel; y = ty + (brush->height / 2); x = tx + (brush->width / 2); pixel = &p->col[y*p->width*3 + x*3]; r = pixel[0]; g = pixel[1]; b = pixel[2]; } else { /* No such colortype! */ r = g = b = 0; } if(runningvals.colornoise > 0.0) { double v = runningvals.colornoise; r = r + RAND_FUNC() / (float)G_MAXRAND * v - v/2; g = g + RAND_FUNC() / (float)G_MAXRAND * v - v/2; b = b + RAND_FUNC() / (float)G_MAXRAND * v - v/2; if(r < 0) r = 0; else if(r > 255) r = 255; if(g < 0) g = 0; else if(g > 255) g = 255; if(b < 0) b = 0; else if(b > 255) b = 255; } applybrush(brush, shadow, &tmp, &atmp, tx,ty, r,g,b); if(runningvals.generaltileable && runningvals.generalpaintedges) { int origwidth = tmp.width - 2 * maxbrushwidth; int origheight = tmp.height - 2 * maxbrushheight; int dox = 0, doy = 0; if(tx < maxbrushwidth) { applybrush(brush, shadow, &tmp, &atmp, tx+origwidth,ty, r,g,b); dox = -1; } else if(tx > origwidth) { applybrush(brush, shadow, &tmp, &atmp, tx-origwidth,ty, r,g,b); dox = 1; } if(ty < maxbrushheight) { applybrush(brush, shadow, &tmp, &atmp, tx,ty+origheight, r,g,b); doy = 1; } else if(ty > origheight) { applybrush(brush, shadow, &tmp, &atmp, tx,ty-origheight, r,g,b); doy = -1; } if(doy) { if(dox < 0) applybrush(brush, shadow, &tmp, &atmp, tx+origwidth,ty+doy*origheight,r,g,b); if(dox > 0) applybrush(brush, shadow, &tmp, &atmp, tx-origwidth,ty+doy*origheight,r,g,b); } } } for(i = 0; i < numbrush; i++) { killppm(&brushes[i]); } g_free(brushes); if(shadows) g_free(shadows); g_free(brushsum); if (xpos) g_free (xpos); if (ypos) g_free (ypos); if(runningvals.generalpaintedges) { crop(&tmp, maxbrushwidth, maxbrushheight, tmp.width - maxbrushwidth, tmp.height - maxbrushheight); if(img_has_alpha) crop(&atmp, maxbrushwidth, maxbrushheight, atmp.width - maxbrushwidth, atmp.height - maxbrushheight); } killppm(p); p->width = tmp.width; p->height = tmp.height; p->col = tmp.col; if(img_has_alpha) { killppm(a); a->width = atmp.width; a->height = atmp.height; a->col = atmp.col; } relief = runningvals.paperrelief / 100.0; if(relief > 0.001) { scale = runningvals.paperscale / 100.0; if(paperppm.col) { memcpy(&tmp, &paperppm, sizeof(struct ppm)); paperppm.col = NULL; } else { tmp.col = NULL; loadppm(runningvals.selectedpaper, &tmp); resize(&tmp, tmp.width * scale, tmp.height * scale); if(runningvals.paperinvert) ppmgamma(&tmp, -1.0, 1,1,1); } for(x = 0; x < p->width; x++) { double h, v; int px = x % tmp.width, py; for(y = 0; y < p->height; y++) { int k = y * p->width * 3 + x * 3; py = y % tmp.height; if(runningvals.paperoverlay) h = (tmp.col[py*tmp.width*3+px*3]-128) * relief; else h = (tmp.col[py*tmp.width*3+px*3] - (int)tmp.col[((py+1)%tmp.height)*tmp.width*3+((px+1)%tmp.width)*3]) / -2.0 * relief; if(h <= 0.0) { v = 1.0 + h/128.0; if(v < 0.0) v = 0.0; else if(v > 1.0) v = 1.0; p->col[k+0] *= v; p->col[k+1] *= v; p->col[k+2] *= v; } else { v = h/128.0; if(v < 0.0) v = 0.0; else if(v > 1.0) v = 1.0; p->col[k+0] = p->col[k+0] * (1.0-v) + 255 * v; p->col[k+1] = p->col[k+1] * (1.0-v) + 255 * v; p->col[k+2] = p->col[k+2] * (1.0-v) + 255 * v; } } } killppm(&tmp); } if(paperppm.col) killppm(&paperppm); if(dirmap.col) killppm(&dirmap); if(sizmap.col) killppm(&sizmap); if(runningvals.run) { if(!standalone) gimp_progress_update(0.8); else { fprintf(stderr, ".\n"); fflush(stderr); } } else { gtk_label_set_text(GTK_LABEL(GTK_BIN(previewbutton)->child), _("Update")); } running = 0; }