2 * This file is part of ShapeFusion (Copyright 2000 Tito Dal Canton)
4 * ShapeFusion is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * ShapeFusion is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with ShapeFusion; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 // For compilers that support precompilation, includes "wx/wx.h".
20 #include "wx/wxprec.h"
26 #if wxUSE_STD_IOSTREAM
27 #include "wx/ioswrap.h"
29 #include "wx/txtstrm.h"
32 #include "../BigEndianBuffer.h"
33 #include "PhysicsDocument.h"
35 #define FOUR_CHARS_TO_INT(a,b,c,d) (((unsigned int)(a) << 24) | ((unsigned int)(b) << 16) | ((unsigned int)(c) << 8) | (unsigned int)(d))
37 IMPLEMENT_DYNAMIC_CLASS(PhysicsDocument, wxDocument)
39 PhysicsDocument::PhysicsDocument() : wxDocument(), PhysicsElement(true)
44 PhysicsDocument::~PhysicsDocument()
48 bool PhysicsDocument::DoOpenDocument(const wxString& file)
50 bool wxOpen = wxDocument::DoOpenDocument(file);
52 if (!(wxOpen && mGoodData)) {
53 wxLogError(wxT("[PhysicsDocument] There was an error while opening, see log"));
59 #if wxUSE_STD_IOSTREAM
60 wxSTD istream& PhysicsDocument::LoadObject(wxSTD istream& stream)
62 wxInputStream& PhysicsDocument::LoadObject(wxInputStream& stream)
65 // validate the wad header, load the first wad
66 BigEndianBuffer wad_header(128);
67 #if wxUSE_STD_IOSTREAM
68 stream.read((char *)wad_header.Data(), wad_header.Size());
70 stream.Read((char *)wad_header.Data(), wad_header.Size());
73 int version = wad_header.ReadShort();
74 int data_version = wad_header.ReadShort();
76 if (!(version == 1 || version == 2) || !(data_version == 0 || data_version == 1)) {
77 wxLogError(wxT("[PhysicsDocument] Error loading: Incorrect version/data version (%i/%i)"), version, data_version);
81 wad_header.ReadBlock(MAXIMUM_WADFILE_NAME_LENGTH, wadfile_name);
83 // skip to the directory offset and wad count
84 wad_header.Position(72);
86 long directory_offset = wad_header.ReadLong();
87 int wad_count = wad_header.ReadShort();
88 wad_header.ReadShort(); // application specific directory data size
89 int entry_header_size = wad_header.ReadShort();
92 wxLogError(wxT("[PhysicsDocument] Error loading: wad count must be 1"));
96 // jump to the directory and read the offset of the first (and
97 // hopefully only) wad
98 BigEndianBuffer directory_entry(10);
99 #if wxUSE_STD_IOSTREAM
100 stream.seekg(directory_offset, std::ios::beg);
101 stream.read((char *) directory_entry.Data(), directory_entry.Size());
103 stream.SeekI(directory_offset, wxFromStart);
104 stream.Read((char *) directory_entry.Data(), directory_entry.Size());
106 long wad_offset = directory_entry.ReadLong();
107 directory_entry.ReadLong(); // wad_size
108 int wad_index = directory_entry.ReadShort();
110 if (wad_index != 0) {
111 wxLogError(wxT("[PhysicsDocument] Error loading: first wad index must be 0"));
115 long next_offset = 0;
119 BigEndianBuffer entry_header(entry_header_size);
120 #if wxUSE_STD_IOSTREAM
121 stream.seekg(next_offset + wad_offset, std::ios::beg);
122 stream.read((char *) entry_header.Data(), entry_header.Size());
124 stream.SeekI(next_offset + wad_offset, wxFromStart);
125 stream.Read((char *) entry_header.Data(), entry_header.Size());
127 unsigned long tag = entry_header.ReadULong();
128 next_offset = entry_header.ReadLong();
129 long entry_size = entry_header.ReadLong();
131 BigEndianBuffer tag_data(entry_size);
132 #if wxUSE_STD_IOSTREAM
133 stream.read((char *) tag_data.Data(), tag_data.Size());
135 stream.Read((char *) tag_data.Data(), tag_data.Size());
140 case FOUR_CHARS_TO_INT('M','N','p','x'): {
141 int count = tag_data.Size() / MonsterDefinition::kSize;
142 mMonsterDefinitions.resize(count);
143 for (int i = 0; i < count; ++i) {
144 mMonsterDefinitions[i].LoadObject(tag_data);
145 if (!mMonsterDefinitions[i].IsGood()) {
151 case FOUR_CHARS_TO_INT('F','X','p','x'): {
152 int count = tag_data.Size() / EffectDefinition::kSize;
153 mEffectDefinitions.resize(count);
154 for (int i = 0; i < count; ++i) {
155 mEffectDefinitions[i].LoadObject(tag_data);
156 if (!mEffectDefinitions[i].IsGood()) {
162 case FOUR_CHARS_TO_INT('P','R','p','x'): {
163 int count = tag_data.Size() / ProjectileDefinition::kSize;
164 mProjectileDefinitions.resize(count);
165 for (int i = 0; i < count; ++i) {
166 mProjectileDefinitions[i].LoadObject(tag_data);
167 if (!mProjectileDefinitions[i].IsGood()) {
173 case FOUR_CHARS_TO_INT('P','X','p','x'): {
174 int count = tag_data.Size() / PhysicsConstants::kSize;
175 mConstants.resize(2);
176 for (int i = 0; i < count; ++i) {
177 mConstants[i].LoadObject(tag_data);
178 if (!mConstants[i].IsGood()) {
184 case FOUR_CHARS_TO_INT('W','P','p','x'): {
185 int count = tag_data.Size() / WeaponDefinition::kSize;
186 mWeaponDefinitions.resize(count);
187 for (int i = 0; i < count; ++i) {
188 mWeaponDefinitions[i].LoadObject(tag_data);
189 if (!mWeaponDefinitions[i].IsGood()) {
196 } while (next_offset);
198 if (mConstants.size() && mMonsterDefinitions.size() && mEffectDefinitions.size() && mProjectileDefinitions.size() && mWeaponDefinitions.size()) {
206 void PhysicsDocument::WriteTag(BigEndianBuffer& buffer, long& offset, unsigned long tag, const std::vector<T>& data, bool last)
208 long entry_size = T::kSize * data.size();
209 offset += entry_size + kEntryHeaderSize;
211 buffer.WriteULong(tag);
212 buffer.WriteLong(last ? 0 : offset);
213 buffer.WriteLong(entry_size);
216 for (typename std::vector<T>::const_iterator it = data.begin(); it != data.end(); ++it) {
217 it->SaveObject(buffer);
222 #if wxUSE_STD_IOSTREAM
223 wxSTD ostream& PhysicsDocument::SaveObject(wxSTD ostream& stream)
225 wxOutputStream& PhysicsDocument::SaveObject(wxOutputStream& stream)
228 unsigned long filesize = SizeInFile();
229 BigEndianBuffer buffer(filesize);
232 buffer.WriteShort(2); // version
233 buffer.WriteShort(0); // data version
234 buffer.WriteBlock(MAXIMUM_WADFILE_NAME_LENGTH, wadfile_name);
235 buffer.WriteULong(0); // blank checksum
236 buffer.WriteLong(filesize - 10); // directory offset
237 buffer.WriteShort(1); // wad count
238 buffer.WriteShort(0); // application specific data size
239 buffer.WriteShort(kEntryHeaderSize); // entry header size
240 buffer.WriteShort(10); // directory entry size
241 buffer.WriteLong(0); // parent checksum
242 buffer.WriteZeroes(40); // unused
245 long next_offset = 0;
246 WriteTag(buffer, next_offset, FOUR_CHARS_TO_INT('M','N','p','x'), mMonsterDefinitions);
247 WriteTag(buffer, next_offset, FOUR_CHARS_TO_INT('F','X','p','x'), mEffectDefinitions);
248 WriteTag(buffer, next_offset, FOUR_CHARS_TO_INT('P','R','p','x'), mProjectileDefinitions);
249 WriteTag(buffer, next_offset, FOUR_CHARS_TO_INT('P','X','p','x'), mConstants);
250 WriteTag(buffer, next_offset, FOUR_CHARS_TO_INT('W','P','p','x'), mWeaponDefinitions, true);
253 buffer.WriteLong(128);
254 buffer.WriteLong(filesize - 128 - 10);
255 buffer.WriteShort(0);
258 buffer.WriteULong(buffer.CalculateCRC());
260 #if wxUSE_STD_IOSTREAM
261 stream.write(reinterpret_cast<char *>(buffer.Data()), buffer.Size());
263 stream.Write(reinterpret_cast<char *>(buffer.Data()), buffer.Size());
269 unsigned long PhysicsDocument::SizeInFile()
271 unsigned long size = 0;
272 size += 128; // wad header
274 size += kEntryHeaderSize;
275 size += MonsterDefinition::kSize * mMonsterDefinitions.size();
277 size += kEntryHeaderSize;
278 size += EffectDefinition::kSize * mEffectDefinitions.size();
280 size += kEntryHeaderSize;
281 size += ProjectileDefinition::kSize * mProjectileDefinitions.size();
283 size += kEntryHeaderSize;
284 size += PhysicsConstants::kSize * mConstants.size();
286 size += kEntryHeaderSize;
287 size += WeaponDefinition::kSize * mWeaponDefinitions.size();
289 size += 10; // directory entry