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

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: writewfobj.c,v 2.2 2020/04/23 03:19:48 greg Exp $";
3 #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 #include "paths.h"
13 #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 return(-1);
224 }
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 return(-1);
231 }
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 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 #endif
244 fclose(fp); /* close it (already flushed) */
245 return(n);
246 }