00001 #include "libcsm/libcsm.h"
00002
00003 USE_PKG(std);
00004
00005 BEGIN_PKG(csm);
00006 ostream& CLogger::debug(string compName)
00007 {
00008 return (cerr<<"<dbg> "<<compName<<" - ");
00009 }
00010 ostream& CLogger::mesg(string compName)
00011 {
00012 return (cerr<<"<msg> "<<compName<<" - ");
00013 }
00014 ostream& CLogger::warn(string compName)
00015 {
00016 return (cerr<<"<wrn> "<<compName<<" - ");
00017 }
00018 ostream& CLogger::err(string compName)
00019 {
00020 return (cerr<<"<err> "<<compName<<" - ");
00021 }
00022
00023 float Vec3Util::dot(vec3_t& v1,vec3_t& v2)
00024 {
00025 return (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z);
00026 }
00027 vec3_t& Vec3Util::cross(vec3_t& v1,vec3_t& v2,vec3_t& result)
00028 {
00029 result.x = v1.y * v2.z - v1.z * v2.y;
00030 result.y = v1.z * v2.x - v1.x * v2.z;
00031 result.z = v1.x * v2.y - v1.y * v2.x;
00032 return result;
00033 }
00034 vec3_t& Vec3Util::clear(vec3_t& v,float val)
00035 {
00036 v.x = val;
00037 v.y = val;
00038 v.z = val;
00039 return v;
00040 }
00041 vec3_t& Vec3Util::scale(vec3_t& v,float factor)
00042 {
00043 return multiply(v,factor,v);
00044 }
00045 vec3_t& Vec3Util::multiply(vec3_t& v,float factor,vec3_t& result)
00046 {
00047 result.x = v.x * factor;
00048 result.y = v.y * factor;
00049 result.z = v.z * factor;
00050 return result;
00051
00052 }
00053 vec3_t& Vec3Util::add(vec3_t& v1,vec3_t& v2,vec3_t& result)
00054 {
00055 result.x = v1.x + v2.x;
00056 result.y = v1.y + v2.y;
00057 result.z = v1.z + v2.z;
00058 return result;
00059 }
00060 vec3_t& Vec3Util::subtract(vec3_t& v1,vec3_t& v2,vec3_t& result)
00061 {
00062 result.x = v1.x - v2.x;
00063 result.y = v1.y - v2.y;
00064 result.z = v1.z - v2.z;
00065 return result;
00066 }
00067 vec3_t& Vec3Util::assign(vec3_t& target,vec3_t& dest)
00068 {
00069 memcpy(&target,&dest,sizeof(vec3_t));
00070 return target;
00071 }
00072 vec3_t& Vec3Util::normalize(vec3_t& v,vec3_t& result)
00073 {
00074 float m = modulus(v);
00075 if(m == 0)
00076 {
00077 clear(result);
00078 }
00079 else
00080 {
00081
00082 assign(result,v);
00083 scale(result, 1/ m);
00084 }
00085 return result;
00086 }
00087 vec3_t& Vec3Util::normalize(vec3_t& v)
00088 {
00089 return normalize(v,v);
00090 }
00091 float Vec3Util::modulus(vec3_t& v)
00092 {
00093 return sqrt(dot(v,v));
00094 }
00095 bool Vec3Util::equals(vec3_t& v1,vec3_t& v2)
00096 {
00097 return (v1.x == v2.x && v1.y == v2.y && v1.z == v2.z);
00098 }
00099
00100
00101
00102
00103
00104
00105 void PropertyTable::load(string& str)
00106 {
00107 string name="";
00108 string value = "";
00109
00110 clear();
00111
00112 bool bDoingName = true;
00113 for(int i=0;i<str.size();i++)
00114 {
00115 switch(str[i])
00116 {
00117 case '\0':
00118 i = str.size();
00119 break;
00120 case '\n':
00121 (*this)[name] = value;
00122 name="";
00123 value="";
00124 bDoingName = true;
00125 break;
00126 case '=':
00127 value="";
00128 bDoingName = false;
00129 break;
00130 case '\"':
00131
00132 break;
00133 default:
00134 if(bDoingName)
00135 {
00136 name+=str[i];
00137 }
00138 else
00139 {
00140 value+=str[i];
00141 }
00142 }
00143
00144 }
00145 }
00146
00147
00148
00149 void BrushFace::loadFaceData(ChunkReader *pChunkReader)
00150 {
00151 pChunkReader->loadVector3(m_Normal);
00152 m_PlaneDistance = pChunkReader->readFloat();
00153 m_TextureName = pChunkReader->readString();
00154 m_LightmapIndex = pChunkReader->readULong();
00155
00156 pChunkReader->loadVector2(m_TexCoords);
00157 pChunkReader->loadVector2(m_TexScales);
00158 m_UVAngle = pChunkReader->readFloat();
00159
00160 ulong len = pChunkReader->readULong();
00161
00162 m_Vertices.clear();
00163
00164 brush_vertex_t vert;
00165 for(ulong l=0L;l<len;l++)
00166 {
00167 pChunkReader->readBuffer(&vert,sizeof(vert));
00168 m_Vertices.push_back(vert);
00169 }
00170 }
00171
00172
00173
00174 const char Chunk::TAG_BRUSH[4] = {'B','R','U','S'};
00175 const char Chunk::TAG_MESH[4] = {'M','E','S','H'};
00176 const char Chunk::TAG_GROUP[4] = {'G','R','U','P'};
00177 const char Chunk::TAG_LMAP[4] = {'L','M','A','P'};
00178 const char Chunk::TAG_ENTITY[4] = {'E','N','T','Y'};
00179 const char Chunk::TAG_DATA[4] = {'D','A','T','A'};
00180 const char Chunk::TAG_UNKNOWN[4]= {'U','N','K','N'};
00181
00182 Chunk::Chunk(Chunk::TAG_TYPE t)
00183 {
00184 m_Type = t;
00185 }
00186 Chunk::~Chunk()
00187 {
00188 resetChunkData();
00189 }
00190 Chunk::Chunk(const Chunk& chunk)
00191 {
00192 m_Type = chunk.m_Type;
00193 memcpy(&(m_Header),&(chunk.m_Header),sizeof(chunk_header_t));
00194
00195 }
00196 Chunk::TAG_TYPE Chunk::getTagType(char tag[4])
00197 {
00198 char ret[5];
00199 memcpy(ret,tag,4);
00200 ret[4] = 0;
00201
00202 for(Chunk::TAG_TYPE t = Chunk::TT_BRUSH; t < Chunk::TT_UNKNOWN; t = (Chunk::TAG_TYPE)((int)t + 1))
00203 {
00204 string str = getFullTagName(t);
00205 if(str == ret)
00206 {
00207 return t;
00208 }
00209 }
00210 return TT_UNKNOWN;
00211 }
00212 string Chunk::getFullTagName(Chunk::TAG_TYPE t)
00213 {
00214 const char *buf = getTagStr(t);
00215 char ret[5];
00216 memcpy(ret,buf,4);
00217 ret[4] = 0;
00218 return ret;
00219 }
00220 const char* Chunk::getTagStr(Chunk::TAG_TYPE t)
00221 {
00222 switch(t)
00223 {
00224 case TT_BRUSH:
00225 return TAG_BRUSH;
00226 case TT_MESH:
00227 return TAG_MESH;
00228 case TT_GROUP:
00229 return TAG_GROUP;
00230 case TT_LMAP:
00231 return TAG_LMAP;
00232 case TT_ENTITY:
00233 return TAG_ENTITY;
00234 case TT_DATA:
00235 return TAG_DATA;
00236 default:
00237 return TAG_UNKNOWN;
00238 }
00239 }
00240
00241 void Chunk::loadChunkData(ChunkReader *pChunkReader)
00242 {
00243 ubyte *buf = new ubyte[getSize()];
00244 ArrayWrapper<ubyte> bufWrapper(buf);
00245 pChunkReader->readBuffer(buf,getSize());
00246
00247 }
00248 void Chunk::resetChunkData()
00249 {
00250
00251
00252 }
00253 void Chunk::setHeader(chunk_header_t& hdr)
00254 {
00255 Chunk::TAG_TYPE t = getTagType(hdr.tag);
00256 if(m_Type != t)
00257 {
00258 throw exception("tried to set an invalid header type on chunk");
00259 }
00260 memcpy(&(m_Header),&(hdr),sizeof(chunk_header_t));
00261 }
00262 Chunk::TAG_TYPE Chunk::getType()
00263 {
00264 return m_Type;
00265 }
00266 ulong Chunk::getSize()
00267 {
00268 return m_Header.len;
00269 }
00270
00271 Chunk* Chunk::newChunk(chunk_header_t& hdr)
00272 {
00273 Chunk::TAG_TYPE t = getTagType(hdr.tag);
00274 Chunk *pChunk = 0;
00275 switch(t)
00276 {
00277 case TT_BRUSH:
00278 pChunk = new ChunkBrush();
00279 break;
00280 case TT_MESH:
00281 pChunk = new ChunkMesh();
00282 break;
00283 case TT_GROUP:
00284 pChunk = new ChunkGroup();
00285 break;
00286 case TT_LMAP:
00287 pChunk = new ChunkLMap();
00288 break;
00289 case TT_ENTITY:
00290 pChunk = new ChunkEntity();
00291 break;
00292 case TT_DATA:
00293 pChunk = new ChunkData();
00294 break;
00295 default:
00296 pChunk = 0;
00297 break;
00298 }
00299 if(pChunk)
00300 {
00301 pChunk->setHeader(hdr);
00302 }
00303 return pChunk;
00304 }
00305 void Chunk::deleteChunk(Chunk* pChunk)
00306 {
00307 if(pChunk != 0)
00308 {
00309 delete pChunk;
00310 pChunk = 0;
00311 }
00312 }
00313
00314
00315
00316 ChunkBrush::ChunkBrush() : Chunk(Chunk::TT_BRUSH)
00317 {
00318 }
00319 ChunkBrush::~ChunkBrush()
00320 {
00321 }
00322 void ChunkBrush::loadChunkData(ChunkReader *pChunkReader)
00323 {
00324
00325
00326 m_Flags = pChunkReader->readULong();
00327
00328 m_Color = pChunkReader->readULong();
00329
00330 m_GroupID = pChunkReader->readULong();
00331
00332 m_Props.load(pChunkReader->readString());
00333
00334 ulong num = pChunkReader->readULong();
00335
00336 m_Faces.clear();
00337
00338
00339 for(ulong l=0;l<num;l++)
00340 {
00341 BrushFace *pFace = new BrushFace();
00342 pFace->loadFaceData(pChunkReader);
00343 m_Faces.push_back(pFace);
00344 }
00345 }
00346 void ChunkBrush::resetChunkData()
00347 {
00348 for(ulong l = 0; l<m_Faces.size(); l++)
00349 {
00350 BrushFace *face = m_Faces[l];
00351 if(face)
00352 {
00353 delete face;
00354 face = 0;
00355 }
00356 }
00357 m_Faces.clear();
00358 }
00359
00360 ChunkMesh::ChunkMesh() : Chunk(Chunk::TT_MESH)
00361 {
00362 }
00363
00364 ChunkMesh::~ChunkMesh()
00365 {
00366 }
00367 void ChunkMesh::loadChunkData(ChunkReader *pChunkReader)
00368 {
00369 m_Flags = pChunkReader->readULong();
00370 m_Color = pChunkReader->readULong();
00371 m_GroupID = pChunkReader->readULong();
00372
00373
00374 m_Props.load(pChunkReader->readString());
00375 m_TextureName = pChunkReader->readString();
00376
00377 ulong num = pChunkReader->readULong();
00378
00379 mesh_vertex_t vert;
00380 for(ulong l=0;l<num;l++)
00381 {
00382
00383 pChunkReader->readBuffer(&vert,sizeof(vert));
00384 m_Vertices.push_back(vert);
00385 }
00386
00387 num = pChunkReader->readULong();
00388 triangle_t tri;
00389 for(l=0;l<num;l++)
00390 {
00391
00392 pChunkReader->readBuffer(&tri,sizeof(tri));
00393 m_Triangles.push_back(tri);
00394 }
00395 }
00396 void ChunkMesh::resetChunkData()
00397 {
00398 m_Vertices.clear();
00399 m_Triangles.clear();
00400 }
00401
00402
00403
00404 ChunkEntity::ChunkEntity() : Chunk(Chunk::TT_ENTITY)
00405 {
00406 }
00407
00408 ChunkEntity::~ChunkEntity()
00409 {
00410 }
00411 void ChunkEntity::loadChunkData(ChunkReader *pChunkReader)
00412 {
00413 m_Flags = pChunkReader->readULong();
00414
00415 pChunkReader->loadVector3(m_Pos);
00416
00417 string str = pChunkReader->readString();
00418
00419 m_GroupID = pChunkReader->readULong();
00420
00421 m_Color[0] = pChunkReader->readULong();
00422 m_Color[1] = pChunkReader->readULong();
00423 m_Color[2] = pChunkReader->readULong();
00424
00425 m_Width = pChunkReader->readULong();
00426 m_Height = pChunkReader->readULong();
00427
00428 }
00429 void ChunkEntity::resetChunkData()
00430 {
00431 }
00432
00433
00434
00435 ChunkData::ChunkData() : Chunk(Chunk::TT_DATA)
00436 {
00437 }
00438
00439 ChunkData::~ChunkData()
00440 {
00441 }
00442 void ChunkData::loadChunkData(ChunkReader *pChunkReader)
00443 {
00444 pChunkReader->loadVector3(m_CameraPos);
00445
00446 m_CameraPitch = pChunkReader->readFloat();
00447 m_CameraYaw = pChunkReader->readFloat();
00448
00449 m_AmbientColor = pChunkReader->readULong();
00450 }
00451 void ChunkData::resetChunkData()
00452 {
00453 }
00454
00455
00456
00457
00458 ChunkGroup::ChunkGroup() : Chunk(Chunk::TT_GROUP)
00459 {
00460 }
00461
00462 ChunkGroup::~ChunkGroup()
00463 {
00464 }
00465 void ChunkGroup::loadChunkData(ChunkReader *pChunkReader)
00466 {
00467 Chunk::loadChunkData(pChunkReader);
00468 }
00469 void ChunkGroup::resetChunkData()
00470 {
00471 }
00472
00473
00474
00475 ChunkLMap::ChunkLMap() : Chunk(Chunk::TT_LMAP)
00476 {
00477 }
00478
00479 ChunkLMap::~ChunkLMap()
00480 {
00481 }
00482 void ChunkLMap::loadChunkData(ChunkReader *pChunkReader)
00483 {
00484 m_Width = pChunkReader->readULong();
00485 m_Height = pChunkReader->readULong();
00486
00487
00488 ulong len = (m_Height * m_Width *4);
00489
00490 m_Pixels = new ubyte[len];
00491 memset(m_Pixels,0,len);
00492 pChunkReader->readBuffer(m_Pixels,len);
00493 }
00494 void ChunkLMap::resetChunkData()
00495 {
00496 }
00497
00498
00499
00500
00501
00502
00503 CLogger ChunkReader::m_Log("ChunkReader");
00504 ChunkReader::ChunkReader() : m_pFile(0), m_pStream(0)
00505 {
00506 }
00507 ChunkReader::~ChunkReader()
00508 {
00509 reset();
00510 }
00511 void ChunkReader::reset()
00512 {
00513 if(m_pStream)
00514 {
00515 delete m_pStream;
00516 }
00517 m_pFile = 0;
00518 }
00519 bool ChunkReader::ok()
00520 {
00521 if(m_pFile)
00522 {
00523 if(m_pStream)
00524 {
00525 return (m_pStream->good());
00526 }
00527
00528 }
00529 return false;
00530 }
00531
00532 void ChunkReader::loadFile(string fileName,CSMFile& file)
00533 {
00534 reset();
00535 m_pStream = new ifstream(fileName.c_str(),ios::binary | ios::in);
00536 m_pFile = &(file);
00537 if(!ok())
00538 {
00539 string mesg = "could not open file ";
00540 mesg+=fileName;
00541 mesg+=" for loading.";
00542 throw exception(mesg.c_str());
00543 }
00544 else
00545 {
00546 m_Log.debug()<<"Loading File : "<<fileName<<" ... "<<endl;
00547 }
00548 while(!m_pStream->eof())
00549 {
00550 Chunk *pChunk = nextChunk();
00551 if(pChunk != 0)
00552 {
00553
00554 if(pChunk->getSize()>0)
00555 {
00556 m_pFile->addChunk(pChunk);
00557
00558
00559 }
00560 }
00561 }
00562 }
00563
00564 Chunk* ChunkReader::nextChunk()
00565 {
00566 if(!ok())
00567 {
00568 throw exception("Invalid/Corrupted Input Stream");
00569 }
00570 if(m_pStream->eof())
00571 {
00572 return 0;
00573 }
00574 chunk_header_t hdr;
00575 readBuffer((char *)&hdr,sizeof(chunk_header_t));
00576 if(hdr.len == 0)
00577 {
00578 return 0;
00579 }
00580
00581 Chunk *pChunk = Chunk::newChunk(hdr);
00582 if(pChunk == 0)
00583 {
00584 m_Log.warn()<<"Null Chunk Encountered"<<endl;
00585 }
00586 else
00587 {
00588
00589 if(pChunk->getSize()>0)
00590 {
00591 pChunk->resetChunkData();
00592 pChunk->loadChunkData(this);
00593
00594 }
00595
00596 }
00597
00598 return pChunk;
00599
00600 }
00601 string ChunkReader::readString()
00602 {
00603 char *buf = new char[CSMFile::MAX_STR_LEN];
00604 ArrayWrapper<char> bufWrapper(buf);
00605
00606 memset(buf,0,CSMFile::MAX_STR_LEN);
00607 int index = 0;
00608 ubyte c = readByte();
00609 while(c != '\0')
00610 {
00611 buf[index++] = c;
00612 c=readByte();
00613 }
00614
00615
00616
00617 return buf;
00618 }
00619
00620 void ChunkReader::readBuffer(void *buf,ulong len)
00621 {
00622 if(!ok())
00623 {
00624 throw exception("error in readBuffer() : invalid or corrupted stream");
00625 }
00626 else
00627 {
00628 memset(buf,0,len);
00629 m_pStream->read((char *)buf,len);
00630 }
00631 }
00632 ubyte ChunkReader::readByte()
00633 {
00634 if(!ok())
00635 {
00636 throw new exception("error in readByte : invalid or corrupted stream");
00637 }
00638 WrapperByte wrapper;
00639 readBuffer(&wrapper,sizeof(wrapper));
00640 return wrapper.val;
00641
00642 }
00643
00644 ulong ChunkReader::readULong()
00645 {
00646 if(!ok())
00647 {
00648 throw new exception("error in readULong : invalid or corrupted stream");
00649 }
00650 WrapperULong wrapper;
00651 readBuffer(&wrapper,sizeof(wrapper));
00652 return wrapper.val;
00653
00654 }
00655
00656 long ChunkReader::readLong()
00657 {
00658 if(!ok())
00659 {
00660 throw new exception("error in readLong : invalid or corrupted stream");
00661 }
00662 WrapperLong wrapper;
00663 readBuffer(&wrapper,sizeof(wrapper));
00664 return wrapper.val;
00665
00666 }
00667
00668 ushort ChunkReader::readUShort()
00669 {
00670 if(!ok())
00671 {
00672 throw new exception("error in readUShort : invalid or corrupted stream");
00673 }
00674 WrapperUShort wrapper;
00675 readBuffer(&wrapper,sizeof(wrapper));
00676 return wrapper.val;
00677
00678 }
00679 short ChunkReader::readShort()
00680 {
00681 if(!ok())
00682 {
00683 throw new exception("error in readShort : invalid or corrupted stream");
00684 }
00685 WrapperShort wrapper;
00686 readBuffer(&wrapper,sizeof(wrapper));
00687 return wrapper.val;
00688
00689 }
00690
00691 float ChunkReader::readFloat()
00692 {
00693 if(!ok())
00694 {
00695 throw new exception("error in readFloat : invalid or corrupted stream");
00696 }
00697 WrapperFloat wrapper;
00698 readBuffer(&wrapper,sizeof(wrapper));
00699 return wrapper.val;
00700
00701 }
00702 double ChunkReader::readDouble()
00703 {
00704 if(!ok())
00705 {
00706 throw new exception("error in readDouble : invalid or corrupted stream");
00707 }
00708 WrapperDouble wrapper;
00709 readBuffer(&wrapper,sizeof(wrapper));
00710 return wrapper.val;
00711
00712 }
00713 void ChunkReader::loadVector3(vec3_t& vec)
00714 {
00715 readBuffer(&vec,sizeof(vec));
00716 }
00717
00718 void ChunkReader::loadVector2(vec2_t& vec)
00719 {
00720 readBuffer(&vec,sizeof(vec));
00721 }
00722
00723
00724
00725 const ulong CSMFile::MAX_STR_LEN = 2 * 1024;
00726
00727 CSMFile::CSMFile()
00728 {
00729 reset();
00730 }
00731 CSMFile::~CSMFile()
00732 {
00733 reset();
00734 }
00735 void CSMFile::reset()
00736 {
00737 clearChunkList(m_Meshes);
00738 clearChunkList(m_Brushes);
00739 clearChunkList(m_Groups);
00740
00741 clearChunkList(m_LMaps);
00742 clearChunkList(m_Entities);
00743 clearChunkList(m_Data);
00744 }
00745
00746 ulong CSMFile::getBrushCount()
00747 {
00748 return m_Brushes.size();
00749 }
00750 ChunkBrush* CSMFile::brushAt(ulong index)
00751 {
00752 return (ChunkBrush *)m_Brushes[index];
00753 }
00754
00755 ulong CSMFile::getMeshCount()
00756 {
00757 return m_Meshes.size();
00758 }
00759 ChunkMesh* CSMFile::meshAt(ulong index)
00760 {
00761 return (ChunkMesh *)m_Meshes[index];
00762 }
00763
00764 ulong CSMFile::getGroupCount()
00765 {
00766 return m_Groups.size();
00767 }
00768 ChunkGroup* CSMFile::groupAt(ulong index)
00769 {
00770 return (ChunkGroup *)m_Groups[index];
00771 }
00772
00773 ulong CSMFile::getDataCount()
00774 {
00775 return m_Data.size();
00776 }
00777 ChunkData* CSMFile::dataAt(ulong index)
00778 {
00779 return (ChunkData *)m_Data[index];
00780 }
00781
00782 ulong CSMFile::getLMapCount()
00783 {
00784 return m_LMaps.size();
00785 }
00786 ChunkLMap* CSMFile::lmapAt(ulong index)
00787 {
00788 return (ChunkLMap *)m_LMaps[index];
00789 }
00790
00791 ulong CSMFile::getEntityCount()
00792 {
00793 return m_Entities.size();
00794 }
00795 ChunkEntity* CSMFile::entityAt(ulong index)
00796 {
00797 return (ChunkEntity *)m_Entities[index];
00798 }
00799 void CSMFile::clearChunkList(ChunkList& lis)
00800 {
00801 for(int i=0;i<lis.size();i++)
00802 {
00803 Chunk::deleteChunk(lis[i]);
00804 lis[i] = 0;
00805 }
00806 lis.clear();
00807 }
00808
00809 void CSMFile::addChunk(Chunk *pChunk)
00810 {
00811 if(pChunk)
00812 {
00813 ChunkList *pLis = 0;
00814 switch(pChunk->getType())
00815 {
00816 case Chunk::TT_BRUSH:
00817 pLis = &(m_Brushes);
00818 break;
00819 case Chunk::TT_MESH:
00820 pLis = &(m_Meshes);
00821 break;
00822 case Chunk::TT_GROUP:
00823 pLis = &(m_Groups);
00824 break;
00825 case Chunk::TT_LMAP:
00826 pLis = &(m_LMaps);
00827 break;
00828 case Chunk::TT_ENTITY:
00829 pLis = &(m_Entities);
00830 break;
00831 case Chunk::TT_DATA:
00832 pLis = &(m_Data);
00833 break;
00834 }
00835 if(pLis)
00836 {
00837 pLis->push_back(pChunk);
00838 }
00839 }
00840 }
00841 END_PKG(csm);