00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "qbsp.h"
00024 #include "l_bsp_hl.h"
00025 #include "l_bsp_q1.h"
00026 #include "l_bsp_q2.h"
00027 #include "l_bsp_q3.h"
00028 #include "l_bsp_sin.h"
00029 #include "l_mem.h"
00030 #include "../botlib/aasfile.h"
00031 #include "aas_store.h"
00032 #include "aas_cfg.h"
00033
00034 #define Sign(x) (x < 0 ? 1 : 0)
00035
00036 int nummapbrushes;
00037 mapbrush_t mapbrushes[MAX_MAPFILE_BRUSHES];
00038
00039 int nummapbrushsides;
00040 side_t brushsides[MAX_MAPFILE_BRUSHSIDES];
00041 brush_texture_t side_brushtextures[MAX_MAPFILE_BRUSHSIDES];
00042
00043 int nummapplanes;
00044 plane_t mapplanes[MAX_MAPFILE_PLANES];
00045 int mapplaneusers[MAX_MAPFILE_PLANES];
00046
00047 #define PLANE_HASHES 1024
00048 plane_t *planehash[PLANE_HASHES];
00049 vec3_t map_mins, map_maxs;
00050
00051 #ifdef SIN
00052 textureref_t side_newrefs[MAX_MAPFILE_BRUSHSIDES];
00053 #endif
00054
00055 map_texinfo_t map_texinfo[MAX_MAPFILE_TEXINFO];
00056 int map_numtexinfo;
00057 int loadedmaptype;
00058
00059
00060 #define USE_HASHING
00061
00062 int c_boxbevels;
00063 int c_edgebevels;
00064 int c_areaportals;
00065 int c_clipbrushes;
00066 int c_squattbrushes;
00067 int c_writtenbrushes;
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084 int PlaneSignBits(vec3_t normal)
00085 {
00086 int i, signbits;
00087
00088 signbits = 0;
00089 for (i = 2; i >= 0; i--)
00090 {
00091 signbits = (signbits << 1) + Sign(normal[i]);
00092 }
00093 return signbits;
00094 }
00095
00096
00097
00098
00099
00100
00101 int PlaneTypeForNormal(vec3_t normal)
00102 {
00103 vec_t ax, ay, az;
00104
00105
00106 if (normal[0] == 1.0 || normal[0] == -1.0)
00107 return PLANE_X;
00108 if (normal[1] == 1.0 || normal[1] == -1.0)
00109 return PLANE_Y;
00110 if (normal[2] == 1.0 || normal[2] == -1.0)
00111 return PLANE_Z;
00112
00113 ax = fabs(normal[0]);
00114 ay = fabs(normal[1]);
00115 az = fabs(normal[2]);
00116
00117 if (ax >= ay && ax >= az)
00118 return PLANE_ANYX;
00119 if (ay >= ax && ay >= az)
00120 return PLANE_ANYY;
00121 return PLANE_ANYZ;
00122 }
00123
00124
00125
00126
00127
00128
00129
00130 #define NORMAL_EPSILON 0.0001
00131
00132 #define DIST_EPSILON 0.02
00133 qboolean PlaneEqual(plane_t *p, vec3_t normal, vec_t dist)
00134 {
00135 #if 1
00136 if (
00137 fabs(p->normal[0] - normal[0]) < NORMAL_EPSILON
00138 && fabs(p->normal[1] - normal[1]) < NORMAL_EPSILON
00139 && fabs(p->normal[2] - normal[2]) < NORMAL_EPSILON
00140 && fabs(p->dist - dist) < DIST_EPSILON )
00141 return true;
00142 #else
00143 if (p->normal[0] == normal[0]
00144 && p->normal[1] == normal[1]
00145 && p->normal[2] == normal[2]
00146 && p->dist == dist)
00147 return true;
00148 #endif
00149 return false;
00150 }
00151
00152
00153
00154
00155
00156
00157 void AddPlaneToHash(plane_t *p)
00158 {
00159 int hash;
00160
00161 hash = (int)fabs(p->dist) / 8;
00162 hash &= (PLANE_HASHES-1);
00163
00164 p->hash_chain = planehash[hash];
00165 planehash[hash] = p;
00166 }
00167
00168
00169
00170
00171
00172
00173 int CreateNewFloatPlane (vec3_t normal, vec_t dist)
00174 {
00175 plane_t *p, temp;
00176
00177 if (VectorLength(normal) < 0.5)
00178 Error ("FloatPlane: bad normal");
00179
00180 if (nummapplanes+2 > MAX_MAPFILE_PLANES)
00181 Error ("MAX_MAPFILE_PLANES");
00182
00183 p = &mapplanes[nummapplanes];
00184 VectorCopy (normal, p->normal);
00185 p->dist = dist;
00186 p->type = (p+1)->type = PlaneTypeForNormal (p->normal);
00187 p->signbits = PlaneSignBits(p->normal);
00188
00189 VectorSubtract (vec3_origin, normal, (p+1)->normal);
00190 (p+1)->dist = -dist;
00191 (p+1)->signbits = PlaneSignBits((p+1)->normal);
00192
00193 nummapplanes += 2;
00194
00195
00196 if (p->type < 3)
00197 {
00198 if (p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0)
00199 {
00200
00201 temp = *p;
00202 *p = *(p+1);
00203 *(p+1) = temp;
00204
00205 AddPlaneToHash (p);
00206 AddPlaneToHash (p+1);
00207 return nummapplanes - 1;
00208 }
00209 }
00210
00211 AddPlaneToHash (p);
00212 AddPlaneToHash (p+1);
00213 return nummapplanes - 2;
00214 }
00215
00216
00217
00218
00219
00220
00221 void SnapVector(vec3_t normal)
00222 {
00223 int i;
00224
00225 for (i=0 ; i<3 ; i++)
00226 {
00227 if ( fabs(normal[i] - 1) < NORMAL_EPSILON )
00228 {
00229 VectorClear (normal);
00230 normal[i] = 1;
00231 break;
00232 }
00233 if ( fabs(normal[i] - -1) < NORMAL_EPSILON )
00234 {
00235 VectorClear (normal);
00236 normal[i] = -1;
00237 break;
00238 }
00239 }
00240 }
00241
00242
00243
00244
00245
00246
00247 void SnapPlane(vec3_t normal, vec_t *dist)
00248 {
00249 SnapVector(normal);
00250
00251 if (fabs(*dist-Q_rint(*dist)) < DIST_EPSILON)
00252 *dist = Q_rint(*dist);
00253 }
00254
00255
00256
00257
00258
00259
00260 #ifndef USE_HASHING
00261 int FindFloatPlane(vec3_t normal, vec_t dist)
00262 {
00263 int i;
00264 plane_t *p;
00265
00266 SnapPlane(normal, &dist);
00267 for (i = 0, p = mapplanes; i < nummapplanes; i++, p++)
00268 {
00269 if (PlaneEqual (p, normal, dist))
00270 {
00271 mapplaneusers[i]++;
00272 return i;
00273 }
00274 }
00275 i = CreateNewFloatPlane (normal, dist);
00276 mapplaneusers[i]++;
00277 return i;
00278 }
00279 #else
00280 int FindFloatPlane (vec3_t normal, vec_t dist)
00281 {
00282 int i;
00283 plane_t *p;
00284 int hash, h;
00285
00286 SnapPlane (normal, &dist);
00287 hash = (int)fabs(dist) / 8;
00288 hash &= (PLANE_HASHES-1);
00289
00290
00291 for (i = -1; i <= 1; i++)
00292 {
00293 h = (hash+i)&(PLANE_HASHES-1);
00294 for (p = planehash[h]; p; p = p->hash_chain)
00295 {
00296 if (PlaneEqual(p, normal, dist))
00297 {
00298 mapplaneusers[p-mapplanes]++;
00299 return p - mapplanes;
00300 }
00301 }
00302 }
00303 i = CreateNewFloatPlane (normal, dist);
00304 mapplaneusers[i]++;
00305 return i;
00306 }
00307 #endif
00308
00309
00310
00311
00312
00313
00314 int PlaneFromPoints (int *p0, int *p1, int *p2)
00315 {
00316 vec3_t t1, t2, normal;
00317 vec_t dist;
00318
00319 VectorSubtract (p0, p1, t1);
00320 VectorSubtract (p2, p1, t2);
00321 CrossProduct (t1, t2, normal);
00322 VectorNormalize (normal);
00323
00324 dist = DotProduct (p0, normal);
00325
00326 return FindFloatPlane (normal, dist);
00327 }
00328
00329
00330
00331
00332
00333
00334
00335
00336 void AddBrushBevels (mapbrush_t *b)
00337 {
00338 int axis, dir;
00339 int i, j, k, l, order;
00340 side_t sidetemp;
00341 brush_texture_t tdtemp;
00342 #ifdef SIN
00343 textureref_t trtemp;
00344 #endif
00345 side_t *s, *s2;
00346 vec3_t normal;
00347 float dist;
00348 winding_t *w, *w2;
00349 vec3_t vec, vec2;
00350 float d;
00351
00352
00353
00354
00355 order = 0;
00356 for (axis=0 ; axis <3 ; axis++)
00357 {
00358 for (dir=-1 ; dir <= 1 ; dir+=2, order++)
00359 {
00360
00361 for (i=0, s=b->original_sides ; i<b->numsides ; i++,s++)
00362 {
00363 if (mapplanes[s->planenum].normal[axis] == dir)
00364 break;
00365 }
00366
00367 if (i == b->numsides)
00368 {
00369 if (nummapbrushsides == MAX_MAP_BRUSHSIDES)
00370 Error ("MAX_MAP_BRUSHSIDES");
00371 nummapbrushsides++;
00372 b->numsides++;
00373 VectorClear (normal);
00374 normal[axis] = dir;
00375 if (dir == 1)
00376 dist = b->maxs[axis];
00377 else
00378 dist = -b->mins[axis];
00379 s->planenum = FindFloatPlane (normal, dist);
00380 s->texinfo = b->original_sides[0].texinfo;
00381 #ifdef SIN
00382 s->lightinfo = b->original_sides[0].lightinfo;
00383 #endif
00384 s->contents = b->original_sides[0].contents;
00385 s->flags |= SFL_BEVEL;
00386 c_boxbevels++;
00387 }
00388
00389
00390 if (i != order)
00391 {
00392 sidetemp = b->original_sides[order];
00393 b->original_sides[order] = b->original_sides[i];
00394 b->original_sides[i] = sidetemp;
00395
00396 j = b->original_sides - brushsides;
00397 tdtemp = side_brushtextures[j+order];
00398 side_brushtextures[j+order] = side_brushtextures[j+i];
00399 side_brushtextures[j+i] = tdtemp;
00400
00401 #ifdef SIN
00402 trtemp = side_newrefs[j+order];
00403 side_newrefs[j+order] = side_newrefs[j+i];
00404 side_newrefs[j+i] = trtemp;
00405 #endif
00406 }
00407 }
00408 }
00409
00410
00411
00412
00413 if (b->numsides == 6)
00414 return;
00415
00416
00417 for (i=6 ; i<b->numsides ; i++)
00418 {
00419 s = b->original_sides + i;
00420 w = s->winding;
00421 if (!w)
00422 continue;
00423 for (j=0 ; j<w->numpoints ; j++)
00424 {
00425 k = (j+1)%w->numpoints;
00426 VectorSubtract (w->p[j], w->p[k], vec);
00427 if (VectorNormalize (vec) < 0.5)
00428 continue;
00429 SnapVector (vec);
00430 for (k=0 ; k<3 ; k++)
00431 if ( vec[k] == -1 || vec[k] == 1)
00432 break;
00433 if (k != 3)
00434 continue;
00435
00436
00437 for (axis=0 ; axis <3 ; axis++)
00438 {
00439 for (dir=-1 ; dir <= 1 ; dir+=2)
00440 {
00441
00442 VectorClear (vec2);
00443 vec2[axis] = dir;
00444 CrossProduct (vec, vec2, normal);
00445 if (VectorNormalize (normal) < 0.5)
00446 continue;
00447 dist = DotProduct (w->p[j], normal);
00448
00449
00450
00451 for (k=0 ; k<b->numsides ; k++)
00452 {
00453
00454 if (PlaneEqual (&mapplanes[b->original_sides[k].planenum]
00455 , normal, dist) )
00456 break;
00457
00458 w2 = b->original_sides[k].winding;
00459 if (!w2)
00460 continue;
00461 for (l=0 ; l<w2->numpoints ; l++)
00462 {
00463 d = DotProduct (w2->p[l], normal) - dist;
00464 if (d > 0.1)
00465 break;
00466 }
00467 if (l != w2->numpoints)
00468 break;
00469 }
00470
00471 if (k != b->numsides)
00472 continue;
00473
00474 if (nummapbrushsides == MAX_MAP_BRUSHSIDES)
00475 Error ("MAX_MAP_BRUSHSIDES");
00476 nummapbrushsides++;
00477 s2 = &b->original_sides[b->numsides];
00478 s2->planenum = FindFloatPlane (normal, dist);
00479 s2->texinfo = b->original_sides[0].texinfo;
00480 #ifdef SIN
00481 s2->lightinfo = b->original_sides[0].lightinfo;
00482 #endif
00483 s2->contents = b->original_sides[0].contents;
00484 s2->flags |= SFL_BEVEL;
00485 c_edgebevels++;
00486 b->numsides++;
00487 }
00488 }
00489 }
00490 }
00491 }
00492
00493
00494
00495
00496
00497
00498
00499 qboolean MakeBrushWindings(mapbrush_t *ob)
00500 {
00501 int i, j;
00502 winding_t *w;
00503 side_t *side;
00504 plane_t *plane;
00505
00506 ClearBounds (ob->mins, ob->maxs);
00507
00508 for (i = 0; i < ob->numsides; i++)
00509 {
00510 plane = &mapplanes[ob->original_sides[i].planenum];
00511 w = BaseWindingForPlane(plane->normal, plane->dist);
00512 for (j = 0; j <ob->numsides && w; j++)
00513 {
00514 if (i == j) continue;
00515 if (ob->original_sides[j].flags & SFL_BEVEL) continue;
00516 plane = &mapplanes[ob->original_sides[j].planenum^1];
00517 ChopWindingInPlace(&w, plane->normal, plane->dist, 0);
00518 }
00519
00520 side = &ob->original_sides[i];
00521 side->winding = w;
00522 if (w)
00523 {
00524 side->flags |= SFL_VISIBLE;
00525 for (j = 0; j < w->numpoints; j++)
00526 AddPointToBounds (w->p[j], ob->mins, ob->maxs);
00527 }
00528 }
00529
00530 for (i = 0; i < 3; i++)
00531 {
00532
00533 if (ob->mins[i] < -MAX_MAP_BOUNDS || ob->maxs[i] > MAX_MAP_BOUNDS)
00534 {
00535 Log_Print("entity %i, brush %i: bounds out of range\n", ob->entitynum, ob->brushnum);
00536 ob->numsides = 0;
00537 break;
00538 }
00539 if (ob->mins[i] > MAX_MAP_BOUNDS || ob->maxs[i] < -MAX_MAP_BOUNDS)
00540 {
00541 Log_Print("entity %i, brush %i: no visible sides on brush\n", ob->entitynum, ob->brushnum);
00542 ob->numsides = 0;
00543 break;
00544 }
00545 }
00546 return true;
00547 }
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557 void MarkBrushBevels(mapbrush_t *brush)
00558 {
00559 int i;
00560 int we;
00561 side_t *s;
00562
00563
00564 for (i = 0; i < brush->numsides; i++)
00565 {
00566 s = brush->original_sides + i;
00567
00568 if (!s->winding)
00569 {
00570 Log_Write("MarkBrushBevels: brush %d no winding", brush->brushnum);
00571 s->flags |= SFL_BEVEL;
00572 }
00573
00574 else if (WindingIsTiny(s->winding))
00575 {
00576 s->flags |= SFL_BEVEL;
00577 Log_Write("MarkBrushBevels: brush %d tiny winding", brush->brushnum);
00578 }
00579
00580 else
00581 {
00582 we = WindingError(s->winding);
00583 if (we == WE_NOTENOUGHPOINTS
00584 || we == WE_SMALLAREA
00585 || we == WE_POINTBOGUSRANGE
00586
00587 )
00588 {
00589 Log_Write("MarkBrushBevels: brush %d %s", brush->brushnum, WindingErrorString());
00590 s->flags |= SFL_BEVEL;
00591 }
00592 }
00593 if (s->flags & SFL_BEVEL)
00594 {
00595 s->flags &= ~SFL_VISIBLE;
00596
00597 if (s->planenum > 0 && s->planenum < nummapplanes)
00598 {
00599
00600 if (mapplanes[s->planenum].type < 3) c_boxbevels++;
00601 else c_edgebevels++;
00602 }
00603 }
00604 }
00605 }
00606
00607
00608
00609
00610
00611
00612
00613 int BrushExists(mapbrush_t *brush)
00614 {
00615 int i, s1, s2;
00616 side_t *side1, *side2;
00617 mapbrush_t *brush1, *brush2;
00618
00619 for (i = 0; i < nummapbrushes; i++)
00620 {
00621 brush1 = brush;
00622 brush2 = &mapbrushes[i];
00623
00624 if (brush1->entitynum != brush2->entitynum) continue;
00625
00626 if (brush1->numsides != brush2->numsides) continue;
00627 for (s1 = 0; s1 < brush1->numsides; s1++)
00628 {
00629 side1 = brush1->original_sides + s1;
00630
00631 for (s2 = 0; s2 < brush2->numsides; s2++)
00632 {
00633 side2 = brush2->original_sides + s2;
00634
00635 if ((side1->planenum & ~1) == (side2->planenum & ~1)
00636
00637
00638
00639 ) break;
00640 }
00641 if (s2 >= brush2->numsides) break;
00642 }
00643 if (s1 >= brush1->numsides) return true;
00644 }
00645 return false;
00646 }
00647
00648
00649
00650
00651
00652
00653 qboolean WriteMapBrush(FILE *fp, mapbrush_t *brush, vec3_t origin)
00654 {
00655 int sn, rotate, shift[2], sv, tv, planenum, p1, i, j;
00656 float scale[2], originshift[2], ang1, ang2, newdist;
00657 vec3_t vecs[2], axis[2];
00658 map_texinfo_t *ti;
00659 winding_t *w;
00660 side_t *s;
00661 plane_t *plane;
00662
00663 if (noliquids)
00664 {
00665 if (brush->contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA))
00666 {
00667 return true;
00668 }
00669 }
00670
00671 if (!brush->contents) return true;
00672
00673 if (fprintf(fp, " { //brush %d\n", brush->brushnum) < 0) return false;
00674
00675 for (sn = 0; sn < brush->numsides; sn++)
00676 {
00677 s = brush->original_sides + sn;
00678
00679 if (!(s->flags & SFL_BEVEL))
00680 {
00681
00682 if (origin[0] || origin[1] || origin[2])
00683 {
00684 newdist = mapplanes[s->planenum].dist +
00685 DotProduct(mapplanes[s->planenum].normal, origin);
00686 planenum = FindFloatPlane(mapplanes[s->planenum].normal, newdist);
00687 }
00688 else
00689 {
00690 planenum = s->planenum;
00691 }
00692
00693 plane = &mapplanes[planenum & ~1];
00694 w = BaseWindingForPlane(plane->normal, plane->dist);
00695
00696 for (i = 0; i < 3; i++)
00697 {
00698 for (j = 0; j < 3; j++)
00699 {
00700 if (fabs(w->p[i][j]) < 0.2) w->p[i][j] = 0;
00701 else if (fabs((int)w->p[i][j] - w->p[i][j]) < 0.3) w->p[i][j] = (int) w->p[i][j];
00702
00703 }
00704 }
00705
00706 if (planenum & 1) p1 = 1;
00707 else p1 = 0;
00708 if (fprintf(fp," ( %5i %5i %5i ) ", (int)w->p[p1][0], (int)w->p[p1][1], (int)w->p[p1][2]) < 0) return false;
00709 if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[!p1][0], (int)w->p[!p1][1], (int)w->p[!p1][2]) < 0) return false;
00710 if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]) < 0) return false;
00711
00712 FreeWinding(w);
00713
00714 if (s->texinfo == TEXINFO_NODE)
00715 {
00716 if (brush->contents & CONTENTS_PLAYERCLIP)
00717 {
00718
00719 if (loadedmaptype == MAPTYPE_SIN)
00720 {
00721 if (fprintf(fp, "generic/misc/clip 0 0 0 1 1") < 0) return false;
00722 }
00723 else if (loadedmaptype == MAPTYPE_QUAKE2)
00724 {
00725 if (fprintf(fp, "e1u1/clip 0 0 0 1 1") < 0) return false;
00726 }
00727 else if (loadedmaptype == MAPTYPE_QUAKE3)
00728 {
00729 if (fprintf(fp, "e1u1/clip 0 0 0 1 1") < 0) return false;
00730 }
00731 else
00732 {
00733 if (fprintf(fp, "clip 0 0 0 1 1") < 0) return false;
00734 }
00735 }
00736 else if (brush->contents == CONTENTS_MONSTERCLIP)
00737 {
00738
00739 if (loadedmaptype == MAPTYPE_SIN)
00740 {
00741 if (fprintf(fp, "generic/misc/monster 0 0 0 1 1") < 0) return false;
00742 }
00743 else if (loadedmaptype == MAPTYPE_QUAKE2)
00744 {
00745 if (fprintf(fp, "e1u1/clip_mon 0 0 0 1 1") < 0) return false;
00746 }
00747 else
00748 {
00749 if (fprintf(fp, "clip 0 0 0 1 1") < 0) return false;
00750 }
00751 }
00752 else
00753 {
00754 if (fprintf(fp, "clip 0 0 0 1 1") < 0) return false;
00755 Log_Write("brush->contents = %d\n", brush->contents);
00756 }
00757 }
00758 else if (loadedmaptype == MAPTYPE_SIN && s->texinfo == 0)
00759 {
00760 if (brush->contents & CONTENTS_DUMMYFENCE)
00761 {
00762 if (fprintf(fp, "generic/misc/fence 0 0 0 1 1") < 0) return false;
00763 }
00764 else if (brush->contents & CONTENTS_MIST)
00765 {
00766 if (fprintf(fp, "generic/misc/volumetric_base 0 0 0 1 1") < 0) return false;
00767 }
00768 else
00769 {
00770 if (fprintf(fp, "generic/misc/red 0 0 0 1 1") < 0) return false;
00771 }
00772 }
00773 else if (loadedmaptype == MAPTYPE_QUAKE3)
00774 {
00775
00776 if (fprintf(fp, "e2u3/floor1_2 0 0 0 1 1 1 0 0") < 0) return false;
00777 }
00778 else
00779 {
00780
00781 ti = &map_texinfo[s->texinfo];
00782
00783 scale[0] = 1 / VectorNormalize2(ti->vecs[0], vecs[0]);
00784 scale[1] = 1 / VectorNormalize2(ti->vecs[1], vecs[1]);
00785
00786 TextureAxisFromPlane(plane, axis[0], axis[1]);
00787
00788 originshift[0] = DotProduct(origin, axis[0]);
00789 originshift[1] = DotProduct(origin, axis[1]);
00790
00791 shift[0] = ti->vecs[0][3] - originshift[0];
00792 shift[1] = ti->vecs[1][3] - originshift[1];
00793
00794 if (axis[0][0]) sv = 0;
00795 else if (axis[0][1]) sv = 1;
00796 else sv = 2;
00797 if (axis[1][0]) tv = 0;
00798 else if (axis[1][1]) tv = 1;
00799 else tv = 2;
00800
00801 if (vecs[0][tv] == 0) ang1 = vecs[0][sv] > 0 ? 90.0 : -90.0;
00802 else ang1 = atan2(vecs[0][sv], vecs[0][tv]) * 180 / Q_PI;
00803 if (ang1 < 0) ang1 += 360;
00804 if (ang1 >= 360) ang1 -= 360;
00805 if (axis[0][tv] == 0) ang2 = axis[0][sv] > 0 ? 90.0 : -90.0;
00806 else ang2 = atan2(axis[0][sv], axis[0][tv]) * 180 / Q_PI;
00807 if (ang2 < 0) ang2 += 360;
00808 if (ang2 >= 360) ang2 -= 360;
00809 rotate = ang2 - ang1;
00810 if (rotate < 0) rotate += 360;
00811 if (rotate >= 360) rotate -= 360;
00812
00813 if (fprintf(fp, "%s %d %d %d", ti->texture, shift[0], shift[1], rotate) < 0) return false;
00814 if (fabs(scale[0] - ((int) scale[0])) < 0.001)
00815 {
00816 if (fprintf(fp, " %d", (int) scale[0]) < 0) return false;
00817 }
00818 else
00819 {
00820 if (fprintf(fp, " %4f", scale[0]) < 0) return false;
00821 }
00822 if (fabs(scale[1] - ((int) scale[1])) < 0.001)
00823 {
00824 if (fprintf(fp, " %d", (int) scale[1]) < 0) return false;
00825 }
00826 else
00827 {
00828 if (fprintf(fp, " %4f", scale[1]) < 0) return false;
00829 }
00830
00831 if (loadedmaptype == MAPTYPE_QUAKE2)
00832 {
00833 if (fprintf(fp, " %ld %ld %ld", s->contents, ti->flags, ti->value) < 0) return false;
00834 }
00835
00836 }
00837 if (fprintf(fp, "\n") < 0) return false;
00838 }
00839 }
00840 if (fprintf(fp, " }\n") < 0) return false;
00841 c_writtenbrushes++;
00842 return true;
00843 }
00844
00845
00846
00847
00848
00849
00850 qboolean WriteOriginBrush(FILE *fp, vec3_t origin)
00851 {
00852 vec3_t normal;
00853 float dist;
00854 int i, s;
00855 winding_t *w;
00856
00857 if (fprintf(fp, " {\n") < 0) return false;
00858
00859 for (i = 0; i < 3; i++)
00860 {
00861 for (s = -1; s <= 1; s += 2)
00862 {
00863
00864 VectorClear(normal);
00865 normal[i] = s;
00866 dist = origin[i] * s + 16;
00867
00868 w = BaseWindingForPlane(normal, dist);
00869
00870 if (fprintf(fp," ( %5i %5i %5i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]) < 0) return false;
00871 if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]) < 0) return false;
00872 if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]) < 0) return false;
00873
00874 FreeWinding(w);
00875
00876
00877
00878 if (loadedmaptype == MAPTYPE_SIN)
00879 {
00880 if (fprintf(fp, "generic/misc/origin 0 0 0 1 1") < 0) return false;
00881 }
00882 else if (loadedmaptype == MAPTYPE_HALFLIFE)
00883 {
00884 if (fprintf(fp, "origin 0 0 0 1 1") < 0) return false;
00885 }
00886 else
00887 {
00888 if (fprintf(fp, "e1u1/origin 0 0 0 1 1") < 0) return false;
00889 }
00890
00891 if (loadedmaptype == MAPTYPE_QUAKE2)
00892 {
00893
00894 }
00895 if (fprintf(fp, "\n") < 0) return false;
00896 }
00897 }
00898 if (fprintf(fp, " }\n") < 0) return false;
00899 c_writtenbrushes++;
00900 return true;
00901 }
00902
00903
00904
00905
00906
00907
00908 mapbrush_t *GetAreaPortalBrush(entity_t *mapent)
00909 {
00910 int portalnum, bn;
00911 mapbrush_t *brush;
00912
00913
00914 portalnum = mapent->areaportalnum;
00915
00916 for (bn = 0; bn < nummapbrushes && portalnum; bn++)
00917 {
00918 brush = &mapbrushes[bn];
00919
00920 if (brush->entitynum == 0)
00921 {
00922 if (brush->contents & CONTENTS_AREAPORTAL)
00923 {
00924 portalnum--;
00925 }
00926 }
00927 }
00928 if (bn < nummapbrushes)
00929 {
00930 return brush;
00931 }
00932 else
00933 {
00934 Log_Print("area portal %d brush not found\n", mapent->areaportalnum);
00935 return NULL;
00936 }
00937 }
00938
00939
00940
00941
00942
00943
00944 qboolean WriteMapFileSafe(FILE *fp)
00945 {
00946 char key[1024], value[1024];
00947 int i, bn, entitybrushes;
00948 epair_t *ep;
00949 mapbrush_t *brush;
00950 entity_t *mapent;
00951
00952
00953
00954 if (fprintf(fp,"//=====================================================\n"
00955 "//\n"
00956 "// map file created with BSPC "BSPC_VERSION"\n"
00957 "//\n"
00958 "// BSPC is designed to decompile material in which you own the copyright\n"
00959 "// or have obtained permission to decompile from the copyright owner. Unless\n"
00960 "// you own the copyright or have permission to decompile from the copyright\n"
00961 "// owner, you may be violating copyright law and be subject to payment of\n"
00962 "// damages and other remedies. If you are uncertain about your rights, contact\n"
00963 "// your legal advisor.\n"
00964 "//\n") < 0) return false;
00965 if (loadedmaptype == MAPTYPE_SIN)
00966 {
00967 if (fprintf(fp,
00968 "// generic/misc/red is used for unknown textures\n") < 0) return false;
00969 }
00970 if (fprintf(fp,"//\n"
00971 "//=====================================================\n") < 0) return false;
00972
00973 for (i = 0; i < num_entities; i++)
00974 {
00975 mapent = &entities[i];
00976 if (!mapent->epairs)
00977 {
00978 continue;
00979 }
00980 if (fprintf(fp, "{\n") < 0) return false;
00981
00982 if (loadedmaptype == MAPTYPE_QUAKE3)
00983 {
00984 if (!stricmp(ValueForKey(mapent, "classname"), "light"))
00985 {
00986 SetKeyValue(mapent, "light", "10000");
00987 }
00988 }
00989
00990 for (ep = mapent->epairs; ep; ep = ep->next)
00991 {
00992 strcpy(key, ep->key);
00993 StripTrailing (key);
00994 strcpy(value, ep->value);
00995 StripTrailing(value);
00996
00997 if (loadedmaptype == MAPTYPE_QUAKE2 ||
00998 loadedmaptype == MAPTYPE_SIN)
00999 {
01000
01001 if (mapent->modelnum >= 0 && !strcmp(key, "origin")) continue;
01002 }
01003
01004 if (mapent->modelnum >= 0 && !strcmp(key, "model") && value[0] == '*') continue;
01005
01006 if (fprintf(fp, " \"%s\" \"%s\"\n", key, value) < 0) return false;
01007 }
01008
01009 if (ValueForKey(mapent, "origin")) GetVectorForKey(mapent, "origin", mapent->origin);
01010 else mapent->origin[0] = mapent->origin[1] = mapent->origin[2] = 0;
01011
01012 if (!strcmp("func_areaportal", ValueForKey(mapent, "classname")))
01013 {
01014 brush = GetAreaPortalBrush(mapent);
01015 if (!brush) return false;
01016 if (!WriteMapBrush(fp, brush, mapent->origin)) return false;
01017 }
01018 else
01019 {
01020 entitybrushes = false;
01021
01022 for (bn = 0; bn < nummapbrushes; bn++)
01023 {
01024 brush = &mapbrushes[bn];
01025
01026 if (brush->entitynum == i)
01027 {
01028
01029 if (!((brush->contents & CONTENTS_AREAPORTAL) && brush->entitynum == 0))
01030 {
01031
01032
01033
01034
01035
01036
01037
01038 {
01039 if (!WriteMapBrush(fp, brush, mapent->origin)) return false;
01040 }
01041 entitybrushes = true;
01042 }
01043 }
01044 }
01045
01046 if (entitybrushes)
01047 {
01048
01049 if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2])
01050 {
01051 if (!WriteOriginBrush(fp, mapent->origin)) return false;
01052 }
01053 }
01054 }
01055 if (fprintf(fp, "}\n") < 0) return false;
01056 }
01057 if (fprintf(fp, "//total of %d brushes\n", c_writtenbrushes) < 0) return false;
01058 return true;
01059 }
01060
01061
01062
01063
01064
01065
01066 void WriteMapFile(char *filename)
01067 {
01068 FILE *fp;
01069 double start_time;
01070
01071 c_writtenbrushes = 0;
01072
01073 start_time = I_FloatTime();
01074
01075 Log_Print("writing %s\n", filename);
01076 fp = fopen(filename, "wb");
01077 if (!fp)
01078 {
01079 Log_Print("can't open %s\n", filename);
01080 return;
01081 }
01082 if (!WriteMapFileSafe(fp))
01083 {
01084 fclose(fp);
01085 Log_Print("error writing map file %s\n", filename);
01086 return;
01087 }
01088 fclose(fp);
01089
01090 Log_Print("written %d brushes\n", c_writtenbrushes);
01091 Log_Print("map file written in %5.0f seconds\n", I_FloatTime() - start_time);
01092 }
01093
01094
01095
01096
01097
01098
01099 void PrintMapInfo(void)
01100 {
01101 Log_Print("\n");
01102 Log_Print("%6i brushes\n", nummapbrushes);
01103 Log_Print("%6i brush sides\n", nummapbrushsides);
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114 }
01115
01116
01117
01118
01119
01120
01121 void ResetMapLoading(void)
01122 {
01123 int i;
01124 epair_t *ep, *nextep;
01125
01126 Q2_ResetMapLoading();
01127 Sin_ResetMapLoading();
01128
01129
01130 for (i = 0; i < nummapbrushsides; i++)
01131 {
01132 if (brushsides[i].winding)
01133 {
01134 FreeWinding(brushsides[i].winding);
01135 }
01136 }
01137
01138
01139 nummapbrushes = 0;
01140 memset(mapbrushes, 0, MAX_MAPFILE_BRUSHES * sizeof(mapbrush_t));
01141
01142 nummapbrushsides = 0;
01143 memset(brushsides, 0, MAX_MAPFILE_BRUSHSIDES * sizeof(side_t));
01144 memset(side_brushtextures, 0, MAX_MAPFILE_BRUSHSIDES * sizeof(brush_texture_t));
01145
01146 nummapplanes = 0;
01147 memset(mapplanes, 0, MAX_MAPFILE_PLANES * sizeof(plane_t));
01148
01149