1
0
forked from 0ad/0ad

Made ScEd output entities into an XML file.

Added CStrW::utf8() (used by XMLWriter).

This was SVN commit r1716.
This commit is contained in:
Ykkrosh 2005-01-12 14:31:47 +00:00
parent 570e3c46d7
commit 4720a00f98
21 changed files with 407 additions and 76 deletions

View File

@ -0,0 +1,19 @@
<!ELEMENT Scenario (Entities)>
<!ELEMENT Entities (Entity*)>
<!ELEMENT Entity (Template,Position,Orientation)>
<!ELEMENT Template (#PCDATA)>
<!ELEMENT Position EMPTY>
<!ATTLIST Position
x CDATA #REQUIRED
y CDATA #REQUIRED
z CDATA #REQUIRED
>
<!ELEMENT Orientation EMPTY>
<!ATTLIST Orientation
angle CDATA #REQUIRED
>

View File

@ -5,7 +5,7 @@ class CMapIO
{
public:
// current file version given to saved maps
enum { FILE_VERSION = 2 };
enum { FILE_VERSION = 3 };
// supported file read version - file with version less than this will be reject
enum { FILE_READ_VERSION = 1 };

View File

@ -32,8 +32,15 @@ void CMapReader::LoadMap(const char* filename, CTerrain *pTerrain, CUnitManager
// unpack the data
UnpackMap(unpacker);
// finally, apply data to the world
// apply data to the world
ApplyData(unpacker, pTerrain, pUnitMan, pLightEnv);
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);
}
}
// UnpackMap: unpack the given data from the raw data stream into local variables
@ -148,29 +155,33 @@ void CMapReader::ApplyData(CFileUnpacker& unpacker, CTerrain *pTerrain, CUnitMan
for (u32 i=0;i<m_Objects.size();i++) {
CObjectEntry* objentry=m_ObjectTypes[m_Objects[i].m_ObjectIndex];
if (objentry && objentry->m_Model) {
// 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 );
if( templateObject )
{
CVector3D orient = ((CMatrix3D*)m_Objects[i].m_Transform)->GetIn();
CVector3D position = ((CMatrix3D*)m_Objects[i].m_Transform)->GetTranslation();
g_EntityManager.create( templateObject, position, atan2( -orient.X, -orient.Z ) );
}
else
{
CUnit* unit=new CUnit(objentry,objentry->m_Model->Clone());
CMatrix3D transform;
memcpy(&transform._11,m_Objects[i].m_Transform,sizeof(float)*16);
unit->GetModel()->SetTransform(transform);
if (unpacker.GetVersion() < 3) {
// add this unit to list of units stored in unit manager
pUnitMan->AddUnit(unit);
// 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);
if (templateObject)
{
CVector3D orient = ((CMatrix3D*)m_Objects[i].m_Transform)->GetIn();
CVector3D position = ((CMatrix3D*)m_Objects[i].m_Transform)->GetTranslation();
g_EntityManager.create(templateObject, position, atan2(-orient.X, -orient.Z));
continue;
}
}
CUnit* unit=new CUnit(objentry,objentry->m_Model->Clone());
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);
}
}
@ -179,3 +190,102 @@ void CMapReader::ApplyData(CFileUnpacker& unpacker, CTerrain *pTerrain, CUnitMan
*pLightEnv=m_LightEnv;
}
}
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);
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;
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();
}
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");
}
g_EntityManager.create(g_EntityTemplateCollection.getTemplate(TemplateName), Position, Orientation);
}
}
else
{
debug_warn("Invalid XML data - DTD shouldn't allow this");
}
}
}

View File

@ -33,6 +33,9 @@ private:
// ApplyData: take all the input data, and rebuild the scene from it
void ApplyData(CFileUnpacker& unpacker, CTerrain *pTerrain, CUnitManager *pUnitMan, CLightEnv *pLightEnv);
// ReadXML: read some other data (entities, etc) in XML format
void ReadXML(const char* filename);
// size of map
u32 m_MapSize;
// heightmap for map

View File

