bsp viewer
[tar-legacy.git] / MCDV / vbsp.hpp
1 #pragma once
2 #include <string>
3 #include <fstream>
4 #include <iostream>
5
6 #include "util.h"
7 #include "interpolation.h"
8
9 #include "generic.hpp"
10 #include "lumps_geometry.hpp"
11 #include "lumps_visibility.hpp"
12 #include "gamelump.hpp"
13
14 #include <glm\glm.hpp>
15 #include <glm\gtc\matrix_transform.hpp>
16 #include <glm\gtc\type_ptr.hpp>
17
18 namespace bsp {
19 #pragma pack(push, 1)
20
21 struct header {
22 unsigned int magicNum;
23 int version;
24 bsp::lumpHeader lumps[64];
25 int mapRevision;
26 };
27
28 #pragma pack(pop)
29 }
30
31 //Transfer structs
32 class basic_mesh {
33 public:
34 std::vector<glm::vec3> vertices;
35 std::vector<glm::vec3> normals;
36 std::vector<int> indices;
37 std::vector<glm::vec2> uvs;
38
39 void test_save_obj(std::string filepath)
40 {
41 std::ofstream outfile;
42 outfile.open(filepath);
43
44 outfile << "# test object from vbsp parser" << std::endl;
45 outfile << "# Written by Sven Monhof, adapted for c++ by Harry Godden" << std::endl;
46
47 for (int i = 0; i < vertices.size(); i++) {
48 glm::vec3 vert = vertices[i];
49 outfile << "v " << vert.x << " " << vert.y << " " << vert.z << std::endl;
50 }
51
52 for (int i = 0; i < normals.size(); i++) {
53 glm::vec3 normal = normals[i];
54 outfile << "vn " << normal.x << " " << normal.y << " " << normal.z << std::endl;
55 }
56
57 for (int i = 0; i < uvs.size(); i++) {
58 glm::vec2 uv = uvs[i];
59 outfile << "vt " << uv.x << " " << uv.y << std::endl;
60 }
61
62 for (int i = 0; i < indices.size() / 3; i++) {
63 int i1 = indices[i * 3 + 0] + 1;
64 int i2 = indices[i * 3 + 1] + 1;
65 int i3 = indices[i * 3 + 2] + 1;
66
67 outfile << "f " << i1 << "/" << i1 << "/" << i1 << " ";
68 outfile << i2 << "/" << i2 << "/" << i2 << " ";
69 outfile << i3 << "/" << i3 << "/" << i3 << std::endl;
70 }
71
72 outfile.close();
73 }
74 };
75
76 class vbsp_level : public util::verboseControl
77 {
78 private:
79 bsp::header header;
80
81 public:
82 // Geo
83 std::vector<bsp::plane> planes;
84 std::vector<bsp::vertex> vertices;
85 std::vector<bsp::edge> edges;
86 std::vector<int> surfEdges;
87 std::vector<bsp::face> faces;
88
89 std::vector<bsp::dispInfo> dispInfo;
90 std::vector<bsp::dispVert> dispVert;
91
92 // Tex info
93 std::vector<bsp::texinfo> texinfos;
94 std::vector<bsp::texdata> texdatas;
95 std::vector<std::string> texDataString;
96
97 // Vis
98 std::vector<vis::node> vis_nodes;
99 std::vector<vis::leaf> vis_leaves;
100 std::vector<vis::model> vis_models;
101
102 std::vector<unsigned short> vis_leaf_faces;
103 std::vector<unsigned short> vis_leafbrushes;
104
105 //Gamelump stuff
106 std::vector<bsp::dgamelump> gameLumps;
107 std::vector<std::string> mdlNamesDict;
108 std::vector<bsp::staticprop> staticProps;
109
110 vbsp_level(std::string path, bool verbose = false){
111 this->use_verbose = verbose;
112
113 //Create main file handle
114 std::ifstream reader(path, std::ios::in | std::ios::binary);
115
116 if (!reader) {
117 throw std::exception("VBSP::LOAD Failed"); return;
118 }
119
120 //Read header
121 reader.read((char*)&this->header, sizeof(this->header));
122 this->debug("Reading VBSP, file version:", this->header.version);
123
124
125 //==============================================================================
126 // Read lumps
127 this->debug("\n==== GEO LUMPS 1,3,12,13 ====\n");
128
129 this->planes = bsp::readPlanes(&reader, this->header.lumps[1]); //Planes
130 this->vertices = bsp::readVertices(&reader, this->header.lumps[3]); //Vertices
131 this->edges = bsp::readEdges(&reader, this->header.lumps[12]); //Edges
132 this->faces = bsp::readFaces(&reader, this->header.lumps[7]); //Faces
133 this->surfEdges = bsp::readLumpGeneric<int>(&reader, this->header.lumps[13]); //Surf edges
134 this->texinfos = bsp::readTexInfos(&reader, this->header.lumps[6]);
135 this->texdatas = bsp::readTexDatas(&reader, this->header.lumps[2]);
136 this->texDataString = this->readTexDataString(&reader, this->header.lumps[44], this->header.lumps[43]);
137
138 //Displacement
139 this->dispInfo = bsp::readLumpGeneric<bsp::dispInfo>(&reader, this->header.lumps[26]);
140 this->dispVert = bsp::readLumpGeneric<bsp::dispVert>(&reader, this->header.lumps[33]);
141
142
143 this->debug("Planes count:", this->planes.size());
144 this->debug("Vertices count:", this->vertices.size());
145 this->debug("Edges count:", this->edges.size());
146 this->debug("Faces count:", this->faces.size());
147 this->debug("SurfEdges count:", this->surfEdges.size());
148 this->debug("Texinfo count:", this->texinfos.size());
149 this->debug("Texdatas count:", this->texdatas.size());
150
151
152 //==============================================================================
153 // Vis lumps and BSP trees
154 this->debug("\n==== VIS LUMPS 5,10,14 ====\n");
155
156 this->vis_nodes = vis::readNodes(&reader, this->header.lumps[5]);
157 this->vis_leaves = vis::readLeaves(&reader, this->header.lumps[10]);
158 this->vis_models = vis::readModels(&reader, this->header.lumps[14]);
159 this->vis_leaf_faces = bsp::readLumpGeneric<unsigned short>(&reader, this->header.lumps[16]);
160
161 this->debug("Nodes:", this->vis_nodes.size());
162 this->debug("Leaves:", this->vis_leaves.size());
163 this->debug("Models:", this->vis_models.size());
164 this->debug("Leaf faces:", this->vis_leaf_faces.size());
165
166 //==============================================================================
167 // Game Lumps
168 this->debug("\n=== Game Lumps [35] ====\n");
169
170 this->gameLumps = bsp::readGameLumps(&reader, this->header.lumps[35]);
171
172 if (this->getGameLumpByID(0x73707270) != NULL) //sprp
173 this->staticProps = this->readStaticProps(&reader, *this->getGameLumpByID(0x73707270));
174
175 this->debug("Game lumps:", this->gameLumps.size());
176 this->debug("[0x73707270|'sprp'] Static props:", this->staticProps.size());
177
178 reader.close();
179 std::cout << "Load complete" << std::endl;
180 }
181
182 vbsp_level() {}
183
184 virtual ~vbsp_level() {}
185
186 //Mesh tools
187
188 //Get vertex index via surf edges
189 int getVertIndex(int i)
190 {
191 if (this->surfEdges[i] < 0)
192 return this->edges[this->surfEdges[i] * -1].vertex[1];
193 return this->edges[this->surfEdges[i]].vertex[0];
194 }
195
196 glm::vec2 getVertexUV(glm::vec3 pos, bsp::texinfo info)
197 {
198 glm::vec3 UVec = glm::vec3(info.textureVecs[0][0], info.textureVecs[0][1], info.textureVecs[0][2]);
199 glm::vec3 VVec = glm::vec3(info.textureVecs[1][0], info.textureVecs[1][1], info.textureVecs[1][2]);
200
201 float u = (glm::dot(UVec, pos) + info.textureVecs[0][3]) / this->texdatas[info.texdata].width;
202 float v = (glm::dot(VVec, pos) + info.textureVecs[1][3]) / this->texdatas[info.texdata].height;
203
204 return glm::vec2(u, v);
205 }
206
207 std::vector<bsp::staticprop> readStaticProps(std::ifstream* reader, bsp::dgamelump info)
208 {
209 reader->seekg(info.offset);
210
211 int ver = info.version;
212
213 //Read the dictionary size
214 int dictEntries = 0;
215 reader->read((char*)&dictEntries, sizeof(dictEntries));
216
217
218
219 //Read dictionary
220 for (int i = 0; i < dictEntries; i++) {
221 char source[128];
222
223 reader->read((char*)source, 128);
224
225 std::string mdlName;
226 for (int x = 0; x < 128; x++) {
227 if (source[x] == (char)0)
228 break;
229
230 mdlName += source[x];
231 }
232
233 this->mdlNamesDict.push_back(mdlName);
234 }
235
236 //Leaf array (just skip this its junk to us)
237 int leafEntries = 0;
238 reader->read((char*)&leafEntries, sizeof(leafEntries));
239 for (int i = 0; i < leafEntries; i++) {
240 unsigned short leaf = 0;
241 reader->read((char*)&leaf, sizeof(leaf));
242 }
243
244
245 //Read all the props and interpret based on the version
246 int numProps = 0;
247 reader->read((char*)&numProps, sizeof(numProps));
248
249 std::vector<bsp::staticprop> props;
250
251 for (int i = 0; i < numProps; i++) {
252
253 bsp::staticprop prop;
254 prop.version = ver;
255
256 //Read in version four stuff always
257 reader->read((char*)&prop.Origin, sizeof(prop.Origin));
258 reader->read((char*)&prop.angle, sizeof(prop.angle));
259
260 //Since 11+
261 if (ver >= 11)
262 reader->read((char*)&prop.uniformscale, sizeof(prop.uniformscale));
263
264 reader->read((char*)&prop.PropType, sizeof(prop.PropType));
265 reader->read((char*)&prop.FirstLeaf, sizeof(prop.FirstLeaf));
266 reader->read((char*)&prop.LeafCount, sizeof(prop.LeafCount));
267 reader->read((char*)&prop.solid, sizeof(prop.solid));
268 reader->read((char*)&prop.flags, sizeof(prop.flags));
269 reader->read((char*)&prop.skin, sizeof(prop.skin));
270 reader->read((char*)&prop.fademindist, sizeof(prop.fademindist));
271 reader->read((char*)&prop.fademaxdist, sizeof(prop.fademaxdist));
272 reader->read((char*)&prop.lightingorigin, sizeof(prop.lightingorigin));
273
274 //Since V5
275 if (ver >= 5)
276 reader->read((char*)&prop.forcedFadeScale, sizeof(prop.forcedFadeScale));
277
278 //V6 & V7
279 if (ver == 6 || ver == 7)
280 {
281 reader->read((char*)&prop.MinDXLevel, sizeof(prop.MinDXLevel));
282 reader->read((char*)&prop.MaxDXLevel, sizeof(prop.MaxDXLevel));
283 }
284
285 //V8+
286 if (ver >= 8)
287 {
288 reader->read((char*)&prop.MinCPULevel, sizeof(prop.MinCPULevel));
289 reader->read((char*)&prop.MaxCPULevel, sizeof(prop.MaxCPULevel));
290 reader->read((char*)&prop.MinGPULevel, sizeof(prop.MinGPULevel));
291 reader->read((char*)&prop.MaxGPULevel, sizeof(prop.MaxGPULevel));
292 }
293
294 //V7+
295 if (ver >= 7) {
296 reader->read((char*)&prop.diffuseModulation, 4);
297 }
298
299 //V10+
300 if (ver >= 10) {
301 reader->read((char*)&prop.unkown, sizeof(prop.unkown));
302 }
303
304 //V9+
305 if (ver >= 9) {
306 reader->read((char*)&prop.DisableDX360, sizeof(prop.DisableDX360));
307 }
308
309 //Set to the string instead of using dictionary
310 prop.mdlName = this->mdlNamesDict[prop.PropType];
311
312 props.push_back(prop);
313 }
314
315 return props;
316 }
317
318 std::string readString(std::ifstream* reader, bsp::lumpHeader info) {
319 reader->seekg(info.lumpOffset);
320 char* str = new char[info.lumpLength];
321
322 reader->read(str, info.lumpLength);
323 return str;
324 }
325
326 std::vector<std::string> readTexDataString(std::ifstream* reader, bsp::lumpHeader info, bsp::lumpHeader info2) {
327 int numIndexes = info.lumpLength / sizeof(int);
328 reader->seekg(info.lumpOffset);
329
330 std::vector<int> indexes = std::vector < int>();
331
332 for (int i = 0; i < numIndexes; i++) {
333 int index = 0;
334 reader->read((char*)&index, sizeof(index));
335
336 indexes.push_back(index);
337 }
338
339 char* texstr = new char[info2.lumpLength];
340
341 reader->seekg(info2.lumpOffset);
342 reader->read(texstr, info2.lumpLength);
343
344 std::vector<std::string> strings = std::vector<std::string>();
345
346 for (int i = 0; i < indexes.size(); i++) {
347 int pos = indexes[i];
348
349 std::string str = "";
350
351 while (true) {
352 char c = texstr[pos++];
353 if (c == (char)0x0)
354 break;
355 str += c;
356 }
357
358 strings.push_back(str);
359 }
360
361 return strings;
362 }
363
364 bsp::dgamelump* getGameLumpByID(int id) {
365 for (int i = 0; i < this->gameLumps.size(); i++) {
366 bsp::dgamelump lump = this->gameLumps[i];
367
368 if (lump.id == id) {
369 return &lump;
370 }
371 }
372
373 return NULL;
374 }
375
376 basic_mesh generate_mesh(int textureIndex) {
377 std::vector<bsp::face_fixed> faces_fixed;
378 std::vector<bsp::face_displacement> faces_disp;
379
380 //Prepare faces
381 for (int c_face_i = 0; c_face_i < faces.size(); c_face_i++)
382 {
383 bsp::face f = this->faces[c_face_i];
384
385 if (this->texinfos[f.texInfo].texdata != -1 && (textureIndex == -1 || textureIndex == this->texinfos[f.texInfo].texdata)) {
386 if (f.dispInfo == -1) {
387 bsp::face_fixed ff;
388 for (int i = 0; i < f.numEdges; ++i) {
389 bsp::vertex_fixed vf;
390 vf.position = vertices[this->getVertIndex(f.firstEdge + i)].position;
391 vf.UV = getVertexUV(vf.position, this->texinfos[f.texInfo]);
392 vf.normal_hard = this->planes[f.planeNum].normal;
393
394 ff.vertices.push_back(vf);
395 }
396
397 faces_fixed.push_back(ff);
398 }
399 else if (f.numEdges == 4) {
400 bsp::dispInfo info = this->dispInfo[f.dispInfo];
401 bsp::face_displacement fd(info.power);
402 glm::vec3 pos[4];
403 pos[0] = vertices[this->getVertIndex(f.firstEdge + 0)].position;
404 pos[1] = vertices[this->getVertIndex(f.firstEdge + 1)].position;
405 pos[2] = vertices[this->getVertIndex(f.firstEdge + 2)].position;
406 pos[3] = vertices[this->getVertIndex(f.firstEdge + 3)].position;
407 int iterator = 0;
408 while ((((pos[0].x - info.startPosition.x) > 0.25) ||
409 ((pos[0].y - info.startPosition.y) > 0.25) ||
410 ((pos[0].z - info.startPosition.z) > 0.25)) &&
411 iterator < 4) {
412 glm::vec3 temp = pos[0];
413 pos[0] = pos[1];
414 pos[1] = pos[2];
415 pos[2] = pos[3];
416 pos[3] = temp;
417 ++iterator;
418 }
419
420 for (int i = 0; i < fd.num_vertices; i++) {
421 bsp::vertex_fixed vf;
422 float x;
423 float y;
424 x = (float)((int)(i % (fd.power + 1)) / (float)(fd.power));
425 y = 1 - (float)((int)(i / fd.power + 1)) / (float)(fd.power);
426 glm::vec3 originalPosition = lerp(lerp(pos[1], pos[2], x), lerp(pos[0], pos[3], x), y);
427 if (info.dispVertStart + i >= this->dispVert.size() || info.dispVertStart + i < 0) {
428 vf.position = originalPosition;
429 }
430 else {
431 vf.position = dispVert[info.dispVertStart + i].vec*dispVert[info.dispVertStart + i].dist + originalPosition;
432 }
433
434 vf.UV = getVertexUV(vf.position, this->texinfos[f.texInfo]);
435 vf.normal_hard = planes[f.planeNum].normal;
436 vf.normalSource = NULL;
437 fd.vertices[i] = vf;
438 }
439 faces_disp.push_back(fd);
440 }
441 }
442 }
443
444 basic_mesh RV;
445
446 std::vector<glm::vec3> verts;
447 std::vector<glm::vec2> uvs;
448 std::vector<int> inds;
449 std::vector<glm::vec3> norms;
450
451 for (int fi = 0; fi < faces_fixed.size(); fi++) {
452 bsp::face_fixed f = faces_fixed[fi];
453
454 int i = verts.size();
455 if (i + f.vertices.size() >= USHRT_MAX) {
456 std::cout << "WARNING::HIT_VERTEX_LIMIT" << std::endl;
457 break;
458 }
459 for (int j = 0; j < f.vertices.size(); ++j) {
460 verts.push_back(f.vertices[j].position);
461 uvs.push_back(f.vertices[j].UV);
462
463 norms.push_back(f.vertices[j].normal_hard);
464
465 /*
466 if (f.vertices[j].normalSource == NULL) {
467 norms.push_back(f.vertices[j].normal_hard);
468 }
469 else {
470 norms.push_back(f.vertices[j].normalSource->getNormal());
471 }*/
472 }
473 for (int j = 0; j < f.vertices.size() - 2; ++j) {
474 inds.push_back(i);
475 inds.push_back(i + j + 1);
476 inds.push_back(i + j + 2);
477 }
478 }
479
480 for (int fd = 0; fd < faces_disp.size(); fd++) {
481 bsp::face_displacement f = faces_disp[fd];
482
483 int i = verts.size();
484 if (i + vertices.size() >= USHRT_MAX) {
485 std::cout << "WARNING::HIT_VERTEX_LIMIT" << std::endl;
486 break;
487 }
488 for (int j = 0; j < f.num_vertices; ++j) {
489 verts.push_back(f.vertices[j].position);
490 uvs.push_back(f.vertices[j].UV);
491 if (f.vertices[j].normalSource == NULL) {
492 norms.push_back(f.vertices[j].normal_hard);
493 }
494 else {
495 norms.push_back(f.vertices[j].normalSource->getNormal());
496 }
497 }
498 for (int j = 0; j < f.num_tris; ++j) {
499 inds.push_back(i + f.tris[j]);
500 }
501 }
502
503 //Adjust position
504 glm::vec3 vec;
505 for (int i = 0; i < verts.size(); ++i) {
506 vec = verts[i] * (2.5f / 100);
507 vec.y *= -1;
508
509 //Swizzle (Y/Z)
510 float temp = vec.z;
511 vec.z = vec.y;
512 vec.y = temp;
513
514 verts[i] = vec;
515 }
516
517 RV.vertices = verts;
518 RV.indices = inds;
519 RV.normals = norms;
520 RV.uvs = uvs;
521
522 return RV;
523 }
524
525 std::vector<float> generate_bigmesh() {
526 std::vector<float> verts;
527 for (int i = 0; i < this->faces.size(); i++) {
528 bsp::face face = this->faces[i];
529
530 std::vector<bsp::vertex> vertices;
531 for (int e = face.firstEdge; e < face.firstEdge + face.numEdges; e++) {
532 //edge_indexes.push_back);
533 int index = this->surfEdges[e];
534 if (index >= 0) //Trace forwards
535 {
536 vertices.push_back(this->vertices[this->edges[index].vertex[0]]);
537 vertices.push_back(this->vertices[this->edges[index].vertex[1]]);
538 }
539 else
540 {
541 vertices.push_back(this->vertices[this->edges[std::abs(index)].vertex[1]]);
542 vertices.push_back(this->vertices[this->edges[std::abs(index)].vertex[0]]);
543 }
544 }
545
546 //Get face normal
547 glm::vec3 normal = this->planes[face.planeNum].normal;
548 if (face.side != 0)
549 normal = -normal;
550
551 normal = glm::normalize(normal);
552
553 //Write to verts array
554 for (int v = 1; v < vertices.size() -1; v++) {
555 //Get verts positions
556 bsp::vertex v0 = vertices[0];
557 bsp::vertex v1 = vertices[v];
558 bsp::vertex v2 = vertices[v + 1];
559
560 //Write
561 verts.push_back(v0.position.x* 0.01f);
562 verts.push_back(v0.position.z* 0.01f);
563 verts.push_back(v0.position.y* 0.01f);
564
565
566 verts.push_back(normal.x);
567 verts.push_back(normal.z);
568 verts.push_back(normal.y);
569
570
571 verts.push_back(v1.position.x* 0.01f);
572 verts.push_back(v1.position.z* 0.01f);
573 verts.push_back(v1.position.y* 0.01f);
574
575
576 verts.push_back(normal.x);
577 verts.push_back(normal.z);
578 verts.push_back(normal.y);
579
580
581 verts.push_back(v2.position.x* 0.01f);
582 verts.push_back(v2.position.z* 0.01f);
583 verts.push_back(v2.position.y* 0.01f);
584
585
586 verts.push_back(normal.x);
587 verts.push_back(normal.z);
588 verts.push_back(normal.y);
589
590 }
591
592 if (i > 35000) {
593 std::cout << "LIMIT HIT FOR NOW" << std::endl;
594 break;
595 }
596 }
597
598 return verts;
599 }
600 };