Each module now includes its own header first. Removed sstream.h and the definition...
[crack-attack.git] / src / OBJModel.cxx
blobbae7edd123538f13cab78e37f45487a3d100c93d
1 /*
2 * Copyright (C) 2006 Bjørn Lindeijer
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 * $Id: OBJModel.cxx,v 1.2 2006/08/12 01:26:55 b_lindeijer Exp $
21 #include "OBJModel.h"
23 #include <GL/gl.h>
24 #include <iostream>
25 #include <list>
27 using namespace std;
29 static void stripNewline(char *str)
31 // Remove newline from the string (either \r,\n or \r\n)
32 int len = strlen(str);
33 if (str[len - 2] == '\r') str[len - 2] = '\0';
34 else str[len - 1] = '\0';
37 static string stripFilename(const string& path)
39 // Strip the filename portion from the given path
40 int pos = path.rfind("/");
41 return path.substr(0, pos + 1);
44 static GLuint loadImage(const string& filename)
46 if (true) {
47 cerr << "Error loading image " << filename << std::endl;
48 return 0;
49 } else {
50 GLuint tid;
52 glGenTextures(1, &tid);
53 glBindTexture(GL_TEXTURE_2D, tid);
54 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
55 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
56 return tid;
60 OBJModel::OBJModel(const string &filename)
62 load(filename);
65 OBJModel::~OBJModel()
67 // FIXME: Delete created materials
71 void OBJModel::render()
73 // TODO: Could be optimized by using vertex arrays
75 vector<Face>::iterator fi;
76 vector<FaceVertex>::iterator vi;
77 int v, vt, vn, vc;
78 Material *activeMaterial = 0;
80 // Draw all faces
81 for (fi = faces.begin(); fi != faces.end(); fi++) {
82 // Check if we need to set new material properties
83 if (fi->material && fi->material != activeMaterial) {
84 glMaterialf(GL_FRONT,GL_SHININESS,fi->material->shininess);
85 glMaterialfv(GL_FRONT,GL_AMBIENT,fi->material->ambient);
86 glMaterialfv(GL_FRONT,GL_DIFFUSE,fi->material->diffuse);
87 glMaterialfv(GL_FRONT,GL_SPECULAR,fi->material->specular);
88 if (fi->material->textureId > 0) {
89 glEnable(GL_TEXTURE_2D);
90 glBindTexture(GL_TEXTURE_2D, fi->material->textureId);
92 else {
93 glDisable(GL_TEXTURE_2D);
95 activeMaterial = fi->material;
97 glBegin(GL_POLYGON);
98 for (vi = fi->vertices.begin(); vi != fi->vertices.end(); vi++) {
99 v = vi->v - 1;
100 vt = vi->vt - 1;
101 vn = vi->vn - 1;
102 vc = vi->vc - 1;
104 if (vt >= 0) {
105 glTexCoord3f(
106 vertexTextures[vt].u,
107 vertexTextures[vt].v,
108 vertexTextures[vt].w);
110 if (vc >= 0) {
111 glColor3f(
112 vertexColors[vc].r,
113 vertexColors[vc].g,
114 vertexColors[vc].b);
117 glNormal3f(
118 vertexNormals[vn].i,
119 vertexNormals[vn].j,
120 vertexNormals[vn].k);
122 glVertex4f(
123 vertices[v].x,
124 vertices[v].y,
125 vertices[v].z,
126 vertices[v].w);
128 glEnd();
131 //SGNode::render();
135 void OBJModel::load(const string &filename)
137 vertices.clear();
138 vertexTextures.clear();
139 vertexNormals.clear();
140 vertexColors.clear();
141 faces.clear();
143 FILE* file = fopen(filename.c_str(), "r");
144 char str[256];
146 if (!file) {
147 cerr << "Error while opening " << filename << "!\n";
148 return;
151 // By default no material is used
152 Material *activeMaterial = 0;
154 while (!feof(file)) {
155 str[0] = '\0';
156 fgets(str, 256, file);
158 switch (str[0]) {
159 case 'v':
160 switch (str[1]) {
161 case ' ': // Plain vertex ("v x y z w")
163 Vertex v;
164 sscanf(str, "v %f %f %f %f",
165 &(v.x), &(v.y), &(v.z), &(v.w));
166 vertices.push_back(v);
167 //cout << "vt " << (v.x * 0.5) << " " << (v.y * 0.5) << " " << (v.z * 0.5) << endl;
169 break;
170 case 't': // Texture vertex ("vt u v w")
172 VertexTexture vt;
173 sscanf(str, "vt %f %f %f", &(vt.u), &(vt.v), &(vt.w));
174 vertexTextures.push_back(vt);
176 break;
177 case 'n': // Vertex Normal ("vn i j k")
179 VertexNormal vn;
180 sscanf(str, "vn %f %f %f", &(vn.i), &(vn.j), &(vn.k));
181 vertexNormals.push_back(vn);
183 break;
184 case 'c': // Vertex Color ("vc r g b a") - not standard OBJ
186 VertexColor vc;
187 sscanf(str, "vc %f %f %f %f",
188 &(vc.r), &(vc.g), &(vc.b), &(vc.a));
189 vertexColors.push_back(vc);
191 break;
192 default: break;
194 break;
195 case 'f': // Face ("f v/vt/vn v/vt/vn v/vt/vn")
197 char* vstr;
198 char texlessfaces;
199 Face f;
200 f.material = activeMaterial;
202 vstr = strtok(&str[2], " "); // skip "f "
203 for (; vstr; vstr = strtok(NULL," ")) {
204 FaceVertex fv;
206 // Check if a//c or a/b/c
207 sscanf(vstr,"%*d%*c%c", &texlessfaces);
208 if (texlessfaces != '/') {
209 sscanf(vstr, "%d/%d/%d", &(fv.v), &(fv.vt), &(fv.vn));
210 } else {
211 sscanf(vstr, "%d//%d", &(fv.v), &(fv.vn));
214 f.vertices.push_back(fv);
217 // Add the face to the object if there are at least 3 vertices
218 if (f.vertices.size() >= 3) {
219 faces.push_back(f);
220 //cout << "f";
221 //vector<FaceVertex>::iterator vi;
222 //for (vi = f.vertices.begin(); vi != f.vertices.end(); vi++) {
223 // cout << " " << vi->v << "/" << vi->v << "/" << vi->vn;
225 //cout << endl;
228 break;
229 case 'o': // Object name ("o name")
231 stripNewline(str);
232 name = string(&str[2]);
234 break;
235 case 'u': // ("usemtl name")
236 if (strncmp(str, "usemtl ", 7) == 0) {
237 stripNewline(str);
238 string matName = string(&str[7]);
239 if (materials.count(matName) > 0) {
240 activeMaterial = materials[matName];
243 break;
244 case 'm': // ("mtllib file1 file2 ...")
245 if (strncmp(str, "mtllib ", 7) == 0) {
246 // Read material libraries
247 string path = stripFilename(filename);
248 char* vstr;
250 vstr = strtok(&str[7], " \r\n"); // skip "mtllib "
251 for (; vstr; vstr = strtok(NULL," \r\n")) {
252 loadMTL(path + string(vstr));
255 break;
256 case 's': // ("shadow_obj file")
257 if (strncmp(str, "shadow_obj ", 11) == 0) {
258 stripNewline(str);
259 shadowObj = string(&str[11]);
261 break;
262 default:
263 // Nothing recognized, ignore.
264 break;
268 cout << "Loaded model " << name << " (" << faces.size() << " faces)\n";
272 void OBJModel::loadMTL(const string &filename)
274 FILE* file = fopen(filename.c_str(), "r");
275 if (!file) {
276 cerr << "Error while opening " << filename << "!\n";
277 return;
280 char str[256];
281 Material* mat = 0;
283 while (!feof(file)) {
284 str[0] = '\0';
285 fgets(str, 256, file);
287 switch (str[0]) {
288 case 'n': // ("newmtl name")
289 if (strncmp(str, "newmtl ", 7) == 0) {
290 // TODO: Check if same name already exists
291 stripNewline(str);
292 string matName = string(&str[7]);
293 if (materials.count(matName) == 0) {
294 mat = new Material();
295 mat->name = matName;
296 materials[matName] = mat;
297 } else {
298 mat = materials[matName];
303 if (!mat) continue;
305 switch (str[0]) {
306 case 'K':
307 switch (str[1]) {
308 case 'a': // ("Ka r g b")
309 // Ambient
310 sscanf(str, "Ka %f %f %f",
311 &mat->ambient[0], &mat->ambient[1], &mat->ambient[2]);
312 break;
313 case 'd': // ("Kd r g b")
314 // Diffuse
315 sscanf(str, "Kd %f %f %f",
316 &mat->diffuse[0], &mat->diffuse[1], &mat->diffuse[2]);
317 break;
318 case 's': // ("Ks r g b")
319 // Specular
320 sscanf(str, "Ks %f %f %f",
321 &mat->specular[0],&mat->specular[1],&mat->specular[2]);
322 break;
323 default: break;
325 case 'i': // ("illum i")
326 // Illumination model (0, 1 or 2)
327 if (strncmp(str, "illum ", 6)) {
328 sscanf(str, "illum %d", &mat->illuminationModel);
330 else if (strncmp(str, "d ", 2)) {
331 sscanf(str, "d %d", &mat->illuminationModel);
333 break;
334 case 'T':
335 if (str[1] == 'r') {
336 // ("Tr transparency")
337 sscanf(str, "Tr %f", &mat->transparency);
339 mat->ambient[3] = mat->transparency;
340 mat->specular[3] = mat->transparency;
341 mat->diffuse[3] = mat->transparency;
342 break;
343 case 'd': // ("d transparency")
344 sscanf(str, "d %f", &mat->transparency);
345 mat->ambient[3] = mat->transparency;
346 mat->specular[3] = mat->transparency;
347 mat->diffuse[3] = mat->transparency;
348 break;
349 case 'N':
350 if (str[1] == 's') {
351 // ("Ns shininess")
352 sscanf(str, "Ns %f", &mat->shininess);
354 break;
355 case 'm':
356 if (strncmp(str, "map_K", 5) == 0) {
357 switch (str[5]) {
358 case 'd': // ("map_Kd filename") - Diffuse map
360 stripNewline(&str[7]);
361 string imageFile =
362 stripFilename(filename) + string(&str[7]);
363 mat->textureId = loadImage(imageFile);
364 break;
366 case 'a': // ("map_Ka filename") - Ambient map
367 break;
368 case 's': // ("map_Ks filename") - Specular map
369 break;
372 else if (strncmp(str, "map_Bump ", 9) == 0) {
373 // ("map_Bump filename") - Bump map
375 else if (strncmp(str, "map_d ", 6) == 0) {
376 // ("map_d filename") - Opacity map
378 break;
379 default:
380 // Nothing recognized, ignore.
381 break;