OSDN Git Service

イニシャルコミット。
[marathon/ShapeFusion.git] / Physics / PhysicsDocument.cpp
1 /*
2  * This file is part of ShapeFusion (Copyright 2000 Tito Dal Canton)
3  *
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.
8  *
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.
13  *
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
17 */
18
19 // For compilers that support precompilation, includes "wx/wx.h".
20 #include "wx/wxprec.h"
21
22 #ifndef WX_PRECOMP
23 #include "wx/wx.h"
24 #endif
25
26 #if wxUSE_STD_IOSTREAM
27     #include "wx/ioswrap.h"
28 #else
29     #include "wx/txtstrm.h"
30 #endif
31
32 #include "../BigEndianBuffer.h"
33 #include "PhysicsDocument.h"
34
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))
36
37 IMPLEMENT_DYNAMIC_CLASS(PhysicsDocument, wxDocument)
38
39 PhysicsDocument::PhysicsDocument() : wxDocument(), PhysicsElement(true)
40 {
41         mConstants.resize(2);
42 }
43
44 PhysicsDocument::~PhysicsDocument()
45 {
46 }
47
48 bool PhysicsDocument::DoOpenDocument(const wxString& file)
49 {
50         bool wxOpen = wxDocument::DoOpenDocument(file);
51
52         if (!(wxOpen && mGoodData)) {
53                 wxLogError(wxT("[PhysicsDocument] There was an error while opening, see log"));
54                 return false;
55         }
56         return true;
57 }
58
59 #if wxUSE_STD_IOSTREAM
60 wxSTD istream& PhysicsDocument::LoadObject(wxSTD istream& stream)
61 #else
62 wxInputStream& PhysicsDocument::LoadObject(wxInputStream& stream)
63 #endif
64 {
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());
69 #else
70         stream.Read((char *)wad_header.Data(), wad_header.Size());
71 #endif
72
73         int version = wad_header.ReadShort();
74         int data_version = wad_header.ReadShort();
75
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);
78                 return stream;
79         }
80
81         wad_header.ReadBlock(MAXIMUM_WADFILE_NAME_LENGTH, wadfile_name);
82
83         // skip to the directory offset and wad count
84         wad_header.Position(72);
85         
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();
90         
91         if (wad_count != 1) {
92                 wxLogError(wxT("[PhysicsDocument] Error loading: wad count must be 1"));
93                 return stream;
94         }
95
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());
102 #else
103         stream.SeekI(directory_offset, wxFromStart);
104         stream.Read((char *) directory_entry.Data(), directory_entry.Size());
105 #endif
106         long wad_offset = directory_entry.ReadLong();
107         directory_entry.ReadLong(); // wad_size
108         int wad_index = directory_entry.ReadShort();
109
110         if (wad_index != 0) {
111                 wxLogError(wxT("[PhysicsDocument] Error loading: first wad index must be 0"));
112                 return stream;
113         }
114
115         long next_offset = 0;
116
117         // read the tags
118         do {
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());
123 #else
124                 stream.SeekI(next_offset + wad_offset, wxFromStart);
125                 stream.Read((char *) entry_header.Data(), entry_header.Size());
126 #endif
127                 unsigned long tag = entry_header.ReadULong();
128                 next_offset = entry_header.ReadLong();
129                 long entry_size = entry_header.ReadLong();
130
131                 BigEndianBuffer tag_data(entry_size);           
132 #if wxUSE_STD_IOSTREAM
133                 stream.read((char *) tag_data.Data(), tag_data.Size());
134 #else
135                 stream.Read((char *) tag_data.Data(), tag_data.Size());
136 #endif
137
138                 switch (tag)
139                 {
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()) {
146                                         return stream;
147                                 }
148                         }
149                         break;
150                 }
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()) {
157                                         return stream;
158                                 }
159                         }
160                         break;
161                 }
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()) {
168                                         return stream;
169                                 }
170                         }
171                         break;
172                 }
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()) {
179                                         return stream;
180                                 }
181                         }
182                         break;
183                 }
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()) {
190                                         return stream;
191                                 }
192                         }
193                         break;
194                 }
195                 }
196         } while (next_offset);
197
198         if (mConstants.size() && mMonsterDefinitions.size() && mEffectDefinitions.size() && mProjectileDefinitions.size() && mWeaponDefinitions.size()) {
199                 mGoodData = true;
200         }
201
202         return stream;
203 }
204
205 template<class T> 
206 void PhysicsDocument::WriteTag(BigEndianBuffer& buffer, long& offset, unsigned long tag, const std::vector<T>& data, bool last)
207 {
208         long entry_size = T::kSize * data.size();
209         offset += entry_size + kEntryHeaderSize;
210
211         buffer.WriteULong(tag);
212         buffer.WriteLong(last ? 0 : offset);
213         buffer.WriteLong(entry_size);
214         buffer.WriteLong(0);
215
216         for (typename std::vector<T>::const_iterator it = data.begin(); it != data.end(); ++it) {
217                 it->SaveObject(buffer);
218         }
219
220 }
221
222 #if wxUSE_STD_IOSTREAM
223 wxSTD ostream& PhysicsDocument::SaveObject(wxSTD ostream& stream)
224 #else
225 wxOutputStream& PhysicsDocument::SaveObject(wxOutputStream& stream)
226 #endif
227 {
228         unsigned long filesize = SizeInFile();
229         BigEndianBuffer buffer(filesize);
230
231         // header
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
243
244         // tags
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);
251
252         // directory
253         buffer.WriteLong(128);
254         buffer.WriteLong(filesize - 128 - 10);
255         buffer.WriteShort(0);
256
257         buffer.Position(68);
258         buffer.WriteULong(buffer.CalculateCRC());
259
260 #if wxUSE_STD_IOSTREAM
261         stream.write(reinterpret_cast<char *>(buffer.Data()), buffer.Size());
262 #else
263         stream.Write(reinterpret_cast<char *>(buffer.Data()), buffer.Size());
264 #endif
265
266         return stream;
267 }
268
269 unsigned long PhysicsDocument::SizeInFile()
270 {
271         unsigned long size = 0;
272         size += 128; // wad header
273
274         size += kEntryHeaderSize;
275         size += MonsterDefinition::kSize * mMonsterDefinitions.size();
276         
277         size += kEntryHeaderSize;
278         size += EffectDefinition::kSize * mEffectDefinitions.size();
279         
280         size += kEntryHeaderSize;
281         size += ProjectileDefinition::kSize * mProjectileDefinitions.size();
282         
283         size += kEntryHeaderSize;
284         size += PhysicsConstants::kSize * mConstants.size();
285
286         size += kEntryHeaderSize;
287         size += WeaponDefinition::kSize * mWeaponDefinitions.size();
288
289         size += 10; // directory entry
290
291         return size;
292 }