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

# User Rev Content
1 greg 2.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     }