Fixes for datatype size on amd64.
[crack-attack.git] / src / OBJModel.cxx
blobafbf60a65cefe1664671682b20469aad797e0430
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.3 2006/08/12 21:36:09 b_lindeijer Exp $
21 #include "OBJModel.h"
23 #include "TextureLoader.h"
25 #include <GL/gl.h>
26 #include <iostream>
27 #include <list>
29 using namespace std;
31 static void stripNewline(char *str)
33 // Remove newline from the string (either \r,\n or \r\n)
34 int len = strlen(str);
35 if (str[len - 2] == '\r') str[len - 2] = '\0';
36 else str[len - 1] = '\0';
39 static string stripFilename(const string& path)
41 // Strip the filename portion from the given path
42 int pos = path.rfind("/");
43 return path.substr(0, pos + 1);
46 static GLuint loadImage(const string& filename)
48 // TODO: Support other sizes than just 128x128
49 GLubyte *imgData = TextureLoader::loadImage(filename.c_str(), 128, 128);
51 if (!imgData) {
52 cerr << "Error loading image " << filename << std::endl;
53 return 0;
56 GLuint tid;
58 glGenTextures(1, &tid);
59 glBindTexture(GL_TEXTURE_2D, tid);
60 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
61 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
62 glTexImage2D(
63 GL_TEXTURE_2D, 0, 3, 128, 128,
64 0, GL_RGBA, GL_UNSIGNED_BYTE, imgData);
66 delete[] imgData;
68 return tid;
71 OBJModel::OBJModel(const string &filename)
73 load(filename);
76 OBJModel::~OBJModel()
78 // FIXME: Delete created materials
82 void OBJModel::render()
84 // TODO: Could be optimized by using vertex arrays
86 vector<Face>::iterator fi;
87 vector<FaceVertex>::iterator vi;
88 int v, vt, vn, vc;
89 Material *activeMaterial = 0;
91 // Draw all faces
92 for (fi = faces.begin(); fi != faces.end(); fi++) {
93 // Check if we need to set new material properties
94 if (fi->material && fi->material != activeMaterial) {
95 glMaterialf(GL_FRONT,GL_SHININESS,fi->material->shininess);
96 glMaterialfv(GL_FRONT,GL_AMBIENT,fi->material->ambient);
97 glMaterialfv(GL_FRONT,GL_DIFFUSE,fi->material->diffuse);
98 glMaterialfv(GL_FRONT,GL_SPECULAR,fi->material->specular);
99 if (fi->material->textureId > 0) {
100 glEnable(GL_TEXTURE_2D);
101 glBindTexture(GL_TEXTURE_2D, fi->material->textureId);
103 else {
104 glDisable(GL_TEXTURE_2D);
106 activeMaterial = fi->material;
108 glBegin(GL_POLYGON);
109 for (vi = fi->vertices.begin(); vi != fi->vertices.end(); vi++) {
110 v = vi->v - 1;
111 vt = vi->vt - 1;
112 vn = vi->vn - 1;
113 vc = vi->vc - 1;
115 if (vt >= 0) {
116 glTexCoord3f(
117 vertexTextures[vt].u,
118 vertexTextures[vt].v,
119 vertexTextures[vt].w);
121 if (vc >= 0) {
122 glColor3f(
123 vertexColors[vc].r,
124 vertexColors[vc].g,
125 vertexColors[vc].b);
128 glNormal3f(
129 vertexNormals[vn].i,
130 vertexNormals[vn].j,
131 vertexNormals[vn].k);
133 glVertex4f(
134 vertices[v].x,
135 vertices[v].y,
136 vertices[v].z,
137 vertices[v].w);
139 glEnd();
142 //SGNode::render();
146 void OBJModel::load(const string &filename)
148 vertices.clear();
149 vertexTextures.clear();
150 vertexNormals.clear();
151 vertexColors.clear();
152 faces.clear();
154 FILE* file = fopen(filename.c_str(), "r");
155 char str[256];
157 if (!file) {
158 cerr << "Error while opening " << filename << "!\n";
159 return;
162 // By default no material is used
163 Material *activeMaterial = 0;
165 while (!feof(file)) {
166 str[0] = '\0';
167 fgets(str, 256, file);
169 switch (str[0]) {
170 case 'v':
171 switch (str[1]) {
172 case ' ': // Plain vertex ("v x y z w")
174 Vertex v;
175 sscanf(str, "v %f %f %f %f",
176 &(v.x), &(v.y), &(v.z), &(v.w));
177 vertices.push_back(v);
178 //cout << "vt " << (v.x * 0.5) << " " << (v.y * 0.5) << " " << (v.z * 0.5) << endl;
180 break;
181 case 't': // Texture vertex ("vt u v w")
183 VertexTexture vt;
184 sscanf(str, "vt %f %f %f", &(vt.u), &(vt.v), &(vt.w));
185 vertexTextures.push_back(vt);
187 break;
188 case 'n': // Vertex Normal ("vn i j k")
190 VertexNormal vn;
191 sscanf(str, "vn %f %f %f", &(vn.i), &(vn.j), &(vn.k));
192 vertexNormals.push_back(vn);
194 break;
195 case 'c': // Vertex Color ("vc r g b a") - not standard OBJ
197 VertexColor vc;
198 sscanf(str, "vc %f %f %f %f",
199 &(vc.r), &(vc.g), &(vc.b), &(vc.a));
200 vertexColors.push_back(vc);
202 break;
203 default: break;
205 break;
206 case 'f': // Face ("f v/vt/vn v/vt/vn v/vt/vn")
208 char* vstr;
209 char texlessfaces;
210 Face f;
211 f.material = activeMaterial;
213 vstr = strtok(&str[2], " "); // skip "f "
214 for (; vstr; vstr = strtok(NULL," ")) {
215 FaceVertex fv;
217 // Check if a//c or a/b/c
218 sscanf(vstr,"%*d%*c%c", &texlessfaces);
219 if (texlessfaces != '/') {
220 sscanf(vstr, "%d/%d/%d", &(fv.v), &(fv.vt), &(fv.vn));
221 } else {
222 sscanf(vstr, "%d//%d", &(fv.v), &(fv.vn));
225 f.vertices.push_back(fv);
228 // Add the face to the object if there are at least 3 vertices
229 if (f.vertices.size() >= 3) {
230 faces.push_back(f);
231 //cout << "f";
232 //vector<FaceVertex>::iterator vi;
233 //for (vi = f.vertices.begin(); vi != f.vertices.end(); vi++) {
234 // cout << " " << vi->v << "/" << vi->v << "/" << vi->vn;
236 //cout << endl;
239 break;
240 case 'o': // Object name ("o name")
242 stripNewline(str);
243 name = string(&str[2]);
245 break;
246 case 'u': // ("usemtl name")
247 if (strncmp(str, "usemtl ", 7) == 0) {
248 stripNewline(str);
249 string matName = string(&str[7]);
250 if (materials.count(matName) > 0) {
251 activeMaterial = materials[matName];
254 break;
255 case 'm': // ("mtllib file1 file2 ...")
256 if (strncmp(str, "mtllib ", 7) == 0) {
257 // Read material libraries
258 string path = stripFilename(filename);
259 char* vstr;
261 vstr = strtok(&str[7], " \r\n"); // skip "mtllib "
262 for (; vstr; vstr = strtok(NULL," \r\n")) {
263 loadMTL(path + string(vstr));
266 break;
267 case 's': // ("shadow_obj file")
268 if (strncmp(str, "shadow_obj ", 11) == 0) {
269 stripNewline(str);
270 shadowObj = string(&str[11]);
272 break;
273 default:
274 // Nothing recognized, ignore.
275 break;
279 //cout << "Loaded model " << name << " (" << faces.size() << " faces)\n";
283 void OBJModel::loadMTL(const string &filename)
285 FILE* file = fopen(filename.c_str(), "r");
286 if (!file) {
287 cerr << "Error while opening " << filename << "!\n";
288 return;
291 char str[256];
292 Material* mat = 0;
294 while (!feof(file)) {
295 str[0] = '\0';
296 fgets(str, 256, file);
298 switch (str[0]) {
299 case 'n': // ("newmtl name")
300 if (strncmp(str, "newmtl ", 7) == 0) {
301 // TODO: Check if same name already exists
302 stripNewline(str);
303 string matName = string(&str[7]);
304 if (materials.count(matName) == 0) {
305 mat = new Material();
306 mat->name = matName;
307 materials[matName] = mat;
308 } else {
309 mat = materials[matName];
314 if (!mat) continue;
316 switch (str[0]) {
317 case 'K':
318 switch (str[1]) {
319 case 'a': // ("Ka r g b")
320 // Ambient
321 sscanf(str, "Ka %f %f %f",
322 &mat->ambient[0], &mat->ambient[1], &mat->ambient[2]);
323 break;
324 case 'd': // ("Kd r g b")
325 // Diffuse
326 sscanf(str, "Kd %f %f %f",
327 &mat->diffuse[0], &mat->diffuse[1], &mat->diffuse[2]);
328 break;
329 case 's': // ("Ks r g b")
330 // Specular
331 sscanf(str, "Ks %f %f %f",
332 &mat->specular[0],&mat->specular[1],&mat->specular[2]);
333 break;
334 default: break;
336 case 'i': // ("illum i")
337 // Illumination model (0, 1 or 2)
338 if (strncmp(str, "illum ", 6)) {
339 sscanf(str, "illum %d", &mat->illuminationModel);
341 else if (strncmp(str, "d ", 2)) {
342 sscanf(str, "d %d", &mat->illuminationModel);
344 break;
345 case 'T':
346 if (str[1] == 'r') {
347 // ("Tr transparency")
348 sscanf(str, "Tr %f", &mat->transparency);
350 mat->ambient[3] = mat->transparency;
351 mat->specular[3] = mat->transparency;
352 mat->diffuse[3] = mat->transparency;
353 break;
354 case 'd': // ("d transparency")
355 sscanf(str, "d %f", &mat->transparency);
356 mat->ambient[3] = mat->transparency;
357 mat->specular[3] = mat->transparency;
358 mat->diffuse[3] = mat->transparency;
359 break;
360 case 'N':
361 if (str[1] == 's') {
362 // ("Ns shininess")
363 sscanf(str, "Ns %f", &mat->shininess);
365 break;
366 case 'm':
367 if (strncmp(str, "map_K", 5) == 0) {
368 switch (str[5]) {
369 case 'd': // ("map_Kd filename") - Diffuse map
371 stripNewline(&str[7]);
372 string imageFile =
373 stripFilename(filename) + string(&str[7]);
374 mat->textureId = loadImage(imageFile);
375 break;
377 case 'a': // ("map_Ka filename") - Ambient map
378 break;
379 case 's': // ("map_Ks filename") - Specular map
380 break;
383 else if (strncmp(str, "map_Bump ", 9) == 0) {
384 // ("map_Bump filename") - Bump map
386 else if (strncmp(str, "map_d ", 6) == 0) {
387 // ("map_d filename") - Opacity map
389 break;
390 default:
391 // Nothing recognized, ignore.
392 break;