ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/writewfobj.c
Revision: 2.1
Committed: Mon Mar 30 18:28:35 2020 UTC (4 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
Created robjutil tool to manipulate Wavefront .OBJ files

File Contents

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