2.0
[tar-legacy.git] / MCDV / vmf_new.hpp
1 // io
2 #pragma once
3 #include <iostream>
4 #include <fstream>
5 #include <sstream>
6 #include "vdf.hpp"
7
8 // stl containers
9 #include <vector>
10 #include <map>
11 #include <set>
12
13 // opengl
14 #include <glad\glad.h>
15 #include <GLFW\glfw3.h>
16 #include <glm\glm.hpp>
17 #include <glm\gtc\matrix_transform.hpp>
18 #include <glm\gtc\type_ptr.hpp>
19
20 //engine
21 #include "Util.h"
22 #include "plane.h"
23 #include "Mesh.hpp"
24 #include "Shader.hpp"
25 #include "IRenderable.hpp"
26 #include "interpolation.h"
27
28 // other
29 #include <limits>
30
31 // Source sdk
32 #include "vfilesys.hpp"
33
34 // UINT16 buffer bit definitions ================
35 // Byte 0
36 #define TAR_MIBUFFER_PLAYSPACE 0x1
37 #define TAR_MIBUFFER_OVERLAP 0x2
38 #define TAR_MIBUFFER_OBJECTIVE_B 0x4
39 #define TAR_MIBUFFER_OBJECTIVE_X 0x8
40 #define TAR_MIBUFFER_BUYZONE_CT 0x10
41 #define TAR_MIBUFFER_BUYZONE_T 0x20
42 #define TAR_MIBUFFER_BUYZONE_X 0x40
43 #define TAR_MIBUFFER_COVER0 0x80
44 // Byte 1
45 #define TAR_MIBUFFER_COVER1 0x100
46 #define TAR_MIBUFFER_MODEL 0x200
47 #define TAR_MIBUFFER_FUNC_DETAIL 0x400
48 #define TAR_MIBUFFER_NEGATIVE 0x800
49 #define TAR_MIBUFFER_USER0 0x1000
50 #define TAR_MIBUFFER_USER1 0x2000
51 #define TAR_MIBUFFER_USER2 0x4000
52 #define TAR_MIBUFFER_USER3 0x8000
53 // ============================================
54
55 typedef unsigned int TAR_MIBUFFER_FLAGS;
56 std::map<unsigned int, TAR_MIBUFFER_FLAGS> g_visgroup_flag_translations;
57
58 bool use_verbose = true;
59 std::string prefix = "";
60
61 inline glm::vec3 get_normal(const glm::vec3& A, const glm::vec3& B, const glm::vec3& C) {
62 return glm::normalize(glm::cross(A - C, B - C));
63 }
64
65 constexpr
66 unsigned int hash(const char* str, int h = 0)
67 {
68 return !str[h] ? 5381 : (hash(str, h + 1) * 33) ^ str[h];
69 }
70
71 //Variadic print
72 void _debug() {
73 std::cout << std::endl;
74 }
75
76 template<typename First, typename ... Strings>
77 void _debug(First arg, const Strings&... rest) {
78 std::cout << arg;
79 _debug(rest...);
80 }
81
82 template<typename First, typename ... Strings>
83 void debug(First arg, const Strings&... rest) {
84 if (use_verbose) {
85 std::cout << prefix;
86 _debug(arg, rest...);
87 }
88 }
89
90 namespace vmf_parse {
91 //Pass Vector3
92 bool Vector3f(std::string str, glm::vec3* vec)
93 {
94 str = sutil::removeChar(str, '(');
95 str = sutil::removeChar(str, ')');
96
97 std::vector<std::string> elems = split(str, ' ');
98 std::vector<float> pelems;
99
100 for (int i = 0; i < elems.size(); i++) {
101 std::string f = sutil::trim(elems[i]);
102
103 //TODO: error check against invalid values here
104 float e = ::atof(f.c_str());
105 pelems.push_back(e);
106 }
107
108 if (pelems.size() == 3) {
109 *vec = glm::vec3(pelems[0], pelems[1], pelems[2]);
110 return true;
111 }
112
113 return false;
114 }
115
116 //Parse Vector 3 with square barackets. Thanks again, valve
117 bool Vector3fS(std::string str, glm::vec3* vec)
118 {
119 str = sutil::removeChar(str, '[');
120 str = sutil::removeChar(str, ']');
121
122 std::vector<std::string> elems = split(str, ' ');
123 std::vector<float> pelems;
124
125 for (int i = 0; i < elems.size(); i++) {
126 std::string f = sutil::trim(elems[i]);
127
128 //TODO: error check against invalid values here
129 float e = ::atof(f.c_str());
130 pelems.push_back(e);
131 }
132
133 if (pelems.size() == 3) {
134 *vec = glm::vec3(pelems[0], pelems[1], pelems[2]);
135 return true;
136 }
137
138 return false;
139 }
140
141 //Parse plane from standard 3 point notation (ax, ay, az) (bx, by, bz) ...
142 bool plane(std::string str, Plane* plane)
143 {
144 std::vector<std::string> points = split(str, '(');
145
146 if (points.size() != 4) { return false; }
147
148 glm::vec3 A, B, C;
149
150 if (!(Vector3f(points[1], &A) && Vector3f(points[2], &B) && Vector3f(points[3], &C))) {
151 return false;
152 }
153
154 *plane = Plane(A, B, C);
155
156 return true;
157 }
158 }
159
160 class material {
161 public:
162 material() {
163 // ok.. what now?
164 }
165
166 /*
167 static std::map<std::string, material*> material_index;
168
169 static material* get(const std::string& tex) {
170 if (!material_index.count(tex)) material_index.insert({ tex, new material() });
171 return material_index[tex];
172 }*/
173
174 static material* get(const std::string& tex) {
175 return NULL;
176 }
177 };
178
179 class dispinfo;
180
181 class side {
182 public:
183 int m_ID;
184 material* m_texture;
185 Plane m_plane;
186 dispinfo* m_dispinfo = NULL;
187 std::vector<glm::vec3> m_vertices;
188
189 static side* create(kv::DataBlock* dataSrc);
190
191 void howmany() {
192 debug(this->m_vertices.size());
193 }
194 };
195
196 class dispinfo : public IRenderable{
197 public:
198 unsigned int power;
199 glm::vec3 startposition;
200
201 std::vector<std::vector<glm::vec3>> normals;
202 std::vector<std::vector<float>> distances;
203
204 side* m_source_side = NULL;
205
206 dispinfo(kv::DataBlock* dataSrc, side* src_side) {
207 this->m_source_side = src_side;
208
209 kv::DataBlock* kv_normals = dataSrc->_GetFirstByName("normals");
210 kv::DataBlock* kv_distances = dataSrc->_GetFirstByName("distances");
211
212 this->power = std::stoi(dataSrc->Values["power"]);
213 vmf_parse::Vector3fS(dataSrc->Values["startposition"], &this->startposition);
214
215 int i_target = glm::pow(2, this->power) + 1;
216
217 for (int x = 0; x < i_target; x++) {
218 this->normals.push_back(std::vector<glm::vec3>());
219 this->distances.push_back(std::vector<float>());
220
221 // Read normals
222 std::vector<float> list;
223 for (auto && v : split(kv_normals->Values["row" + std::to_string(x)]))
224 list.push_back(::atof(v.c_str()));
225
226 for (int xx = 0; xx < i_target; xx++) {
227 this->normals[x].push_back(
228 glm::vec3(
229 list[xx * 3 + 0],
230 list[xx * 3 + 1],
231 list[xx * 3 + 2])
232 );
233 }
234
235 // Read distances
236 for (auto && v : split(kv_distances->Values["row" + std::to_string(x)]))
237 this->distances[x].push_back(std::stof(v.c_str()));
238 }
239 }
240
241 // internal draw method
242 void IRenderable::_Draw(Shader* shader, std::vector<glm::mat4> transform_stack = {}) {
243 this->m_mesh->Draw();
244 }
245
246 // Compute GL Mesh
247 void IRenderable::SetupDrawable() {
248 if (this->m_source_side->m_vertices.size() != 4) {
249 debug("Displacement info matched to face with {", this->m_source_side->m_vertices.size(), "} vertices!!!");
250 return;
251 }
252
253 // Match 'starting point'
254 std::map<float, glm::vec3*> distancesToStart;
255 for (auto && p : this->m_source_side->m_vertices)
256 distancesToStart.insert({ glm::distance(this->startposition, p), &p });
257
258 // The corners of displacement
259 glm::vec3* SW = distancesToStart.begin()->second;
260
261 // Find what point in vector it was
262 int pos = 0;
263 for (auto && point : this->m_source_side->m_vertices)
264 if (&point == SW) break; else pos++;
265
266 // Get the rest of the points, in clockwise order (they should already be sorted by polytope generation)
267 glm::vec3* NW = &this->m_source_side->m_vertices[(pos + 1) % 4];
268 glm::vec3* NE = &this->m_source_side->m_vertices[(pos + 2) % 4];
269 glm::vec3* SE = &this->m_source_side->m_vertices[(pos + 3) % 4];
270
271 int points = glm::pow(2, this->power) + 1; // calculate the point count (5, 9, 17)
272
273 // Initialize list for floats
274 std::vector<float> meshData;
275
276 std::vector<glm::vec3> finalPoints;
277 std::vector<glm::vec3> finalNormals;
278
279 for (int row = 0; row < points; row++) {
280 for (int col = 0; col < points; col++) {
281 //Generate original base points
282
283 float dx = (float)col / (float)(points - 1); //Time values for linear interpolation
284 float dy = (float)row / (float)(points - 1);
285
286 glm::vec3 LWR = lerp(*SW, *SE, dx);
287 glm::vec3 UPR = lerp(*NW, *NE, dx);
288 glm::vec3 P = lerp(LWR, UPR, dy); // Original point location
289
290 glm::vec3 offset = this->normals[col][row] * this->distances[col][row]; // Calculate offset
291 P = P + offset; //Add offset to P
292
293 finalPoints.push_back(P);
294 }
295 }
296
297 for (int row = 0; row < points; row++) {
298 for (int col = 0; col < points; col++) {
299 std::vector<glm::vec3*> kernalpts = { NULL, NULL, NULL, NULL };
300
301 if(row + 1 < points) kernalpts[0] = &finalPoints[((row + 1) * points) + (col + 0)];
302 if(col - 1 > 0) kernalpts[1] = &finalPoints[((row + 0) * points) + (col - 1)];
303
304 if(row - 1 > 0) kernalpts[2] = &finalPoints[((row - 1) * points) + (col + 0)];
305 if(col + 1 < points) kernalpts[3] = &finalPoints[((row + 0) * points) + (col + 1)];
306
307 glm::vec3* A = &finalPoints[((row + 0) * points) + (col + 0)];
308 glm::vec3 cNorm = glm::vec3(1, 0, 0);
309
310 for (int t = 0; t < 1; t++) {
311 glm::vec3* B = kernalpts[(t + 0) % 4];
312 glm::vec3* C = kernalpts[(t + 1) % 4];
313
314 if ((B != NULL) && (C != NULL)) {
315 glm::vec3 v0 = *A - *C;
316 glm::vec3 v1 = *B - *C;
317 glm::vec3 n = glm::cross(v0, v1);
318 cNorm += glm::normalize(n);
319 }
320 }
321
322 finalNormals.push_back(glm::normalize(cNorm));
323 }
324 }
325
326 int i_condition = 0;
327 for (int row = 0; row < points - 1; row++) {
328 for (int col = 0; col < points - 1; col++) {
329 // Gather point pointers
330 // hehe :(
331 glm::vec3* SW = &finalPoints [((row + 0) * points) + (col + 0)];
332 glm::vec3* SW_N = &finalNormals [((row + 0) * points) + (col + 0)];
333 glm::vec3* SE = &finalPoints [((row + 0) * points) + (col + 1)];
334 glm::vec3* SE_N = &finalNormals [((row + 0) * points) + (col + 1)];
335 glm::vec3* NW = &finalPoints [((row + 1) * points) + (col + 0)];
336 glm::vec3* NW_N = &finalNormals [((row + 1) * points) + (col + 0)];
337 glm::vec3* NE = &finalPoints [((row + 1) * points) + (col + 1)];
338 glm::vec3* NE_N = &finalNormals [((row + 1) * points) + (col + 1)];
339
340 #pragma region lots of triangles
341 // Insert triangles.
342 if (i_condition++ % 2 == 0) {//Condition 0
343 glm::vec3 n1 = get_normal(*SW, *NW, *NE);
344 meshData.push_back(-NE->x);
345 meshData.push_back(NE->z);
346 meshData.push_back(NE->y);
347 meshData.push_back(-n1.x);
348 meshData.push_back(n1.z);
349 meshData.push_back(n1.y);
350
351 meshData.push_back(-NW->x);
352 meshData.push_back(NW->z);
353 meshData.push_back(NW->y);
354 meshData.push_back(-n1.x);
355 meshData.push_back(n1.z);
356 meshData.push_back(n1.y);
357
358 meshData.push_back(-SW->x);
359 meshData.push_back(SW->z);
360 meshData.push_back(SW->y);
361 meshData.push_back(-n1.x);
362 meshData.push_back(n1.z);
363 meshData.push_back(n1.y);
364
365 glm::vec3 n2 = get_normal(*SW, *NE, *SE);
366 meshData.push_back(-SE->x);
367 meshData.push_back(SE->z);
368 meshData.push_back(SE->y);
369 meshData.push_back(-n2.x);
370 meshData.push_back(n2.z);
371 meshData.push_back(n2.y);
372
373 meshData.push_back(-NE->x);
374 meshData.push_back(NE->z);
375 meshData.push_back(NE->y);
376 meshData.push_back(-n2.x);
377 meshData.push_back(n2.z);
378 meshData.push_back(n2.y);
379
380 meshData.push_back(-SW->x); // tri2
381 meshData.push_back(SW->z);
382 meshData.push_back(SW->y);
383 meshData.push_back(-n2.x);
384 meshData.push_back(n2.z);
385 meshData.push_back(n2.y);
386 }
387 else { //Condition 1
388 glm::vec3 n1 = get_normal(*SW, *NW, *SE);
389 meshData.push_back(-SE->x);
390 meshData.push_back(SE->z);
391 meshData.push_back(SE->y);
392 meshData.push_back(-n1.x);
393 meshData.push_back(n1.z);
394 meshData.push_back(n1.y);
395
396 meshData.push_back(-NW->x);
397 meshData.push_back(NW->z);
398 meshData.push_back(NW->y);
399 meshData.push_back(-n1.x);
400 meshData.push_back(n1.z);
401 meshData.push_back(n1.y);
402
403 meshData.push_back(-SW->x);
404 meshData.push_back(SW->z);
405 meshData.push_back(SW->y);
406 meshData.push_back(-n1.x);
407 meshData.push_back(n1.z);
408 meshData.push_back(n1.y);
409
410
411 glm::vec3 n2 = get_normal(*NW, *NE, *SE);
412 meshData.push_back(-SE->x);
413 meshData.push_back(SE->z);
414 meshData.push_back(SE->y);
415 meshData.push_back(-n2.x);
416 meshData.push_back(n2.z);
417 meshData.push_back(n2.y);
418
419 meshData.push_back(-NE->x);
420 meshData.push_back(NE->z);
421 meshData.push_back(NE->y);
422 meshData.push_back(-n2.x);
423 meshData.push_back(n2.z);
424 meshData.push_back(n2.y);
425
426 meshData.push_back(-NW->x); //tri2
427 meshData.push_back(NW->z);
428 meshData.push_back(NW->y);
429 meshData.push_back(-n2.x);
430 meshData.push_back(n2.z);
431 meshData.push_back(n2.y);
432 }
433 #pragma endregion
434
435 }
436 i_condition++;
437 }
438
439 this->m_mesh = new Mesh(meshData, MeshMode::POS_XYZ_NORMAL_XYZ);
440 }
441 };
442
443 side* side::create(kv::DataBlock* dataSrc) {
444 side* s = new side();
445 s->m_ID = ::atof(dataSrc->Values["id"].c_str());
446 s->m_texture = material::get(dataSrc->Values["material"]);
447
448 if (!vmf_parse::plane(dataSrc->Values["plane"], &s->m_plane)) return s;
449
450 kv::DataBlock* kv_dispInfo = dataSrc->_GetFirstByName("dispinfo");
451 if (kv_dispInfo != NULL) s->m_dispinfo = new dispinfo(kv_dispInfo, s);
452 return s;
453 }
454
455 class vmf;
456
457 class editorvalues {
458 public:
459 std::vector<unsigned int> m_visgroups;
460 glm::vec3 m_editorcolor;
461
462 TAR_MIBUFFER_FLAGS m_miflags;
463
464 editorvalues(){}
465 editorvalues(kv::DataBlock* dataSrc) {
466 if (dataSrc == NULL) return;
467
468 for (auto && vgroup : kv::getList(dataSrc->Values, "visgroupid")) {
469 unsigned int vgroupid = std::stoi(vgroup);
470 this->m_visgroups.push_back(vgroupid);
471
472 if (g_visgroup_flag_translations.count(vgroupid))
473 this->m_miflags |= g_visgroup_flag_translations[vgroupid];
474 }
475
476 #ifdef VMF_READ_SOLID_COLORS
477 if (vmf_parse::Vector3f(dataSrc->Values["color"], &this->m_editorcolor))
478 this->m_editorcolor = this->m_editorcolor / 255.0f;
479 else
480 this->m_editorcolor = glm::vec3(1, 0, 0);
481 #endif
482 }
483 };
484
485 class solid : public IRenderable {
486 public:
487 std::vector<side*> m_sides;
488 editorvalues m_editorvalues;
489 glm::vec3 NWU;
490 glm::vec3 SEL;
491
492 solid(kv::DataBlock* dataSrc) {
493 // Read editor values
494 this->m_editorvalues = editorvalues(dataSrc->_GetFirstByName("editor"));
495
496 // Read solids
497 for (auto && s : dataSrc->_GetAllByName("side")) m_sides.push_back(side::create(s));
498
499 // Process polytope problem. (still questionable why this is a thing)
500 std::vector<glm::vec3> intersecting;
501
502 float x, _x, y, _y, z, _z;
503 _x = _y = _z = std::numeric_limits<float>::max();
504 x = y = z = std::numeric_limits<float>::min();
505
506 for (int i = 0; i < m_sides.size(); i++) {
507 for (int j = 0; j < m_sides.size(); j++) {
508 for (int k = 0; k < m_sides.size(); k++) {
509 // skip common planes
510 if (i == j || i == k || j == k) continue;
511
512 // Calculate intersection of 3 planes
513 // will return false if unable to solve (planes are parralel)
514 glm::vec3 p(0, 0, 0);
515 if (!Plane::FinalThreePlaneIntersection(
516 this->m_sides[i]->m_plane,
517 this->m_sides[j]->m_plane,
518 this->m_sides[k]->m_plane,
519 &p)) continue;
520
521 // Check if we are part of the solid using simple polarity checks
522 bool inbounds = true;
523 for (auto && m : this->m_sides) {
524 if (Plane::EvalPointPolarity(m->m_plane, p) < -0.01f) {
525 inbounds = false;
526 break;
527 }
528 } if (!inbounds) continue;
529
530 // Check if there is already a very similar vertex, and skip it
531 bool similar = false;
532 for (auto && v : intersecting)
533 if (glm::distance(v, p) < 0.5f) {
534 similar = true; break;
535 }
536 if (similar) continue;
537
538 // Add points to all surfaces
539 this->m_sides[i]->m_vertices.push_back(p);
540 this->m_sides[j]->m_vertices.push_back(p);
541 this->m_sides[k]->m_vertices.push_back(p);
542
543 intersecting.push_back(p);
544
545 // Calculate bounds
546 _x = glm::min(_x, p.x);
547 _y = glm::min(_y, p.y);
548 _z = glm::min(_z, p.z);
549 x = glm::max(x, p.x);
550 y = glm::max(y, p.y);
551 z = glm::max(z, p.z);
552 }
553 }
554 }
555
556 for (auto && side : this->m_sides) {
557 // Sort out deez rascals
558 Plane::InPlaceOrderCoplanarClockWise(side->m_plane, &side->m_vertices);
559 }
560
561 // Append bounds data
562 this->NWU = glm::vec3(-x, z, y);
563 this->SEL = glm::vec3(-_x, _z, _y);
564 }
565
566 /* Check if this solid contains any displacement infos. */
567 bool containsDisplacements() {
568 for (auto && s : this->m_sides) {
569 if (s->m_dispinfo != NULL)
570 return true;
571 }
572 return false;
573 }
574
575 void IRenderable::_Draw(Shader* shader, std::vector<glm::mat4> transform_stack = {}) {
576 bool dispDrawn = false;
577 for (auto && s : this->m_sides) {
578 if (s->m_dispinfo != NULL) {
579 s->m_dispinfo->Draw(shader);
580 dispDrawn = true;
581 }
582 }
583
584 // Only draw solid if thre is no displacement info
585 if (!dispDrawn) {
586 this->m_mesh->Draw();
587 }
588 }
589
590 void IRenderable::SetupDrawable() {
591 std::vector<float> verts;
592 for (auto && s : this->m_sides) {
593 if (s->m_dispinfo != NULL) continue;
594 if (s->m_vertices.size() < 3) continue;
595
596 for (int j = 0; j < s->m_vertices.size() - 2; j++) {
597 glm::vec3* c = &s->m_vertices[0];
598 glm::vec3* b = &s->m_vertices[j + 1];
599 glm::vec3* a = &s->m_vertices[j + 2];
600
601 verts.push_back(-a->x);
602 verts.push_back(a->z);
603 verts.push_back(a->y);
604
605 verts.push_back(s->m_plane.normal.x);
606 verts.push_back(-s->m_plane.normal.z);
607 verts.push_back(-s->m_plane.normal.y);
608
609 verts.push_back(-b->x);
610 verts.push_back(b->z);
611 verts.push_back(b->y);
612
613 verts.push_back(s->m_plane.normal.x);
614 verts.push_back(-s->m_plane.normal.z);
615 verts.push_back(-s->m_plane.normal.y);
616
617 verts.push_back(-c->x);
618 verts.push_back(c->z);
619 verts.push_back(c->y);
620
621 verts.push_back(s->m_plane.normal.x);
622 verts.push_back(-s->m_plane.normal.z);
623 verts.push_back(-s->m_plane.normal.y);
624 }
625 }
626
627 this->m_mesh = new Mesh(verts, MeshMode::POS_XYZ_NORMAL_XYZ);
628 }
629 };
630
631 class entity {
632 public:
633 std::string m_classname;
634 int m_id;
635 std::map<std::string, std::string> m_keyvalues;
636 editorvalues m_editorvalues;
637 std::vector<solid> m_internal_solids;
638 glm::vec3 m_origin;
639
640 entity (kv::DataBlock* dataSrc) {
641
642
643 if ((dataSrc->_GetFirstByName("solid") == NULL) && (dataSrc->Values.count("origin") == 0))
644 throw std::exception(("origin could not be resolved for entity ID: " + dataSrc->Values["id"]).c_str());
645
646 this->m_classname = dataSrc->Values["classname"];
647 this->m_id = (int)::atof(dataSrc->Values["id"].c_str());
648 this->m_keyvalues = dataSrc->Values;
649 this->m_editorvalues = editorvalues(dataSrc->_GetFirstByName("editor"));
650
651 if (dataSrc->_GetFirstByName("solid") == NULL) {
652 vmf_parse::Vector3f(dataSrc->Values["origin"], &this->m_origin);
653 this->m_origin = glm::vec3(-this->m_origin.x, this->m_origin.z, this->m_origin.y);
654 }
655 else {
656 for (auto && s : dataSrc->_GetAllByName("solid")) {
657 this->m_internal_solids.push_back(solid(s));
658 }
659
660 // Calculate origin
661 glm::vec3 NWU = this->m_internal_solids[0].NWU;
662 glm::vec3 SEL = this->m_internal_solids[0].SEL;
663 for (auto && i : this->m_internal_solids) {
664 NWU.z = glm::max(NWU.z, i.NWU.z);
665 NWU.y = glm::max(NWU.y, i.NWU.y);
666 NWU.x = glm::max(NWU.x, i.NWU.x);
667 SEL.z = glm::min(SEL.z, i.SEL.z);
668 SEL.y = glm::min(SEL.y, i.SEL.y);
669 SEL.x = glm::min(SEL.x, i.SEL.x);
670 }
671
672 this->m_origin = (NWU + SEL) * 0.5f;
673 }
674 }
675 };
676
677 struct BoundingBox {
678 glm::vec3 NWU;
679 glm::vec3 SEL;
680 };
681
682 bool check_in_whitelist(std::vector<unsigned int>* visgroups_in, std::set<unsigned int> filter) {
683 if (filter.count(0xBEEEEEEE)) return true;
684
685 for (auto && vgroup : *visgroups_in)
686 if (filter.count(vgroup))
687 return true;
688
689 return false;
690 }
691
692 class vmf {
693 private:
694 static vfilesys* s_fileSystem;
695
696 public:
697 // Static setup functions
698 static void LinkVFileSystem(vfilesys* sys) {
699 vmf::s_fileSystem = sys;
700 }
701
702 vmf() {}
703
704 std::vector<solid> m_solids;
705 std::vector<entity> m_entities;
706
707 std::map<std::string, unsigned int> m_visgroups;
708
709 std::set<unsigned int> m_whitelist_visgroups;
710 std::set<std::string> m_whitelist_classnames;
711
712 static std::map<std::string, Mesh*> s_model_dict;
713
714 void LinkVisgroupFlagTranslations(std::map<std::string, TAR_MIBUFFER_FLAGS> map) {
715 for (auto && translation : map) {
716 if (this->m_visgroups.count(translation.first)) {
717 g_visgroup_flag_translations.insert({ this->m_visgroups[translation.first], translation.second });
718 }
719 }
720 }
721
722 static vmf* from_file(const std::string& path, std::map<std::string, TAR_MIBUFFER_FLAGS> translations = {}) {
723 vmf* v = new vmf();
724 prefix = "vmf [" + path + "] ";
725 use_verbose = true;
726 debug("Opening");
727
728 std::ifstream ifs(path);
729 if (!ifs) throw std::exception("355 VMF File read error.");
730
731 std::string file_str((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
732
733 debug("Processing VMF data");
734 kv::FileData file_kv(file_str);
735
736 debug("Processing visgroups");
737 // Process visgroup list
738 for (auto && vg : file_kv.headNode._GetFirstByName("visgroups")->_GetAllByName("visgroup")) {
739 v->m_visgroups.insert({ vg->Values["name"], std::stoi(vg->Values["visgroupid"]) });
740 std::cout << "'" << vg->Values["name"] << "': " << std::stoi(vg->Values["visgroupid"]) << "\n";
741 }
742 v->LinkVisgroupFlagTranslations(translations);
743
744 debug("Processing solids");
745 // Solids
746 for (auto && kv_solid : file_kv.headNode._GetFirstByName("world")->_GetAllByName("solid")) {
747 v->m_solids.push_back(solid(kv_solid));
748 }
749
750 debug("Processing entities");
751 // Entities
752 for (auto && kv_entity : file_kv.headNode._GetAllByName("entity")) {
753 try {
754 entity ent = entity(kv_entity);
755 v->m_entities.push_back(ent);
756 } catch (std::exception e) {
757 debug("374 ENTITY::EXCEPTION ( ", e.what(), ") ");
758 }
759 }
760
761 debug("Done!");
762 return v;
763 }
764
765 void InitModelDict() {
766 for (auto && i : this->m_entities) {
767 switch (hash(i.m_classname.c_str())) {
768 case hash("prop_static"):
769 case hash("prop_dynamic"):
770 case hash("prop_physics"):
771
772 std::string modelName = kv::tryGetStringValue(i.m_keyvalues, "model", "error.mdl");
773 std::string baseName = split(modelName, ".")[0];
774 if (vmf::s_model_dict.count(modelName)) continue; // Skip already defined models
775
776 vtx_mesh* vtx = vmf::s_fileSystem->get_resource_handle<vtx_mesh>(baseName + ".dx90.vtx");
777 vvd_data* vvd = vmf::s_fileSystem->get_resource_handle<vvd_data>(baseName + ".vvd");
778
779 if (vvd == NULL || vtx == NULL) {
780 debug( "Failed to load resource: ", baseName, "\n");
781 continue;
782 }
783
784 // GENERATE MESH TING
785 std::vector<float> meshData;
786 for (auto && vert : vtx->vertexSequence) {
787 meshData.push_back(vvd->verticesLOD0[vert].m_vecPosition.x);
788 meshData.push_back(vvd->verticesLOD0[vert].m_vecPosition.y);
789 meshData.push_back(vvd->verticesLOD0[vert].m_vecPosition.z);
790 meshData.push_back(-vvd->verticesLOD0[vert].m_vecNormal.x);
791 meshData.push_back(vvd->verticesLOD0[vert].m_vecNormal.z);
792 meshData.push_back(vvd->verticesLOD0[vert].m_vecNormal.y);
793 }
794
795 vmf::s_model_dict.insert({ modelName, new Mesh(meshData, MeshMode::POS_XYZ_NORMAL_XYZ) }); // Add to our list
796 break;
797 }
798 }
799 }
800
801 void SetFilters(std::set<std::string> visgroups, std::set<std::string> classnames){
802 this->m_whitelist_visgroups = std::set<unsigned int>{};
803 if (visgroups.size() == 0) this->m_whitelist_visgroups.insert(0xBEEEEEEE);
804
805 for (auto && vname : visgroups)
806 if (this->m_visgroups.count(vname))
807 this->m_whitelist_visgroups.insert(this->m_visgroups[vname]);
808
809 this->m_whitelist_classnames = classnames;
810 }
811
812 void DrawWorld(Shader* shader, std::vector<glm::mat4> transform_stack = {}, unsigned int infoFlags = 0x00) {
813 glm::mat4 model = glm::mat4();
814 shader->setMatrix("model", model);
815 shader->setUnsigned("Info", infoFlags);
816
817 // Draw solids
818 for (auto && solid : this->m_solids) {
819 if (check_in_whitelist(&solid.m_editorvalues.m_visgroups, this->m_whitelist_visgroups)) {
820 shader->setUnsigned("Info", infoFlags);
821 solid.Draw(shader);
822 }
823 }
824
825 model = glm::mat4();
826 shader->setMatrix("model", model);
827 // Draw
828 }
829
830 void DrawEntities(Shader* shader, std::vector<glm::mat4> transform_stack = {}, unsigned int infoFlags = 0x00) {
831 glm::mat4 model = glm::mat4();
832 shader->setMatrix("model", model);
833 shader->setUnsigned("Info", infoFlags);
834
835 // Draw props
836 for (auto && ent : this->m_entities) {
837 // Visgroup pre-check
838 if (check_in_whitelist(&ent.m_editorvalues.m_visgroups, this->m_whitelist_visgroups)) {
839
840 if (this->m_whitelist_classnames.count(ent.m_classname)) {
841 if (ent.m_classname == "prop_static" ||
842 ent.m_classname == "prop_dynamic" ||
843 ent.m_classname == "prop_physics" ) {
844
845 model = glm::mat4();
846 model = glm::translate(model, ent.m_origin);
847 glm::vec3 rot;
848 vmf_parse::Vector3f(kv::tryGetStringValue(ent.m_keyvalues, "angles", "0 0 0"), &rot);
849 model = glm::rotate(model, glm::radians(rot.y), glm::vec3(0, 1, 0)); // Yaw
850 model = glm::rotate(model, glm::radians(rot.x), glm::vec3(0, 0, 1)); // ROOOOOLLLLL
851 model = glm::rotate(model, -glm::radians(rot.z), glm::vec3(1, 0, 0)); // Pitch
852 model = glm::scale(model, glm::vec3(::atof(kv::tryGetStringValue(ent.m_keyvalues, "uniformscale", "1").c_str())));
853 shader->setMatrix("model", model);
854 shader->setUnsigned("Info", infoFlags);
855
856 vmf::s_model_dict[kv::tryGetStringValue(ent.m_keyvalues, "model", "error.mdl")]->Draw();
857 }
858 else {
859 model = glm::mat4();
860 shader->setMatrix("model", model);
861 shader->setUnsigned("Info", infoFlags);
862
863 for (auto && s : ent.m_internal_solids) {
864 s.Draw(shader);
865 }
866 }
867 }
868 }
869 }
870
871 // Resets
872 model = glm::mat4();
873 shader->setMatrix("model", model);
874 shader->setUnsigned("Info", infoFlags);
875 }
876
877 BoundingBox getVisgroupBounds(const std::string& visgroup) {
878 BoundingBox bounds;
879 if (!this->m_visgroups.count(visgroup)) return bounds;
880
881 unsigned int vgroup = this->m_visgroups[visgroup];
882
883 bounds.NWU = glm::vec3(
884 std::numeric_limits<float>::min(),
885 std::numeric_limits<float>::min(),
886 std::numeric_limits<float>::min());
887
888 bounds.SEL = glm::vec3(
889 std::numeric_limits<float>::max(),
890 std::numeric_limits<float>::max(),
891 std::numeric_limits<float>::max());
892
893 for (auto && iSolid : this->m_solids) {
894 if (!check_in_whitelist(&iSolid.m_editorvalues.m_visgroups, std::set<unsigned int>{ vgroup })) continue;
895 if (iSolid.NWU.z > bounds.NWU.z) bounds.NWU.z = iSolid.NWU.z;
896 if (iSolid.NWU.y > bounds.NWU.y) bounds.NWU.y = iSolid.NWU.y;
897 if (iSolid.NWU.x > bounds.NWU.x) bounds.NWU.x = iSolid.NWU.x;
898
899 if (iSolid.SEL.z < bounds.SEL.z) bounds.SEL.z = iSolid.SEL.z;
900 if (iSolid.SEL.y < bounds.SEL.y) bounds.SEL.y = iSolid.SEL.y;
901 if (iSolid.SEL.x < bounds.SEL.x) bounds.SEL.x = iSolid.SEL.x;
902 }
903
904 std::cout << "Bounds MAXY: " << bounds.NWU.y << "\n";
905 std::cout << "Bounds MINY: " << bounds.SEL.y << "\n";
906
907 return bounds;
908 }
909
910 std::vector<entity*> get_entities_by_classname(const std::string& classname) {
911 std::vector<entity*> ents;
912 for (auto && i : this->m_entities) {
913 if (i.m_classname == classname) {
914 ents.push_back(&i);
915 }
916 }
917
918 return ents;
919 }
920 };
921
922 vfilesys* vmf::s_fileSystem = NULL;
923 std::map<std::string, Mesh*> vmf::s_model_dict;