00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "glut-model.h"
00035
00036 #include <fstream>
00037
00038 #include "common/wave_ex.h"
00039 #include "nstream/nstream.h"
00040 #include "perf/perf.h"
00041 #include "util/file.h"
00042 #include "util/parsing.h"
00043 #include "util/token_stream.h"
00044 #include "wave-glut/wave-glut.h"
00045 #include "wave-glut/texture.h"
00046
00047
00048 namespace glut {
00049
00050
00051
00052 MaterialRegistry::~MaterialRegistry(void) throw() { }
00053
00054
00055
00056
00057
00058
00059
00060
00061 static void
00062 getDictionaryFromNextLine
00063 (
00064 IO std::istream& stream,
00065 IN const char * debug_info,
00066 OUT dictionary_t& d
00067 )
00068 {
00069 ASSERT(stream.good(), "bad?");
00070 ASSERT(debug_info, "null");
00071 d.clear();
00072
00073 eParseBehavior behavior = (eParseBehavior)
00074 (eParse_StripComments | eParse_StripBogus);
00075
00076 std::string line = getNextLineFromStream(stream, behavior);
00077 getDictionaryFromString(line.c_str(), debug_info, d);
00078 }
00079
00080
00081
00082 static byte_t
00083 getOptionalByte
00084 (
00085 IN const dictionary_t& d,
00086 IN const char * key
00087 )
00088 {
00089 int i = atoi(getOptionalValue(d, key, "0"));
00090 if (i < 0 || i > 255) {
00091 WAVE_EX(wex);
00092 wex << "Bad byte value (" << key << " = " << i << ")";
00093 }
00094 return (byte_t) i;
00095 }
00096
00097
00098
00099 static void
00100 writePoint3dToStream
00101 (
00102 IO std::ostream& stream,
00103 IN const point3d_t& p
00104 )
00105 {
00106 ASSERT(stream.good(), "bad?");
00107 stream << "x " << p.x << " y " << p.y << " z " << p.z;
00108 }
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153 void
00154 parseColor
00155 (
00156 IO std::istream& stream,
00157 OUT img_color_t& color
00158 )
00159 {
00160 ASSERT(stream.good(), "bad?");
00161 color.clear();
00162
00163 dictionary_t d;
00164 getDictionaryFromNextLine(stream, "polygon color", d);
00165
00166 color.red = getOptionalByte(d, "r");
00167 color.green = getOptionalByte(d, "g");
00168 color.blue = getOptionalByte(d, "b");
00169 color.alpha = getOptionalByte(d, "a");
00170 }
00171
00172
00173
00174 void
00175 parseMaterial
00176 (
00177 IO std::istream& stream,
00178 IN const char * parentDir,
00179 OUT material_t& material
00180 )
00181 {
00182 perf::Timer timer("parseMaterial");
00183 ASSERT(stream.good(), "bad?");
00184 ASSERT(parentDir, "null");
00185 material.clear();
00186
00187 expectToken(stream, "{");
00188
00189 std::string token;
00190 for (;;) {
00191 getNextToken(stream, token);
00192 if ("}" == token) {
00193 break;
00194 } else if ("isTransparent" == token) {
00195 getNextToken(stream, token);
00196 if ("1" == token ||
00197 !strcasecmp("true", token.c_str()) ||
00198 !strcasecmp("t", token.c_str())) {
00199
00200 material.isTransparent = true;
00201 }
00202 } else if ("texture" == token) {
00203 getNextToken(stream, token);
00204
00205
00206 smart_ptr<nstream::Manager> mgr =
00207 nstream::getFilesystemManager(parentDir);
00208 ASSERT_THROW(mgr, "failed to create filesystem mgr: "
00209 << parentDir);
00210 media::image_t image;
00211 ASSERT_THROW(
00212 media::loadImage(mgr, token.c_str(), image),
00213 "Failed to load image: " << token);
00214
00215 material.texture_id = createTextureFromImage(image);
00216 } else {
00217 WAVE_EX(wex);
00218 wex << "Unknown keyword in texture file: " << token;
00219 }
00220 }
00221 }
00222
00223
00224
00225 void
00226 parsePolygon
00227 (
00228 IN MaterialRegistry * mreg,
00229 IO std::istream& stream,
00230 OUT polygon_t& polygon
00231 )
00232 {
00233 ASSERT(mreg, "null");
00234 ASSERT(stream.good(), "bad?");
00235 polygon.clear();
00236
00237
00238 expectToken(stream, "{");
00239 std::string token;
00240
00241
00242 expectToken(stream, "nVertices");
00243 polygon.nVertices = readInteger(stream, token);
00244 if (polygon.nVertices < 3) {
00245 WAVE_EX(wex);
00246 wex << "Too few vertices in polygon: " << polygon.nVertices;
00247 }
00248
00249
00250 polygon.indices = new int[polygon.nVertices];
00251 polygon.u = new float[polygon.nVertices];
00252 polygon.v = new float[polygon.nVertices];
00253 ASSERT(polygon.indices && polygon.u && polygon.v, "out of memory");
00254
00255
00256 expectToken(stream, "vertices");
00257 expectToken(stream, "{");
00258 for (int i = 0; i < polygon.nVertices; ++i) {
00259
00260 expectToken(stream, "pv");
00261
00262
00263 std::string line = getNextLineFromStream(stream, eParse_Strip);
00264 dictionary_t d;
00265 getDictionaryFromString(line.c_str(), "polygon vertex", d);
00266
00267
00268 polygon.indices[i] = atoi(getRequiredValue(d, "i"));
00269 polygon.u[i] = atof(getOptionalValue(d, "u", "0"));
00270 polygon.v[i] = atof(getOptionalValue(d, "v", "0"));
00271 }
00272 expectToken(stream, "}");
00273
00274
00275 expectToken(stream, "normal");
00276 parsePoint3d(stream, polygon.normal);
00277
00278
00279 expectToken(stream, "material");
00280 getNextToken(stream, token);
00281 DPRINTF("material = '%s'", token.c_str());
00282 polygon.material = mreg->getMaterial(token.c_str());
00283 if (!polygon.material) {
00284 WAVE_EX(wex);
00285 wex << "Failed to load material for polygon: " << token;
00286 }
00287
00288
00289 expectToken(stream, "}");
00290 }
00291
00292
00293
00294 void
00295 parseModel
00296 (
00297 IN MaterialRegistry * mreg,
00298 IO std::istream& stream,
00299 OUT model_t& model
00300 )
00301 {
00302 perf::Timer timer("parseModel");
00303 ASSERT(mreg, "null");
00304 ASSERT(stream.good(), "bad?");
00305 model.clear();
00306
00307
00308 expectToken(stream, "{");
00309 std::string token;
00310
00311
00312 expectToken(stream, "nVertices");
00313 model.nVertices = readInteger(stream, token);
00314 if (model.nVertices < 3) {
00315 WAVE_EX(wex);
00316 wex << "Too few vertices in model: " << model.nVertices;
00317 }
00318 model.vertices = new point3d_t[model.nVertices];
00319 ASSERT(model.vertices, "out of memory");
00320
00321
00322 expectToken(stream, "vertices");
00323 expectToken(stream, "{");
00324 for (int i = 0; i < model.nVertices; ++i) {
00325 expectToken(stream, "vertex");
00326 parsePoint3d(stream, model.vertices[i]);
00327 if (!i) {
00328 model.boundingBox.setToPoint(model.vertices[0]);
00329 } else {
00330 model.boundingBox.includePoint(model.vertices[i]);
00331 }
00332 }
00333 expectToken(stream, "}");
00334 model.boundingBox.dump("bounding box");
00335
00336
00337 expectToken(stream, "nPolygons");
00338 model.nPolygons = readInteger(stream, token);
00339 if (model.nPolygons < 1) {
00340 WAVE_EX(wex);
00341 wex << "Too few polygons in model: " << model.nPolygons;
00342 }
00343 model.polygons = new polygon_t[model.nPolygons];
00344 ASSERT(model.polygons, "out of memory");
00345
00346
00347 expectToken(stream, "polygons");
00348 expectToken(stream, "{");
00349 for (int i = 0; i < model.nPolygons; ++i) {
00350 expectToken(stream, "polygon");
00351 parsePolygon(mreg, stream, model.polygons[i]);
00352 }
00353 expectToken(stream, "}");
00354 }
00355
00356
00357
00358 void
00359 parseLodEntry
00360 (
00361 IN MaterialRegistry * mreg,
00362 IO std::istream& stream,
00363 OUT lod_entry_t& entry
00364 )
00365 {
00366 ASSERT(mreg, "null");
00367 ASSERT(stream.good(), "bad?");
00368 entry.clear();
00369
00370
00371 expectToken(stream, "{");
00372 std::string token;
00373
00374
00375 expectToken(stream, "distance");
00376 entry.distance = readFloat(stream, token);
00377 if (entry.distance <= 0.0) {
00378 WAVE_EX(wex);
00379 wex << "Bad level-of-detail distance: " << entry.distance;
00380 }
00381
00382
00383 expectToken(stream, "model");
00384 parseModel(mreg, stream, entry.model);
00385 }
00386
00387
00388
00389 void
00390 parseLodModel
00391 (
00392 IN MaterialRegistry * mreg,
00393 IO std::istream& stream,
00394 OUT lod_model_t& model
00395 )
00396 {
00397 perf::Timer timer("parseLodModel");
00398 ASSERT(mreg, "null");
00399 ASSERT(stream.good(), "bad?");
00400 model.clear();
00401
00402
00403 std::string token;
00404 expectToken(stream, "lodModel");
00405 expectToken(stream, "{");
00406
00407
00408 expectToken(stream, "nEntries");
00409 int nEntries = readInteger(stream, token);
00410 if (nEntries < 1) {
00411 WAVE_EX(wex);
00412 wex << "Bad count of lod entries: " << nEntries;
00413 }
00414 model.entries = new lod_entry_t[nEntries];
00415 ASSERT(model.entries, "out of memory");
00416
00417
00418 for (int i = 0; i < nEntries; ++i) {
00419 expectToken(stream, "lodEntry");
00420 parseLodEntry(mreg, stream, model.entries[i]);
00421
00422
00423 model_t& child = model.entries[i].model;
00424 if (!i) {
00425 model.boundingBox = child.getBoundingBox();
00426 } else {
00427 model.boundingBox.expand(child.getBoundingBox());
00428 }
00429 }
00430
00431
00432 model.nEntries = nEntries;
00433 }
00434
00435
00436
00437 void
00438 writeModelToStream
00439 (
00440 IO std::ostream& stream,
00441 IN const model_t& model
00442 )
00443 {
00444 perf::Timer timer("writeModelToStream");
00445 ASSERT(stream.good(), "bad?");
00446
00447
00448 stream << " {\n";
00449
00450
00451 stream << "nVertices " << model.nVertices << "\n";
00452
00453
00454 stream << "vertices {\n";
00455 for (int i = 0; i < model.nVertices; ++i) {
00456 stream << "\tvertex\t";
00457 writePoint3dToStream(stream, model.vertices[i]);
00458 stream << "\n";
00459 }
00460 stream << "}\n";
00461
00462
00463 stream << "nPolygons " << model.nPolygons << "\n";
00464
00465
00466 stream << "polygons {\n";
00467 for (int i = 0; i < model.nPolygons; ++i) {
00468 const polygon_t& poly = model.polygons[i];
00469
00470
00471 stream << "\tpolygon {\n";
00472
00473
00474 stream << "\t\tnVertices " << poly.nVertices << "\n";
00475
00476
00477 stream << "\t\tvertices {\n";
00478 for (int j = 0; j < poly.nVertices; ++j) {
00479 stream << "\t\t\tpv\t";
00480 stream << "i " << poly.indices[j] << "\t";
00481 stream << "u " << ((poly.u) ? poly.u[j] : 0.0) << "\t";
00482 stream << "v " << ((poly.v) ? poly.v[j] : 0.0) << "\n";
00483 }
00484 stream << "\t\t}\n";
00485
00486
00487 stream << "\t\tnormal\t";
00488 writePoint3dToStream(stream, poly.normal);
00489 stream << "\n";
00490
00491
00492 stream << "\t\tmaterial\t";
00493 stream << "BOGUS_ID";
00494 stream << "\n";
00495
00496
00497 stream << "\t}\n";
00498 }
00499 stream << "}\n";
00500
00501
00502 stream << "}\n";
00503 }
00504
00505
00506
00507 smart_ptr<Renderable>
00508 loadModel
00509 (
00510 IN const char * filename,
00511 IN MaterialRegistry * reg
00512 )
00513 {
00514 ASSERT(filename, "null");
00515 ASSERT(reg, "null");
00516
00517 std::ifstream infile(filename);
00518 if (!infile.good()) {
00519 WAVE_EX(wex);
00520 wex << "Failed to open wavepacket glut model file: ";
00521 wex << filename;
00522 }
00523
00524 smart_ptr<lod_model_t> r = new lod_model_t;
00525 ASSERT(r, "out of memory");
00526
00527 parseLodModel(reg, infile, *r);
00528
00529 return r;
00530 }
00531
00532
00533
00534 };
00535