Skip to content

Commit 4ef82c3

Browse files
committed
add map boundary config
can select from a preset or a limit set in one of your FGDs for #112
1 parent af74aa5 commit 4ef82c3

File tree

10 files changed

+179
-29
lines changed

10 files changed

+179
-29
lines changed

src/bsp/Bsp.cpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -1796,7 +1796,7 @@ STRUCTCOUNT Bsp::delete_unused_hulls(bool noProgress) {
17961796
void Bsp::delete_oob_nodes(int iNode, int16_t* parentBranch, vector<BSPPLANE>& clipOrder, int oobFlags,
17971797
bool* oobHistory, bool isFirstPass, int& removedNodes) {
17981798
BSPNODE& node = nodes[iNode];
1799-
float oob_coord = g_limits.max_mapboundary;
1799+
float oob_coord = g_settings.mapsize_max;
18001800

18011801
if (node.iPlane < 0) {
18021802
return;
@@ -1867,7 +1867,7 @@ void Bsp::delete_oob_nodes(int iNode, int16_t* parentBranch, vector<BSPPLANE>& c
18671867
void Bsp::delete_oob_clipnodes(int iNode, int16_t* parentBranch, vector<BSPPLANE>& clipOrder, int oobFlags,
18681868
bool* oobHistory, bool isFirstPass, int& removedNodes) {
18691869
BSPCLIPNODE& node = clipnodes[iNode];
1870-
float oob_coord = g_limits.max_mapboundary;
1870+
float oob_coord = g_settings.mapsize_max;
18711871

18721872
if (node.iPlane < 0) {
18731873
return;
@@ -1948,7 +1948,7 @@ void Bsp::delete_oob_clipnodes(int iNode, int16_t* parentBranch, vector<BSPPLANE
19481948
}
19491949

19501950
void Bsp::delete_oob_data(int clipFlags) {
1951-
float oob_coord = g_limits.max_mapboundary;
1951+
float oob_coord = g_settings.mapsize_max;
19521952
BSPMODEL& worldmodel = models[0];
19531953

19541954
// remove OOB nodes and clipnodes
@@ -2159,7 +2159,7 @@ void Bsp::delete_oob_data(int clipFlags) {
21592159
void Bsp::delete_box_nodes(int iNode, int16_t* parentBranch, vector<BSPPLANE>& clipOrder,
21602160
vec3 clipMins, vec3 clipMaxs, bool* oobHistory, bool isFirstPass, int& removedNodes) {
21612161
BSPNODE& node = nodes[iNode];
2162-
float oob_coord = g_limits.max_mapboundary;
2162+
float oob_coord = g_settings.mapsize_max;
21632163

21642164
if (node.iPlane < 0) {
21652165
return;
@@ -2223,7 +2223,7 @@ void Bsp::delete_box_nodes(int iNode, int16_t* parentBranch, vector<BSPPLANE>& c
22232223
void Bsp::delete_box_clipnodes(int iNode, int16_t* parentBranch, vector<BSPPLANE>& clipOrder,
22242224
vec3 clipMins, vec3 clipMaxs, bool* oobHistory, bool isFirstPass, int& removedNodes) {
22252225
BSPCLIPNODE& node = clipnodes[iNode];
2226-
float oob_coord = g_limits.max_mapboundary;
2226+
float oob_coord = g_settings.mapsize_max;
22272227

22282228
if (node.iPlane < 0) {
22292229
return;

src/editor/AppSettings.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ void AppSettings::loadDefault()
3737
confirm_exit = true;
3838
unicode_font = false;
3939
first_load = true;
40+
mapsize_min = -32768;
41+
mapsize_max = 32768;
42+
mapsize_auto = true;
4043
settings_tab = 0;
4144
engine = ENGINE_SVEN_COOP;
4245

@@ -93,6 +96,7 @@ void AppSettings::load() {
9396
else if (key == "confirm_exit") { g_settings.confirm_exit = atoi(val.c_str()) != 0; }
9497
else if (key == "unicode_font") { g_settings.unicode_font = atoi(val.c_str()) != 0; }
9598
else if (key == "first_load") { g_settings.first_load = atoi(val.c_str()) != 0; }
99+
else if (key == "mapsize_auto") { g_settings.mapsize_auto = atoi(val.c_str()) != 0; }
96100
else if (key == "fov") { g_settings.fov = atof(val.c_str()); }
97101
else if (key == "zfar") { g_settings.zfar = atof(val.c_str()); }
98102
else if (key == "zfarmdl") { g_settings.zFarMdl = atof(val.c_str()); }
@@ -108,6 +112,8 @@ void AppSettings::load() {
108112
else if (key == "autoload_layout") { g_settings.autoload_layout = atoi(val.c_str()) != 0; }
109113
else if (key == "autoload_layout_width") { g_settings.autoload_layout_width = atoi(val.c_str()); }
110114
else if (key == "autoload_layout_height") { g_settings.autoload_layout_height = atoi(val.c_str()); }
115+
else if (key == "mapsize_min") { g_settings.mapsize_min = atoi(val.c_str()); }
116+
else if (key == "mapsize_max") { g_settings.mapsize_max = atoi(val.c_str()); }
111117
else if (key == "engine") {
112118
g_settings.engine = clamp(atoi(val.c_str()), 0, 1);
113119
g_limits = g_engine_limits[g_settings.engine];
@@ -213,6 +219,9 @@ void AppSettings::save() {
213219
file << "autoload_layout=" << g_settings.autoload_layout << endl;
214220
file << "autoload_layout_width=" << g_settings.autoload_layout_width << endl;
215221
file << "autoload_layout_height=" << g_settings.autoload_layout_height << endl;
222+
file << "mapsize_min=" << g_settings.mapsize_min << endl;
223+
file << "mapsize_max=" << g_settings.mapsize_max << endl;
224+
file << "mapsize_auto=" << g_settings.mapsize_auto << endl;
216225
file << "engine=" << g_settings.engine << endl;
217226
}
218227

src/editor/AppSettings.h

+3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ struct AppSettings {
2121
bool confirm_exit;
2222
bool unicode_font;
2323
bool first_load;
24+
int mapsize_min;
25+
int mapsize_max;
26+
bool mapsize_auto;
2427

2528
bool debug_open;
2629
bool keyvalue_open;

src/editor/Fgd.cpp

+30-4
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ bool Fgd::parse() {
102102

103103
while (true) {
104104
// skip over comments
105-
readUntil(readPtr, "/@");
105+
readUntil(readPtr, "(/@");
106106
if (readPtr >= endFileData) { break; }
107107

108108
if (readPtr[0] == '/' && readPtr[1] == '/') {
@@ -113,12 +113,12 @@ bool Fgd::parse() {
113113
// name of the definition
114114
readPtr += 1;
115115
char* oldReadPtr = readPtr;
116-
string defName = readUntil(readPtr, whitespace);
116+
string defName = readUntil(readPtr, " \t\n(/@");
117117
string defNameLower = toLowerCase(defName);
118118
if (readPtr >= endFileData) { break; }
119119

120120
if (defNameLower == "include") {
121-
string fgdName = trimSpaces(readUntil(readPtr, "/@"));
121+
string fgdName = trimSpaces(readUntil(readPtr, "(/@"));
122122
if (readPtr >= endFileData) { break; }
123123

124124
replaceAll(fgdName, "\"", "");
@@ -136,7 +136,33 @@ bool Fgd::parse() {
136136
}
137137

138138
delete tmp;
139-
continue;
139+
}
140+
else if (defNameLower == "mapsize") {
141+
trimSpaces(readUntil(readPtr, "(/@"));
142+
if (readPtr >= endFileData) { break; }
143+
144+
if (readPtr[0] != '(') {
145+
logf("Invalid @MapSize format in %s.fgd\n", name.c_str());
146+
continue;
147+
}
148+
readPtr++;
149+
150+
string sizeStr = trimSpaces(readUntil(readPtr, ")/@"));
151+
if (readPtr >= endFileData) { break; }
152+
153+
if (readPtr[0] != ')') {
154+
logf("Invalid @MapSize format in %s.fgd\n", name.c_str());
155+
continue;
156+
}
157+
158+
vector<string> parts = splitString(sizeStr, ",");
159+
if (parts.size() != 2) {
160+
logf("Invalid @MapSize format '%s' in %s.fgd\n", sizeStr.c_str(), name.c_str());
161+
continue;
162+
}
163+
164+
mapSizeMin = atoi(parts[0].c_str());
165+
mapSizeMax = atoi(parts[1].c_str());
140166
}
141167
else if (defNameLower == "baseclass" || defNameLower == "solidclass" || defNameLower == "pointclass") {
142168
readPtr = oldReadPtr;

src/editor/Fgd.h

+3
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ class Fgd {
109109
vector<FgdClass*> classes;
110110
unordered_map<string, FgdClass*> classMap;
111111

112+
int mapSizeMin = 0;
113+
int mapSizeMax = 0;
114+
112115
vector<FgdGroup> pointEntGroups;
113116
vector<FgdGroup> solidEntGroups;
114117

src/editor/Gui.cpp

+84-15
Original file line numberDiff line numberDiff line change
@@ -1153,24 +1153,92 @@ void Gui::drawMenuBar() {
11531153
ImGui::PushItemFlag(ImGuiItemFlags_AutoClosePopups, false);
11541154

11551155
bool changed = false;
1156-
ImGui::MenuItem("Engine", 0, false, false);
1156+
if (ImGui::BeginMenu("Engine")) {
1157+
if (ImGui::MenuItem("Half-Life", 0, g_settings.engine == ENGINE_HALF_LIFE, !app->isLoading)) {
1158+
changed = g_settings.engine != ENGINE_HALF_LIFE;
1159+
g_settings.engine = ENGINE_HALF_LIFE;
1160+
if (g_settings.mapsize_auto) {
1161+
g_settings.mapsize_min = -4096;
1162+
g_settings.mapsize_max = 4096;
1163+
}
1164+
}
1165+
tooltip(g, "The standard GoldSrc engine.\n");
11571166

1158-
if (ImGui::MenuItem("Half-Life", 0, g_settings.engine == ENGINE_HALF_LIFE, !app->isLoading)) {
1159-
changed = g_settings.engine != ENGINE_HALF_LIFE;
1160-
g_settings.engine = ENGINE_HALF_LIFE;
1167+
if (ImGui::MenuItem("Sven Co-op", 0, g_settings.engine == ENGINE_SVEN_COOP, !app->isLoading)) {
1168+
changed = g_settings.engine != ENGINE_SVEN_COOP;
1169+
g_settings.engine = ENGINE_SVEN_COOP;
1170+
if (g_settings.mapsize_auto) {
1171+
g_settings.mapsize_min = -32768;
1172+
g_settings.mapsize_max = 32768;
1173+
}
1174+
}
1175+
tooltip(g, "Sven Co-op has higher map limits than Half-Life. Some maps need this selected to display correctly in the editor."
1176+
"\n\nAttempting to run a "
1177+
"Sven Co-op map in Half-Life may result in AllocBlock Full errors, Bad Surface Extents, "
1178+
"crashes caused by large textures, and visual glitches caused by crossing the +/-4096 map boundary. "
1179+
"See the Porting Tools menu for solutions to these problems.");
1180+
1181+
ImGui::EndMenu();
11611182
}
1162-
tooltip(g, "The standard GoldSrc engine. Assumes a +/-4096 map boundary.\n");
11631183

1164-
if (ImGui::MenuItem("Sven Co-op", 0, g_settings.engine == ENGINE_SVEN_COOP, !app->isLoading)) {
1165-
changed = g_settings.engine != ENGINE_SVEN_COOP;
1166-
g_settings.engine = ENGINE_SVEN_COOP;
1184+
if (ImGui::BeginMenu("Map Size")) {
1185+
if (ImGui::MenuItem("Auto", 0, g_settings.mapsize_auto)) {
1186+
if (g_settings.engine == ENGINE_HALF_LIFE) {
1187+
g_settings.mapsize_min = -4096;
1188+
g_settings.mapsize_max = 4096;
1189+
}
1190+
else if (g_settings.engine == ENGINE_SVEN_COOP) {
1191+
g_settings.mapsize_min = -32768;
1192+
g_settings.mapsize_max = 32768;
1193+
}
1194+
g_settings.mapsize_auto = true;
1195+
}
1196+
tooltip(g, "The map size will be set according to the Engine you choose.");
1197+
1198+
if (ImGui::MenuItem("+/-4096 (Half-Life)", 0, !g_settings.mapsize_auto && g_settings.mapsize_min == -4096 && g_settings.mapsize_max == 4096)) {
1199+
g_settings.mapsize_min = -4096;
1200+
g_settings.mapsize_max = 4096;
1201+
g_settings.mapsize_auto = false;
1202+
}
1203+
tooltip(g, "The default map size for Half-Life and most of its mods.");
1204+
1205+
if (ImGui::MenuItem("+/-32768 (Sven Co-op)", 0, !g_settings.mapsize_auto && g_settings.mapsize_min == -32768 && g_settings.mapsize_max == 32768)) {
1206+
g_settings.mapsize_min = -32768;
1207+
g_settings.mapsize_max = 32768;
1208+
g_settings.mapsize_auto = false;
1209+
}
1210+
tooltip(g, "The safe maximum map size for Sven Co-op maps.");
1211+
1212+
if (ImGui::MenuItem("+/-131072 (Sven Co-op)", 0, !g_settings.mapsize_auto && g_settings.mapsize_min == -131072 && g_settings.mapsize_max == 131072)) {
1213+
g_settings.mapsize_min = -131072;
1214+
g_settings.mapsize_max = 131072;
1215+
g_settings.mapsize_auto = false;
1216+
}
1217+
tooltip(g, "Players can technically run around in this giant area but the game may become buggy mess once you pass the +/-32768 boundary.");
1218+
1219+
for (int i = 0; i < g_app->fgds.size(); i++) {
1220+
Fgd* fgd = g_app->fgds[i];
1221+
int min = fgd->mapSizeMin;
1222+
int max = fgd->mapSizeMax;
1223+
1224+
if (min == 0 && max == 0) {
1225+
continue;
1226+
}
1227+
1228+
string name;
1229+
if (min != -max)
1230+
name = "(" + to_string(min) + ", " + to_string(max) + ") " + fgd->name + ".fgd";
1231+
else
1232+
name = "+/-" + to_string(max) + " (" + fgd->name + ".fgd)";
1233+
1234+
if (ImGui::MenuItem(name.c_str(), 0, g_settings.mapsize_min == min && g_settings.mapsize_max == max)) {
1235+
g_settings.mapsize_min = min;
1236+
g_settings.mapsize_max = max;
1237+
}
1238+
tooltip(g, ("The @mapsize loaded from " + fgd->name + ".fgd.").c_str());
1239+
}
1240+
ImGui::EndMenu();
11671241
}
1168-
tooltip(g, "Sven Co-op has higher map limits than Half-Life. Some maps need this selected to display correctly in the editor."
1169-
"\n\nAttempting to run a "
1170-
"Sven Co-op map in Half-Life may result in AllocBlock Full errors, Bad Surface Extents, "
1171-
"crashes caused by large textures, and visual glitches caused by crossing the +/-4096 map boundary. "
1172-
"See the Porting Tools menu for solutions to these problems.\n\n"
1173-
"The map boundary for Sven Co-op is effectively +/-32768. Rendering glitches occur beyond that point.");
11741242

11751243
if (changed) {
11761244
g_limits = g_engine_limits[g_settings.engine];
@@ -1395,6 +1463,8 @@ void Gui::drawMenuBar() {
13951463

13961464
for (int i = 0; i < 10; i++) {
13971465
if (ImGui::MenuItem(optionNames[i], 0, false, !app->isLoading)) {
1466+
LumpReplaceCommand* command = new LumpReplaceCommand("Delete OOB Data");
1467+
13981468
if (map->ents[0]->hasKey("origin")) {
13991469
vec3 ori = map->ents[0]->getOrigin();
14001470
logf("Moved worldspawn origin by %f %f %f\n", ori.x, ori.y, ori.z);
@@ -1403,7 +1473,6 @@ void Gui::drawMenuBar() {
14031473

14041474
}
14051475

1406-
LumpReplaceCommand* command = new LumpReplaceCommand("Delete OOB Data");
14071476
map->delete_oob_data(clipFlags[i]);
14081477
command->pushUndoState();
14091478
}

src/editor/Renderer.cpp

+44-2
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,11 @@ void Renderer::renderLoop() {
424424
}
425425

426426
if ((g_render_flags & RENDER_MAP_BOUNDARY) && !emptyMapLoaded) {
427-
drawBox(mapRenderer->map->ents[0]->getOrigin() * -1, g_limits.max_mapboundary * 2, COLOR4(0, 255, 0, 64));
427+
glDepthFunc(GL_LESS);
428+
drawBox(mapRenderer->map->ents[0]->getOrigin() * -1, g_settings.mapsize_max * 2, COLOR4(0, 255, 0, 64));
429+
glDepthFunc(GL_LEQUAL); // draw lines in front (still causes some z fighting)
430+
drawBoxOutline(mapRenderer->map->ents[0]->getOrigin() * -1, g_settings.mapsize_max * 2, COLOR4(0, 0, 0, 255));
431+
glDepthFunc(GL_LESS);
428432
}
429433

430434
if (hasCullbox) {
@@ -2382,6 +2386,44 @@ void Renderer::drawBox(vec3 center, float width, COLOR4 color) {
23822386
buffer.draw(GL_TRIANGLES);
23832387
}
23842388

2389+
void Renderer::drawBoxOutline(vec3 center, float width, COLOR4 color) {
2390+
width *= 0.5f;
2391+
vec3 sz = vec3(width, width, width);
2392+
vec3 pos = vec3(center.x, center.z, -center.y);
2393+
vec3 mins = pos - sz;
2394+
vec3 maxs = pos + sz;
2395+
2396+
vec3 corners[8] = {
2397+
vec3(mins.x, mins.y, mins.z), // 0
2398+
vec3(maxs.x, mins.y, mins.z), // 1
2399+
vec3(mins.x, maxs.y, mins.z), // 2
2400+
vec3(maxs.x, maxs.y, mins.z), // 3
2401+
vec3(mins.x, mins.y, maxs.z), // 4
2402+
vec3(maxs.x, mins.y, maxs.z), // 5
2403+
vec3(mins.x, maxs.y, maxs.z), // 6
2404+
vec3(maxs.x, maxs.y, maxs.z), // 7
2405+
};
2406+
2407+
cVert edges[24] = {
2408+
cVert(corners[0], color), cVert(corners[1], color),
2409+
cVert(corners[1], color), cVert(corners[3], color),
2410+
cVert(corners[3], color), cVert(corners[2], color),
2411+
cVert(corners[2], color), cVert(corners[0], color),
2412+
cVert(corners[4], color), cVert(corners[5], color),
2413+
cVert(corners[5], color), cVert(corners[7], color),
2414+
cVert(corners[7], color), cVert(corners[6], color),
2415+
cVert(corners[6], color), cVert(corners[4], color),
2416+
cVert(corners[0], color), cVert(corners[4], color),
2417+
cVert(corners[1], color), cVert(corners[5], color),
2418+
cVert(corners[2], color), cVert(corners[6], color),
2419+
cVert(corners[3], color), cVert(corners[7], color),
2420+
};
2421+
2422+
VertexBuffer buffer(colorShader, COLOR_4B | POS_3F, &edges, 24);
2423+
buffer.upload();
2424+
buffer.draw(GL_LINES);
2425+
}
2426+
23852427
void Renderer::drawBox(vec3 mins, vec3 maxs, COLOR4 color) {
23862428
mins = vec3(mins.x, mins.z, -mins.y);
23872429
maxs = vec3(maxs.x, maxs.z, -maxs.y);
@@ -4469,7 +4511,7 @@ void Renderer::merge(string fpath) {
44694511
map2->remove_unused_model_structures().print_delete_stats(2);
44704512

44714513
BspMerger merger;
4472-
mergeResult = merger.merge(maps, vec3(), thismap->name, true, true, true, g_engine_limits->max_mapboundary);
4514+
mergeResult = merger.merge(maps, vec3(), thismap->name, true, true, true, g_settings.mapsize_max);
44734515

44744516
if (!mergeResult.map || !mergeResult.map->valid) {
44754517
delete map2;

src/editor/Renderer.h

+1
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ class Renderer {
284284
void drawLine(vec3 start, vec3 end, COLOR4 color);
285285
void drawLine2D(vec2 start, vec2 end, COLOR4 color);
286286
void drawBox(vec3 center, float width, COLOR4 color);
287+
void drawBoxOutline(vec3 center, float width, COLOR4 color);
287288
void drawBox(vec3 mins, vec3 maxs, COLOR4 color);
288289
void drawPolygon3D(Polygon3D& poly, COLOR4 color);
289290
float drawPolygon2D(Polygon3D poly, vec2 pos, vec2 maxSz, COLOR4 color); // returns render scale

src/globals.h

-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ struct MapLimits {
3535
int max_entdata;
3636
int max_allocblocks;
3737
int max_texturepixels;
38-
int max_mapboundary; // how far from the map origin you can play the game without weird glitches
3938
};
4039

4140
class Renderer;

src/main.cpp

-2
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,6 @@ void init_limits() {
726726
g_engine_limits[ENGINE_HALF_LIFE].max_texinfos = 32767;
727727
g_engine_limits[ENGINE_HALF_LIFE].max_allocblocks = 64;
728728
g_engine_limits[ENGINE_HALF_LIFE].max_texturepixels = 262144;
729-
g_engine_limits[ENGINE_HALF_LIFE].max_mapboundary = 4096;
730729

731730
g_engine_limits[ENGINE_SVEN_COOP].max_surface_extents = 64;
732731
g_engine_limits[ENGINE_SVEN_COOP].max_models = 4096;
@@ -748,7 +747,6 @@ void init_limits() {
748747
g_engine_limits[ENGINE_SVEN_COOP].max_texinfos = 32767;
749748
g_engine_limits[ENGINE_SVEN_COOP].max_allocblocks = 1024;
750749
g_engine_limits[ENGINE_SVEN_COOP].max_texturepixels = 1048576;
751-
g_engine_limits[ENGINE_SVEN_COOP].max_mapboundary = 32768;
752750

753751
g_limits = g_engine_limits[ENGINE_SVEN_COOP];
754752
}

0 commit comments

Comments
 (0)