@ -10,6 +10,12 @@
#include "LightEnv.h"
#include "TextureManager.h"
#include "ps/XMLWriter.h"
#include "lib/res/vfs.h"
#include "simulation/Entity.h"
#include "simulation/BaseEntity.h"
#include "simulation/BaseEntityCollection.h"
///////////////////////////////////////////////////////////////////////////////////////////////////
// CMapWriter constructor: nothing to do at the minute
CMapWriter::CMapWriter()
@ -27,6 +33,10 @@ void CMapWriter::SaveMap(const char* filename, CTerrain *pTerrain, CLightEnv *pL
// write it out
packer.Write(filename);
CStr filename_xml (filename);
filename_xml = filename_xml.Left(filename_xml.Length()-4) + ".xml";
WriteXML(filename_xml, pUnitMan);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
@ -118,22 +128,29 @@ void CMapWriter::EnumObjects(CUnitManager *pUnitMan,
// resize object array to required size
const std::vector<CUnit*>& units=pUnitMan->GetUnits();
objects.resize(units.size());
SObjectDesc* objptr=&objects[0];
objects.clear();
objects.reserve(units.size()); // slightly larger than necessary (if there are some entities)
// now iterate through all the units
for (u32 j=0;j<(u32)units.size();j++) {
for (size_t j=0;j<units.size();j++) {
CUnit* unit=units[j];
// Ignore entities, since they're outputted to XML instead
if (unit->GetEntity())
continue;
u16 index=u16(GetObjectIndex(unit->GetObject(),objectsInUse));
if (index==0xffff) {
index=(u16)objectsInUse.size();
objectsInUse.push_back(unit->GetObject());
}
objptr->m_ObjectIndex=index;
memcpy(objptr->m_Transform,&unit->GetModel()->GetTransform()._11,sizeof(float)*16);
objptr++;
SObjectDesc obj;
obj.m_ObjectIndex=index;
memcpy(obj.m_Transform,&unit->GetModel()->GetTransform()._11,sizeof(float)*16);
objects.push_back(obj);
}
// now build outgoing objectTypes array
@ -220,3 +237,77 @@ void CMapWriter::PackTerrain(CFilePacker& packer, CTerrain *pTerrain)
packer.PackRaw(&tiles[0],(u32)(sizeof(STileDesc)*tiles.size()));
}
void CMapWriter::WriteXML(const char* filename, CUnitManager* pUnitMan)
{
// HACK: ScEd uses non-VFS filenames, so just use fopen instead of vfs_open
#ifdef SCED
FILE* f = fopen(filename, "wb");
if (! f)
{
debug_warn("Failed to open map XML file");
return;
}
#else
Handle h = vfs_open(filename, FILE_WRITE|FILE_NO_AIO);
if (h <= 0)
{
debug_warn("Failed to open map XML file");
return;
}
#endif
XML_Start("utf-8");
XML_Doctype("Scenario", "/maps/scenario.dtd");
{
XML_Element("Scenario");
{
XML_Element("Entities");
const std::vector<CUnit*>& units = pUnitMan->GetUnits();
for (std::vector<CUnit*>::const_iterator unit = units.begin(); unit != units.end(); ++unit) {
CEntity* entity = (*unit)->GetEntity();
// Ignore objects that aren't entities
if (! entity)
continue;
XML_Element("Entity");
XML_Setting("Template", entity->m_base->m_Tag);
{
CVector3D position = entity->m_position;
XML_Element("Position");
XML_Attribute("x", position.X);
XML_Attribute("y", position.Y);
XML_Attribute("z", position.Z);
}
{
float angle = entity->m_orientation;
XML_Element("Orientation");
XML_Attribute("angle", angle);
}
}
}
}
// HACK: continued from above
#ifdef SCED
CStr d = xml_file_.HACK_GetData();
fwrite(d.data(), d.length(), 1, f);
fclose(f);
#else
if (! XML_StoreVFS(h))
{
debug_warn("Failed to write map XML file");
}
vfs_close(h);
#endif
}

View File

@ -37,6 +37,9 @@ private:
// each object in the world
void EnumObjects(CUnitManager *pUnitMan, std::vector<CStr>& objectTypes,
std::vector<SObjectDesc>& objects);
// WriteXML: output some other data (entities, etc) in XML format
void WriteXML(const char* filename, CUnitManager* pUnitMan);
};
#endif

View File

@ -80,16 +80,24 @@ bool CObjectEntry::BuildModel()
const char* animfilename = m_Animations[t].m_FileName.c_str();
m_Animations[t].m_AnimData = m_Model->BuildAnimation(animfilename,m_Animations[t].m_Speed);
if( m_Animations[t].m_AnimName.LowerCase() == "idle" )
CStr AnimNameLC = m_Animations[t].m_AnimName.LowerCase();
if( AnimNameLC == "idle" )
m_IdleAnim = m_Animations[t].m_AnimData;
if( m_Animations[t].m_AnimName.LowerCase() == "walk" )
else
if( AnimNameLC == "walk" )
m_WalkAnim = m_Animations[t].m_AnimData;
if( m_Animations[t].m_AnimName.LowerCase() == "attack" )
else
if( AnimNameLC == "attack" )
m_MeleeAnim = m_Animations[t].m_AnimData;
if( m_Animations[t].m_AnimName.LowerCase() == "death" )
else
if( AnimNameLC == "death" )
m_DeathAnim = m_Animations[t].m_AnimData;
if( m_Animations[t].m_AnimName.LowerCase() == "decay" )
else
if( AnimNameLC == "decay" )
m_CorpseAnim = m_Animations[t].m_AnimData;
//else
// debug_out("Invalid animation name '%s'\n", (const char*)AnimNameLC);
}
else
{

View File

@ -142,7 +142,7 @@ void CObjectManager::LoadObjects(int type)
pathname += m_ObjectTypes[type].m_Name;
pathname += "/";
Handle dir=vfs_open_dir(pathname.c_str());
Handle dir=vfs_open_dir(pathname);
vfsDirEnt dent;
if (dir > 0)

View File

@ -1345,6 +1345,8 @@ void ScEd_Init()
char path[512];
::GetModuleFileName(0,path,512);
g_Quickstart = true;
char* argv[1];
argv[0] = path;
Init(1, argv, false);

View File

@ -13,6 +13,40 @@
CStrW::CStrW(const CStr8 &asciStr) : std::wstring(asciStr.begin(), asciStr.end()) {}
CStr8::CStr8(const CStrW &wideStr) : std:: string(wideStr.begin(), wideStr.end()) {}
static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
CStr8 CStrW::utf8() const
{
// Adapted from http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.c
CStr8 result;
const wchar_t* source = &*begin();
for (size_t i = 0; i < Length(); ++i)
{
unsigned short bytesToWrite;
wchar_t ch = (*this)[i];
if (ch < 0x80) bytesToWrite = 1;
else if (ch < 0x800) bytesToWrite = 2;
else if (ch < 0x10000) bytesToWrite = 3;
else if (ch <= 0x7FFFFFFF) bytesToWrite = 4;
else bytesToWrite = 3, ch = 0x0000FFFD; // replacement character
char buf[4];
char* target = &buf[bytesToWrite];
switch (bytesToWrite)
{
case 4: *--target = ((ch | 0x80) & 0xBF); ch >>= 6;
case 3: *--target = ((ch | 0x80) & 0xBF); ch >>= 6;
case 2: *--target = ((ch | 0x80) & 0xBF); ch >>= 6;
case 1: *--target = (ch | firstByteMark[bytesToWrite]);
}
result += CStr(buf, bytesToWrite);
}
return result;
}
#else
#include "CStr.h"
@ -175,18 +209,18 @@ CStr CStr::UCase() const
}
// Retrieve the substring of the first n characters
CStr CStr::Left(long len) const
CStr CStr::Left(size_t len) const
{
assert(len >= 0);
assert(len <= (long)length());
assert(len <= length());
return substr(0, len);
}
// Retrieve the substring of the last n characters
CStr CStr::Right(long len) const
CStr CStr::Right(size_t len) const
{
assert(len >= 0);
assert(len <= (long)length());
assert(len <= length());
return substr(length()-len, len);
}

