UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
map.cpp
Go to the documentation of this file.
1 
5 /*
6 Copyright (C) 1997-2001 Id Software, Inc.
7 
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 
17 See the GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 
23 */
24 
25 
26 #include "map.h"
27 #include "bsp.h"
28 #include "textures.h"
29 #include "check/check.h"
30 #include "check/checkentities.h"
31 #include "common/aselib.h"
32 #include "../../shared/parse.h"
33 
36 
39 
41 
45 
46 #define PLANE_HASHES 1024
48 
49 static int c_boxbevels = 0;
50 static int c_edgebevels = 0;
51 
52 /*
53 =============================================================================
54 PLANE FINDING
55 =============================================================================
56 */
57 
62 static inline int GetPlaneHashValueForDistance (const vec_t distance)
63 {
64  int hash = (int)fabs(distance) * 27;
65  hash &= (PLANE_HASHES - 1);
66  return hash;
67 }
68 
72 static int PlaneTypeForNormal (const vec3_t normal)
73 {
74  vec_t ax, ay, az;
75 
76  /* NOTE: should these have an epsilon around 1.0? */
77  if (normal[0] == 1.0 || normal[0] == -1.0)
78  return PLANE_X;
79  if (normal[1] == 1.0 || normal[1] == -1.0)
80  return PLANE_Y;
81  if (normal[2] == 1.0 || normal[2] == -1.0)
82  return PLANE_Z;
83 
84  ax = fabs(normal[0]);
85  ay = fabs(normal[1]);
86  az = fabs(normal[2]);
87 
88  if (ax >= ay && ax >= az)
89  return PLANE_ANYX;
90  if (ay >= ax && ay >= az)
91  return PLANE_ANYY;
92  return PLANE_ANYZ;
93 }
94 
102 static inline bool PlaneEqual (const plane_t* p, const vec3_t normal, const vec_t dist)
103 {
104  if (fabs(p->normal[0] - normal[0]) < NORMAL_EPSILON
105  && fabs(p->normal[1] - normal[1]) < NORMAL_EPSILON
106  && fabs(p->normal[2] - normal[2]) < NORMAL_EPSILON
107  && fabs(p->dist - dist) < MAP_DIST_EPSILON)
108  return true;
109  return false;
110 }
111 
112 static inline void AddPlaneToHash (plane_t* p)
113 {
114  const int hash = GetPlaneHashValueForDistance(p->dist);
115  p->hash_chain = planehash[hash];
116  planehash[hash] = p;
117 }
118 
119 static uint16_t CreateNewFloatPlane (vec3_t normal, vec_t dist)
120 {
121  plane_t* p;
122 
123  if (VectorLength(normal) < 0.5)
124  Sys_Error("FloatPlane: bad normal (%.3f:%.3f:%.3f)", normal[0], normal[1], normal[2]);
125  /* create a new plane */
126  if (nummapplanes + 2 > MAX_MAP_PLANES)
127  Sys_Error("MAX_MAP_PLANES (%i)", nummapplanes + 2);
128 
129  p = &mapplanes[nummapplanes];
130  VectorCopy(normal, p->normal);
131  p->dist = dist;
132  p->type = (p + 1)->type = PlaneTypeForNormal(p->normal);
133 
134  VectorSubtract(vec3_origin, normal, (p + 1)->normal);
135  (p + 1)->dist = -dist;
136 
137  nummapplanes += 2;
138 
139  /* always put axial planes facing positive first */
140  if (AXIAL(p)) {
141  if (p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0) {
142  /* flip order by swapping the planes */
143  const plane_t temp = *p;
144  *p = *(p + 1);
145  *(p + 1) = temp;
146 
147  AddPlaneToHash(p);
148  AddPlaneToHash(p + 1);
149  return nummapplanes - 1;
150  }
151  }
152 
153  AddPlaneToHash(p);
154  AddPlaneToHash(p + 1);
155  return nummapplanes - 2;
156 }
157 
163 static inline bool SnapVector (vec3_t normal)
164 {
165  for (int i = 0; i < 3; i++) {
166  if (fabs(normal[i] - 1) < NORMAL_EPSILON) {
167  VectorClear(normal);
168  normal[i] = 1;
169  return true;
170  }
171  if (fabs(normal[i] - -1) < NORMAL_EPSILON) {
172  VectorClear(normal);
173  normal[i] = -1;
174  return true;
175  }
176  }
177  return false;
178 }
179 
186 static inline void SnapPlane (vec3_t normal, vec_t* dist)
187 {
188  SnapVector(normal);
189 
190  if (fabs(*dist - Q_rint(*dist)) < MAP_DIST_EPSILON)
191  *dist = Q_rint(*dist);
192 }
193 
195 {
196  int i;
197  plane_t* p;
198  int hash;
199 
200  SnapPlane(normal, &dist);
201  hash = GetPlaneHashValueForDistance(dist);
202 
203  /* search the border bins as well */
204  for (i = -1; i <= 1; i++) {
205  const int h = (hash + i) & (PLANE_HASHES - 1);
206  for (p = planehash[h]; p; p = p->hash_chain) {
207  if (PlaneEqual(p, normal, dist)) {
208  const intptr_t index = p - mapplanes;
209  return (int16_t)index;
210  }
211  }
212  }
213 
214  return CreateNewFloatPlane(normal, dist);
215 }
216 
227 static int16_t PlaneFromPoints (const mapbrush_t* b, const vec3_t p0, const vec3_t p1, const vec3_t p2)
228 {
229  vec3_t t1, t2, normal;
230  vec_t dist;
231 
232  VectorSubtract(p0, p1, t1);
233  VectorSubtract(p2, p1, t2);
234  CrossProduct(t1, t2, normal);
235  VectorNormalize(normal);
236 
237  dist = DotProduct(p0, normal);
238 
239  if (!VectorNotEmpty(normal))
240  Sys_Error("PlaneFromPoints: Bad normal (null) for brush %i", b->brushnum);
241 
242  return FindOrCreateFloatPlane(normal, dist);
243 }
244 
245 
246 /*==================================================================== */
247 
248 
254 static int BrushContents (mapbrush_t* b)
255 {
256  int contentFlags, i;
257  const side_t* s;
258 
259  s = &b->original_sides[0];
260  contentFlags = s->contentFlags;
261  for (i = 1; i < b->numsides; i++, s++) {
262  if (s->contentFlags != contentFlags) {
263  Verb_Printf(VERB_EXTRA, "Entity %i, Brush %i: mixed face contents (f: %i, %i)\n"
264  , b->entitynum, b->brushnum, s->contentFlags, contentFlags);
265  break;
266  }
267  }
268 
269  return contentFlags;
270 }
271 
278 {
279  const byte levelflags = (brush->contentFlags >> 8) & 0xFF;
280  return levelflags;
281 }
282 
283 /*============================================================================ */
284 
289 static void AddBrushBevels (mapbrush_t* b)
290 {
291  int axis, dir;
292  int i, l, order;
293  vec3_t normal;
294 
295  /* add the axial planes */
296  order = 0;
297  for (axis = 0; axis < 3; axis++) {
298  for (dir = -1; dir <= 1; dir += 2, order++) {
299  side_t* s;
300  /* see if the plane is already present */
301  for (i = 0, s = b->original_sides; i < b->numsides; i++, s++) {
302  if (mapplanes[s->planenum].normal[axis] == dir)
303  break;
304  }
305 
306  if (i == b->numsides) { /* add a new side */
307  float dist;
309  Sys_Error("MAX_MAP_BRUSHSIDES (%i)", nummapbrushsides);
311  b->numsides++;
312  VectorClear(normal);
313  normal[axis] = dir;
314  if (dir == 1)
315  dist = b->mbBox.maxs[axis];
316  else
317  dist = -b->mbBox.mins[axis];
318  s->planenum = FindOrCreateFloatPlane(normal, dist);
319  s->texinfo = b->original_sides[0].texinfo;
321  s->bevel = true;
322  c_boxbevels++;
323  }
324 
325  /* if the plane is not in it canonical order, swap it */
326  if (i != order) {
327  const ptrdiff_t index = b->original_sides - brushsides;
328  side_t sidetemp = b->original_sides[order];
329  brush_texture_t tdtemp = side_brushtextures[index + order];
330 
331  b->original_sides[order] = b->original_sides[i];
332  b->original_sides[i] = sidetemp;
333 
334  side_brushtextures[index + order] = side_brushtextures[index + i];
335  side_brushtextures[index + i] = tdtemp;
336  }
337  }
338  }
339 
340  /* add the edge bevels */
341  if (b->numsides == 6)
342  return; /* pure axial */
343 
344  /* test the non-axial plane edges */
345  for (i = 6; i < b->numsides; i++) {
346  side_t* s = b->original_sides + i;
347  winding_t* w = s->winding;
348  if (!w)
349  continue;
350 
351  for (int j = 0; j < w->numpoints; j++) {
352  int k = (j + 1) % w->numpoints;
353  vec3_t vec;
354 
355  VectorSubtract(w->p[j], w->p[k], vec);
356  if (VectorNormalize(vec) < 0.5)
357  continue;
358 
359  SnapVector(vec);
360 
361  for (k = 0; k < 3; k++)
362  if (vec[k] == -1 || vec[k] == 1
363  || (vec[k] == 0.0f && vec[(k + 1) % 3] == 0.0f))
364  break; /* axial */
365  if (k != 3)
366  continue; /* only test non-axial edges */
367 
368  /* try the six possible slanted axials from this edge */
369  for (axis = 0; axis < 3; axis++) {
370  for (dir = -1; dir <= 1; dir += 2) {
371  /* construct a plane */
372  vec3_t vec2 = {0, 0, 0};
373  float dist;
374  side_t* s2;
375 
376  vec2[axis] = dir;
377  CrossProduct(vec, vec2, normal);
378  if (VectorNormalize(normal) < 0.5)
379  continue;
380  dist = DotProduct(w->p[j], normal);
381 
382  /* if all the points on all the sides are
383  * behind this plane, it is a proper edge bevel */
384  for (k = 0; k < b->numsides; k++) {
385  winding_t* w2;
386  float minBack;
387 
388  /* @note: This leads to different results on different archs
389  * due to float rounding/precision errors - use the -ffloat-store
390  * feature of gcc to 'fix' this */
391  /* if this plane has already been used, skip it */
392  if (PlaneEqual(&mapplanes[b->original_sides[k].planenum], normal, dist))
393  break;
394 
395  w2 = b->original_sides[k].winding;
396  if (!w2)
397  continue;
398  minBack = 0.0f;
399  for (l = 0; l < w2->numpoints; l++) {
400  const float d = DotProduct(w2->p[l], normal) - dist;
401  if (d > 0.1)
402  break; /* point in front */
403  if (d < minBack)
404  minBack = d;
405  }
406  /* if some point was at the front */
407  if (l != w2->numpoints)
408  break;
409  /* if no points at the back then the winding is on the bevel plane */
410  if (minBack > -0.1f)
411  break;
412  }
413 
414  if (k != b->numsides)
415  continue; /* wasn't part of the outer hull */
416  /* add this plane */
418  Sys_Error("MAX_MAP_BRUSHSIDES (%i)", nummapbrushsides);
420  s2 = &b->original_sides[b->numsides];
421  s2->planenum = FindOrCreateFloatPlane(normal, dist);
422  s2->texinfo = b->original_sides[0].texinfo;
424  s2->bevel = true;
425  c_edgebevels++;
426  b->numsides++;
427  }
428  }
429  }
430  }
431 }
432 
436 static bool MakeBrushWindings (mapbrush_t* brush)
437 {
438  int i, j;
439 
440  brush->mbBox.setNegativeVolume();
441 
442  for (i = 0; i < brush->numsides; i++) {
443  const plane_t* plane = &mapplanes[brush->original_sides[i].planenum];
444  winding_t* w = BaseWindingForPlane(plane->normal, plane->dist);
445  for (j = 0; j < brush->numsides && w; j++) {
446  if (i == j)
447  continue;
448  /* back side clipaway */
449  if (brush->original_sides[j].planenum == (brush->original_sides[j].planenum ^ 1))
450  continue;
451  if (brush->original_sides[j].bevel)
452  continue;
453  plane = &mapplanes[brush->original_sides[j].planenum ^ 1];
454  ChopWindingInPlace(&w, plane->normal, plane->dist, 0); /*CLIP_EPSILON); */
455  }
456 
457  side_t* side = &brush->original_sides[i];
458  side->winding = w;
459  if (w) {
460  side->visible = true;
461  for (j = 0; j < w->numpoints; j++)
462  brush->mbBox.add(w->p[j]);
463  }
464  }
465 
466  for (i = 0; i < 3; i++) {
467  if (brush->mbBox.mins[i] < -MAX_WORLD_WIDTH || brush->mbBox.maxs[i] > MAX_WORLD_WIDTH)
468  Com_Printf("entity %i, brush %i: bounds out of world range (%f:%f)\n",
469  brush->entitynum, brush->brushnum, brush->mbBox.mins[i], brush->mbBox.maxs[i]);
470  if (brush->mbBox.mins[i] > MAX_WORLD_WIDTH || brush->mbBox.maxs[i] < -MAX_WORLD_WIDTH) {
471  Com_Printf("entity %i, brush %i: no visible sides on brush\n", brush->entitynum, brush->brushnum);
472  brush->mbBox.reset();
473  }
474  }
475 
476  return true;
477 }
478 
484 static inline void CheckFlags (side_t* side, const mapbrush_t* b)
485 {
487  Sys_Error("Brush %i (entity %i) has invalid mix of passable and actorclip", b->brushnum, b->entitynum);
489  Sys_Error("Brush %i (entity %i) has invalid mix of clips and solid flags", b->brushnum, b->entitynum);
490 }
491 
493 static int materialsCnt = 0;
494 
498 static void GenerateMaterialFile (const char* filename, int mipTexIndex, side_t* s)
499 {
500  bool terrainByTexture = false;
501  char fileBase[MAX_OSPATH], materialPath[MAX_OSPATH];
502 
503  if (!config.generateMaterialFile)
504  return;
505 
506  /* we already have a material definition for this texture */
507  if (textureref[mipTexIndex].materialMarked)
508  return;
509 
510  assert(filename);
511 
512  Com_StripExtension(filename, fileBase, sizeof(fileBase));
513  Com_sprintf(materialPath, sizeof(materialPath), "materials/%s.mat", Com_SkipPath(fileBase));
514 
515  ScopedFile f;
516  FS_OpenFile(materialPath, &f, FILE_APPEND);
517  if (!f) {
518  Com_Printf("Could not open material file '%s' for writing\n", materialPath);
519  config.generateMaterialFile = false;
520  return;
521  }
522 
523  if (strstr(textureref[mipTexIndex].name, "dirt")
524  || strstr(textureref[mipTexIndex].name, "rock")
525  || strstr(textureref[mipTexIndex].name, "grass")) {
526  terrainByTexture = true;
527  }
528 
529  if ((s->contentFlags & CONTENTS_TERRAIN) || terrainByTexture) {
530  FS_Printf(&f, "{\n\tmaterial %s\n\t{\n\t\ttexture <fillme>\n\t\tterrain 0 64\n\t\tlightmap\n\t}\n}\n", textureref[mipTexIndex].name);
531  textureref[mipTexIndex].materialMarked = true;
532  materialsCnt++;
533  }
534 
535  /* envmap for water surfaces */
536  if ((s->contentFlags & CONTENTS_WATER)
537  || strstr(textureref[mipTexIndex].name, "glass")
538  || strstr(textureref[mipTexIndex].name, "window")) {
539  FS_Printf(&f, "{\n\tmaterial %s\n\tspecular 2.0\n\t{\n\t\tenvmap 0\n\t}\n}\n", textureref[mipTexIndex].name);
540  textureref[mipTexIndex].materialMarked = true;
541  materialsCnt++;
542  }
543 
544  if (strstr(textureref[mipTexIndex].name, "wood")) {
545  FS_Printf(&f, "{\n\tmaterial %s\n\tspecular 0.2\n}\n", textureref[mipTexIndex].name);
546  textureref[mipTexIndex].materialMarked = true;
547  materialsCnt++;
548  }
549 
550  if (strstr(textureref[mipTexIndex].name, "wall")) {
551  FS_Printf(&f, "{\n\tmaterial %s\n\tspecular 0.6\n\tbump 2.0\n}\n", textureref[mipTexIndex].name);
552  textureref[mipTexIndex].materialMarked = true;
553  materialsCnt++;
554  }
555 }
556 
558 static int footstepsCnt = 0;
559 
568 static void GenerateFootstepList (const char* filename, int mipTexIndex)
569 {
570  if (!config.generateFootstepFile)
571  return;
572 
573  if (textureref[mipTexIndex].footstepMarked)
574  return;
575 
576  assert(filename);
577 
578  char fileBase[MAX_OSPATH];
579  Com_StripExtension(filename, fileBase, sizeof(fileBase));
580 
581  ScopedFile f;
582  FS_OpenFile(va("%s.footsteps", fileBase), &f, FILE_APPEND);
583  if (!f) {
584  Com_Printf("Could not open footstep file '%s.footsteps' for writing\n", fileBase);
585  config.generateFootstepFile = false;
586  return;
587  }
588 #ifdef _WIN32
589  FS_Printf(&f, "terrain %s {\n}\n\n", textureref[mipTexIndex].name);
590 #else
591  FS_Printf(&f, "%s\n", textureref[mipTexIndex].name);
592 #endif
593  footstepsCnt++;
594  textureref[mipTexIndex].footstepMarked = true;
595 }
596 
603 static void ParseBrush (entity_t* mapent, const char* filename)
604 {
605  int j, k;
606  brush_texture_t td;
607  vec3_t planepts[3];
608  const int checkOrFix = config.performMapCheck || config.fixMap ;
609 
611  Sys_Error("nummapbrushes == MAX_MAP_BRUSHES (%i)", nummapbrushes);
612 
613  mapbrush_t* b = &mapbrushes[nummapbrushes];
614  OBJZERO(*b);
615  b->original_sides = &brushsides[nummapbrushsides];
616  b->entitynum = num_entities - 1;
617  b->brushnum = nummapbrushes - mapent->firstbrush;
618 
619  do {
620  if (Q_strnull(GetToken()))
621  break;
622  if (*parsedToken == '}')
623  break;
624 
626  Sys_Error("nummapbrushsides == MAX_MAP_BRUSHSIDES (%i)", nummapbrushsides);
627  side_t* side = &brushsides[nummapbrushsides];
628 
629  /* read the three point plane definition */
630  for (int i = 0; i < 3; i++) {
631  if (i != 0)
632  GetToken();
633  if (*parsedToken != '(')
634  Sys_Error("parsing brush");
635 
636  for (j = 0; j < 3; j++) {
637  GetToken();
638  planepts[i][j] = atof(parsedToken);
639  }
640 
641  GetToken();
642  if (*parsedToken != ')')
643  Sys_Error("parsing brush");
644  }
645 
646  /* read the texturedef */
647  GetToken();
648  if (strlen(parsedToken) >= MAX_TEXPATH) {
649  if (config.performMapCheck || config.fixMap)
650  Com_Printf(" ");/* hack to make this look like output from Check_Printf() */
651  Com_Printf("ParseBrush: texture name too long (limit %i): %s\n", MAX_TEXPATH, parsedToken);
652  if (config.fixMap)
653  Sys_Error("Aborting, as -fix is active and saving might corrupt *.map by truncating texture name");
654  }
655  Q_strncpyz(td.name, parsedToken, sizeof(td.name));
656 
657  td.shift[0] = atof(GetToken());
658  td.shift[1] = atof(GetToken());
659  td.rotate = atof(GetToken());
660  td.scale[0] = atof(GetToken());
661  td.scale[1] = atof(GetToken());
662 
663  /* find default flags and values */
664  const int mt = FindMiptex(td.name);
665  side->surfaceFlags = td.surfaceFlags = side->contentFlags = td.value = 0;
666 
667  if (TokenAvailable()) {
668  side->contentFlags = atoi(GetToken());
669  side->surfaceFlags = td.surfaceFlags = atoi(GetToken());
670  td.value = atoi(GetToken());
671  }
672 
673  /* if in check or fix mode, let them choose to do this (with command line options),
674  * and then call is made elsewhere */
675  if (!checkOrFix) {
676  SetImpliedFlags(side, &td, b);
677  /* if no other content flags are set - make this solid */
678  if (!checkOrFix && side->contentFlags == 0)
680  }
681 
682  /* translucent objects are automatically classified as detail and window */
684  side->contentFlags |= CONTENTS_DETAIL;
686  side->contentFlags |= CONTENTS_WINDOW;
687  side->contentFlags &= ~CONTENTS_SOLID;
688  }
689  if (config.fulldetail)
690  side->contentFlags &= ~CONTENTS_DETAIL;
691  if (!checkOrFix) {
692  if (!(side->contentFlags & ((LAST_VISIBLE_CONTENTS - 1)
694  side->contentFlags |= CONTENTS_SOLID;
695 
696  /* hints and skips are never detail, and have no content */
697  if (side->surfaceFlags & (SURF_HINT | SURF_SKIP)) {
698  side->contentFlags = 0;
699  side->surfaceFlags &= ~CONTENTS_DETAIL;
700  }
701  }
702 
703  /* check whether the flags are ok */
704  CheckFlags(side, b);
705 
706  /* generate a list of textures that should have footsteps when walking on them */
707  if (mt > 0 && (side->surfaceFlags & SURF_FOOTSTEP))
708  GenerateFootstepList(filename, mt);
709  GenerateMaterialFile(filename, mt, side);
710 
711  /* find the plane number */
712  int planenum = PlaneFromPoints(b, planepts[0], planepts[1], planepts[2]);
713  if (planenum == PLANENUM_LEAF) {
714  Com_Printf("Entity %i, Brush %i: plane with no normal\n", b->entitynum, b->brushnum);
715  continue;
716  }
717 
718  for (j = 0; j < 3; j++)
719  VectorCopy(planepts[j], mapplanes[planenum].planeVector[j]);
720 
721  /* see if the plane has been used already */
722  for (k = 0; k < b->numsides; k++) {
723  const side_t* s2 = b->original_sides + k;
724  if (s2->planenum == planenum) {
725  Com_Printf("Entity %i, Brush %i: duplicate plane\n", b->entitynum, b->brushnum);
726  break;
727  }
728  if (s2->planenum == (planenum ^ 1)) {
729  Com_Printf("Entity %i, Brush %i: mirrored plane\n", b->entitynum, b->brushnum);
730  break;
731  }
732  }
733  if (k != b->numsides)
734  continue; /* duplicated */
735 
736  /* keep this side */
737  side = b->original_sides + b->numsides;
738  side->planenum = planenum;
739  side->texinfo = TexinfoForBrushTexture(&mapplanes[planenum],
741  side->brush = b;
742 
743  /* save the td off in case there is an origin brush and we
744  * have to recalculate the texinfo */
745  side_brushtextures[nummapbrushsides] = td;
746 
747  Verb_Printf(VERB_DUMP, "Brush %i Side %i (%f %f %f) (%f %f %f) (%f %f %f) texinfo:%i[%s] plane:%i\n", nummapbrushes, nummapbrushsides,
748  planepts[0][0], planepts[0][1], planepts[0][2],
749  planepts[1][0], planepts[1][1], planepts[1][2],
750  planepts[2][0], planepts[2][1], planepts[2][2],
751  side->texinfo, td.name, planenum);
752 
754  b->numsides++;
755  } while (1);
756 
757  /* get the content for the entire brush */
758  b->contentFlags = BrushContents(b);
759 
760  /* copy all set face contentflags to the brush contentflags */
761  for (int m = 0; m < b->numsides; m++)
763 
764  /* set DETAIL, TRANSLUCENT contentflags on all faces, if they have been set on any.
765  * called separately, if in check/fix mode */
766  if (!checkOrFix)
768 
769  /* allow detail brushes to be removed */
770  if (config.nodetail && (b->contentFlags & CONTENTS_DETAIL)) {
771  b->numsides = 0;
772  return;
773  }
774 
775  /* allow water brushes to be removed */
776  if (config.nowater && (b->contentFlags & CONTENTS_WATER)) {
777  b->numsides = 0;
778  return;
779  }
780 
781  /* create windings for sides and bounds for brush */
783 
784  Verb_Printf(VERB_DUMP, "Brush %i mins (%f %f %f) maxs (%f %f %f)\n", nummapbrushes,
785  b->mbBox.mins[0], b->mbBox.mins[1], b->mbBox.mins[2],
786  b->mbBox.maxs[0], b->mbBox.maxs[1], b->mbBox.maxs[2]);
787 
788  /* origin brushes are removed, but they set
789  * the rotation origin for the rest of the brushes (like func_door)
790  * in the entity. After the entire entity is parsed, the planenums
791  * and texinfos will be adjusted for the origin brush */
792  if (!checkOrFix && (b->contentFlags & CONTENTS_ORIGIN)) {
793  char string[32];
794  vec3_t origin;
795 
796  if (num_entities == 1) {
797  Sys_Error("Entity %i, Brush %i: origin brushes not allowed in world"
798  , b->entitynum, b->brushnum);
799  return;
800  }
801 
802  b->mbBox.getCenter(origin);
803 
804  Com_sprintf(string, sizeof(string), "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
805  SetKeyValue(&entities[b->entitynum], "origin", string);
806  Verb_Printf(VERB_EXTRA, "Entity %i, Brush %i: set origin to %s\n", b->entitynum, b->brushnum, string);
807 
808  VectorCopy(origin, entities[b->entitynum].origin);
809 
810  /* don't keep this brush */
811  b->numsides = 0;
812 
813  return;
814  }
815 
816  if (!checkOrFix)
817  AddBrushBevels(b);
818 
819  nummapbrushes++;
820  mapent->numbrushes++;
821 }
822 
831 static void MoveBrushesToWorld (entity_t* mapent)
832 {
833  int newbrushes, worldbrushes, i;
834  mapbrush_t* temp;
835 
836  /* this is pretty gross, because the brushes are expected to be
837  * in linear order for each entity */
838 
839  newbrushes = mapent->numbrushes;
840  worldbrushes = entities[0].numbrushes;
841 
842  if (newbrushes == 0)
843  Sys_Error("Empty func_group - clean your map");
844 
845  temp = Mem_AllocTypeN(mapbrush_t, newbrushes);
846  memcpy(temp, mapbrushes + mapent->firstbrush, newbrushes * sizeof(*temp));
847 
848  /* make space to move the brushes (overlapped copy) */
849  memmove(mapbrushes + worldbrushes + newbrushes,
850  mapbrushes + worldbrushes,
851  sizeof(mapbrush_t) * (nummapbrushes - worldbrushes - newbrushes));
852 
853  /* copy the new brushes down */
854  memcpy(mapbrushes + worldbrushes, temp, sizeof(*temp) * newbrushes);
855 
856  /* fix up indexes */
857  entities[0].numbrushes += newbrushes;
858  for (i = 1; i < num_entities; i++)
859  entities[i].firstbrush += newbrushes;
860  Mem_Free(temp);
861 
862  mapent->numbrushes = 0;
863 }
864 
869 static void AdjustBrushesForOrigin (const entity_t* ent)
870 {
871  for (int i = 0; i < ent->numbrushes; i++) {
872  mapbrush_t* b = &mapbrushes[ent->firstbrush + i];
873  for (int j = 0; j < b->numsides; j++) {
874  side_t* s = &b->original_sides[j];
875  const ptrdiff_t index = s - brushsides;
876  const vec_t newdist = mapplanes[s->planenum].dist -
877  DotProduct(mapplanes[s->planenum].normal, ent->origin);
879  side_brushtextures[index].surfaceFlags |= SURF_ORIGIN;
880  s->planenum = FindOrCreateFloatPlane(mapplanes[s->planenum].normal, newdist);
881  s->texinfo = TexinfoForBrushTexture(&mapplanes[s->planenum],
882  &side_brushtextures[index], ent->origin, s->contentFlags & CONTENTS_TERRAIN);
883  s->brush = b;
884  }
885  /* create windings for sides and bounds for brush */
887  }
888 }
889 
895 static inline bool IsInlineModelEntity (const char* entName)
896 {
897  const bool inlineModelEntity = (Q_streq("func_breakable", entName)
898  || Q_streq("func_door", entName)
899  || Q_streq("func_door_sliding", entName)
900  || Q_streq("func_rotating", entName)
901  || Q_strstart(entName, "trigger_"));
902  return inlineModelEntity;
903 }
904 
911 entity_t* FindTargetEntity (const char* target)
912 {
913  for (int i = 0; i < num_entities; i++) {
914  const char* n = ValueForKey(&entities[i], "targetname");
915  if (Q_streq(n, target))
916  return &entities[i];
917  }
918 
919  return nullptr;
920 }
921 
928 static bool ParseMapEntity (const char* filename, const char* entityString)
929 {
930  entity_t* mapent;
931  const char* entName;
932  static int worldspawnCount = 0;
933  int notCheckOrFix = !(config.performMapCheck || config.fixMap);
934 
935  if (Q_strnull(GetToken()))
936  return false;
937 
938  if (*parsedToken != '{')
939  Sys_Error("ParseMapEntity: { not found");
940 
942  Sys_Error("num_entities == MAX_MAP_ENTITIES (%i)", num_entities);
943 
944  mapent = &entities[num_entities++];
945  OBJZERO(*mapent);
946  mapent->firstbrush = nummapbrushes;
947  mapent->numbrushes = 0;
948 
949  do {
950  if (Q_strnull(GetToken()))
951  Sys_Error("ParseMapEntity: EOF without closing brace");
952  if (*parsedToken == '}')
953  break;
954  if (*parsedToken == '{')
955  ParseBrush(mapent, filename);
956  else {
958  e->next = mapent->epairs;
959  mapent->epairs = e;
960  }
961  } while (true);
962 
963  GetVectorForKey(mapent, "origin", mapent->origin);
964 
965  entName = ValueForKey(mapent, "classname");
966 
967  /* offset all of the planes and texinfo if needed */
968  if (IsInlineModelEntity(entName) && VectorNotEmpty(mapent->origin))
969  AdjustBrushesForOrigin(mapent);
970 
971  if (num_entities == 1 && !Q_streq("worldspawn", entName))
972  Sys_Error("The first entity must be worldspawn, it is: %s", entName);
973  if (notCheckOrFix && Q_streq("func_group", entName)) {
974  /* group entities are just for editor convenience
975  * toss all brushes into the world entity */
976  MoveBrushesToWorld(mapent);
977  num_entities--;
978  } else if (IsInlineModelEntity(entName)) {
979  if (mapent->numbrushes == 0 && notCheckOrFix) {
980  Com_Printf("Warning: %s has no brushes assigned (entnum: %i)\n", entName, num_entities);
981  num_entities--;
982  }
983  } else if (Q_streq("worldspawn", entName)) {
984  worldspawnCount++;
985  if (worldspawnCount > 1)
986  Com_Printf("Warning: more than one %s in one map\n", entName);
987 
988  const char* text = entityString;
989  do {
990  const char* token = Com_Parse(&text);
991  if (Q_strnull(token))
992  break;
993  const char* key = Mem_StrDup(token);
994  token = Com_Parse(&text);
995  if (Q_strnull(token))
996  break;
997  const char* value = Mem_StrDup(token);
998  epair_t* e = AddEpair(key, value, num_entities);
999  if (!config.fixMap || !EpairCheckForDuplicate(mapent, e)) {
1000  e->next = mapent->epairs;
1001  e->ump = true;
1002  mapent->epairs = e;
1003  }
1004  } while (true);
1005  }
1006  return true;
1007 }
1008 
1013 static inline void WriteMapEntities (qFILE* f, const epair_t* e)
1014 {
1015  if (!e)
1016  return;
1017 
1018  if (e->next)
1019  WriteMapEntities(f, e->next);
1020 
1021  if (!e->ump)
1022  FS_Printf(f, "\"%s\" \"%s\"\n", e->key, e->value);
1023 }
1024 
1025 
1032 static void WriteMapBrush (const mapbrush_t* brush, const int j, qFILE* f)
1033 {
1034  FS_Printf(f, "// brush %i\n{\n", j);
1035  for (int k = 0; k < brush->numsides; k++) {
1036  const side_t* side = &brush->original_sides[k];
1037  const ptrdiff_t index = side - brushsides;
1038  const brush_texture_t* t = &side_brushtextures[index];
1039  const plane_t* p = &mapplanes[side->planenum];
1040 
1041  for (int i = 0; i < 3; i++)
1042  FS_Printf(f, "( %.7g %.7g %.7g ) ", p->planeVector[i][0], p->planeVector[i][1], p->planeVector[i][2]);
1043  FS_Printf(f, "%s ", t->name);
1044  FS_Printf(f, "%.7g %.7g %.7g ", t->shift[0], t->shift[1], t->rotate);
1045  FS_Printf(f, "%.7g %.7g ", t->scale[0], t->scale[1]);
1046  FS_Printf(f, "%i %i %i\n", side->contentFlags, t->surfaceFlags, t->value);
1047  }
1048  FS_Printf(f, "}\n");
1049 }
1050 
1055 void WriteMapFile (const char* filename)
1056 {
1057  int removed;
1058 
1059  Verb_Printf(VERB_NORMAL, "writing map: '%s'\n", filename);
1060 
1061  ScopedFile f;
1062  FS_OpenFile(filename, &f, FILE_WRITE);
1063  if (!f)
1064  Sys_Error("Could not open %s for writing", filename);
1065 
1066  removed = 0;
1067  for (int i = 0; i < num_entities; i++) {
1068  const entity_t* mapent = &entities[i];
1069  const epair_t* e = mapent->epairs;
1070 
1071  /* maybe we don't want to write it back into the file */
1072  if (mapent->skip) {
1073  removed++;
1074  continue;
1075  }
1076  FS_Printf(&f, "// entity %i\n{\n", i - removed);
1077  WriteMapEntities(&f, e);
1078 
1079  /* need 2 counters. j counts the brushes in the source entity.
1080  * jc counts the brushes written back. they may differ if some are skipped,
1081  * eg they are microbrushes */
1082  int j, jc;
1083  for (j = 0, jc = 0; j < mapent->numbrushes; j++) {
1084  const mapbrush_t* brush = &mapbrushes[mapent->firstbrush + j];
1085  if (brush->skipWriteBack)
1086  continue;
1087  WriteMapBrush(brush, jc++, &f);
1088  }
1089 
1090  /* add brushes from func_groups with single members to worldspawn */
1091  if (i == 0) {
1092  int numToAdd;
1093  mapbrush_t** brushesToAdd = Check_ExtraBrushesForWorldspawn(&numToAdd);
1094  if (brushesToAdd != nullptr) {
1095  for (int k = 0; k < numToAdd; k++) {
1096  if (brushesToAdd[k]->skipWriteBack)
1097  continue;
1098  WriteMapBrush(brushesToAdd[k], j++, &f);
1099  }
1100  Mem_Free(brushesToAdd);
1101  }
1102  }
1103  FS_Printf(&f, "}\n");
1104  }
1105 
1106  if (removed)
1107  Verb_Printf(VERB_NORMAL, "removed %i entities\n", removed);
1108 }
1109 
1117 static void ParseUMP (const char* name, char* entityString, bool inherit)
1118 {
1119  char filename[MAX_QPATH];
1120  byte* buf;
1121  const char* text;
1122 
1123  *entityString = '\0';
1124 
1125  /* load the map info */
1126  Com_sprintf(filename, sizeof(filename), "maps/%s.ump", name);
1127  FS_LoadFile(filename, &buf);
1128  if (!buf)
1129  return;
1130 
1131  /* parse it */
1132  text = (const char*)buf;
1133  do {
1134  const char* token = Com_Parse(&text);
1135  if (!text)
1136  break;
1137 
1138  if (Q_streq(token, "extends")) {
1139  token = Com_Parse(&text);
1140  if (inherit)
1141  Com_Printf("ParseUMP: Too many extends in %s 'extends %s' ignored\n", filename, token);
1142  else
1143  ParseUMP(token, entityString, true);
1144  } else if (Q_streq(token, "worldspawn")) {
1145  const char* start = nullptr;
1146  const int length = Com_GetBlock(&text, &start);
1147  if (length == -1) {
1148  Com_Printf("ParseUMP: Not a valid worldspawn block in '%s'\n", filename);
1149  } else {
1150  if (length >= MAX_TOKEN_CHARS) {
1151  Com_Printf("worldspawn is too big - only %i characters are allowed", MAX_TOKEN_CHARS);
1152  } else if (length == 0) {
1153  Com_Printf("no worldspawn settings in ump file\n");
1154  } else {
1155  Q_strncpyz(entityString, start, length);
1156  Com_Printf("use worldspawn settings from ump file\n");
1157  }
1158  }
1159  } else if (token[0] == '{') {
1160  /* ignore unknown block */
1161  text = strchr(text, '}') + 1;
1162  if (!text)
1163  break;
1164  }
1165  } while (text);
1166 
1167  /* free the file */
1168  FS_FreeFile(buf);
1169 }
1170 
1174 static const char* GetUMPName (const char* mapFilename)
1175 {
1176  static char name[MAX_QPATH];
1177  const char* filename = Com_SkipPath(mapFilename);
1178  /* if we are in no subdir, we don't have any ump */
1179  if (filename == nullptr)
1180  return nullptr;
1181 
1182  const char* mapsDir = "maps/";
1183  const int lMaps = strlen(mapsDir);
1184  const int l = strlen(filename);
1185  const int targetLength = strlen(mapFilename) - lMaps - l;
1186  if (targetLength <= 0)
1187  return nullptr;
1188  Q_strncpyz(name, mapFilename + lMaps, targetLength);
1189  Com_Printf("...ump: '%s%s.ump'\n", mapsDir, name);
1190  return name;
1191 }
1192 
1197 void LoadMapFile (const char* filename)
1198 {
1199  Verb_Printf(VERB_EXTRA, "--- LoadMapFile ---\n");
1200 
1201  LoadScriptFile(filename);
1202 
1203  OBJZERO(mapbrushes);
1204  nummapbrushes = 0;
1205 
1206  OBJZERO(brushsides);
1207  nummapbrushsides = 0;
1208 
1209  OBJZERO(side_brushtextures);
1210 
1211  OBJZERO(mapplanes);
1212 
1213  num_entities = 0;
1214  /* Create this shortcut to mapTiles[0] */
1215  curTile = &mapTiles.mapTiles[0];
1216  /* Set the number of tiles to 1. This is fix for ufo2map right now. */
1217  mapTiles.numTiles = 1;
1218 
1219  char entityString[2 * MAX_TOKEN_CHARS] = "";
1220  const char* ump = GetUMPName(filename);
1221  if (ump != nullptr)
1222  ParseUMP(ump, entityString, false);
1223 
1224  while (ParseMapEntity(filename, entityString));
1225 
1226  int subdivide = atoi(ValueForKey(&entities[0], "subdivide"));
1227  if (subdivide >= 256 && subdivide <= 2048) {
1228  Verb_Printf(VERB_EXTRA, "Using subdivide %d from worldspawn.\n", subdivide);
1229  config.subdivideSize = subdivide;
1230  }
1231 
1232  if (footstepsCnt)
1233  Com_Printf("Generated footstep file with %i entries\n", footstepsCnt);
1234  if (materialsCnt)
1235  Com_Printf("Generated material file with %i entries\n", materialsCnt);
1236 
1237  AABB mapBox;
1238  mapBox.setNegativeVolume();
1239  for (int i = 0; i < entities[0].numbrushes; i++) {
1240  if (mapbrushes[i].mbBox.mins[0] > MAX_WORLD_WIDTH)
1241  continue; /* no valid points */
1242  mapBox.add(mapbrushes[i].mbBox);
1243  }
1244 
1245  /* save a copy of the brushes */
1246  memcpy(mapbrushes + nummapbrushes, mapbrushes, sizeof(mapbrush_t) * nummapbrushes);
1247 
1248  Verb_Printf(VERB_EXTRA, "%5i brushes\n", nummapbrushes);
1249  Verb_Printf(VERB_EXTRA, "%5i total sides\n", nummapbrushsides);
1250  Verb_Printf(VERB_EXTRA, "%5i boxbevels\n", c_boxbevels);
1251  Verb_Printf(VERB_EXTRA, "%5i edgebevels\n", c_edgebevels);
1252  Verb_Printf(VERB_EXTRA, "%5i entities\n", num_entities);
1253  Verb_Printf(VERB_EXTRA, "%5i planes\n", nummapplanes);
1254  char sizeStr[AABB_STRING];
1255  mapBox.asIntString(sizeStr, sizeof(sizeStr));
1256  Verb_Printf(VERB_EXTRA, "size: %s\n", sizeStr);
1257 }
#define SURF_ORIGIN
Definition: defines.h:266
bool Q_strnull(const char *string)
Definition: shared.h:138
vec_t VectorLength(const vec3_t v)
Calculate the length of a vector.
Definition: mathlib.cpp:434
Performs check on a loaded mapfile, and makes changes that can be saved back to the source map...
vec3_t normal
Definition: map.h:99
static int c_boxbevels
Definition: map.cpp:49
#define VectorCopy(src, dest)
Definition: vector.h:51
#define Mem_AllocTypeN(type, n)
Definition: mem.h:38
#define MAX_MAP_ENTITIES
Definition: defines.h:136
#define CONTENTS_WEAPONCLIP
Definition: defines.h:249
void setNegativeVolume()
Sets mins and maxs to their starting points before using addPoint.
Definition: aabb.h:98
vec3_t planeVector[3]
Definition: map.h:106
void Sys_Error(const char *error,...)
Definition: g_main.cpp:421
textureref_t textureref[MAX_MAP_TEXTURES]
Definition: textures.cpp:30
int nummapbrushes
Definition: map.cpp:35
int texinfo
Definition: map.h:62
#define LAST_VISIBLE_CONTENTS
Definition: defines.h:230
mapbrush_t mapbrushes[MAX_MAP_BRUSHES]
Definition: map.cpp:34
QGL_EXTERN GLint GLenum type
Definition: r_gl.h:94
bool ump
Definition: bspfile.h:40
#define PLANE_ANYX
Definition: defines.h:196
#define PLANE_ANYY
Definition: defines.h:197
const char * Com_SkipPath(const char *pathname)
Returns just the filename from a given path.
Definition: shared.cpp:37
vec3_t origin
Definition: bspfile.h:47
int FS_OpenFile(const char *filename, qFILE *file, filemode_t mode)
Finds and opens the file in the search path.
Definition: files.cpp:162
#define CONTENTS_ORIGIN
Definition: defines.h:248
#define NORMAL_EPSILON
Definition: defines.h:381
static void MoveBrushesToWorld(entity_t *mapent)
Takes all of the brushes from the current entity and adds them to the world's brush list...
Definition: map.cpp:831
#define CONTENTS_PASSABLE
Definition: defines.h:244
struct epair_s * next
Definition: bspfile.h:37
const char * va(const char *format,...)
does a varargs printf into a temp buffer, so I don't need to have varargs versions of all text functi...
Definition: shared.cpp:410
bool bevel
Definition: map.h:69
static char mapFilename[MAX_OSPATH]
Definition: ufo2map.cpp:50
int entitynum
Definition: map.h:76
static bool IsInlineModelEntity(const char *entName)
Checks whether this entity is an inline model that should have brushes.
Definition: map.cpp:895
bool skip
Definition: bspfile.h:51
static int materialsCnt
How many materials were created for this map.
Definition: map.cpp:493
int firstbrush
Definition: bspfile.h:48
brush_texture_t side_brushtextures[MAX_MAP_SIDES]
Definition: map.cpp:40
bool EpairCheckForDuplicate(const entity_t *ent, const epair_t *e)
Definition: bspfile.cpp:418
#define CONTENTS_SOLID
Definition: defines.h:223
#define MAX_MAP_PLANES
Definition: defines.h:139
voidpf uLong int origin
Definition: ioapi.h:45
#define SURF_ALPHATEST
Definition: defines.h:268
#define PLANE_Z
Definition: defines.h:193
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
void Com_StripExtension(const char *in, char *out, const size_t size)
Removes the file extension from a filename.
Definition: shared.cpp:259
int type
Definition: map.h:105
int TexinfoForBrushTexture(plane_t *plane, brush_texture_t *bt, const vec3_t origin, bool isTerrain)
Definition: textures.cpp:89
bool materialMarked
Definition: textures.h:36
Definition: aabb.h:42
const char * filename
Definition: ioapi.h:41
const vec3_t vec3_origin
Definition: mathlib.cpp:35
plane_t mapplanes[MAX_MAP_PLANES]
Definition: map.cpp:43
float vec_t
Definition: ufotypes.h:37
void CheckPropagateParserContentFlags(mapbrush_t *b)
some contentlflags are set as a result of some surface flag. For example, if one face is TRANS* then ...
Definition: check.cpp:1619
#define SURF_FOOTSTEP
Definition: defines.h:265
void CrossProduct(const vec3_t v1, const vec3_t v2, vec3_t cross)
binary operation on vectors in a three-dimensional space
Definition: mathlib.cpp:820
void ChopWindingInPlace(winding_t **inout, const vec3_t normal, const vec_t dist, const vec_t epsilon)
Definition: polylib.cpp:299
winding_t * winding
Definition: map.h:63
void SetImpliedFlags(side_t *side, brush_texture_t *tex, const mapbrush_t *brush)
Sets surface flags dependent on assigned texture.
Definition: check.cpp:1448
int FS_LoadFile(const char *path, byte **buffer)
Filenames are relative to the quake search path.
Definition: files.cpp:384
int numsides
Definition: map.h:83
#define MAX_OSPATH
Definition: filesys.h:44
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
const char * value
Definition: bspfile.h:39
vec3_t maxs
Definition: aabb.h:258
static void WriteMapBrush(const mapbrush_t *brush, const int j, qFILE *f)
write a brush to the .map file
Definition: map.cpp:1032
static int footstepsCnt
Amount of footstep surfaces found in this map.
Definition: map.cpp:558
void LoadScriptFile(const char *filename)
Definition: scriplib.cpp:47
#define Mem_StrDup(in)
Definition: mem.h:48
entity_t entities[MAX_MAP_ENTITIES]
Definition: bspfile.cpp:395
void WriteMapFile(const char *filename)
Definition: map.cpp:1055
AABB mbBox
Definition: map.h:81
static const char * GetUMPName(const char *mapFilename)
The contract is that the directory name is equal to the base of the ump filename. ...
Definition: map.cpp:1174
#define CONTENTS_WINDOW
Definition: defines.h:224
voidpf void * buf
Definition: ioapi.h:42
#define CONTENTS_DETAIL
Definition: defines.h:251
bool footstepMarked
Definition: textures.h:35
static void ParseBrush(entity_t *mapent, const char *filename)
Parses a brush from the map file.
Definition: map.cpp:603
side_t brushsides[MAX_MAP_SIDES]
Definition: map.cpp:37
epair_t * ParseEpair(int entNum)
Parses one key and value for an entity from the current tokens.
Definition: bspfile.cpp:453
vec2_t scale
Definition: map.h:36
#define CONTENTS_WATER
Definition: defines.h:226
static void AdjustBrushesForOrigin(const entity_t *ent)
If there was an origin brush, offset all of the planes and texinfo.
Definition: map.cpp:869
static int16_t PlaneFromPoints(const mapbrush_t *b, const vec3_t p0, const vec3_t p1, const vec3_t p2)
Builds a plane normal and distance from three points on the plane. If the normal is nearly axial...
Definition: map.cpp:227
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
#define AXIAL(p)
Definition: defines.h:201
#define MAX_MAP_BRUSHSIDES
Definition: defines.h:141
void SetKeyValue(entity_t *ent, const char *key, const char *value)
Definition: bspfile.cpp:546
unsigned int key
Definition: cl_input.cpp:68
#define SURF_BLEND33
Definition: defines.h:257
Definition: map.h:98
static bool MakeBrushWindings(mapbrush_t *brush)
makes basewindings for sides and mins / maxs for the brush
Definition: map.cpp:436
void add(const vec3_t point)
If the point is outside the box, expand the box to accommodate it.
Definition: aabb.cpp:57
#define DotProduct(x, y)
Returns the distance between two 3-dimensional vectors.
Definition: vector.h:44
static void AddBrushBevels(mapbrush_t *b)
Adds any additional planes necessary to allow the brush to be expanded against axial bounding boxes...
Definition: map.cpp:289
#define MAX_TEXPATH
Definition: defines.h:95
void GetVectorForKey(const entity_t *ent, const char *key, vec3_t vec)
Converts the value of a entity parameter into a vec3_t.
Definition: bspfile.cpp:592
int value
Definition: map.h:39
#define OBJZERO(obj)
Definition: shared.h:178
QGL_EXTERN GLuint GLsizei GLsizei * length
Definition: r_gl.h:110
vec_t rotate
Definition: map.h:35
static void CheckFlags(side_t *side, const mapbrush_t *b)
Checks whether the surface and content flags are correct.
Definition: map.cpp:484
static int PlaneTypeForNormal(const vec3_t normal)
Set the type of the plane according to it's normal vector.
Definition: map.cpp:72
static int BrushContents(mapbrush_t *b)
Get the content flags for a given brush.
Definition: map.cpp:254
static wrapCache_t * hash[MAX_WRAP_HASH]
Definition: r_font.cpp:86
static uint16_t CreateNewFloatPlane(vec3_t normal, vec_t dist)
Definition: map.cpp:119
static int GetPlaneHashValueForDistance(const vec_t distance)
Planes are stored by their distance (resp. the calculated hash) in the plane hash table...
Definition: map.cpp:62
mapbrush_t ** Check_ExtraBrushesForWorldspawn(int *numBrushes)
single brushes in func_groups are moved to worldspawn. this function allocates space for pointers to ...
uint16_t planenum
Definition: map.h:61
#define MAX_MAP_SIDES
Definition: defines.h:383
char const * Q_strstart(char const *str, char const *start)
Matches the start of a string.
Definition: shared.cpp:587
#define PLANE_ANYZ
Definition: defines.h:198
vec3_t normal
Definition: lightmap.cpp:281
int FS_Printf(qFILE *f, const char *msg,...)
Can print chunks for 1024 chars into a file.
Definition: files.cpp:1495
void LoadMapFile(const char *filename)
Definition: map.cpp:1197
#define MAX_TOKEN_CHARS
Definition: defines.h:372
entity_t * FindTargetEntity(const char *target)
Searches the entities array for an entity with the parameter targetname that matches the searched tar...
Definition: map.cpp:911
struct side_s * original_sides
Definition: map.h:84
struct mapbrush_s * brush
Definition: map.h:72
for storing the vertices of the side of a brush or other polygon
Definition: polylib.h:30
#define VectorNotEmpty(a)
Definition: vector.h:72
bool visible
Definition: map.h:67
#define MAP_DIST_EPSILON
Definition: defines.h:380
void getCenter(vec3_t center) const
Calculates the center of the bounding box.
Definition: aabb.h:155
char parsedToken[MAX_TOKEN_CHARS]
Definition: scriplib.cpp:45
void Verb_Printf(const verbosityLevel_t importance, const char *format,...) __attribute__((format(__printf__
Definition: map.h:60
static config_t config
Definition: test_all.cpp:43
QGL_EXTERN GLuint index
Definition: r_gl.h:110
dMapTile_t * curTile
Definition: bsp.cpp:32
int Com_GetBlock(const char **text, const char **start)
Get the start and end point of a block in the given text.
Definition: parse.cpp:272
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
#define VectorClear(a)
Definition: vector.h:55
#define SURF_SKIP
Definition: defines.h:262
uint32_t contentFlags
Definition: map.h:65
static void GenerateMaterialFile(const char *filename, int mipTexIndex, side_t *s)
Generates material files in case the settings can be guessed from map file.
Definition: map.cpp:498
void asIntString(char *str, size_t len)
Prints a representation of the box.
Definition: aabb.h:167
static void SnapPlane(vec3_t normal, vec_t *dist)
Snaps normal to axis-aligned if it is within an epsilon of axial.
Definition: map.cpp:186
const char * Com_Parse(const char *data_p[], char *target, size_t size, bool replaceWhitespaces)
Parse a token out of a string.
Definition: parse.cpp:107
static void WriteMapEntities(qFILE *f, const epair_t *e)
Recurse down the epair list.
Definition: map.cpp:1013
#define CONTENTS_TERRAIN
Definition: defines.h:245
struct plane_s * hash_chain
Definition: map.h:107
int numbrushes
Definition: bspfile.h:49
bool skipWriteBack
Definition: map.h:92
#define CONTENTS_ACTORCLIP
Definition: defines.h:243
int numTiles
Definition: tracing.h:82
#define PLANENUM_LEAF
Definition: defines.h:45
TR_TILE_TYPE mapTiles[MAX_MAPTILES]
Definition: tracing.h:79
#define MAX_QPATH
Definition: filesys.h:40
QGL_EXTERN GLint i
Definition: r_gl.h:113
vec3_t p[4]
Definition: polylib.h:32
static bool SnapVector(vec3_t normal)
Round the vector to int values.
Definition: map.cpp:163
int brushnum
Definition: map.h:77
vec_t VectorNormalize(vec3_t v)
Calculate unit vector for a given vec3_t.
Definition: mathlib.cpp:745
const char * key
Definition: bspfile.h:38
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition: r_gl.h:110
#define CONTENTS_TRANSLUCENT
Definition: defines.h:252
vec_t dist
Definition: map.h:100
byte GetLevelFlagsFromBrush(const mapbrush_t *brush)
Extract the level flags (1-8) from the content flags of the given brush.
Definition: map.cpp:277
Definition: map.h:75
static void AddPlaneToHash(plane_t *p)
Definition: map.cpp:112
#define PLANE_HASHES
Definition: map.cpp:46
static plane_t * planehash[PLANE_HASHES]
Definition: map.cpp:47
#define Mem_Free(ptr)
Definition: mem.h:35
int nummapbrushsides
Definition: map.cpp:38
uint32_t surfaceFlags
Definition: map.h:38
winding_t * BaseWindingForPlane(const vec3_t normal, const vec_t dist)
Definition: polylib.cpp:116
vec_t vec3_t[3]
Definition: ufotypes.h:39
const char * GetToken()
Parses the next token from the current script on the stack and store the result in parsedToken...
Definition: scriplib.cpp:75
static void GenerateFootstepList(const char *filename, int mipTexIndex)
Generate a list of textures that should have footsteps when walking on them.
Definition: map.cpp:568
#define MAX_WORLD_WIDTH
-MAX_WORLD_WIDTH up tp +MAX_WORLD_WIDTH
Definition: defines.h:288
vec2_t shift
Definition: map.h:34
vec_t Q_rint(const vec_t in)
Round to nearest integer.
Definition: mathlib.cpp:156
vec3_t mins
Definition: aabb.h:257
#define SURF_HINT
Definition: defines.h:261
uint32_t surfaceFlags
Definition: map.h:66
#define Q_streq(a, b)
Definition: shared.h:136
#define SURF_BLEND66
Definition: defines.h:258
static bool ParseMapEntity(const char *filename, const char *entityString)
Parsed map entites and brushes.
Definition: map.cpp:928
int FindMiptex(const char *name)
Definition: textures.cpp:38
const char * ValueForKey(const entity_t *ent, const char *key)
Definition: bspfile.cpp:558
bool TokenAvailable(void)
Returns true if there is another token on the line.
Definition: scriplib.cpp:92
#define AABB_STRING
Definition: aabb.h:40
epair_t * AddEpair(const char *key, const char *value, int entNum)
Definition: bspfile.cpp:428
static bool PlaneEqual(const plane_t *p, const vec3_t normal, const vec_t dist)
Checks whether the given normal and distance vectors match the given plane by some epsilon value...
Definition: map.cpp:102
#define CONTENTS_LIGHTCLIP
Definition: defines.h:246
#define PLANE_Y
Definition: defines.h:192
uint8_t byte
Definition: ufotypes.h:34
#define MAX_MAP_BRUSHES
Definition: defines.h:135
static struct mdfour * m
Definition: md4.cpp:35
void reset()
Definition: aabb.h:83
int num_entities
Definition: bspfile.cpp:394
uint16_t FindOrCreateFloatPlane(vec3_t normal, vec_t dist)
Definition: map.cpp:194
#define VectorSubtract(a, b, dest)
Definition: vector.h:45
uint32_t contentFlags
Definition: map.h:79
int nummapplanes
Definition: map.cpp:44
epair_t * epairs
Definition: bspfile.h:50
#define PLANE_X
Definition: defines.h:191
static mapTiles_t mapTiles
int numpoints
Definition: polylib.h:31
void FS_FreeFile(void *buffer)
Definition: files.cpp:411
static int c_edgebevels
Definition: map.cpp:50
static void ParseUMP(const char *name, char *entityString, bool inherit)
Parses an ump file that contains the random map definition.
Definition: map.cpp:1117
char name[MAX_TEXPATH]
Definition: map.h:37