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