Fix issue in Rocket.lua script.
[Cafu-Engine.git] / Common / World.cpp
blob9e06305b3fe0481b39421f748313a3f62d85a94e
1 /*
2 Cafu Engine, http://www.cafu.de/
3 Copyright (c) Carsten Fuchs and other contributors.
4 This project is licensed under the terms of the MIT license.
5 */
7 /********************/
8 /*** World (Code) ***/
9 /********************/
11 #include "World.hpp"
12 #include "Bitmap/Bitmap.hpp"
13 #include "ClipSys/CollisionModel_static.hpp"
14 #include "GameSys/Entity.hpp"
15 #include "GameSys/World.hpp"
16 #include "MaterialSystem/Material.hpp"
17 #include "MaterialSystem/MaterialManager.hpp"
18 #include "SceneGraph/_aux.hpp"
19 #include "SceneGraph/Node.hpp"
20 #include "SceneGraph/BspTreeNode.hpp"
21 #include "String.hpp"
23 #include <cassert>
24 #include <cstring>
25 #include <fstream>
28 /************/
29 /*** MapT ***/
30 /************/
32 const double MapT::RoundEpsilon = 0.08; // ca. 2.0 / 25.4 // Make sure that this matches FaceNodeT::ROUND_EPSILON in SceneGraph/FaceNode.cpp!
33 const double MapT::MinVertexDist = 0.40; // ca. 10.0 / 25.4
36 /**********************/
37 /*** SharedTerrainT ***/
38 /**********************/
40 SharedTerrainT::SharedTerrainT(const BoundingBox3dT& BB_, unsigned long SideLength_, const ArrayT<unsigned short>& HeightData_, MaterialT* Material_)
41 : BB(BB_),
42 SideLength(SideLength_),
43 HeightData(HeightData_),
44 Material(Material_),
45 Terrain(&HeightData[0], SideLength, BB.AsBoxOfFloat())
50 SharedTerrainT::SharedTerrainT(std::istream& InFile)
52 using namespace cf::SceneGraph;
54 BB.Min =aux::ReadVector3d(InFile);
55 BB.Max =aux::ReadVector3d(InFile);
56 SideLength=aux::ReadUInt32(InFile);
57 Material =MaterialManager->GetMaterial(aux::ReadString(InFile));
59 HeightData.PushBackEmptyExact(SideLength*SideLength);
61 for (unsigned long i=0; i<HeightData.Size(); i++)
62 HeightData[i]=aux::ReadUInt16(InFile);
64 Terrain=TerrainT(&HeightData[0], SideLength, BB.AsBoxOfFloat());
68 void SharedTerrainT::WriteTo(std::ostream& OutFile) const
70 using namespace cf::SceneGraph;
72 aux::Write(OutFile, BB.Min);
73 aux::Write(OutFile, BB.Max);
74 aux::Write(OutFile, aux::cnc_ui32(SideLength));
75 aux::Write(OutFile, Material->Name); // There are only few terrains, no need for the Pool here.
77 for (unsigned long i=0; i<HeightData.Size(); i++)
78 aux::Write(OutFile, HeightData[i]);
82 /*************************/
83 /*** StaticEntityDataT ***/
84 /*************************/
86 StaticEntityDataT::StaticEntityDataT()
87 : m_BspTree(NULL),
88 m_CollModel(NULL)
93 StaticEntityDataT::StaticEntityDataT(std::istream& InFile, cf::SceneGraph::aux::PoolT& Pool, ModelManagerT& ModelMan, cf::SceneGraph::LightMapManT& LightMapMan, cf::SceneGraph::SHLMapManT& SHLMapMan, PlantDescrManT& PlantDescrMan)
94 : m_BspTree(NULL),
95 m_CollModel(NULL)
97 // Read the shared terrain data.
98 ArrayT<const TerrainT*> ShTe_SceneGr;
99 ArrayT<cf::ClipSys::CollisionModelStaticT::TerrainRefT> ShTe_CollDet;
101 for (unsigned long TerrainNr = cf::SceneGraph::aux::ReadUInt32(InFile); TerrainNr > 0; TerrainNr--)
103 SharedTerrainT* ShTe = new SharedTerrainT(InFile);
105 m_Terrains.PushBack(ShTe);
106 ShTe_SceneGr.PushBack(&ShTe->Terrain);
107 ShTe_CollDet.PushBack(cf::ClipSys::CollisionModelStaticT::TerrainRefT(&ShTe->Terrain, ShTe->Material, ShTe->BB));
110 // Read the SceneGraph BSP tree.
111 // Don't call cf::SceneGraph::BspTreeNodeT::CreateFromFile_cw() directly, because it would expect
112 // that the "BspTree" string that states the identity of this NodeT has already been read!
113 m_BspTree = dynamic_cast<cf::SceneGraph::BspTreeNodeT*>(cf::SceneGraph::GenericNodeT::CreateFromFile_cw(InFile, Pool,
114 LightMapMan, SHLMapMan, PlantDescrMan, ShTe_SceneGr, ModelMan));
116 if (m_BspTree == NULL)
118 // TODO: Clean-up...
119 throw WorldT::LoadErrorT("Could not read scene graph bsp tree node for game entity!");
122 // Read the ClipSys collision model.
123 bool HasCollisionModel = false;
124 assert(sizeof(HasCollisionModel) == 1);
125 InFile.read((char*)&HasCollisionModel, sizeof(HasCollisionModel));
127 m_CollModel = HasCollisionModel ? new cf::ClipSys::CollisionModelStaticT(InFile, Pool, ShTe_CollDet) : NULL;
131 StaticEntityDataT::~StaticEntityDataT()
133 delete m_BspTree;
134 delete m_CollModel;
136 // Delete the terrains that were shared by the BspTree and the CollModel.
137 for (unsigned int TerrainNr = 0; TerrainNr < m_Terrains.Size(); TerrainNr++)
138 delete m_Terrains[TerrainNr];
142 void StaticEntityDataT::WriteTo(std::ostream& OutFile, cf::SceneGraph::aux::PoolT& Pool) const
144 // Write the shared terrain data.
145 cf::SceneGraph::aux::Write(OutFile, cf::SceneGraph::aux::cnc_ui32(m_Terrains.Size()));
147 for (unsigned long TerrainNr = 0; TerrainNr < m_Terrains.Size(); TerrainNr++)
148 m_Terrains[TerrainNr]->WriteTo(OutFile);
150 // Write the SceneGraph BSP tree.
151 m_BspTree->WriteTo(OutFile, Pool);
153 // Write the ClipSys collision model.
154 const bool HasCollisionModel = (m_CollModel!=NULL);
155 assert(sizeof(HasCollisionModel) == 1);
157 OutFile.write((char*)&HasCollisionModel, sizeof(HasCollisionModel));
158 if (m_CollModel)
159 m_CollModel->SaveToFile(OutFile, Pool);
163 /**************/
164 /*** WorldT ***/
165 /**************/
167 WorldT::WorldT()
172 WorldT::~WorldT()
174 for (unsigned int EntNr = 0; EntNr < m_StaticEntityData.Size(); EntNr++)
175 delete m_StaticEntityData[EntNr];
179 static std::string GetModDir(const char* FileName)
181 std::string ModDir=FileName;
183 // Determine the game directory, cleverly assuming that the destination file is in "Worlds".
184 // Strip the file name, extention and the "Worlds" directory off.
185 size_t i=ModDir.find_last_of("/\\");
187 ModDir=ModDir.substr(0, i==std::string::npos ? 0 : i);
189 i=ModDir.find_last_of("/\\");
191 ModDir=ModDir.substr(0, i==std::string::npos ? 0 : i);
193 return ModDir;
197 WorldT::WorldT(const char* FileName, ModelManagerT& ModelMan, cf::GuiSys::GuiResourcesT& GuiRes, ProgressFunctionT ProgressFunction) /*throw (LoadErrorT)*/
199 // Set the plant descriptions manager mod directory to the one from the world to load.
200 PlantDescrMan.SetModDir(GetModDir(FileName));
202 std::ifstream InFile(FileName, std::ios::in | std::ios::binary);
203 if (InFile.bad()) throw LoadErrorT("Unable to open Cafu world file.");
205 // Determine the size of the input file.
206 InFile.seekg(0, std::ios::end);
207 const std::streampos InFileSize=InFile.tellg();
208 InFile.seekg(0, std::ios::beg);
209 if (ProgressFunction) ProgressFunction(float(InFile.tellg())/float(InFileSize), "Opening file.");
211 char FileHeader[32];
212 InFile.read(FileHeader, 32);
213 if (strcmp(FileHeader, "CAFU WORLD BSP FILE.")) throw LoadErrorT("Invalid file header. Not a Cafu world file.");
215 unsigned short FileVersion;
216 InFile.read((char*)&FileVersion, sizeof(FileVersion));
217 if (FileVersion != 30) throw LoadErrorT("Invalid file version. Current version is 30.");
219 cf::SceneGraph::aux::PoolT Pool;
222 // 1.3. Read global SHL map data.
223 InFile.read((char*)&cf::SceneGraph::SHLMapManT::NrOfBands, sizeof(cf::SceneGraph::SHLMapManT::NrOfBands ));
224 InFile.read((char*)&cf::SceneGraph::SHLMapManT::NrOfRepres, sizeof(cf::SceneGraph::SHLMapManT::NrOfRepres));
226 // Read the lookup-table the indices are referring to (nothing is written when FaceT::SHLMapInfoT::NrOfRepres==0 (uncompressed data)).
227 SHLMapMan.ReadSHLCoeffsTable(InFile);
230 // 5. Read GameEntities
231 if (ProgressFunction) ProgressFunction(float(InFile.tellg())/float(InFileSize), "Reading Game Entities.");
233 const unsigned int NumGameEnts = cf::SceneGraph::aux::ReadUInt32(InFile);
235 for (unsigned int EntNr = 0; EntNr < NumGameEnts; EntNr++)
237 m_StaticEntityData.PushBack(new StaticEntityDataT(InFile, Pool, ModelMan, LightMapMan, SHLMapMan, PlantDescrMan));
240 if (ProgressFunction) ProgressFunction(1.0f, "World file loaded.");
244 void WorldT::SaveToDisk(const char* FileName) const /*throw (SaveErrorT)*/
246 std::ofstream OutFile(FileName, std::ios::out | std::ios::binary);
247 if (OutFile.bad()) throw SaveErrorT("Unable to open world BSP file.");
249 cf::SceneGraph::aux::PoolT Pool;
251 char FileHeader[32] = "CAFU WORLD BSP FILE."; OutFile.write(FileHeader, 32);
252 unsigned short FileVersion = 30; OutFile.write((char*)&FileVersion, sizeof(FileVersion));
255 // 1.3. Write global SHL map data.
256 OutFile.write((char*)&cf::SceneGraph::SHLMapManT::NrOfBands , sizeof(cf::SceneGraph::SHLMapManT::NrOfBands ));
257 OutFile.write((char*)&cf::SceneGraph::SHLMapManT::NrOfRepres, sizeof(cf::SceneGraph::SHLMapManT::NrOfRepres));
259 // Write the lookup-table the indices are referring to (nothing is written when cf::SceneGraph::SHLMapManT::NrOfRepres==0 (uncompressed data)).
260 // This writes a total of cf::SceneGraph::SHLMapManT::NrOfRepres*NR_OF_SH_COEFFS coefficients.
261 SHLMapMan.WriteSHLCoeffsTable(OutFile);
264 // 5. Write GameEntities
265 cf::SceneGraph::aux::Write(OutFile, cf::SceneGraph::aux::cnc_ui32(m_StaticEntityData.Size()));
267 for (unsigned int EntNr = 0; EntNr < m_StaticEntityData.Size(); EntNr++)
269 m_StaticEntityData[EntNr]->WriteTo(OutFile, Pool);