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.
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"
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_
)
42 SideLength(SideLength_
),
43 HeightData(HeightData_
),
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()
93 StaticEntityDataT::StaticEntityDataT(std::istream
& InFile
, cf::SceneGraph::aux::PoolT
& Pool
, ModelManagerT
& ModelMan
, cf::SceneGraph::LightMapManT
& LightMapMan
, cf::SceneGraph::SHLMapManT
& SHLMapMan
, PlantDescrManT
& PlantDescrMan
)
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
)
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()
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
));
159 m_CollModel
->SaveToFile(OutFile
, Pool
);
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
);
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.");
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
);