View File

@ -119,7 +119,8 @@ public:
CStr(utf16string String) : std::tstring(String.begin(), String.end()) {}
#endif
// Transparent CStrW/8 conversion.
// Transparent CStrW/8 conversion. Non-ASCII characters are not
// handled correctly.
#ifndef _UNICODE
CStr8(const CStrW &wideStr);
#else
@ -170,10 +171,10 @@ public:
CStr UCase() const;
// Retrieve the substring of the first n characters
CStr Left(long len) const;
CStr Left(size_t len) const;
// Retrieve the substring of the last n characters
CStr Right(long len) const;
CStr Right(size_t len) const;
// Remove all occurrences of some character or substring
void Remove(const CStr& Str);
@ -213,6 +214,11 @@ public:
// Conversion to utf16string
inline utf16string utf16() const
{ return utf16string(begin(), end()); }
// Conversion to UTF-8, encoded in a CStr8
#ifdef _UNICODE
CStr8 utf8() const;
#endif
// Calculates a hash of the string's contents
size_t GetHashCode() const;

View File

@ -15,7 +15,7 @@
////////////////////////////////////////////////////////////////////////////////
// CFileUnpacker: class to assist in reading of binary files
class CFileUnpacker
class CFileUnpacker
{
public:
// exceptions thrown by class

View File

@ -5,6 +5,9 @@
#include "ps/CLogger.h"
#include "lib/res/vfs.h"
// TODO: Write to the VFS handle all the time frequently, instead of buffering
// the entire file, so that large files get written faster.
enum { EL_ATTR, EL_TEXT, EL_SUBEL };
XMLWriter_File::XMLWriter_File(const char* encoding)
@ -152,4 +155,9 @@ template <> void XMLWriter_File::ElementAttribute<T>(const char* name, T& value,
TYPE(int)
TYPE(float)
TYPE(double)
TYPE(const char*)
TYPE(const char*)
template <> void XMLWriter_File::ElementAttribute<CStrW>(const char* name, CStrW& value, bool newelement)
{
ElementAttribute(name, value.utf8(), newelement);
}

View File

@ -92,6 +92,8 @@ public:
bool StoreVFS(Handle h);
CStr HACK_GetData() { return m_Data; }
private:
friend class XMLWriter_Element;

View File

@ -149,7 +149,12 @@ void CEntity::snapToGround()
{
CTerrain *pTerrain = g_Game->GetWorld()->GetTerrain();
#ifdef SCED
extern CTerrain g_Terrain;
m_graphics_position.Y = g_Terrain.getExactGroundLevel( m_graphics_position.X, m_graphics_position.Z );
#else
m_graphics_position.Y = pTerrain->getExactGroundLevel( m_graphics_position.X, m_graphics_position.Z );
#endif
}
void CEntity::update( size_t timestep )

View File

@ -134,7 +134,6 @@ void CEntityManager::destroy( u16 handle )
{
m_reaper.push_back( m_entities[handle].m_entity );
m_entities[handle].m_entity->me.m_handle = INVALID_HANDLE;
//delete( m_entities[handle].m_entity ); // PT: Don't delete here, because the reaper will kill it later
}
bool CEntityManager::m_extant = false;

View File

@ -2,6 +2,7 @@
#include "ps/CLogger.h"
#include "ps/Parser.h"
#include "ps/XMLWriter.h"
#define ensure(x) if (!(x)) { ++err_count; LOG(ERROR, "", "%s:%d - test failed! (%s)", __FILE__, __LINE__, #x); }
@ -96,4 +97,63 @@ void PerformTests()
LOG(ERROR, "", "%d test failures!", err_count);
debug_warn("Test failures!");
}
{
XML_Start("utf-8");
XML_Doctype("Scenario", "/maps/scenario.dtd");
{
XML_Element("Scenario");
{
XML_Comment("Comment test.");
XML_Comment("Comment test again.");
{
XML_Element("a");
XML_Attribute("one", 1);
XML_Attribute("two", "TWO");
XML_Text("b");
XML_Text(" (etc)");
}
{
XML_Element("c");
XML_Text("d");
}
XML_Setting("c2", "d2");
{
XML_Element("e");
{
{
XML_Element("f");
XML_Text("g");
}
{
XML_Element("h");
}
{
XML_Element("i");
XML_Attribute("j", 1.23);
{
XML_Element("k");
XML_Attribute("l", 2.34);
XML_Text("m");
}
}
}
}
}
}
// For this test to be useful, it should actually test something.
}
{
const wchar_t chr_utf16[] = { 0x12, 0xff, 0x1234, 0x3456, 0x5678, 0x7890, 0x9abc, 0xbcde, 0xfffe };
const unsigned char chr_utf8[] = { 0x12, 0xc3, 0xbf, 0xe1, 0x88, 0xb4, 0xe3, 0x91, 0x96, 0xe5, 0x99, 0xb8, 0xe7, 0xa2, 0x90, 0xe9, 0xaa, 0xbc, 0xeb, 0xb3, 0x9e, 0xef, 0xbf, 0xbe };
CStrW str_utf16 (chr_utf16, sizeof(chr_utf16)/sizeof(wchar_t));
CStr8 str_utf8 = str_utf16.utf8();
ensure(str_utf8.length() == sizeof(chr_utf8));
ensure(memcmp(str_utf8.data(), chr_utf8, sizeof(chr_utf8)) == 0);
}
}

