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 "bsp.h"
00036
00037 #include <iostream>
00038
00039 #include "geometry/plane.h"
00040 #include "perf/perf.h"
00041
00042
00043 namespace quake {
00044
00045
00046
00047
00048 struct direntry_t {
00049 int32_t offset;
00050 int32_t length;
00051 };
00052
00053
00054 typedef std::map<eLumpType, direntry_t> lump_entry_map_t;
00055
00056 #define DECLARE_LUMP_READER(type) \
00057 lump_object_t * readLump ## type (IO std::istream& in);
00058
00059
00060 typedef lump_object_t * (*lump_reader_t)(IO std::istream& in);
00061
00062
00063 struct lump_entry_t {
00064 eLumpType type;
00065 lump_reader_t reader;
00066 int obj_size;
00067 };
00068
00069 #define LUMP_READER_ENTRY( type , size ) \
00070 { eLump_ ## type , readLump ## type , size },
00071
00072
00073
00074 DECLARE_LUMP_READER(Entities);
00075 DECLARE_LUMP_READER(Faces);
00076 DECLARE_LUMP_READER(Leaffaces);
00077 DECLARE_LUMP_READER(Leafs);
00078 DECLARE_LUMP_READER(Meshverts);
00079 DECLARE_LUMP_READER(Nodes);
00080 DECLARE_LUMP_READER(Planes);
00081 DECLARE_LUMP_READER(Textures);
00082 DECLARE_LUMP_READER(Vertices);
00083
00084
00085
00086 static const lump_entry_t s_lumpMap[] = {
00087 LUMP_READER_ENTRY(Entities, -1)
00088 LUMP_READER_ENTRY(Faces, 14 * sizeof(int32_t) + 12 * sizeof(float))
00089 LUMP_READER_ENTRY(Leaffaces, sizeof(int32_t))
00090 LUMP_READER_ENTRY(Leafs, 12 * sizeof(int32_t))
00091 LUMP_READER_ENTRY(Meshverts, sizeof(int32_t))
00092 LUMP_READER_ENTRY(Nodes, 9 * sizeof(int32_t))
00093 LUMP_READER_ENTRY(Planes, 4 * sizeof(float))
00094 LUMP_READER_ENTRY(Textures, 64 + 2 * sizeof(int32_t))
00095 LUMP_READER_ENTRY(Vertices, 4 + 10 * sizeof(float))
00096
00097
00098 { eLump_Invalid, NULL, 0 }
00099 };
00100
00101
00102
00103
00104 Bsp::~Bsp(void) throw() { }
00105 lump_object_t::~lump_object_t(void) throw() { }
00106
00107 entity_t::~entity_t(void) throw() { }
00108 face_t::~face_t(void) throw() { }
00109 leaf_t::~leaf_t(void) throw() { }
00110 leafface_t::~leafface_t(void) throw() { }
00111 meshvert_t::~meshvert_t(void) throw() { }
00112 node_t::~node_t(void) throw() { }
00113 plane_t::~plane_t(void) throw() { }
00114 texture_path_t::~texture_path_t(void) throw() { }
00115 vertex_t::~vertex_t(void) throw() { }
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125 static const lump_entry_t *
00126 getLumpEntry
00127 (
00128 IN eLumpType type
00129 )
00130 throw()
00131 {
00132 for (const lump_entry_t * p = s_lumpMap; p->reader; ++p) {
00133 if (p->type == type)
00134 return p;
00135 }
00136
00137 DPRINTF("Could not find lump type in static map: %d", type);
00138 return NULL;
00139 }
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149 lump_object_t *
00150 readLumpEntities
00151 (
00152 IO std::istream& in
00153 )
00154 {
00155 ASSERT_THROW(in.good(), "bad input BSP stream");
00156
00157 static entity_t s_entity;
00158
00159 s_entity.dictionary.clear();
00160
00161
00162 char a;
00163 std::string key, value;
00164 in >> a;
00165 if (!a) {
00166
00167 return NULL;
00168 }
00169 ASSERT_THROW('{' == a, "Expected an opening bracket, but read: " << a);
00170 while (true) {
00171 in >> a;
00172 if ('}' == a) {
00173 break;
00174 }
00175 ASSERT_THROW('\"' == a, "Malformed key. " <<
00176 "Should start with quotes, but read this: " << a);
00177
00178 key.clear();
00179 value.clear();
00180
00181 while (true) {
00182 in >> a;
00183 if ('\"' == a) {
00184 break;
00185 }
00186 key += a;
00187 }
00188
00189 while (true) {
00190 in >> a;
00191 if ('\"' == a) {
00192 break;
00193 }
00194 }
00195
00196 while (true) {
00197 in >> a;
00198 if ('\"' == a) {
00199 break;
00200 }
00201 value += a;
00202 }
00203
00204
00205 s_entity.dictionary[key] = value;
00206 }
00207
00208 return &s_entity;
00209 }
00210
00211
00212
00213 lump_object_t *
00214 readLumpFaces
00215 (
00216 IO std::istream& in
00217 )
00218 {
00219 ASSERT_THROW(in.good(), "bad input BSP stream");
00220
00221 static face_t s_face;
00222
00223 s_face.texture = readInt(in);
00224 s_face.effect = readInt(in);
00225 s_face.type = readInt(in);
00226 s_face.vertex = readInt(in);
00227 s_face.nVertices = readInt(in);
00228 s_face.meshvert = readInt(in);
00229 s_face.nMeshverts = readInt(in);
00230 s_face.lmIndex = readInt(in);
00231 s_face.lmStart[0] = readInt(in);
00232 s_face.lmStart[1] = readInt(in);
00233 s_face.lmSize[0] = readInt(in);
00234 s_face.lmSize[1] = readInt(in);
00235 s_face.origin = readPoint3d(in);
00236 s_face.lmVecs[0] = readPoint3d(in);
00237 s_face.lmVecs[1] = readPoint3d(in);
00238 s_face.normal = readPoint3d(in);
00239 s_face.size[0] = readInt(in);
00240 s_face.size[1] = readInt(in);
00241
00242 return &s_face;
00243 }
00244
00245
00246
00247 lump_object_t *
00248 readLumpLeaffaces
00249 (
00250 IO std::istream& in
00251 )
00252 {
00253 ASSERT_THROW(in.good(), "bad input BSP stream");
00254
00255 static leafface_t s_lf;
00256 s_lf.face = readInt(in);
00257 return &s_lf;
00258 }
00259
00260
00261
00262 lump_object_t *
00263 readLumpLeafs
00264 (
00265 IO std::istream& in
00266 )
00267 {
00268 ASSERT_THROW(in.good(), "bad BSP input stream");
00269
00270 static leaf_t s_leaf;
00271
00272 int32_t * n = (int32_t *) &s_leaf.cluster;
00273
00274 for (int j = 0; j < 12; ++j) {
00275 n[j] = readInt(in);
00276 }
00277 return &s_leaf;
00278 }
00279
00280
00281
00282 lump_object_t *
00283 readLumpMeshverts
00284 (
00285 IO std::istream& in
00286 )
00287 {
00288 ASSERT_THROW(in.good(), "bad BSP input stream");
00289
00290 static meshvert_t s_meshvert;
00291
00292 s_meshvert.vertex = readInt(in);
00293
00294 return &s_meshvert;
00295 }
00296
00297
00298
00299 lump_object_t *
00300 readLumpNodes
00301 (
00302 IO std::istream& in
00303 )
00304 {
00305 ASSERT_THROW(in.good(), "bad BSP input stream");
00306
00307 static node_t s_node;
00308
00309
00310 int32_t * n = (int32_t *) &s_node.plane;
00311 for (int j = 0; j < 9; ++j) {
00312 n[j] = readInt(in);
00313 }
00314 return &s_node;
00315 }
00316
00317
00318
00319 lump_object_t *
00320 readLumpPlanes
00321 (
00322 IO std::istream& in
00323 )
00324 {
00325 ASSERT_THROW(in.good(), "bad bsp stream in readLumpPlanes");
00326
00327 static plane_t s_plane;
00328
00329 s_plane.n = readPoint3d(in);
00330 s_plane.d = readFloat(in);
00331
00332 return &s_plane;
00333 }
00334
00335
00336
00337 lump_object_t *
00338 readLumpTextures
00339 (
00340 IO std::istream& in
00341 )
00342 {
00343 ASSERT_THROW(in.good(), "bad bsp stream");
00344
00345 static texture_path_t s_texture;
00346
00347 in.read(s_texture.name, 64);
00348 s_texture.name[64] = 0;
00349 s_texture.flags = readInt(in);
00350 s_texture.contents = readInt(in);
00351
00352 return &s_texture;
00353 }
00354
00355
00356
00357 lump_object_t *
00358 readLumpVertices
00359 (
00360 IO std::istream& in
00361 )
00362 {
00363 ASSERT_THROW(in.good(), "Bad BSP stream");
00364
00365 static vertex_t s_vertex;
00366
00367 s_vertex.position = readPoint3d(in);
00368 s_vertex.texcoord[0][0] = readFloat(in);
00369 s_vertex.texcoord[0][1] = readFloat(in);
00370 s_vertex.texcoord[1][0] = readFloat(in);
00371 s_vertex.texcoord[1][1] = readFloat(in);
00372 s_vertex.normal = readPoint3d(in);
00373 in.read((char *) &s_vertex.color, 4);
00374
00375 return &s_vertex;
00376 }
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386 class BspImpl : public Bsp {
00387 public:
00388
00389 BspImpl(void) throw();
00390 ~BspImpl(void) throw() { }
00391
00392
00393 void initialize(IN smart_ptr<nstream::Stream>& stream);
00394
00395
00396 virtual BspVersion getVersion(void) const throw() { return m_version; }
00397 virtual const char * getName(void) const throw() { return m_name.c_str(); }
00398 virtual const vec_lump_type_t& getLumps(void) const throw() { return m_lumps; }
00399 virtual int getLumpObjectCount(IN eLumpType type);
00400 virtual void startLumpIteration(IN eLumpType type);
00401 virtual const lump_object_t * getNextLumpObject(void);
00402
00403 private:
00404
00405
00406 direntry_t * getEntry(IN eLumpType type) throw();
00407
00408
00409 BspVersion m_version;
00410 std::string m_name;
00411 vec_lump_type_t m_lumps;
00412 lump_entry_map_t m_lumpMap;
00413 smart_ptr<nstream::Stream> m_stream;
00414 std::istream * m_pinput;
00415 const lump_entry_t * m_entry;
00416 int m_index;
00417 int m_max;
00418 };
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428 BspImpl::BspImpl
00429 (
00430 void
00431 )
00432 throw()
00433 {
00434 m_index = -1;
00435 m_max = 0;
00436 m_pinput = NULL;
00437 m_entry = NULL;
00438 }
00439
00440
00441
00442 void
00443 BspImpl::initialize
00444 (
00445 IN smart_ptr<nstream::Stream>& stream
00446 )
00447 {
00448 perf::Timer timer("loadBsp");
00449 ASSERT(stream, "null");
00450 ASSERT_THROW(stream->good(), "bad input BSP stream");
00451 ASSERT(!m_stream, "already have a stream");
00452
00453
00454 m_stream = stream;
00455
00456
00457 smart_ptr<nstream::File> file = stream->getFile();
00458 ASSERT_THROW(file, "stream not attached to file?");
00459 m_name = file->getName();
00460 DPRINTF("Reading bsp file from stream: %s", m_name.c_str());
00461
00462
00463 std::istream& in = stream->getStream();
00464 ASSERT_THROW(in.good(), "bad input BSP stream");
00465
00466
00467 m_version.read(in);
00468 ASSERT_THROW(m_version.isValid(), "Could not parse BSP version");
00469
00470
00471 ASSERT_THROW(m_version.getLumpTypes(m_lumps),
00472 "Could not determine BSP lumps from version");
00473
00474
00475 for (vec_lump_type_t::const_iterator i = m_lumps.begin();
00476 i != m_lumps.end(); ++i) {
00477 eLumpType type = *i;
00478
00479
00480
00481 direntry_t entry;
00482 entry.offset = readInt(in);
00483 entry.length = readInt(in);
00484
00485
00486
00487
00488 ASSERT_THROW(entry.offset > 0,
00489 "bad lump offset: " << entry.offset);
00490 ASSERT_THROW(entry.length >= 0,
00491 "bad lump length: " << entry.length);
00492
00493
00494 m_lumpMap[type] = entry;
00495 }
00496 }
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506 int
00507 BspImpl::getLumpObjectCount
00508 (
00509 IN eLumpType type
00510 )
00511 {
00512
00513 direntry_t * dirent = this->getEntry(type);
00514 if (!dirent) {
00515 return 0;
00516 }
00517 ASSERT(dirent->length >= 0, "Bad length: %d", dirent->length);
00518
00519
00520 const lump_entry_t * p = getLumpEntry(type);
00521 if (!p) {
00522 return 0;
00523 }
00524 if (p->obj_size < 0) {
00525
00526 return -1;
00527 }
00528 ASSERT(p->obj_size > 0, "Bad object size: %d", p->obj_size);
00529
00530 return (dirent->length / p->obj_size);
00531 }
00532
00533
00534
00535 void
00536 BspImpl::startLumpIteration
00537 (
00538 IN eLumpType type
00539 )
00540 {
00541 perf::Timer timer("Bsp::startLumpIteration");
00542 DPRINTF("Caller has requested to start iterating lump '%s'",
00543 getLumpName(type));
00544
00545
00546 m_index = 0;
00547 m_entry = NULL;
00548 m_max = 0;
00549 m_pinput = NULL;
00550
00551
00552 direntry_t * dirent = this->getEntry(type);
00553 if (!dirent) {
00554 return;
00555 }
00556
00557
00558 m_entry = getLumpEntry(type);
00559 if (!m_entry) {
00560 DPRINTF("Coult not find lump entry for type %d", type);
00561 return;
00562 }
00563 ASSERT(m_entry->reader, "null reader in lump entry map");
00564
00565 DPRINTF(" Moving to offset %d", dirent->offset);
00566 ASSERT(dirent->offset > 0, "Bad lump offset: %d", dirent->offset);
00567
00568 ASSERT(m_stream, "null");
00569 m_pinput = &m_stream->getStream();
00570 ASSERT(m_pinput, "null");
00571 ASSERT_THROW(m_pinput->good(), "bad input BSP stream");
00572 m_pinput->seekg(dirent->offset);
00573
00574
00575 m_max = dirent->offset + dirent->length;
00576 }
00577
00578
00579
00580 const lump_object_t *
00581 BspImpl::getNextLumpObject
00582 (
00583 void
00584 )
00585 {
00586 if (!m_entry || !m_pinput) {
00587 return NULL;
00588 }
00589 int offset = m_pinput->tellg();
00590 if (offset >= m_max)
00591 return NULL;
00592
00593
00594 lump_object_t * retval = m_entry->reader(*m_pinput);
00595 if (!retval) {
00596 DPRINTF("lump reader returned null object");
00597 return NULL;
00598 }
00599 retval->index = m_index;
00600
00601
00602 ++m_index;
00603
00604
00605 return retval;
00606 }
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616 direntry_t *
00617 BspImpl::getEntry
00618 (
00619 IN eLumpType type
00620 )
00621 throw()
00622 {
00623 lump_entry_map_t::iterator i = m_lumpMap.find(type);
00624 if (m_lumpMap.end() == i) {
00625 return NULL;
00626 }
00627 return &i->second;
00628 }
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638 smart_ptr<Bsp>
00639 Bsp::load
00640 (
00641 IN smart_ptr<nstream::Stream>& stream
00642 )
00643 {
00644 ASSERT(stream, "null");
00645
00646 smart_ptr<BspImpl> local = new BspImpl;
00647 ASSERT(local, "out of memory");
00648
00649 local->initialize(stream);
00650
00651 return local;
00652 }
00653
00654
00655
00656 };
00657