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
00035 #include "physics-loader.h"
00036
00037 #include <fstream>
00038
00039 #include "common/wave_ex.h"
00040 #include "datahash/datahash_util.h"
00041 #include "datahash/datahash_text.h"
00042 #include "hfield/heightfield.h"
00043 #include "perf/perf.h"
00044 #include "threadsafe/smart_mutex.h"
00045 #include "trimesh/trimesh.h"
00046 #include "util/file.h"
00047 #include "util/parsing.h"
00048 #include "util/token_stream.h"
00049
00050
00051 namespace aesop {
00052
00054
00057 static const char * s_name = "Physics Meta Loader";
00058
00059
00060
00061
00062 struct shape_context_t {
00063 smart_ptr<hfield::Heightfield> hfield;
00064 smart_ptr<trimesh::Trimesh> trimesh;
00065 };
00066
00067
00068
00070
00071
00072
00074
00075 class PhysicsMeta : public ComponentData {
00076 public:
00077 ~PhysicsMeta(void) throw() {
00078 if (m_meta.shape) {
00079 shape_context_t * ctx =
00080 (shape_context_t *) m_meta.shape->getContext();
00081 if (ctx) {
00082 delete ctx;
00083 }
00084 }
00085 }
00086
00087
00088 void dump(IN const char * txt) const throw() {
00089 DPRINTF("%s: PhysicsMeta", txt);
00090 m_meta.dump(txt);
00091 }
00092
00093
00094 physics_meta_t m_meta;
00095
00096 private:
00097 };
00098
00099
00100
00102
00103
00104
00106
00107 static int
00108 checkFlag
00109 (
00110 IN const char * modelFlags,
00111 IN const char * name,
00112 IN int value
00113 )
00114 {
00115 ASSERT(modelFlags, "null");
00116 ASSERT(name, "null");
00117 ASSERT(value, "null");
00118
00119
00120
00121 if (strstr(modelFlags, name))
00122 return value;
00123 return 0;
00124 }
00125
00126
00127 #define TEST_FLAG(key, flag) \
00128 flags |= checkFlag(textFlags, key , PhysicsObject::eFlag_ ##flag );
00129
00130
00131 static void
00132 updateFlagsFromData
00133 (
00134 IO int& flags,
00135 IN const Datahash * data
00136 )
00137 {
00138 if (!data)
00139 return;
00140
00141 const char * textFlags = getOptionalString(data, "flags", "");
00142
00143 TEST_FLAG("ghost", Ghost);
00144 TEST_FLAG("events", Events);
00145 TEST_FLAG("moveable", Moveable);
00146 }
00147
00148
00149
00150 static smart_ptr<PhysicsMeta>
00151 loadShape
00152 (
00153 IN const Datahash * physicsData,
00154 IN const Datahash * typeData,
00155 IN const Datahash * instData,
00156 IN const char * parentDir
00157 )
00158 {
00159 ASSERT(physicsData, "null");
00160 ASSERT(typeData, "null");
00161
00162 ASSERT(parentDir, "null");
00163
00164
00165 smart_ptr<nstream::Manager> mgr =
00166 nstream::getFilesystemManager(parentDir);
00167 ASSERT_THROW(mgr, "failed to create fileystem manager");
00168
00169
00170 smart_ptr<PhysicsMeta> pm = new PhysicsMeta;
00171 ASSERT(pm, "out of memory");
00172 physics_meta_t& meta = pm->m_meta;
00173 meta.clear();
00174
00175
00176
00177 meta.mass = 0.0;
00178 const char * val = getKeyWithOverrides("mass", instData, typeData,
00179 physicsData, eDatahash_Optional);
00180 if (val) {
00181 meta.mass = atof(val);
00182 }
00183
00184
00185 updateFlagsFromData(meta.objectFlags, physicsData);
00186 updateFlagsFromData(meta.objectFlags, typeData);
00187 updateFlagsFromData(meta.objectFlags, instData);
00188
00189
00190 const char * shape = getString(physicsData, "shape");
00191
00192
00193
00194
00195
00196
00197
00198 if (!strcmp("box", shape)) {
00199 const char * val = getKeyWithOverrides("dimensions",
00200 instData, typeData, physicsData, eDatahash_Required);
00201 point3d_t p;
00202 parsePoint3d(val, p);
00203 p.dump("box dimensions");
00204
00205 meta.shape = createBoxShape(p);
00206
00207 } else if (!strcmp("capsule", shape)) {
00208
00209 float height = atof(getKeyWithOverrides("height",
00210 instData, typeData, physicsData, eDatahash_Required));
00211 float radius = atof(getKeyWithOverrides("radius",
00212 instData, typeData, physicsData, eDatahash_Required));
00213 meta.shape = createCapsuleShape(height, radius);
00214
00215 } else if (!strcmp("trimesh", shape)) {
00216
00217 const char * tfile = getKeyWithOverrides("trimesh",
00218 instData, typeData, physicsData, eDatahash_Required);
00219 std::string path = parentDir;
00220 path += "/";
00221 path += tfile;
00222
00223 DPRINTF("Creating triangle mesh physics model from path: %s",
00224 path.c_str());
00225
00226 smart_ptr<trimesh::Trimesh> trimesh =
00227 trimesh::Trimesh::load(path.c_str());
00228 ASSERT(trimesh, "failed to load trimesh");
00229 trimesh->dump(path.c_str());
00230
00231 meta.shape = createTrimeshShape(trimesh);
00232 ASSERT(meta.shape, "failed to create trimesh shape");
00233
00234
00235 shape_context_t * ctx = new shape_context_t;
00236 ASSERT(ctx, "out of memory");
00237 ctx->trimesh = trimesh;
00238 meta.shape->setContext(ctx);
00239
00240 } else if (!strcmp("hfield", shape)) {
00241
00242 const char * hfile = getKeyWithOverrides("hfield",
00243 instData, typeData, physicsData, eDatahash_Required);
00244
00245 DPRINTF("Creating heightfield physics model from path: %s",
00246 hfile);
00247
00248 smart_ptr<nstream::Stream> stream =
00249 nstream::openNamedStream(mgr, hfile);
00250 ASSERT(stream, "null");
00251
00252 smart_ptr<hfield::Heightfield> hfield =
00253 hfield::Heightfield::create(stream);
00254 ASSERT(hfield, "failed to load heightfield from %s", hfile);
00255 hfield->dump("Loading for physics shape");
00256
00257 float y = hfield->getHeight(5, 0.5);
00258 DPRINTF("Height at x=5, z=0.5: %f", y);
00259
00260 meta.shape = createHeightfieldShape(hfield);
00261 ASSERT(meta.shape, "failed to create heightfield shape");
00262
00263
00264 shape_context_t * ctx = new shape_context_t;
00265 ASSERT(ctx, "out of memory");
00266 ctx->hfield = hfield;
00267 meta.shape->setContext(ctx);
00268 } else {
00269 WAVE_EX(wex);
00270 wex << "Unknown physics shape: " << shape;
00271 }
00272
00273
00274 ASSERT(meta.shape, "null");
00275 return pm;
00276 }
00277
00278
00279
00281
00282
00283
00285
00286 class PhysicsRegistry : public TypeComponentLoader {
00287 public:
00288
00289 PhysicsRegistry(void) throw() { }
00290 ~PhysicsRegistry(void) throw() { }
00291
00292
00293 void initialize(void) throw() { }
00294 bool getPhysicsMetaTS(IN smart_ptr<Instance>& instance,
00295 OUT physics_meta_t& meta);
00296
00297
00298 const char * getComponentName(void) const throw() { return "physics"; }
00299 const char * getLoaderName(void) const throw() { return s_name; }
00300 bool isMyFormat(IN const Datahash * data,
00301 IN const char * path) const;
00302 smart_ptr<ComponentData> loadTS(IN smart_ptr<Instance>& instance,
00303 IN const Datahash * data,
00304 IN const char * path);
00305
00306 private:
00307
00308 typedef std::map<std::string, smart_ptr<Datahash> > data_map_t;
00309
00310
00311
00312
00313 smart_mutex m_mutex;
00314 data_map_t m_dataMap;
00315 };
00316
00317 static smart_ptr<PhysicsRegistry> s_registry;
00318
00319
00320
00321 bool
00322 PhysicsRegistry::isMyFormat
00323 (
00324 IN const Datahash * data,
00325 IN const char * path
00326 )
00327 const
00328 {
00329 ASSERT(data, "null");
00330 ASSERT(path, "null");
00331
00332 DPRINTF("Checking '%s'", path);
00333
00334 const char * physicsId = getString(data, "id");
00335
00336
00337 if (strcmp("physics", GetExtension(physicsId))) {
00338 DPRINTF("Extension does not match!");
00339 return false;
00340 }
00341
00342 std::ifstream stream(path);
00343 if (!stream.good()) {
00344 WAVE_EX(wex);
00345 wex << "Failed to open file for reading: " << path;
00346 }
00347
00348 std::string token;
00349 getNextToken(stream, token);
00350 DPRINTF(" token: %s", token.c_str());
00351 if ("physicsFormat" != token)
00352 return false;
00353
00354 getNextToken(stream, token);
00355 DPRINTF(" token: %s", token.c_str());
00356 if ("physics-shape-0.1" != token)
00357 return false;
00358
00359
00360 return true;
00361 }
00362
00363
00364
00365 smart_ptr<ComponentData>
00366 PhysicsRegistry::loadTS
00367 (
00368 IN smart_ptr<Instance>& instance,
00369 IN const Datahash * typeData,
00370 IN const char * path
00371 )
00372 {
00373 ASSERT(instance, "null");
00374 ASSERT(typeData, "null");
00375 ASSERT(path, "null");
00376
00377 DPRINTF("PHYSICS MODEL LOAD");
00378 const char * physicsId = getString(typeData, "id");
00379 DPRINTF("Asked to load physics component data for type: %s",
00380 instance->getTypeId());
00381 DPRINTF(" Uses physics model: %s", physicsId);
00382
00383
00384 smart_ptr<Datahash> physicsData;
00385 {
00386
00387 mlock l(m_mutex);
00388 data_map_t::iterator i = m_dataMap.find(path);
00389 if (m_dataMap.end() != i) {
00390 DPRINTF(" Already loaded physics data from disk!");
00391 physicsData = i->second;
00392 }
00393 }
00394
00395 if (!physicsData) {
00396 DPRINTF("Loading physics meta '%s' from file '%s'",
00397 physicsId, path);
00398 physicsData = readHashFromTextFile(path);
00399
00400
00401 {
00402 mlock l(m_mutex);
00403 m_dataMap[path] = physicsData;
00404 }
00405 }
00406 ASSERT(physicsData, "null");
00407
00408
00409 std::string parentDir;
00410 GetParentDirectory(path, parentDir);
00411
00412
00413 smart_ptr<Datahash> instData = instance->getInstanceData("physics");
00414
00415
00416
00417 smart_ptr<PhysicsMeta> pm;
00418 try {
00419 pm = loadShape(physicsData, typeData, instData,
00420 parentDir.c_str());
00421 ASSERT(pm, "null");
00422
00423 } catch (std::exception& e) {
00424 DPRINTF("Error loading physics shape from file: %s", path);
00425 DPRINTF("Exception: %s", e.what());
00426
00427
00428 ASSERT(false, "Failed to load model!");
00429 }
00430 ASSERT(pm->m_meta.shape, "null");
00431 return pm;
00432 }
00433
00434
00435
00437
00438
00439
00441
00442
00443
00445
00446
00447
00449
00450 smart_ptr<TypeComponentLoader>
00451 getPhysicsLoader
00452 (
00453 void
00454 )
00455 {
00456 if (!s_registry) {
00457 s_registry = new PhysicsRegistry;
00458 ASSERT(s_registry, "null");
00459 s_registry->initialize();
00460 }
00461
00462 return s_registry;
00463 }
00464
00465
00466
00467 bool
00468 getPhysicsMetaFromInstance
00469 (
00470 IN smart_ptr<Instance>& instance,
00471 OUT physics_meta_t& meta
00472 )
00473 {
00474 ASSERT(instance, "null");
00475 meta.clear();
00476
00477 DPRINTF("getPhysicsMetaFromInstance");
00478
00479 smart_ptr<ComponentData> data = instance->getComponentData("physics");
00480 if (!data) {
00481 DPRINTF("No physics data for instance?");
00482 return false;
00483 }
00484
00485 smart_ptr<PhysicsMeta> pm = data;
00486 ASSERT(pm, "failed to upcast?");
00487
00488 meta = pm->m_meta;
00489 return true;
00490 }
00491
00492
00493
00494 };
00495