1 //
2 // Copyright 2013 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24
25
26 #include "shape_utils.h"
27
28 #include <cassert>
29 #include <cstdio>
30 #include <cstring>
31 #include <iterator>
32 #include <fstream>
33 #include <sstream>
34
35 //------------------------------------------------------------------------------
sgets(char * s,int size,char ** stream)36 static char const * sgets( char * s, int size, char ** stream ) {
37 for (int i=0; i<size; ++i) {
38 if ( (*stream)[i]=='\n' || (*stream)[i]=='\0') {
39
40 memcpy(s, *stream, i);
41 s[i]='\0';
42
43 if ((*stream)[i]=='\0')
44 return 0;
45 else {
46 (*stream) += i+1;
47 return s;
48 }
49 }
50 }
51 return 0;
52 }
53
54 //------------------------------------------------------------------------------
~Shape()55 Shape::~Shape() {
56 for (int i=0; i<(int)tags.size(); ++i)
57 delete tags[i];
58
59 for (int i=0; i<(int)mtls.size(); ++i)
60 delete mtls[i];
61 }
62
63 //------------------------------------------------------------------------------
parseObj(char const * shapestr,Scheme shapescheme,bool isLeftHanded,bool parsemtl)64 Shape * Shape::parseObj(char const * shapestr, Scheme shapescheme, bool isLeftHanded,
65 bool parsemtl) {
66
67 Shape * s = new Shape;
68
69 s->scheme = shapescheme;
70 s->isLeftHanded = isLeftHanded;
71
72 char * str=const_cast<char *>(shapestr), line[256], buf[256], usemtl=-1;
73 bool done = false;
74 while (! done) {
75 done = sgets(line, sizeof(line), &str)==0;
76 if (line[0]) {
77 char* end = &line[strlen(line)-1];
78 if (*end == '\n') *end = '\0'; // strip trailing nl
79 }
80 float x, y, z, u, v;
81 switch (line[0]) {
82 case 'v': switch (line[1]) {
83 case ' ': if (sscanf(line, "v %f %f %f", &x, &y, &z) == 3) {
84 s->verts.push_back(x);
85 s->verts.push_back(y);
86 s->verts.push_back(z);
87 } break;
88 case 't': if (sscanf(line, "vt %f %f", &u, &v) == 2) {
89 s->uvs.push_back(u);
90 s->uvs.push_back(v);
91 } break;
92 case 'n' : if (sscanf(line, "vn %f %f %f", &x, &y, &z) == 3) {
93 s->normals.push_back(x);
94 s->normals.push_back(y);
95 s->normals.push_back(z);
96 } break; // skip normals for now
97 } break;
98 case 'f': if (line[1] == ' ') {
99 int vi, ti, ni;
100 const char* cp = &line[2];
101 while (*cp == ' ') cp++;
102 int nverts = 0, nitems=0;
103 while( (nitems=sscanf(cp, "%d/%d/%d", &vi, &ti, &ni))>0) {
104 nverts++;
105 s->faceverts.push_back(vi-1);
106 if(nitems > 1) s->faceuvs.push_back(ti-1);
107 if(nitems > 2) s->facenormals.push_back(ni-1);
108 while (*cp && *cp != ' ') cp++;
109 while (*cp == ' ') cp++;
110 }
111 s->nvertsPerFace.push_back(nverts);
112 if (! s->mtls.empty()) {
113 s->mtlbind.push_back(usemtl);
114 }
115 } break;
116 case 't' : if (line[1] == ' ') {
117 Shape::tag * t = tag::parseTag( line );
118 if (t)
119 s->tags.push_back(t);
120 } break;
121 case 'u' : if (parsemtl && sscanf(line, "usemtl %s", buf)==1) {
122 usemtl = s->FindMaterial(buf);
123 } break;
124 case 'm' : if (parsemtl && sscanf(line, "mtllib %s", buf)==1) {
125 std::ifstream ifs(buf);
126 if (ifs) {
127 std::stringstream ss;
128 ss << ifs.rdbuf();
129 ifs.close();
130 std::string tmpStr = ss.str();
131 s->parseMtllib(tmpStr.c_str());
132 s->mtllib = buf;
133 }
134 } break;
135 }
136 }
137 return s;
138 }
139
140 //------------------------------------------------------------------------------
parseObj(ShapeDesc const & shapeDesc,bool parsemtl)141 Shape * Shape::parseObj(ShapeDesc const & shapeDesc, bool parsemtl) {
142 return parseObj(shapeDesc.data.c_str(), shapeDesc.scheme, shapeDesc.isLeftHanded,
143 parsemtl);
144 }
145
146 //------------------------------------------------------------------------------
parseTag(char const * line)147 Shape::tag * Shape::tag::parseTag(char const * line) {
148 tag * t = 0;
149
150 const char* cp = &line[2];
151
152 char tname[50];
153 while (*cp == ' ') cp++;
154 if (sscanf(cp, "%s", tname )!=1) return t;
155 while (*cp && *cp != ' ') cp++;
156
157 int nints=0, nfloats=0, nstrings=0;
158 while (*cp == ' ') cp++;
159 if (sscanf(cp, "%d/%d/%d", &nints, &nfloats, &nstrings)!=3) return t;
160 while (*cp && *cp != ' ') cp++;
161
162 std::vector<int> tintargs;
163 for (int i=0; i<nints; ++i) {
164 int val;
165 while (*cp == ' ') cp++;
166 if (sscanf(cp, "%d", &val)!=1) return t;
167 tintargs.push_back(val);
168 while (*cp && *cp != ' ') cp++;
169 }
170
171 std::vector<float> tfloatargs;
172 for (int i=0; i<nfloats; ++i) {
173 float val;
174 while (*cp == ' ') cp++;
175 if (sscanf(cp, "%f", &val)!=1) return t;
176 tfloatargs.push_back(val);
177 while (*cp && *cp != ' ') cp++;
178 }
179
180 std::vector<std::string> tstringargs;
181 for (int i=0; i<nstrings; ++i) {
182 char val[512];
183 while (*cp == ' ') cp++;
184 if (sscanf(cp, "%s", val)!=1) return t;
185 tstringargs.push_back(std::string(val));
186 while (*cp && *cp != ' ') cp++;
187 }
188
189 t = new Shape::tag;
190 t->name = tname;
191 t->intargs = tintargs;
192 t->floatargs = tfloatargs;
193 t->stringargs = tstringargs;
194
195 return t;
196 }
197
198 //------------------------------------------------------------------------------
material()199 Shape::material::material() {
200 memset(ka, 0, sizeof(float)*3);
201 memset(kd, 0, sizeof(float)*3);
202 memset(ks, 0, sizeof(float)*3);
203 memset(tf, 0, sizeof(float)*3);
204 ns = ni = d = 0.0f;
205 illum=0;
206 }
207
208 //------------------------------------------------------------------------------
parseMtllib(char const * mtlstr)209 void Shape::parseMtllib(char const * mtlstr) {
210
211 char * str=const_cast<char *>(mtlstr), line[256];
212
213 material * mtl=0;
214
215 bool done = false;
216 float r, g, b, a;
217 while (! done) {
218 done = sgets(line, sizeof(line), &str)==0;
219 char* end = &line[strlen(line)-1];
220 if (*end == '\n') *end = '\0'; // strip trailing nl
221 switch (line[0]) {
222 case 'n': char name[256];
223 if (sscanf(line, "newmtl %s", name) == 1) {
224 mtl = new material;
225 mtl->name = name;
226 mtls.push_back(mtl);
227 } break;
228 case 'K': if (sscanf(line+2, " %f %f %f", &r, &g, &b) == 3) {
229 switch (line[1]) {
230 case 'a': mtl->ka[0]=r; mtl->ka[1]=g; mtl->ka[2]=b; break;
231 case 'd': mtl->kd[0]=r; mtl->kd[1]=g; mtl->kd[2]=b; break;
232 case 's': mtl->ks[0]=r; mtl->ks[1]=g; mtl->ks[2]=b; break;
233 }
234 } break;
235 case 'N': if (sscanf(line+2, " %f", &a) == 1) {
236 switch (line[1]) {
237 case 's' : mtl->ns = a; break;
238 case 'i' : mtl->ni = a; break;
239 }
240 } break;
241 case 'd': if (sscanf(line, "d %f", &a) == 1) {
242 mtl->d = a;
243 } break;
244 case 'T': if (line[1]=='f') {
245 if (sscanf(line, "Tf %f %f %f", &r, &g, &b) == 3) {
246 mtl->tf[0]=r; mtl->tf[1]=g; mtl->tf[2]=b;
247 } break;
248 } break;
249 case 'i': int illum;
250 if (sscanf(line, "illum %d", &illum) == 1) {
251 mtl->illum = illum;
252 } break;
253 case 's': if (sscanf(line, "sharpness %f", &a) == 1) {
254 mtl->sharpness = a;
255 } break;
256 }
257 }
258 }
259
260 //------------------------------------------------------------------------------
genTag() const261 std::string Shape::tag::genTag() const {
262 std::stringstream t;
263
264 t<<"\"t \""<<name<<"\" ";
265
266 t<<intargs.size()<<"/"<<floatargs.size()<<"/"<<stringargs.size()<<" ";
267
268 std::copy(intargs.begin(), intargs.end(), std::ostream_iterator<int>(t));
269 t<<" ";
270
271 std::copy(floatargs.begin(), floatargs.end(), std::ostream_iterator<float>(t));
272 t<<" ";
273
274 std::copy(stringargs.begin(), stringargs.end(), std::ostream_iterator<std::string>(t));
275 t<<"\\n\"\n";
276
277 return t.str();
278 }
279
280 //------------------------------------------------------------------------------
genShape(char const * name) const281 std::string Shape::genShape(char const * name) const {
282 std::stringstream sh;
283
284 sh<<"static char const * "<<name<<" = \n";
285
286 for (int i=0; i<(int)verts.size(); i+=3)
287 sh << "\"v " << verts[i] << " " << verts[i+1] << " " << verts[i+2] <<"\\n\"\n";
288
289 for (int i=0; i<(int)uvs.size(); i+=2)
290 sh << "\"vt " << uvs[i] << " " << uvs[i+1] << "\\n\"\n";
291
292 for (int i=0; i<(int)normals.size(); i+=3)
293 sh << "\"vn " << normals[i] << " " << normals[i+1] << " " << normals[i+2] <<"\\n\"\n";
294
295 sh << "\"s off\\n\"\n";
296
297 for (int i=0, idx=0; i<(int)nvertsPerFace.size();++i) {
298 sh << "\"f ";
299 for (int j=0; j<nvertsPerFace[i];++j) {
300 int vert = faceverts[idx+j]+1,
301 uv = (int)faceuvs.size()>0 ? faceuvs[idx+j]+1 : vert,
302 normal = (int)facenormals.size()>0 ? facenormals[idx+j]+1 : vert;
303 sh << vert << "/" << uv << "/" << normal << " ";
304 }
305 sh << "\\n\"\n";
306 idx+=nvertsPerFace[i];
307 }
308
309 for (int i=0; i<(int)tags.size(); ++i)
310 sh << tags[i]->genTag();
311
312 return sh.str();
313 }
314
315 //------------------------------------------------------------------------------
genObj() const316 std::string Shape::genObj() const {
317 std::stringstream sh;
318
319 sh<<"# This file uses centimeters as units for non-parametric coordinates.\n\n";
320
321 for (int i=0; i<(int)verts.size(); i+=3)
322 sh << "v " << verts[i] << " " << verts[i+1] << " " << verts[i+2] <<"\n";
323
324 for (int i=0; i<(int)uvs.size(); i+=2)
325 sh << "vt " << uvs[i] << " " << uvs[i+1] << "\n";
326
327 for (int i=0; i<(int)normals.size(); i+=3)
328 sh << "vn " << normals[i] << " " << normals[i+1] << " " << normals[i+2] <<"\n";
329
330 for (int i=0, idx=0; i<(int)nvertsPerFace.size();++i) {
331 sh << "f ";
332 for (int j=0; j<nvertsPerFace[i];++j) {
333 int vert = faceverts[idx+j]+1,
334 uv = (int)faceuvs.size()>0 ? faceuvs[idx+j]+1 : vert,
335 normal = (int)facenormals.size()>0 ? facenormals[idx+j]+1 : vert;
336 sh << vert << "/" << uv << "/" << normal << " ";
337 }
338 sh << "\n";
339 idx+=nvertsPerFace[i];
340 }
341
342 for (int i=0; i<(int)tags.size(); ++i)
343 sh << tags[i]->genTag();
344
345 return sh.str();
346 }
347
348 //------------------------------------------------------------------------------
genRIB() const349 std::string Shape::genRIB() const {
350 std::stringstream rib;
351
352 rib << "HierarchicalSubdivisionMesh \"catmull-clark\" ";
353
354 rib << "[";
355 std::copy(nvertsPerFace.begin(), nvertsPerFace.end(), std::ostream_iterator<int>(rib));
356 rib << "] ";
357
358 rib << "[";
359 std::copy(faceverts.begin(), faceverts.end(), std::ostream_iterator<int>(rib));
360 rib << "] ";
361
362 std::stringstream names, nargs, intargs, floatargs, strargs;
363 for (int i=0; i<(int)tags.size();) {
364 tag * t = tags[i];
365
366 names << t->name;
367
368 nargs << t->intargs.size() << " " << t->floatargs.size() << " " << t->stringargs.size();
369
370 std::copy(t->intargs.begin(), t->intargs.end(), std::ostream_iterator<int>(intargs));
371
372 std::copy(t->floatargs.begin(), t->floatargs.end(), std::ostream_iterator<float>(floatargs));
373
374 std::copy(t->stringargs.begin(), t->stringargs.end(), std::ostream_iterator<std::string>(strargs));
375
376 if (++i<(int)tags.size()) {
377 names << " ";
378 nargs << " ";
379 intargs << " ";
380 floatargs << " ";
381 strargs << " ";
382 }
383 }
384
385 rib << "["<<names.str()<<"] " << "["<<nargs.str()<<"] " << "["<<intargs.str()<<"] " << "["<<floatargs.str()<<"] " << "["<<strargs.str()<<"] ";
386
387 rib << "\"P\" [";
388 std::copy(verts.begin(), verts.end(), std::ostream_iterator<float>(rib));
389 rib << "] ";
390
391 return rib.str();
392 }
393