ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/psketch.c
Revision: 2.2
Committed: Sat Aug 26 18:26:56 2017 UTC (6 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.1: +69 -100 lines
Log Message:
Improved sketching result, but still not great

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: psketch.c,v 2.1 2017/08/26 16:07:22 greg Exp $";
3 #endif
4 /*
5 * psketch.c - modify picture to sketch objects with named modifiers
6 *
7 * 9/23/2017
8 */
9
10 #include "copyright.h"
11
12 #include <string.h>
13
14 #include "standard.h"
15 #include "platform.h"
16 #include "resolu.h"
17 #include "color.h"
18
19 #define MAXMOD 2048 /* maximum number of modifiers */
20 #define USESORT 12 /* switch to sorted search */
21
22 double smoothing = 0.8; /* weight for moving average filter */
23 double mixfact = 0.3; /* amount to mix above/below */
24
25 char *modlist[MAXMOD]; /* (sorted) modifier list */
26 int nmods = 0; /* number of modifiers */
27
28 unsigned char *hasmod; /* scanline bitmap */
29 unsigned char *hasmod1;
30 COLOR *scan[2]; /* i/o scanlines */
31 RESOLU pres; /* input resolution */
32 int bmwidth; /* bytes per bitmap */
33
34 #undef tstbit /* conflicting def's in param.h */
35 #undef setbit
36 #undef clrbit
37 #undef tglbit
38
39 #define bitop(bm,x,op) ((bm)[(x)>>3] op (1<<((x)&7)))
40 #define tstbit(bm,x) bitop(bm,x,&)
41 #define setbit(bm,x) bitop(bm,x,|=)
42 #define clrbit(bm,x) bitop(bm,x,&=~)
43 #define tglbit(bm,x) bitop(bm,x,^=)
44
45 const char *octree, *infname; /* input octree and picture names */
46 FILE *infp; /* picture input stream */
47 FILE *mafp; /* pipe from rtrace with modifiers */
48 int linesread = 0; /* scanlines read so far */
49
50 static int
51 find_mod(const char *s)
52 {
53 int ilower, iupper;
54 int c, i;
55
56 if (nmods < USESORT) { /* linear search */
57 for (i = nmods; i-- > 0; )
58 if (!strcmp(s, modlist[i]))
59 return(i);
60 return(-1);
61 }
62 ilower = 0; iupper = nmods;
63 c = iupper; /* binary search */
64 while ((i = (iupper + ilower) >> 1) != c) {
65 c = strcmp(s, modlist[i]);
66 if (c > 0)
67 ilower = i;
68 else if (c < 0)
69 iupper = i;
70 else
71 return(i);
72 c = i;
73 }
74 return(-1);
75 }
76
77 static int
78 read_scan(void)
79 {
80 const int spread = (int)(smoothing*10);
81 int x, width = scanlen(&pres);
82 unsigned char *tbmp;
83 COLOR *tscn;
84 char modbuf[516];
85 /* advance buffer */
86 tscn = scan[0];
87 scan[0] = scan[1];
88 scan[1] = tscn;
89 /* check if we are at the end */
90 if (linesread >= numscans(&pres))
91 return(0);
92 /* set scanline bitmap */
93 if (linesread) {
94 /* load & check materials */
95 memset(hasmod1, 0, bmwidth);
96 for (x = 0; x < width; x++) {
97 int len;
98 if (fgets(modbuf, sizeof(modbuf), mafp) == NULL) {
99 fprintf(stderr, "Error reading from rtrace!\n");
100 return(-1);
101 }
102 len = strlen(modbuf);
103 if (len < 3 || (modbuf[len-1] != '\n') |
104 (modbuf[len-2] != '\t')) {
105 fprintf(stderr, "Garbled rtrace output: %s", modbuf);
106 return(-1);
107 }
108 modbuf[len-2] = '\0';
109 if (find_mod(modbuf) >= 0)
110 setbit(hasmod1, x);
111 }
112 /* smear to cover around object */
113 memset(hasmod, 0, bmwidth);
114 for (x = spread; x < width-spread; x++) {
115 int ox;
116 if (!tstbit(hasmod1,x)) continue;
117 for (ox = -spread; ox <= spread; ox++)
118 setbit(hasmod,x+ox);
119 }
120 }
121 /* read next picture scanline */
122 if (freadscan(scan[1], width, infp) < 0) {
123 fprintf(stderr, "%s: error reading scanline %d\n",
124 infname, linesread);
125 return(-1);
126 }
127 return(++linesread);
128 }
129
130 static int
131 spcmp(const void *p1, const void *p2)
132 {
133 return strcmp(*(const char **)p1, *(const char **)p2);
134 }
135
136 static int
137 get_started(void)
138 {
139 char combuf[1024];
140
141 if (nmods >= USESORT) /* need to sort for search? */
142 qsort(modlist, nmods, sizeof(char *), &spcmp);
143 /* open pipe from rtrace */
144 sprintf(combuf, "vwrays -fd %s | rtrace -h -fda -om %s",
145 infname, octree);
146 mafp = popen(combuf, "r");
147 if (mafp == NULL) {
148 perror("popen");
149 return(0);
150 }
151 /* allocate bitmaps & buffers */
152 bmwidth = (scanlen(&pres)+7) >> 3;
153 hasmod = (unsigned char *)malloc(bmwidth);
154 hasmod1 = (unsigned char *)malloc(bmwidth);
155 scan[0] = (COLOR *)malloc(scanlen(&pres)*sizeof(COLOR));
156 scan[1] = (COLOR *)malloc(scanlen(&pres)*sizeof(COLOR));
157 if (!hasmod | !hasmod1 | !scan[0] | !scan[1]) {
158 perror("malloc");
159 return(0);
160 }
161 if (!read_scan()) /* read first scanline */
162 return(0);
163 return(1);
164 }
165
166 static int
167 advance_scanline(void)
168 {
169 static int alldone = 0;
170 int width = scanlen(&pres);
171 int height = numscans(&pres);
172 int x, xstart = 0, xstop = width, xstep = 1;
173 COLOR cmavg;
174
175 if (alldone) /* finished last scanline? */
176 return(0);
177 alldone = (linesread >= height);
178 /* advance scanline */
179 if (read_scan() < !alldone)
180 return(-1);
181 if (linesread & 1) { /* process in horizontal zig-zag */
182 xstart = width-1;
183 xstop = -1;
184 xstep = -1;
185 }
186 setcolor(cmavg, .0f, .0f, .0f); /* process this scanline */
187 for (x = xstart; x != xstop; x += xstep) {
188 COLOR cmix;
189 if (!tstbit(hasmod,x)) continue;
190 /* apply moving average */
191 scalecolor(scan[0][x], 1.-smoothing);
192 scalecolor(cmavg, smoothing);
193 addcolor(cmavg, scan[0][x]);
194 copycolor(scan[0][x], cmavg);
195 /* mix pixel into next scanline */
196 copycolor(cmix, scan[0][x]);
197 scalecolor(cmix, mixfact);
198 scalecolor(scan[1][x], 1.-mixfact);
199 addcolor(scan[1][x], cmix);
200 }
201 /* write out result */
202 if (fwritescan(scan[0], width, stdout) < 0) {
203 perror("write error");
204 return(-1);
205 }
206 return(1);
207 }
208
209 static int
210 clean_up(void)
211 {
212 char linebuf[128];
213 /* read unused materials */
214 while (fgets(linebuf, sizeof(linebuf), mafp) != NULL)
215 ;
216 if (pclose(mafp) != 0) {
217 fprintf(stderr, "Error running rtrace!\n");
218 return(0);
219 }
220 fclose(infp);
221 free(hasmod);
222 free(hasmod1);
223 free(scan[0]);
224 free(scan[1]);
225 return(1);
226 }
227
228 int
229 main(int argc, char *argv[])
230 {
231 int i, rval;
232 char pfmt[LPICFMT+1];
233 /* process options */
234 for (i = 1; i < argc && argv[i][0] == '-'; i++)
235 switch (argv[i][1]) {
236 case 'm': /* new modifier name */
237 if (nmods >= MAXMOD) {
238 fprintf(stderr, "%s: too many modifiers\n", argv[0]);
239 return(1);
240 }
241 modlist[nmods++] = argv[++i];
242 break;
243 case 'M': /* modifier file */
244 rval = wordfile(modlist, MAXMOD-nmods, argv[++i]);
245 if (rval < 0) {
246 fprintf(stderr, "%s: cannot open modifier file '%s'\n",
247 argv[0], argv[i]);
248 return(1);
249 }
250 nmods += rval;
251 break;
252 case 's': /* filter smoothing amount */
253 smoothing = atof(argv[++i]);
254 if ((smoothing <= FTINY) | (smoothing >= 1.-FTINY)) {
255 fprintf(stderr, "%s: smoothing factor must be in (0,1) range\n",
256 argv[0]);
257 return(1);
258 }
259 break;
260 default:
261 fprintf(stderr, "%s: unknown option '%s'\n",
262 argv[0], argv[i]);
263 return(1);
264 }
265 if ((argc-i < 2) | (argc-i > 3)) {
266 fprintf(stderr, "Usage: %s [-m modname][-M modfile][-s smoothing] octree input.hdr [output.hdr]\n",
267 argv[0]);
268 return(1);
269 }
270 if (!nmods) {
271 fprintf(stderr, "%s: at least one '-m' or '-M' option needed\n",
272 argv[0]);
273 return(1);
274 }
275 octree = argv[i];
276 infname = argv[i+1]; /* open input picture */
277 infp = fopen(infname, "rb");
278 if (infp == NULL) {
279 fprintf(stderr, "%s: cannot open input '%s' for reading\n",
280 argv[0], argv[i+1]);
281 return(1);
282 }
283 if (i+2 < argc && /* open output picture */
284 freopen(argv[i+2], "w", stdout) == NULL) {
285 fprintf(stderr, "%s: cannot open output '%s' for writing\n",
286 argv[0], argv[i+2]);
287 return(1);
288 }
289 SET_FILE_BINARY(stdout);
290 strcpy(pfmt, PICFMT); /* copy format/resolution */
291 if (checkheader(infp, pfmt, stdout) < 0 || !fgetsresolu(&pres, infp)) {
292 fprintf(stderr, "%s: bad format for input picture\n",
293 argv[0]);
294 return(1);
295 }
296 printargs(argc, argv, stdout); /* complete header */
297 fputformat(pfmt, stdout);
298 fputc('\n', stdout);
299 fputsresolu(&pres, stdout); /* resolution does not change */
300 if (!get_started())
301 return(1);
302 while ((rval = advance_scanline()))
303 if (rval < 0)
304 return(1);
305 if (!clean_up())
306 return(1);
307 return(0);
308 }