View File

@ -187,29 +187,15 @@ void CEditorData::InitResources()
// InitSingletons: create and initialise required singletons
void CEditorData::InitSingletons()
{
// // create terrain related stuff
// new CTextureManager;
//
// // create actor related stuff
// new CSkeletonAnimManager;
// new CObjectManager;
// new CUnitManager;
//
// // create entity related stuff
// new CBaseEntityCollection;
// new CEntityManager;
// g_EntityTemplateCollection.loadTemplates();
new CEntityManager;
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// Init: perform one time initialisation of the editor
bool CEditorData::Init()
{
// // start up Xerces
// XMLPlatformUtils::Initialize();
//
// // create and initialise singletons
// InitSingletons();
// create and initialise singletons
InitSingletons();
// load default textures
InitResources();
@ -223,6 +209,8 @@ bool CEditorData::Init()
// set up the info box
m_InfoBox.Initialise();
g_EntityTemplateCollection.loadTemplates();
return true;
}
@ -230,20 +218,7 @@ bool CEditorData::Init()
// Terminate: close down the editor (destroy singletons in reverse order to construction)
void CEditorData::Terminate()
{
// // destroy entity related stuff
// delete CEntityManager::GetSingletonPtr();
// delete CBaseEntityCollection::GetSingletonPtr();
//
// // destroy actor related stuff
// delete CUnitManager::GetSingletonPtr();
// delete CObjectManager::GetSingletonPtr();
// delete CSkeletonAnimManager::GetSingletonPtr();
//
// // destroy terrain related stuff
// delete CTextureManager::GetSingletonPtr();
// close down Xerces
// XMLPlatformUtils::Terminate();
delete &g_EntityManager;
}
void CEditorData::InitCamera()
@ -636,6 +611,7 @@ bool CEditorData::LoadTerrain(const char* filename)
void CEditorData::UpdateWorld(float time)
{
if (m_Mode==SCENARIO_EDIT || m_Mode==TEST_MODE) {
g_EntityManager.interpolateAll(0.f);
const std::vector<CUnit*>& units=g_UnitMan.GetUnits();
for (uint i=0;i<units.size();++i) {
units[i]->GetModel()->Update(time);

View File

@ -41,7 +41,7 @@ void CPaintObjectCommand::Finalize()
CVector3D orient = m_Unit->GetModel()->GetTransform().GetIn();
CVector3D position = m_Unit->GetModel()->GetTransform().GetTranslation();
g_UnitMan.RemoveUnit(m_Unit);
g_EntityManager.create( templateObject, position, atan2( orient.X, orient.Z ) );
g_EntityManager.create( templateObject, position, atan2( -orient.X, -orient.Z ) );
}
}

View File

@ -62,6 +62,7 @@ void CPaintObjectTool::OnLButtonUp(unsigned int flags,int px,int py)
// terminate current command, if we've got one
if (m_PaintCmd) {
m_PaintCmd->Finalize();
if (! m_PaintCmd->IsUndoable()) delete m_PaintCmd;
m_PaintCmd=0;
m_Rotation=0;
}

View File

@ -580,10 +580,12 @@ void CMainFrame::OnFileSaveMap()
char buf[256];
sprintf(buf,"Error trying to write to \"%s\"",savename);
MessageBox(buf,"Error",MB_OK);
#ifdef NDEBUG
} catch (...) {
char buf[256];
sprintf(buf,"Error saving file \"%s\"",savename);
MessageBox(buf,"Error",MB_OK);
#endif
}
}
}
@ -645,10 +647,12 @@ void CMainFrame::OnFileLoadMap()
char buf[256];
sprintf(buf,"Error reading \"%s\" - doesn't seem to a PMP file",loadname);
MessageBox(buf,"Error",MB_OK);
#ifdef NDEBUG
} catch (...) {
char buf[256];
sprintf(buf,"Error loading file \"%s\"",loadname);
MessageBox(buf,"Error",MB_OK);
#endif
}
}
}