Subversion Repositories gelsvn

Rev

Rev 421 | Rev 510 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
79 jab 1
// bdl, jab, feb 2005
2
// Inspired and partly lifted from Nate Robins' Obj loader
3
 
4
#include "TriMesh.h"
5
#include <CGLA/Vec3f.h>
6
#include <stdio.h>
7
#include <iostream>
8
 
9
using namespace std;
10
using namespace CGLA;
11
 
12
namespace Geometry {
13
 
14
	namespace
15
	{
16
		string get_path(const string& _filename)
17
		{
18
			// Make sure we only have slashes and not backslashes
19
			string filename = _filename;
20
			replace(filename.begin(),filename.end(),'\\','/');
21
 
22
			// Find the last occurrence of slash.
23
			// Everything before is path.
24
			unsigned int n = filename.rfind("/");
25
			if(n > filename.size())
26
				return "./";
27
			string pathname = "";
28
			pathname.assign(filename,0,n);
29
			pathname.append("/");
30
			return pathname;
31
		}
32
	}
33
	class TriMeshObjLoader
34
	{
35
		TriMesh *mesh;
36
		std::string pathname;
37
 
38
		int get_vert(int i) {
39
			assert(i!=0);
40
			if (i<0) {
41
				return mesh->geometry.no_vertices()+i;
42
			} else
43
				return i-1;
44
		}
45
 
46
		int get_normal(int i) {
47
			if (i<0) {
48
				return mesh->normals.no_vertices()+i;
49
			} else
50
				return i-1;
51
		}
52
 
53
		int get_texcoord(int i) {
54
			if (i<0) {
55
				return mesh->texcoords.no_vertices()+i;
56
			} else
57
				return i-1;
58
		}
59
 
60
		void read_material_library(const string& filename);
61
 
62
	public:
63
 
64
		TriMeshObjLoader(TriMesh *_mesh): mesh(_mesh) {}
65
 
66
		void load(const std::string& filename);
67
	};
68
 
69
	void TriMeshObjLoader::read_material_library(const string& filename)
70
	{
71
		string fn = pathname + filename;
72
		FILE* file = fopen(fn.data(), "r");
73
		if (!file) 
74
			{
75
				cerr << "Could not open " << filename << endl;
76
				return;
77
			}
78
 
79
		char  buf[128];
80
		unsigned int nummaterials=1;
81
 
82
		// count the number of materials in the file 
83
		while(fscanf(file, "%s", buf) != EOF) 
84
			{
85
				switch(buf[0]) 
86
					{
87
					case '#':				/* comment */
88
						/* eat up rest of line */
89
						fgets(buf, sizeof(buf), file);
90
						break;
91
					case 'n':				/* newmtl */
92
						fgets(buf, sizeof(buf), file);
93
						nummaterials++;
94
						sscanf(buf, "%s %s", buf, buf);
95
						break;
96
					default:
97
						/* eat up rest of line */
98
						fgets(buf, sizeof(buf), file);
99
						break;
100
					}
101
			}
102
		rewind(file);
103
 
104
		/* allocate memory for the materials */
105
		mesh->materials.resize(nummaterials);
106
 
107
		/* now, read in the data */
108
		nummaterials = 0;
109
		while(fscanf(file, "%s", buf) != EOF) {
110
			switch(buf[0]) {
111
			case '#':				/* comment */
112
				/* eat up rest of line */
113
				fgets(buf, sizeof(buf), file);
114
				break;
115
			case 'n':				/* newmtl */
116
				fgets(buf, sizeof(buf), file);
117
				sscanf(buf, "%s %s", buf, buf);
118
				nummaterials++;
119
				mesh->materials[nummaterials].name = buf;
120
				break;
121
			case 'N':
421 jrf 122
        switch(buf[1])
123
          {
124
          case 's':
125
				    fscanf(file, "%f", &mesh->materials[nummaterials].shininess);
126
				    /* wavefront shininess is from [0, 1000], so scale for OpenGL */
127
				    mesh->materials[nummaterials].shininess /= 1000.0;
128
				    mesh->materials[nummaterials].shininess *= 128.0;
129
            break;
130
          case 'i':
131
				    fscanf(file, "%f", &mesh->materials[nummaterials].ior_in);
132
            break;
133
					default:
134
						/* eat up rest of line */
135
						fgets(buf, sizeof(buf), file);
136
						break;
137
          }
79 jab 138
				break;
139
			case 'K': 
140
				switch(buf[1]) 
141
					{
142
					case 'd':
143
						fscanf(file, "%f %f %f",
144
									 &mesh->materials[nummaterials].diffuse[0],
145
									 &mesh->materials[nummaterials].diffuse[1],
146
									 &mesh->materials[nummaterials].diffuse[2]);
147
						break;
148
					case 's':
149
						fscanf(file, "%f %f %f",
150
									 &mesh->materials[nummaterials].specular[0],
151
									 &mesh->materials[nummaterials].specular[1],
152
									 &mesh->materials[nummaterials].specular[2]);
153
						break;
154
					case 'a':
155
						fscanf(file, "%f %f %f",
156
									 &mesh->materials[nummaterials].ambient[0],
157
									 &mesh->materials[nummaterials].ambient[1],
158
									 &mesh->materials[nummaterials].ambient[2]);
159
						break;
160
					default:
161
						/* eat up rest of line */
162
						fgets(buf, sizeof(buf), file);
163
						break;
164
					}
165
				break;
421 jrf 166
      case 'T':
167
				fscanf(file, "%f %f %f",
168
               &mesh->materials[nummaterials].transmission[0],
169
               &mesh->materials[nummaterials].transmission[1],
170
               &mesh->materials[nummaterials].transmission[2]);
171
        break;
172
      case 'i':
173
				fscanf(file, "%d", &mesh->materials[nummaterials].illum);
174
        break;
79 jab 175
			case 'm': // Map ... all maps are treated equally.
176
				{
177
					fscanf(file,"%s",buf);
178 bj 178
					mesh->materials[nummaterials].tex_path = pathname;
179
					mesh->materials[nummaterials].tex_name = string(buf);
79 jab 180
				}
181
				break;
182
			default:
183
				/* eat up rest of line */
184
				fgets(buf, sizeof(buf), file);
185
				break;
186
			}
187
		}
436 jrf 188
    fclose(file);
79 jab 189
	}
190
 
191
 
192
	void TriMeshObjLoader::load(const std::string& filename) 
193
	{
194
		pathname = get_path(filename);
195
		FILE *fp = fopen(filename.data(), "r");
196
		if (fp==0) {
197
			cerr << "File " << filename << " does not exist" << endl;
364 jrf 198
      exit(0);
79 jab 199
		}
200
		mesh->materials.resize(1);
201
 
202
		char buf[256];
203
		Vec3f v_geo;
204
		Vec3f v_normals;
205
		Vec3f v_texcoords;
206
 
207
		Vec3i f_geo;
208
		Vec3i f_normals;
209
		Vec3i f_texcoords;
210
		int current_material=0;
211
		int v,n,t;
212
		while(fscanf(fp, "%s", buf) != EOF) 
213
			{
214
				switch(buf[0]) 
215
					{
216
					case '#': // A comment
217
						fgets(buf, sizeof(buf), fp);
218
						break;
219
					case 'm':
220
						fgets(buf, sizeof(buf), fp);
221
						sscanf(buf, "%s %s", buf, buf);
222
						read_material_library(buf);
223
						break;
224
					case 'u':
225
						fgets(buf, sizeof(buf), fp);
226
						sscanf(buf, "%s %s", buf, buf);
227
						current_material = mesh->find_material(buf);
228
						break;
229
					case 'v': // v, vn, vt
230
						switch(buf[1]) 
231
							{
232
							case '\0': // vertex
233
								fscanf(fp, "%f %f %f", &v_geo[0], &v_geo[1], &v_geo[2]);
234
								mesh->geometry.add_vertex(v_geo);
235
								break;
236
							case 'n': // normal
237
								fscanf(fp, "%f %f %f", &v_normals[0], &v_normals[1], &v_normals[2]);
238
								mesh->normals.add_vertex(v_normals);
239
								break;
240
							case 't': // texcoord
241
								fscanf(fp, "%f %f", &v_texcoords[0], &v_texcoords[1]);
242
								v_texcoords[2]=1;
243
								mesh->texcoords.add_vertex(v_texcoords);
244
								break;
245
							}
246
						break;
247
					case 'f':
248
						v = n = t = 0;
249
						fscanf(fp, "%s", buf);
250
						// can be one of %d, %d//%d, %d/%d, %d/%d/%d 
251
						if(sscanf(buf, "%d/%d/%d", &v, &t, &n) == 3)
252
							{ // v/t/n
253
 
254
								f_geo[0]=get_vert(v); 
255
								f_texcoords[0]=get_texcoord(t);
256
								f_normals[0]=get_normal(n);
257
 
258
								fscanf(fp, "%d/%d/%d", &v, &t, &n); 
259
								f_geo[1]=get_vert(v); 
260
								f_texcoords[1]=get_texcoord(t);
261
								f_normals[1]=get_normal(n);
262
 
263
								fscanf(fp, "%d/%d/%d", &v, &t, &n); 
264
								f_geo[2]=get_vert(v); 
265
								f_texcoords[2]=get_texcoord(t);
266
								f_normals[2]=get_normal(n);
267
 
268
								int idx = mesh->geometry.add_face(f_geo);
269
								mesh->normals.add_face(f_normals, idx);
270
								mesh->texcoords.add_face(f_texcoords, idx);
271
								mesh->mat_idx.push_back(current_material);
272
 
273
								// Load a general polygon and convert to triangles
274
								while(fscanf(fp, "%d/%d/%d", &v, &t, &n)==3) 
275
									{
276
										f_geo[1]=f_geo[2];
277
										f_normals[1]=f_normals[2];
278
										f_texcoords[1]=f_texcoords[2];
279
 
280
										f_geo[2]=get_vert(v);
281
										f_normals[2]=get_normal(n);
282
										f_texcoords[2]=get_texcoord(t);
283
 
284
										int idx = mesh->geometry.add_face(f_geo);
285
										mesh->normals.add_face(f_normals, idx);
286
										mesh->texcoords.add_face(f_texcoords, idx);
287
										mesh->mat_idx.push_back(current_material);
288
									}
289
							} 
290
						else if (sscanf(buf, "%d//%d", &v, &n)==2)
291
							{// v//n 
292
								f_geo[0]=get_vert(v);
293
								f_normals[0]=get_normal(n);
294
 
295
								fscanf(fp, "%d//%d", &v, &n); 
296
								f_geo[1]=get_vert(v);
297
								f_normals[1]=get_normal(n);
298
 
299
								fscanf(fp, "%d//%d", &v, &n); 
300
								f_geo[2]=get_vert(v);
301
								f_normals[2]=get_normal(n);
302
 
303
								int idx = mesh->geometry.add_face(f_geo);
304
								mesh->normals.add_face(f_normals, idx);
305
								mesh->mat_idx.push_back(current_material);
306
 
307
								// Load a general polygon and convert to triangles
308
								while(fscanf(fp, "%d//%d", &v, &n)==2) 
309
									{
310
										f_geo[1]=f_geo[2];
311
										f_normals[1]=f_normals[2];
312
										f_geo[2]=get_vert(v);
313
										int idx = mesh->geometry.add_face(f_geo);
314
										mesh->normals.add_face(f_normals, idx);
315
										mesh->mat_idx.push_back(current_material);
316
									}
317
							} 
318
						else if (sscanf(buf, "%d/%d", &v, &t) == 2)
319
							{ // v/t 
320
								f_geo[0]=get_vert(v);
321
								f_texcoords[0]=get_texcoord(t);
322
 
323
								fscanf(fp, "%d/%d", &v, &t); 
324
								f_geo[1]=get_vert(v);
325
								f_texcoords[1]=get_texcoord(t);
326
 
327
								fscanf(fp, "%d/%d", &v, &t); 
328
								f_geo[2]=get_vert(v);
329
								f_texcoords[2]=get_texcoord(t);
330
 
331
								int idx = mesh->geometry.add_face(f_geo);
332
								mesh->texcoords.add_face(f_texcoords, idx);
333
								mesh->mat_idx.push_back(current_material);
334
 
335
								// Load a general polygon and convert to triangles
336
								while(fscanf(fp, "%d/%d", &v, &t)==2) 
337
									{
338
										f_geo[1]=f_geo[2];
339
										f_texcoords[1]=f_texcoords[2];
340
 
341
										f_geo[2]=get_vert(v);
342
										f_texcoords[2]=get_texcoord(t);
343
 
344
										int idx = mesh->geometry.add_face(f_geo);
345
										mesh->texcoords.add_face(f_texcoords, idx);
346
										mesh->mat_idx.push_back(current_material);
347
									}
348
							} 
349
						else if (sscanf(buf, "%d", &v)==1)
350
							{ // v 
351
								f_geo[0]=get_vert(v);
352
 
353
								fscanf(fp, "%d", &v);
354
								f_geo[1]=get_vert(v);
355
 
356
								fscanf(fp, "%d", &v);
357
								f_geo[2]=get_vert(v);
358
 
359
								mesh->geometry.add_face(f_geo);
360
								mesh->mat_idx.push_back(current_material);
361
 
362
								// Load a general polygon and convert to triangles
363
								while(fscanf(fp, "%d", &v)==1) 
364
									{
365
										f_geo[1]=f_geo[2];
366
										f_geo[2]=get_vert(v);
367
										mesh->geometry.add_face(f_geo);
368
										mesh->mat_idx.push_back(current_material);
369
									}
370
							}
371
						break;
372
					default:
373
						fgets(buf, sizeof(buf), fp);
374
						break;
375
					}
376
			}
436 jrf 377
    fclose(fp);
79 jab 378
	}
379
 
380
 
381
	void obj_load(const string& filename, TriMesh &mesh)
382
	{
383
		TriMeshObjLoader loader(&mesh);
384
		loader.load(filename);
385
	}
386
 
387
}