ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/writewfobj.c
Revision: 2.3
Committed: Thu Apr 23 22:35:27 2020 UTC (4 years ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R3
Changes since 2.2: +11 -7 lines
Log Message:
Made error reporting and return value more consistent

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.3 static const char RCSid[] = "$Id: writewfobj.c,v 2.2 2020/04/23 03:19:48 greg Exp $";
3 greg 2.1 #endif
4     /*
5     * writewfobj.c
6     *
7     * Routines for writing out Wavefront file.
8     *
9     * Created by Greg Ward on Thu Feb 12 2004.
10     */
11    
12 greg 2.2 #include "paths.h"
13 greg 2.1 #include "rterror.h"
14     #include "objutil.h"
15    
16     /* Delete unreferenced vertices */
17     static void
18     del_unref_verts(Scene *sc)
19     {
20     int *vmap;
21     Face *f;
22     int nused, i;
23     /* allocate index map */
24     if (!sc->nverts)
25     return;
26     i = sc->nverts;
27     if (sc->ntex > i)
28     i = sc->ntex;
29     if (sc->nnorms > i)
30     i = sc->nnorms;
31     vmap = (int *)emalloc(sizeof(int)*i);
32     /* remap positions */
33     for (i = nused = 0; i < sc->nverts; i++) {
34     if (sc->vert[i].vflist == NULL) {
35     vmap[i] = -1;
36     continue;
37     }
38     if (nused != i)
39     sc->vert[nused] = sc->vert[i];
40     vmap[i] = nused++;
41     }
42     if (nused == sc->nverts)
43     goto skip_pos;
44     sc->vert = (Vertex *)erealloc((char *)sc->vert,
45     sizeof(Vertex)*(nused+(CHUNKSIZ-1)));
46     sc->nverts = nused;
47     for (f = sc->flist; f != NULL; f = f->next)
48     for (i = f->nv; i--; )
49     if ((f->v[i].vid = vmap[f->v[i].vid]) < 0)
50     error(CONSISTENCY,
51     "Link error in del_unref_verts()");
52     skip_pos:
53     /* remap texture coord's */
54     if (!sc->ntex)
55     goto skip_tex;
56     memset((void *)vmap, 0, sizeof(int)*sc->ntex);
57     for (f = sc->flist; f != NULL; f = f->next)
58     for (i = f->nv; i--; )
59     if (f->v[i].tid >= 0)
60     vmap[f->v[i].tid] = 1;
61     for (i = nused = 0; i < sc->ntex; i++) {
62     if (!vmap[i])
63     continue;
64     if (nused != i)
65     sc->tex[nused] = sc->tex[i];
66     vmap[i] = nused++;
67     }
68     if (nused == sc->ntex)
69     goto skip_tex;
70     sc->tex = (TexCoord *)erealloc((char *)sc->tex,
71     sizeof(TexCoord)*(nused+(CHUNKSIZ-1)));
72     sc->ntex = nused;
73     for (f = sc->flist; f != NULL; f = f->next)
74     for (i = f->nv; i--; )
75     if (f->v[i].tid >= 0)
76     f->v[i].tid = vmap[f->v[i].tid];
77     skip_tex:
78     /* remap normals */
79     if (!sc->nnorms)
80     goto skip_norms;
81     memset((void *)vmap, 0, sizeof(int)*sc->nnorms);
82     for (f = sc->flist; f != NULL; f = f->next)
83     for (i = f->nv; i--; )
84     if (f->v[i].nid >= 0)
85     vmap[f->v[i].nid] = 1;
86     for (i = nused = 0; i < sc->nnorms; i++) {
87     if (!vmap[i])
88     continue;
89     if (nused != i)
90     memcpy((void *)sc->norm[nused],
91     (void *)sc->norm[i],
92     sizeof(Normal));
93     vmap[i] = nused++;
94     }
95     if (nused == sc->nnorms)
96     goto skip_norms;
97     sc->norm = (Normal *)erealloc((char *)sc->norm,
98     sizeof(Normal)*(nused+(CHUNKSIZ-1)));
99     sc->nnorms = nused;
100     for (f = sc->flist; f != NULL; f = f->next)
101     for (i = f->nv; i--; )
102     if (f->v[i].nid >= 0)
103     f->v[i].nid = vmap[f->v[i].nid];
104     skip_norms:
105     /* clean up */
106     efree((char *)vmap);
107     }
108    
109     /* Write out header comments */
110     static void
111     write_header(Scene *sc, FILE *fp)
112     {
113     int i;
114    
115     for (i = 0; i < sc->ndescr; i++)
116     fprintf(fp, "# %s\n", sc->descr[i]);
117     fputs("#\n", fp);
118     fprintf(fp, "# %d final faces\n", sc->nfaces);
119     fprintf(fp,
120     "#\t%d vertices, %d texture coordinates, %d surface normals\n",
121     sc->nverts, sc->ntex, sc->nnorms);
122     fputs("#\n\n", fp);
123     }
124    
125     /* Write out vertex lists */
126     static void
127     write_verts(Scene *sc, FILE *fp)
128     {
129     int i;
130    
131     fputs("# Vertex positions\n", fp);
132     for (i = 0; i < sc->nverts; i++)
133     fprintf(fp, "v %.12g %.12g %.12g\n",
134     sc->vert[i].p[0],
135     sc->vert[i].p[1],
136     sc->vert[i].p[2]);
137     fputs("\n# Vertex texture coordinates\n", fp);
138     for (i = 0; i < sc->ntex; i++)
139     fprintf(fp, "vt %.6g %.6g\n",
140     sc->tex[i].u, sc->tex[i].v);
141     fputs("\n# Vertex normals\n", fp);
142     for (i = 0; i < sc->nnorms; i++)
143     fprintf(fp, "vn %.6f %.6f %.6f\n",
144     sc->norm[i][0],
145     sc->norm[i][1],
146     sc->norm[i][2]);
147     fputc('\n', fp);
148     }
149    
150     /* Write out an object group */
151     static void
152     write_group(const Scene *sc, int gid, FILE *fp)
153     {
154     int mid = -1;
155     const Face *f;
156     int j;
157    
158     fprintf(fp, "# Face group\ng %s\n", sc->grpname[gid]);
159     for (f = sc->flist; f != NULL; f = f->next) {
160     if (f->grp != gid)
161     continue;
162     if (f->mat != mid)
163     fprintf(fp, "usemtl %s\n", sc->matname[mid=f->mat]);
164     fputc('f', fp);
165     for (j = 0; j < f->nv; j++) {
166     fprintf(fp, " %d/", f->v[j].vid - sc->nverts);
167     if (f->v[j].tid >= 0)
168     fprintf(fp, "%d/", f->v[j].tid - sc->ntex);
169     else
170     fputc('/', fp);
171     if (f->v[j].nid >= 0)
172     fprintf(fp, "%d", f->v[j].nid - sc->nnorms);
173     }
174     fputc('\n', fp);
175     }
176     fprintf(fp, "# End of face group %s\n\n", sc->grpname[gid]);
177     }
178    
179     /* Write a .OBJ to stream, return # faces written */
180     int
181     toOBJ(Scene *sc, FILE *fp)
182     {
183     int i;
184    
185     if (sc == NULL || sc->nfaces <= 0 || fp == NULL)
186     return(0);
187     if (verbose)
188     fputs(" Removing unreferenced vertices\r", stderr);
189     del_unref_verts(sc); /* clean up, first */
190     if (verbose)
191     fputs(" Writing vertices \r", stderr);
192     write_header(sc, fp); /* write out header */
193     write_verts(sc, fp); /* write out vertex lists */
194     /* write out each object group */
195     for (i = 0; i < sc->ngrps; i++) {
196     if (verbose)
197     fprintf(stderr, " Writing faces %s \r",
198     sc->grpname[i]);
199     write_group(sc, i, fp);
200     }
201     if (fflush(fp) < 0) {
202     error(SYSTEM, "Error flushing .OBJ output");
203     return(-1);
204     }
205     return(sc->nfaces);
206     }
207    
208     /* Write a .OBJ file, return # faces written */
209     int
210     writeOBJ(Scene *sc, const char *fspec)
211     {
212     extern char *progname;
213     FILE *fp;
214     int n;
215    
216     if (sc == NULL || sc->nfaces <= 0 || fspec == NULL || !*fspec)
217     return(0);
218     #if POPEN_SUPPORT
219     if (fspec[0] == '!') {
220     if ((fp = popen(fspec+1, "w")) == NULL) {
221     sprintf(errmsg, "%s: cannot execute", fspec);
222     error(SYSTEM, errmsg);
223 greg 2.3 return(-1);
224 greg 2.1 }
225     } else
226     #endif
227     if ((fp = fopen(fspec, "w")) == NULL) {
228     sprintf(errmsg, "%s: cannot open for writing", fspec);
229     error(SYSTEM, errmsg);
230 greg 2.3 return(-1);
231 greg 2.1 }
232     /* start off header */
233     fprintf(fp, "# Wavefront .OBJ file created by %s\n#\n", progname);
234     n = toOBJ(sc, fp); /* write scene */
235     #if POPEN_SUPPORT
236 greg 2.3 if (fspec[0] == '!') {
237     if (pclose(fp)) {
238     sprintf(errmsg, "%s: error writing to command\n", fspec);
239     error(SYSTEM, errmsg);
240     return(-1);
241     }
242     } else
243 greg 2.1 #endif
244 greg 2.3 fclose(fp); /* close it (already flushed) */
245 greg 2.1 return(n);
246     }