2004-06-01 19:34:12 +02:00
|
|
|
#include "precompiled.h"
|
2004-05-29 22:56:24 +02:00
|
|
|
|
2004-06-02 17:03:17 +02:00
|
|
|
#include "types.h"
|
2004-05-29 22:56:24 +02:00
|
|
|
#include "MapReader.h"
|
|
|
|
#include "UnitManager.h"
|
2004-12-12 20:43:55 +01:00
|
|
|
#include "Unit.h"
|
2005-01-18 01:46:18 +01:00
|
|
|
#include "Game.h"
|
2004-05-29 22:56:24 +02:00
|
|
|
#include "ObjectManager.h"
|
|
|
|
#include "BaseEntity.h"
|
|
|
|
#include "BaseEntityCollection.h"
|
|
|
|
#include "EntityManager.h"
|
|
|
|
|
|
|
|
#include "Model.h"
|
|
|
|
#include "Terrain.h"
|
|
|
|
#include "TextureManager.h"
|
|
|
|
|
|
|
|
// CMapReader constructor: nothing to do at the minute
|
|
|
|
CMapReader::CMapReader()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
// LoadMap: try to load the map from given file; reinitialise the scene to new data if successful
|
2004-07-31 17:57:18 +02:00
|
|
|
void CMapReader::LoadMap(const char* filename, CTerrain *pTerrain, CUnitManager *pUnitMan, CLightEnv *pLightEnv)
|
2004-05-29 22:56:24 +02:00
|
|
|
{
|
|
|
|
CFileUnpacker unpacker;
|
|
|
|
unpacker.Read(filename,"PSMP");
|
|
|
|
|
|
|
|
// check version
|
|
|
|
if (unpacker.GetVersion()<FILE_READ_VERSION) {
|
|
|
|
throw CFileUnpacker::CFileVersionError();
|
|
|
|
}
|
|
|
|
|
|
|
|
// unpack the data
|
|
|
|
UnpackMap(unpacker);
|
|
|
|
|
2005-01-12 15:31:47 +01:00
|
|
|
// apply data to the world
|
2004-07-31 17:57:18 +02:00
|
|
|
ApplyData(unpacker, pTerrain, pUnitMan, pLightEnv);
|
2005-01-12 15:31:47 +01:00
|
|
|
|
|
|
|
if (unpacker.GetVersion()>=3) {
|
|
|
|
// read the corresponding XML file
|
|
|
|
CStr filename_xml (filename);
|
|
|
|
filename_xml = filename_xml.Left(filename_xml.Length()-4) + ".xml";
|
|
|
|
ReadXML(filename_xml);
|
|
|
|
}
|
2004-05-29 22:56:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// UnpackMap: unpack the given data from the raw data stream into local variables
|
|
|
|
void CMapReader::UnpackMap(CFileUnpacker& unpacker)
|
|
|
|
{
|
|
|
|
// now unpack everything into local data
|
|
|
|
UnpackTerrain(unpacker);
|
|
|
|
UnpackObjects(unpacker);
|
|
|
|
if (unpacker.GetVersion()>=2) {
|
|
|
|
UnpackLightEnv(unpacker);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnpackLightEnv: unpack lighting parameters from input stream
|
|
|
|
void CMapReader::UnpackLightEnv(CFileUnpacker& unpacker)
|
|
|
|
{
|
|
|
|
unpacker.UnpackRaw(&m_LightEnv.m_SunColor,sizeof(m_LightEnv.m_SunColor));
|
|
|
|
unpacker.UnpackRaw(&m_LightEnv.m_Elevation,sizeof(m_LightEnv.m_Elevation));
|
|
|
|
unpacker.UnpackRaw(&m_LightEnv.m_Rotation,sizeof(m_LightEnv.m_Rotation));
|
|
|
|
unpacker.UnpackRaw(&m_LightEnv.m_TerrainAmbientColor,sizeof(m_LightEnv.m_TerrainAmbientColor));
|
|
|
|
unpacker.UnpackRaw(&m_LightEnv.m_UnitsAmbientColor,sizeof(m_LightEnv.m_UnitsAmbientColor));
|
2004-10-30 23:57:46 +02:00
|
|
|
m_LightEnv.CalculateSunDirection();
|
2004-05-29 22:56:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// UnpackObjects: unpack world objects from input stream
|
|
|
|
void CMapReader::UnpackObjects(CFileUnpacker& unpacker)
|
|
|
|
{
|
|
|
|
// unpack object types
|
|
|
|
u32 numObjTypes;
|
|
|
|
unpacker.UnpackRaw(&numObjTypes,sizeof(numObjTypes));
|
|
|
|
m_ObjectTypes.resize(numObjTypes);
|
|
|
|
for (uint i=0;i<numObjTypes;i++) {
|
|
|
|
CStr objname;
|
|
|
|
unpacker.UnpackString(objname);
|
|
|
|
|
|
|
|
CObjectEntry* object=g_ObjMan.FindObject((const char*) objname);
|
|
|
|
m_ObjectTypes[i]=object;
|
|
|
|
}
|
|
|
|
|
|
|
|
// unpack object data
|
|
|
|
u32 numObjects;
|
|
|
|
unpacker.UnpackRaw(&numObjects,sizeof(numObjects));
|
|
|
|
m_Objects.resize(numObjects);
|
|
|
|
unpacker.UnpackRaw(&m_Objects[0],sizeof(SObjectDesc)*numObjects);
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnpackTerrain: unpack the terrain from the end of the input data stream
|
|
|
|
// - data: map size, heightmap, list of textures used by map, texture tile assignments
|
|
|
|
void CMapReader::UnpackTerrain(CFileUnpacker& unpacker)
|
|
|
|
{
|
|
|
|
// unpack map size
|
|
|
|
unpacker.UnpackRaw(&m_MapSize,sizeof(m_MapSize));
|
|
|
|
|
|
|
|
// unpack heightmap
|
|
|
|
u32 verticesPerSide=m_MapSize*PATCH_SIZE+1;
|
|
|
|
m_Heightmap.resize(SQR(verticesPerSide));
|
|
|
|
unpacker.UnpackRaw(&m_Heightmap[0],SQR(verticesPerSide)*sizeof(u16));
|
|
|
|
|
|
|
|
// unpack texture names; find handle for each texture
|
|
|
|
u32 numTextures;
|
|
|
|
unpacker.UnpackRaw(&numTextures,sizeof(numTextures));
|
|
|
|
|
|
|
|
m_TerrainTextures.reserve(numTextures);
|
|
|
|
for (uint i=0;i<numTextures;i++) {
|
|
|
|
CStr texturename;
|
|
|
|
unpacker.UnpackString(texturename);
|
|
|
|
|
|
|
|
Handle handle;
|
|
|
|
CTextureEntry* texentry=g_TexMan.FindTexture(texturename);
|
|
|
|
if (!texentry) {
|
|
|
|
// ack; mismatch between texture datasets?
|
|
|
|
handle=0;
|
|
|
|
} else {
|
2004-06-07 21:57:19 +02:00
|
|
|
handle=texentry->GetHandle();
|
2004-05-29 22:56:24 +02:00
|
|
|
}
|
|
|
|
m_TerrainTextures.push_back(handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
// unpack tile data
|
|
|
|
u32 tilesPerSide=m_MapSize*PATCH_SIZE;
|
|
|
|
m_Tiles.resize(SQR(tilesPerSide));
|
2004-06-11 04:14:18 +02:00
|
|
|
unpacker.UnpackRaw(&m_Tiles[0],(u32)(sizeof(STileDesc)*m_Tiles.size()));
|
2004-05-29 22:56:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// ApplyData: take all the input data, and rebuild the scene from it
|
2004-07-31 17:57:18 +02:00
|
|
|
void CMapReader::ApplyData(CFileUnpacker& unpacker, CTerrain *pTerrain, CUnitManager *pUnitMan, CLightEnv *pLightEnv)
|
2004-05-29 22:56:24 +02:00
|
|
|
{
|
|
|
|
// initialise the terrain
|
2004-07-31 17:57:18 +02:00
|
|
|
pTerrain->Initialize(m_MapSize,&m_Heightmap[0]);
|
2004-05-29 22:56:24 +02:00
|
|
|
|
|
|
|
// setup the textures on the minipatches
|
|
|
|
STileDesc* tileptr=&m_Tiles[0];
|
|
|
|
for (u32 j=0;j<m_MapSize;j++) {
|
|
|
|
for (u32 i=0;i<m_MapSize;i++) {
|
|
|
|
for (u32 m=0;m<PATCH_SIZE;m++) {
|
|
|
|
for (u32 k=0;k<PATCH_SIZE;k++) {
|
2004-07-31 17:57:18 +02:00
|
|
|
CMiniPatch& mp=pTerrain->GetPatch(i,j)->m_MiniPatches[m][k];
|
2004-05-29 22:56:24 +02:00
|
|
|
|
|
|
|
mp.Tex1=m_TerrainTextures[tileptr->m_Tex1Index];
|
|
|
|
mp.Tex1Priority=tileptr->m_Priority;
|
|
|
|
|
|
|
|
tileptr++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// empty out existing units
|
2004-07-31 17:57:18 +02:00
|
|
|
pUnitMan->DeleteAll();
|
2004-05-29 22:56:24 +02:00
|
|
|
|
|
|
|
// add new objects
|
|
|
|
for (u32 i=0;i<m_Objects.size();i++) {
|
|
|
|
CObjectEntry* objentry=m_ObjectTypes[m_Objects[i].m_ObjectIndex];
|
|
|
|
if (objentry && objentry->m_Model) {
|
|
|
|
|
2005-01-12 15:31:47 +01:00
|
|
|
if (unpacker.GetVersion() < 3) {
|
|
|
|
|
|
|
|
// Hijack the standard actor instantiation for actors that correspond to entities.
|
|
|
|
// Not an ideal solution; we'll have to figure out a map format that can define entities separately or somesuch.
|
|
|
|
|
|
|
|
CBaseEntity* templateObject = g_EntityTemplateCollection.getTemplateByActor(objentry);
|
2004-07-31 17:57:18 +02:00
|
|
|
|
2005-01-12 15:31:47 +01:00
|
|
|
if (templateObject)
|
|
|
|
{
|
|
|
|
CVector3D orient = ((CMatrix3D*)m_Objects[i].m_Transform)->GetIn();
|
|
|
|
CVector3D position = ((CMatrix3D*)m_Objects[i].m_Transform)->GetTranslation();
|
2004-05-29 22:56:24 +02:00
|
|
|
|
2005-01-12 15:31:47 +01:00
|
|
|
g_EntityManager.create(templateObject, position, atan2(-orient.X, -orient.Z));
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
2004-05-29 22:56:24 +02:00
|
|
|
}
|
2005-01-12 15:31:47 +01:00
|
|
|
|
|
|
|
CUnit* unit=new CUnit(objentry,objentry->m_Model->Clone());
|
2004-05-29 22:56:24 +02:00
|
|
|
|
2005-01-12 15:31:47 +01:00
|
|
|
CMatrix3D transform;
|
|
|
|
memcpy(&transform._11,m_Objects[i].m_Transform,sizeof(float)*16);
|
|
|
|
unit->GetModel()->SetTransform(transform);
|
|
|
|
|
|
|
|
// add this unit to list of units stored in unit manager
|
|
|
|
pUnitMan->AddUnit(unit);
|
2004-05-29 22:56:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unpacker.GetVersion()>=2) {
|
|
|
|
// copy over the lighting parameters
|
2004-07-31 17:57:18 +02:00
|
|
|
*pLightEnv=m_LightEnv;
|
2004-05-29 22:56:24 +02:00
|
|
|
}
|
|
|
|
}
|
2005-01-12 15:31:47 +01:00
|
|
|
|
|
|
|
|
|
|
|
void CMapReader::ReadXML(const char* filename)
|
|
|
|
{
|
|
|
|
#ifdef SCED
|
|
|
|
// HACK: ScEd uses absolute filenames, not VFS paths. I can't be bothered
|
|
|
|
// to make Xeromyces work with non-VFS, so just cheat:
|
|
|
|
CStr filename_vfs (filename);
|
|
|
|
filename_vfs = filename_vfs.substr(filename_vfs.ReverseFind("\\mods\\official\\") + 15);
|
|
|
|
filename_vfs.Replace("\\", "/");
|
|
|
|
filename = filename_vfs;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
CXeromyces XeroFile;
|
|
|
|
if (XeroFile.Load(filename) != PSRETURN_OK)
|
|
|
|
throw CFileUnpacker::CFileReadError();
|
|
|
|
|
|
|
|
// Define all the elements and attributes used in the XML file
|
|
|
|
#define EL(x) int el_##x = XeroFile.getElementID(#x)
|
|
|
|
#define AT(x) int at_##x = XeroFile.getAttributeID(#x)
|
|
|
|
EL(scenario);
|
|
|
|
EL(entities);
|
|
|
|
EL(entity);
|
|
|
|
EL(template);
|
2005-01-17 00:09:41 +01:00
|
|
|
EL(player);
|
2005-01-12 15:31:47 +01:00
|
|
|
EL(position);
|
|
|
|
EL(orientation);
|
|
|
|
AT(x);
|
|
|
|
AT(y);
|
|
|
|
AT(z);
|
|
|
|
AT(angle);
|
|
|
|
#undef AT
|
|
|
|
#undef EL
|
|
|
|
|
|
|
|
XMBElement root = XeroFile.getRoot();
|
|
|
|
assert(root.getNodeName() == el_scenario);
|
|
|
|
|
|
|
|
// <scenario>
|
|
|
|
|
|
|
|
XMBElementList children = root.getChildNodes();
|
|
|
|
for (int i = 0; i < children.Count; ++i)
|
|
|
|
{
|
|
|
|
XMBElement child = children.item(i);
|
|
|
|
if (child.getNodeName() == el_entities)
|
|
|
|
{
|
|
|
|
// <entities>
|
|
|
|
|
|
|
|
XMBElementList children = child.getChildNodes();
|
|
|
|
for (int i = 0; i < children.Count; ++i)
|
|
|
|
{
|
|
|
|
XMBElement child = children.item(i);
|
|
|
|
assert(child.getNodeName() == el_entity);
|
|
|
|
|
|
|
|
// <entity>
|
|
|
|
|
|
|
|
CStrW TemplateName;
|
2005-01-17 00:09:41 +01:00
|
|
|
int PlayerID;
|
2005-01-12 15:31:47 +01:00
|
|
|
CVector3D Position;
|
|
|
|
float Orientation;
|
|
|
|
|
|
|
|
XMBElementList children = child.getChildNodes();
|
|
|
|
for (int i = 0; i < children.Count; ++i)
|
|
|
|
{
|
|
|
|
XMBElement child = children.item(i);
|
|
|
|
int element_name = child.getNodeName();
|
|
|
|
|
|
|
|
if (element_name == el_template)
|
|
|
|
{
|
|
|
|
// <template>
|
|
|
|
TemplateName = child.getText();
|
|
|
|
}
|
2005-01-17 00:09:41 +01:00
|
|
|
else if (element_name == el_player)
|
|
|
|
{
|
|
|
|
// <player>
|
|
|
|
PlayerID = CStr(child.getText()).ToInt();
|
|
|
|
}
|
2005-01-12 15:31:47 +01:00
|
|
|
else if (element_name == el_position)
|
|
|
|
{
|
|
|
|
// <position>
|
|
|
|
XMBAttributeList attrs = child.getAttributes();
|
|
|
|
Position = CVector3D(
|
|
|
|
CStr(attrs.getNamedItem(at_x)).ToFloat(),
|
|
|
|
CStr(attrs.getNamedItem(at_y)).ToFloat(),
|
|
|
|
CStr(attrs.getNamedItem(at_z)).ToFloat()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
else if (element_name == el_orientation)
|
|
|
|
{
|
|
|
|
// <orientation>
|
|
|
|
XMBAttributeList attrs = child.getAttributes();
|
|
|
|
Orientation = CStr(attrs.getNamedItem(at_angle)).ToFloat();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
debug_warn("Invalid XML data - DTD shouldn't allow this");
|
|
|
|
}
|
|
|
|
|
2005-01-17 00:09:41 +01:00
|
|
|
HEntity ent = g_EntityManager.create(g_EntityTemplateCollection.getTemplate(TemplateName), Position, Orientation);
|
2005-01-18 13:45:56 +01:00
|
|
|
|
|
|
|
#ifdef SCED // HACK: ScEd doesn't have a g_Game, so we can't use its CPlayers
|
2005-01-23 22:56:47 +01:00
|
|
|
ent->SetPlayer( (CPlayer*)(intptr_t)PlayerID );
|
2005-01-18 13:45:56 +01:00
|
|
|
#else
|
2005-01-23 22:56:47 +01:00
|
|
|
ent->SetPlayer( g_Game->GetPlayer( PlayerID ) );
|
2005-01-18 13:45:56 +01:00
|
|
|
#endif
|
2005-01-12 15:31:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
debug_warn("Invalid XML data - DTD shouldn't allow this");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|