-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathlevel.cpp
407 lines (349 loc) · 11.1 KB
/
level.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
#include "core/dktypes.h"
#include "core/cmdlib.h"
#include "core/VirtualStream.h"
#include <nstd/String.hpp>
#include <nstd/File.hpp>
#include "regions_d1.h"
#include "regions_d2.h"
#include "textures.h"
#include "level.h"
//-------------------------------------------------------------
// Auto-detects level format
//-------------------------------------------------------------
ELevelFormat CDriverLevelLoader::DetectLevelFormat(IVirtualStream* pFile)
{
long curPos = pFile->Tell();
int lump_count = 255;
LUMP lump;
OUT_CITYLUMP_INFO cityLumps;
for (int i = 0; i < lump_count; i++)
{
// read lump info
pFile->Read(&lump, sizeof(LUMP), 1);
// stop marker
if (lump.type == 255)
break;
switch (lump.type)
{
case LUMP_PERMANENTPAGES:
MsgInfo("Detected old 'Driver 1 DEMO' LEV file\n");
pFile->Seek(curPos, VS_SEEK_SET);
return LEV_FORMAT_DRIVER1_OLD;
case LUMP_MODELS:
case LUMP_MAP:
case LUMP_TEXTURENAMES:
case LUMP_MODELNAMES:
case LUMP_LOWDETAILTABLE:
case LUMP_MOTIONCAPTURE:
case LUMP_OVERLAYMAP:
case LUMP_PALLET:
case LUMP_SPOOLINFO:
case LUMP_CHAIR:
case LUMP_CAR_MODELS:
case LUMP_TEXTUREINFO:
case LUMP_STRAIGHTS2:
case LUMP_CURVES2:
break;
case LUMP_JUNCTIONS2:
{
MsgInfo("Detected 'Driver 2 DEMO' 1.6 alpha LEV file\n");
pFile->Seek(curPos, VS_SEEK_SET);
return LEV_FORMAT_DRIVER2_ALPHA16; // as it is an old junction format - it's clearly a alpha 1.6 level
break;
}
case LUMP_JUNCTIONS2_NEW:
{
MsgInfo("Detected 'Driver 2' final LEV file\n");
pFile->Seek(curPos, VS_SEEK_SET);
return LEV_FORMAT_DRIVER2_RETAIL; // most recent LEV file
break;
}
case LUMP_LOADTIME_DATA:
case LUMP_INMEMORY_DATA:
break;
case LUMP_LUMPDESC:
{
int loadtime_data_ofs;
pFile->Read(&cityLumps, 1, sizeof(cityLumps));
pFile->Seek(cityLumps.inmem_offset, VS_SEEK_SET);
break;
}
case LUMP_ROADMAP:
case LUMP_ROADS:
case LUMP_JUNCTIONS:
case LUMP_ROADSURF:
case LUMP_ROADBOUNDS:
case LUMP_JUNCBOUNDS:
case LUMP_SUBDIVISION:
default: // maybe Lump 11?
{
MsgInfo("Detected 'Driver 1' LEV file\n");
pFile->Seek(curPos, VS_SEEK_SET);
return LEV_FORMAT_DRIVER1;
break;
}
}
if (lump.type == LUMP_LOADTIME_DATA ||
lump.type == LUMP_INMEMORY_DATA ||
lump.type == LUMP_LUMPDESC)
{
// restart
i = -1;
lump_count = 255;
continue;
}
// skip lump
pFile->Seek(lump.size, VS_SEEK_CUR);
// position alignment
if ((pFile->Tell() % 4) != 0)
pFile->Seek(4 - (pFile->Tell() % 4), VS_SEEK_CUR);
}
pFile->Seek(curPos, VS_SEEK_SET);
return LEV_FORMAT_INVALID;
}
//-------------------------------------------------------------
// Iterates LEV file lumps and loading data from them
//-------------------------------------------------------------
void CDriverLevelLoader::ProcessLumps(IVirtualStream* pFile)
{
int lump_count = 255; // Driver 2 difference: you not need to read lump count
// Driver 1 has lump count
if (m_format == LEV_FORMAT_DRIVER1)
pFile->Read(&lump_count, sizeof(int), 1);
LUMP lump;
for (int i = 0; i < lump_count; i++)
{
// read lump info
pFile->Read(&lump, sizeof(LUMP), 1);
// stop marker
if (lump.type == 255)
break;
int l_ofs = pFile->Tell();
switch (lump.type)
{
// Lumps shared between formats
// almost identical
case LUMP_PERMANENTPAGES:
if (m_textures)
m_textures->LoadPermanentTPagesD1Demo(pFile);
break;
case LUMP_MODELS:
DevMsg(SPEW_WARNING, "LUMP_MODELS ofs=%d size=%d\n", pFile->Tell(), lump.size);
if(m_models)
m_models->LoadLevelModelsLump(pFile);
break;
case LUMP_MAP:
DevMsg(SPEW_WARNING, "LUMP_MAP ofs=%d size=%d\n", pFile->Tell(), lump.size);
if(m_map)
m_map->LoadMapLump(pFile);
break;
case LUMP_TEXTURENAMES:
DevMsg(SPEW_WARNING, "LUMP_TEXTURENAMES ofs=%d size=%d\n", pFile->Tell(), lump.size);
if(m_textures)
m_textures->LoadTextureNamesLump(pFile, lump.size);
break;
case LUMP_MODELNAMES:
DevMsg(SPEW_WARNING, "LUMP_MODELNAMES ofs=%d size=%d\n", pFile->Tell(), lump.size);
if(m_models)
m_models->LoadModelNamesLump(pFile, lump.size);
break;
case LUMP_LOWDETAILTABLE:
if(m_models)
m_models->LoadLowDetailTableLump(pFile, lump.size);
DevMsg(SPEW_WARNING, "LUMP_LOWDETAILTABLE ofs=%d size=%d\n", pFile->Tell(), lump.size);
break;
case LUMP_MOTIONCAPTURE:
DevMsg(SPEW_WARNING, "LUMP_MOTIONCAPTURE ofs=%d size=%d\n", pFile->Tell(), lump.size);
break;
case LUMP_OVERLAYMAP:
DevMsg(SPEW_WARNING, "LUMP_OVERLAYMAP ofs=%d size=%d\n", pFile->Tell(), lump.size);
if(m_textures)
m_textures->LoadOverlayMapLump(pFile, lump.size);
break;
case LUMP_PALLET:
DevMsg(SPEW_WARNING, "LUMP_PALLET ofs=%d size=%d\n", pFile->Tell(), lump.size);
if(m_textures)
m_textures->LoadPalletLump(pFile);
break;
case LUMP_SPOOLINFO:
DevMsg(SPEW_WARNING, "LUMP_SPOOLINFO ofs=%d size=%d\n", pFile->Tell(), lump.size);
if(m_map)
m_map->LoadSpoolInfoLump(pFile);
break;
case LUMP_CHAIR:
DevMsg(SPEW_WARNING, "LUMP_CHAIR ofs=%d size=%d\n", pFile->Tell(), lump.size);
// TODO: get chairs
break;
case LUMP_CAR_MODELS:
DevMsg(SPEW_WARNING, "LUMP_CAR_MODELS ofs=%d size=%d\n", pFile->Tell(), lump.size);
if(m_models)
m_models->LoadCarModelsLump(pFile, lump.size);
break;
case LUMP_TEXTUREINFO:
DevMsg(SPEW_WARNING, "LUMP_TEXTUREINFO ofs=%d size=%d\n", pFile->Tell(), lump.size);
if(m_textures)
m_textures->LoadTextureInfoLump(pFile);
break;
// Driver 2 - only lumps
case LUMP_STRAIGHTS2:
DevMsg(SPEW_WARNING, "LUMP_STRAIGHTS2 ofs=%d size=%d\n", pFile->Tell(), lump.size);
if (m_map)
((CDriver2LevelMap*)m_map)->LoadStraightsLump(pFile);
break;
case LUMP_CURVES2:
DevMsg(SPEW_WARNING, "LUMP_CURVES2 ofs=%d size=%d\n", pFile->Tell(), lump.size);
if (m_map)
((CDriver2LevelMap*)m_map)->LoadCurvesLump(pFile);
break;
case LUMP_JUNCTIONS2:
DevMsg(SPEW_WARNING, "LUMP_JUNCTIONS2 ofs=%d size=%d\n", pFile->Tell(), lump.size);
if (m_map)
((CDriver2LevelMap*)m_map)->LoadJunctionsLump(pFile, true);
break;
case LUMP_JUNCTIONS2_NEW:
DevMsg(SPEW_WARNING, "LUMP_JUNCTIONS2_NEW ofs=%d size=%d\n", pFile->Tell(), lump.size);
if (m_map)
((CDriver2LevelMap*)m_map)->LoadJunctionsLump(pFile, false);
break;
// Driver 1 - only lumps
case LUMP_ROADMAP:
DevMsg(SPEW_WARNING, "LUMP_ROADMAP ofs=%d size=%d\n", pFile->Tell(), lump.size);
if (m_map)
((CDriver1LevelMap*)m_map)->LoadRoadMapLump(pFile);
break;
case LUMP_ROADS:
DevMsg(SPEW_WARNING, "LUMP_ROADS ofs=%d size=%d\n", pFile->Tell(), lump.size);
if (m_map)
((CDriver1LevelMap*)m_map)->LoadRoadsLump(pFile);
break;
case LUMP_JUNCTIONS:
DevMsg(SPEW_WARNING, "LUMP_JUNCTIONS ofs=%d size=%d\n", pFile->Tell(), lump.size);
if (m_map)
((CDriver1LevelMap*)m_map)->LoadJunctionsLump(pFile);
break;
case LUMP_ROADSURF:
DevMsg(SPEW_WARNING, "LUMP_ROADSURF ofs=%d size=%d\n", pFile->Tell(), lump.size);
if (m_map)
((CDriver1LevelMap*)m_map)->LoadRoadSurfaceLump(pFile, lump.size);
break;
case LUMP_ROADBOUNDS:
DevMsg(SPEW_WARNING, "LUMP_ROADBOUNDS ofs=%d size=%d\n", pFile->Tell(), lump.size);
if (m_map)
((CDriver1LevelMap*)m_map)->LoadRoadBoundsLump(pFile);
break;
case LUMP_JUNCBOUNDS:
DevMsg(SPEW_WARNING, "LUMP_JUNCBOUNDS ofs=%d size=%d\n", pFile->Tell(), lump.size);
if (m_map)
((CDriver1LevelMap*)m_map)->LoadJuncBoundsLump(pFile);
break;
case LUMP_SUBDIVISION:
DevMsg(SPEW_WARNING, "LUMP_SUBDIVISION ofs=%d size=%d\n", pFile->Tell(), lump.size);
break;
default:
DevMsg(SPEW_WARNING, "LUMP type: %d (0x%X) ofs=%d size=%d\n", lump.type, lump.type, pFile->Tell(), lump.size);
}
// seek back to initial position
pFile->Seek(l_ofs, VS_SEEK_SET);
// skip lump
pFile->Seek(lump.size, VS_SEEK_CUR);
// position alignment
if ((pFile->Tell() % 4) != 0)
pFile->Seek(4 - (pFile->Tell() % 4), VS_SEEK_CUR);
}
}
//---------------------------------------------------------------------------------------------------------------------------------
CDriverLevelLoader::CDriverLevelLoader()
{
}
CDriverLevelLoader::~CDriverLevelLoader()
{
Release();
}
ELevelFormat CDriverLevelLoader::GetFormat() const
{
return m_format;
}
void CDriverLevelLoader::Initialize(OUT_CITYLUMP_INFO& lumpInfo, CDriverLevelTextures* textures, CDriverLevelModels* models, CBaseLevelMap* map)
{
m_lumpInfo = &lumpInfo;
m_textures = textures;
m_models = models;
m_map = map;
m_map->Init(models, textures);
}
void CDriverLevelLoader::Release()
{
}
//-------------------------------------------------------------
// Loads the LEV file data
//-------------------------------------------------------------
bool CDriverLevelLoader::Load(IVirtualStream* pStream)
{
if (!pStream)
return false;
//-------------------------------------------------------------------
// perform auto-detection if format is not specified
if (m_format == LEV_FORMAT_AUTODETECT)
m_format = DetectLevelFormat(pStream);
if (m_map)
m_map->SetFormat(m_format);
if (m_textures)
m_textures->SetFormat(m_format);
if (m_format == LEV_FORMAT_DRIVER1_OLD)
{
ProcessLumps(pStream);
return true;
}
LUMP curLump;
pStream->Read(&curLump, sizeof(curLump), 1);
if (curLump.type != LUMP_LUMPDESC)
{
MsgError("Not a valid LEV file!\n");
return false;
}
// read chunk offsets
pStream->Read(m_lumpInfo, sizeof(OUT_CITYLUMP_INFO), 1);
DevMsg(SPEW_NORM, "data1_offset = %d\n", m_lumpInfo->loadtime_offset);
DevMsg(SPEW_NORM, "data1_size = %d\n", m_lumpInfo->loadtime_size);
DevMsg(SPEW_NORM, "tpage_offset = %d\n", m_lumpInfo->tpage_offset);
DevMsg(SPEW_NORM, "tpage_size = %d\n", m_lumpInfo->tpage_size);
DevMsg(SPEW_NORM, "data2_offset = %d\n", m_lumpInfo->inmem_offset);
DevMsg(SPEW_NORM, "data2_size = %d\n", m_lumpInfo->inmem_size);
DevMsg(SPEW_NORM, "spooled_offset = %d\n", m_lumpInfo->spooled_offset);
DevMsg(SPEW_NORM, "spooled_size = %d\n", m_lumpInfo->spooled_size);
// read cells
//-----------------------------------------------------
// seek to section 1 - lump data 1
pStream->Seek(m_lumpInfo->loadtime_offset, VS_SEEK_SET);
// read lump
pStream->Read(&curLump, sizeof(curLump), 1);
if (curLump.type != LUMP_LOADTIME_DATA)
{
MsgError("Not a LUMP_LOADTIME_DATA!\n");
return false;
}
DevMsg(SPEW_INFO, "entering LUMP_LOADTIME_DATA size = %d\n--------------\n", curLump.size);
// read sublumps
ProcessLumps(pStream);
//-----------------------------------------------------
// read global textures
if (m_textures)
{
pStream->Seek(m_lumpInfo->tpage_offset, VS_SEEK_SET);
m_textures->LoadPermanentTPages(pStream);
}
//-----------------------------------------------------
// seek to section 3 - lump data 2
pStream->Seek(m_lumpInfo->inmem_offset, VS_SEEK_SET);
// read lump
pStream->Read(&curLump, sizeof(curLump), 1);
if (curLump.type != LUMP_INMEMORY_DATA)
{
MsgError("Not a lump LUMP_INMEMORY_DATA!\n");
return false;
}
DevMsg(SPEW_INFO, "entering LUMP_INMEMORY_DATA size = %d\n--------------\n", curLump.size);
// read sublumps
ProcessLumps(pStream);
return true;
}