From 547968da608af0e7a34fcfa280de41568a9c07f3 Mon Sep 17 00:00:00 2001 From: khang Date: Tue, 2 Apr 2024 20:21:24 -0400 Subject: [PATCH 1/7] Add info_room and info_room_target --- .gitignore | 2 + src/sdhlt/sdHLVIS/vis.cpp | 84 ++++++++++++++++++++++++++++++++++++++- src/sdhlt/sdHLVIS/vis.h | 19 +++++++++ 3 files changed, 104 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1c9957c..230983d 100644 --- a/.gitignore +++ b/.gitignore @@ -100,3 +100,5 @@ Temporary Items !/tools/wad.cfg *.zip + +/build*/ \ No newline at end of file diff --git a/src/sdhlt/sdHLVIS/vis.cpp b/src/sdhlt/sdHLVIS/vis.cpp index e2fbc55..c158c7e 100644 --- a/src/sdhlt/sdHLVIS/vis.cpp +++ b/src/sdhlt/sdHLVIS/vis.cpp @@ -75,6 +75,9 @@ overview_t g_overview[g_overview_max]; int g_overview_count = 0; leafinfo_t* g_leafinfos = NULL; +const int g_room_max = MAX_MAP_ENTITIES; +room_t g_room[g_room_max]; +int g_room_count = 0; static int totalvis = 0; @@ -589,6 +592,15 @@ static void LeafFlow(const int leafnum) outbuffer[i >> 3] |= (1 << (i & 7)); } } + + if (!g_leafinfos[leafnum].additional_leaves.empty()) + { + for (int leaf : g_leafinfos[leafnum].additional_leaves) + { + outbuffer[leaf >> 3] |= (1 << (leaf & 7)); + } + } + numvis = 0; for (i = 0; i < g_portalleafs; i++) { @@ -948,6 +960,24 @@ static void LoadPortals(char* portal_image) } } } + + for (j = 0; j < g_room_count; j++) + { + int d1 = g_room[j].visleafnum - g_leafstarts[i]; + + if (0 <= d1 && d1 < g_leafcounts[i]) + { + for (int k = 0; k < g_portalleafs; k++) + { + int d2 = g_room[j].target_visleafnum - g_leafstarts[k]; + + if (0 <= d2 && d2 < g_leafcounts[k]) + { + g_leafinfos[i].additional_leaves.push_back(k); + } + } + } + } } for (i = 0, p = g_portals; i < g_numportals; i++) { @@ -1788,7 +1818,10 @@ int main(const int argc, char** argv) int i; for (i = 0; i < g_numentities; i++) { - if (!strcmp (ValueForKey (&g_entities[i], "classname"), "info_overview_point")) + const char* current_entity_classname = ValueForKey (&g_entities[i], "classname"); + + if (!strcmp (current_entity_classname, "info_overview_point") + ) { if (g_overview_count < g_overview_max) { @@ -1800,6 +1833,55 @@ int main(const int argc, char** argv) g_overview_count++; } } + + // Check for length because we have `info_room` and `info_room_target` + else if (!strcmp (current_entity_classname, "info_room") + && strlen(current_entity_classname) == strlen("info_room") + ) + { + if (g_room_count < g_room_max) + { + vec3_t room_origin; + + GetVectorForKey (&g_entities[i], "origin", room_origin); + g_room[g_room_count].visleafnum = VisLeafnumForPoint (room_origin); + + const char* target = ValueForKey (&g_entities[i], "target"); + + if (strlen(target) == 0) + { + continue; + } + + bool has_target = false; + + // Find the target entity. + // Rewalk yes, very sad. + for (int j = 0; j < g_numentities; j++) + { + const char* current_entity_classname_nested = ValueForKey (&g_entities[j], "classname"); + + // Find a `info_room_target` and check if its targetname matches our target + if (!strcmp (current_entity_classname_nested, "info_room_target") + && !strcmp(ValueForKey (&g_entities[j], "targetname"), target)) + { + vec3_t room_target_origin; + + GetVectorForKey (&g_entities[j], "origin", room_target_origin); + g_room[g_room_count].target_visleafnum = VisLeafnumForPoint (room_target_origin); + + has_target = true; + } + } + + if (!has_target) + { + Warning("Entity %d (info_room) does not have a target.", i); + } + + g_room_count++; + } + } } } LoadPortalsByFilename(portalfile); diff --git a/src/sdhlt/sdHLVIS/vis.h b/src/sdhlt/sdHLVIS/vis.h index 7b73212..26a35c8 100644 --- a/src/sdhlt/sdHLVIS/vis.h +++ b/src/sdhlt/sdHLVIS/vis.h @@ -18,6 +18,8 @@ #include "zones.h" #include "cmdlinecfg.h" +#include + #define DEFAULT_MAXDISTANCE_RANGE 0 @@ -143,6 +145,21 @@ extern unsigned g_portalleafs; extern unsigned int g_maxdistance; //extern bool g_postcompile; + +// This allows the current leaf to have portal to selected leaf. +// TODO: vector for target so it can do a lot. Though doing the entity won't be as simple. +// That means we need to parse string and what not. +// For the time being, ONE target is good enough. +typedef struct +{ + int visleafnum; + int target_visleafnum; +} +room_t; +extern const int g_room_max; +extern room_t g_room[]; +extern int g_room_count; + typedef struct { vec3_t origin; @@ -158,6 +175,8 @@ typedef struct { bool isoverviewpoint; bool isskyboxpoint; + // For info_room + std::vector additional_leaves; } leafinfo_t; extern leafinfo_t *g_leafinfos; From e3f1193cc97db1cca216110fe5754d911efe4f12 Mon Sep 17 00:00:00 2001 From: khang Date: Tue, 2 Apr 2024 20:34:02 -0400 Subject: [PATCH 2/7] commit .fgd --- tools/sdhlt.fgd | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tools/sdhlt.fgd b/tools/sdhlt.fgd index 4971e84..d76b820 100644 --- a/tools/sdhlt.fgd +++ b/tools/sdhlt.fgd @@ -86,6 +86,19 @@ ] ] +// info_room +// It makes all entities inside info_room_target visible inside the room where this entity is. +@PointClass color(255 255 255) = info_room : "Disable VIS in info_room_target for this room" +[ + target(target_source) : "Name of info_room_target" +] + +// info_room_target +@PointClass color(255 255 255) = info_room_target : "Disable VIS in this room for info_room" +[ + targetname(target_destination) : "Name" +] + // info_sunlight // It generates a fake light_environment which defines sv_skycolor and sv_skyvec in game. // If you are using multiple light_environments, you will probably need this entity. From ed1e73353a8853b80f21a0c02b2aab10a5de5507 Mon Sep 17 00:00:00 2001 From: khang Date: Tue, 2 Apr 2024 22:33:43 -0400 Subject: [PATCH 3/7] remove unnecessary condition --- src/sdhlt/sdHLVIS/vis.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/sdhlt/sdHLVIS/vis.cpp b/src/sdhlt/sdHLVIS/vis.cpp index c158c7e..741d6cb 100644 --- a/src/sdhlt/sdHLVIS/vis.cpp +++ b/src/sdhlt/sdHLVIS/vis.cpp @@ -1834,10 +1834,7 @@ int main(const int argc, char** argv) } } - // Check for length because we have `info_room` and `info_room_target` - else if (!strcmp (current_entity_classname, "info_room") - && strlen(current_entity_classname) == strlen("info_room") - ) + else if (!strcmp (current_entity_classname, "info_room")) { if (g_room_count < g_room_max) { From f2ec7a4674deee972ca8380921cf60604fb80bce Mon Sep 17 00:00:00 2001 From: khang Date: Thu, 4 Apr 2024 14:15:59 -0400 Subject: [PATCH 4/7] add "neighbor" key to BFS traversal add surrounding leaves --- src/sdhlt/sdHLVIS/vis.cpp | 52 +++++++++++++++++++++++++++++++++------ src/sdhlt/sdHLVIS/vis.h | 6 +++++ tools/sdhlt.fgd | 1 + 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/sdhlt/sdHLVIS/vis.cpp b/src/sdhlt/sdHLVIS/vis.cpp index 741d6cb..2885911 100644 --- a/src/sdhlt/sdHLVIS/vis.cpp +++ b/src/sdhlt/sdHLVIS/vis.cpp @@ -518,6 +518,35 @@ static void LeafThread(int unused) #pragma warning(pop) #endif +// Recursively add `add` to `current` visibility leaf. +std::unordered_map leaf_flow_add_exclude = {}; +static void LeafFlowNeighborAddLeaf(const int current, const int add, const int neighbor) +{ + auto outbuffer = g_uncompressed + current * g_bitbytes; + + outbuffer[add >> 3] |= (1 << (add & 7)); + leaf_flow_add_exclude[current] = true; + + if (neighbor == 0) + { + return; + } + + auto leaf = &g_leafs[current]; + + for (int i = 0; i < leaf->numportals; i++) + { + auto p = leaf->portals[i]; + + if (leaf_flow_add_exclude[p->leaf]) { + // Log("leaf %d neighbor %d is excluded\n", current, p->leaf); + continue; + } + + LeafFlowNeighborAddLeaf(p->leaf, add, neighbor - 1); + } +} + // ===================================================================================== // LeafFlow // Builds the entire visibility list for a leaf @@ -593,14 +622,6 @@ static void LeafFlow(const int leafnum) } } - if (!g_leafinfos[leafnum].additional_leaves.empty()) - { - for (int leaf : g_leafinfos[leafnum].additional_leaves) - { - outbuffer[leaf >> 3] |= (1 << (leaf & 7)); - } - } - numvis = 0; for (i = 0; i < g_portalleafs; i++) { @@ -819,6 +840,19 @@ static void CalcVis() CalcPortalVis(); + // Add additional leaves to the uncompressed vis. + for (i = 0; i < g_portalleafs; i++) + { + if (!g_leafinfos[i].additional_leaves.empty()) + { + for (int leaf : g_leafinfos[i].additional_leaves) + { + LeafFlowNeighborAddLeaf(i, leaf, g_leafinfos[i].neighbor); + leaf_flow_add_exclude.clear(); + } + } + } + // // assemble the leaf vis lists by oring and compressing the portal lists // @@ -974,6 +1008,7 @@ static void LoadPortals(char* portal_image) if (0 <= d2 && d2 < g_leafcounts[k]) { g_leafinfos[i].additional_leaves.push_back(k); + g_leafinfos[i].neighbor = g_room[j].neighbor; } } } @@ -1842,6 +1877,7 @@ int main(const int argc, char** argv) GetVectorForKey (&g_entities[i], "origin", room_origin); g_room[g_room_count].visleafnum = VisLeafnumForPoint (room_origin); + g_room[g_room_count].neighbor = std::clamp(IntForKey (&g_entities[i], "neighbor"), 0, MAX_ROOM_NEIGHBOR); const char* target = ValueForKey (&g_entities[i], "target"); diff --git a/src/sdhlt/sdHLVIS/vis.h b/src/sdhlt/sdHLVIS/vis.h index 26a35c8..3b27234 100644 --- a/src/sdhlt/sdHLVIS/vis.h +++ b/src/sdhlt/sdHLVIS/vis.h @@ -19,6 +19,7 @@ #include "cmdlinecfg.h" #include +#include #define DEFAULT_MAXDISTANCE_RANGE 0 @@ -150,15 +151,19 @@ extern unsigned int g_maxdistance; // TODO: vector for target so it can do a lot. Though doing the entity won't be as simple. // That means we need to parse string and what not. // For the time being, ONE target is good enough. +#define MAX_ROOM_NEIGHBOR 16 typedef struct { int visleafnum; int target_visleafnum; + // Traversal of neighbors being affected. + int neighbor; } room_t; extern const int g_room_max; extern room_t g_room[]; extern int g_room_count; +extern std::unordered_map leaf_flow_add_exclude; typedef struct { @@ -177,6 +182,7 @@ typedef struct bool isskyboxpoint; // For info_room std::vector additional_leaves; + int neighbor; } leafinfo_t; extern leafinfo_t *g_leafinfos; diff --git a/tools/sdhlt.fgd b/tools/sdhlt.fgd index d76b820..8ba4fd8 100644 --- a/tools/sdhlt.fgd +++ b/tools/sdhlt.fgd @@ -91,6 +91,7 @@ @PointClass color(255 255 255) = info_room : "Disable VIS in info_room_target for this room" [ target(target_source) : "Name of info_room_target" + neighbor(interger) : "Layer of surrounding neighbor to be affected" : 1 ] // info_room_target From 8a8f1b23f4a00330529cb04e1ce4d550957a75b5 Mon Sep 17 00:00:00 2001 From: khang Date: Thu, 4 Apr 2024 14:33:17 -0400 Subject: [PATCH 5/7] fix windows build --- src/sdhlt/sdHLVIS/vis.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sdhlt/sdHLVIS/vis.cpp b/src/sdhlt/sdHLVIS/vis.cpp index 2885911..d70c63e 100644 --- a/src/sdhlt/sdHLVIS/vis.cpp +++ b/src/sdhlt/sdHLVIS/vis.cpp @@ -16,10 +16,13 @@ #ifdef SYSTEM_WIN32 #define WIN32_LEAN_AND_MEAN #include +// std:clamp() is at least MVSC 19 +#define CLAMP(x, min, max) x <= min ? min : x >= max ? max : x #endif #ifdef SYSTEM_POSIX #include +#define CLAMP(x, min, max) std::clamp(x, min, max) #endif #ifdef ZHLT_NETVIS @@ -1877,7 +1880,7 @@ int main(const int argc, char** argv) GetVectorForKey (&g_entities[i], "origin", room_origin); g_room[g_room_count].visleafnum = VisLeafnumForPoint (room_origin); - g_room[g_room_count].neighbor = std::clamp(IntForKey (&g_entities[i], "neighbor"), 0, MAX_ROOM_NEIGHBOR); + g_room[g_room_count].neighbor = CLAMP(IntForKey (&g_entities[i], "neighbor"), 0, MAX_ROOM_NEIGHBOR); const char* target = ValueForKey (&g_entities[i], "target"); From 927200a75fc1daf9eb7b36bdeed74c306927eb17 Mon Sep 17 00:00:00 2001 From: seedee Date: Mon, 8 Jul 2024 13:20:16 +0100 Subject: [PATCH 6/7] Rename entities --- src/sdhlt/sdHLVIS/vis.cpp | 8 ++++---- src/sdhlt/sdHLVIS/vis.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sdhlt/sdHLVIS/vis.cpp b/src/sdhlt/sdHLVIS/vis.cpp index d70c63e..f629857 100644 --- a/src/sdhlt/sdHLVIS/vis.cpp +++ b/src/sdhlt/sdHLVIS/vis.cpp @@ -1872,7 +1872,7 @@ int main(const int argc, char** argv) } } - else if (!strcmp (current_entity_classname, "info_room")) + else if (!strcmp (current_entity_classname, "info_portal")) { if (g_room_count < g_room_max) { @@ -1897,8 +1897,8 @@ int main(const int argc, char** argv) { const char* current_entity_classname_nested = ValueForKey (&g_entities[j], "classname"); - // Find a `info_room_target` and check if its targetname matches our target - if (!strcmp (current_entity_classname_nested, "info_room_target") + // Find a `info_leaf` and check if its targetname matches our target + if (!strcmp (current_entity_classname_nested, "info_leaf") && !strcmp(ValueForKey (&g_entities[j], "targetname"), target)) { vec3_t room_target_origin; @@ -1912,7 +1912,7 @@ int main(const int argc, char** argv) if (!has_target) { - Warning("Entity %d (info_room) does not have a target.", i); + Warning("Entity %d (info_portal) does not have a target leaf.", i); } g_room_count++; diff --git a/src/sdhlt/sdHLVIS/vis.h b/src/sdhlt/sdHLVIS/vis.h index 3b27234..e864adb 100644 --- a/src/sdhlt/sdHLVIS/vis.h +++ b/src/sdhlt/sdHLVIS/vis.h @@ -180,7 +180,7 @@ typedef struct { bool isoverviewpoint; bool isskyboxpoint; - // For info_room + // For info_portal std::vector additional_leaves; int neighbor; } From 372df54e19a04a47276b4c5a42cdcd7cd97dcd2e Mon Sep 17 00:00:00 2001 From: seedee Date: Mon, 8 Jul 2024 13:20:52 +0100 Subject: [PATCH 7/7] Fix integer, add help context --- tools/sdhlt.fgd | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/tools/sdhlt.fgd b/tools/sdhlt.fgd index 8ba4fd8..4847b40 100644 --- a/tools/sdhlt.fgd +++ b/tools/sdhlt.fgd @@ -77,25 +77,27 @@ // info_overview_point // It makes all entities visible from this place. This is useful for overview mode (dev_overview 1). // If "Reversed" is selected, this place will become visible from the entire map. This is useful for large skybox model. -@PointClass color(255 0 0) = info_overview_point : "Disable VIS here for overview" +@PointClass color(255 0 0) = info_overview_point : "Disable VIS here by creating portals to every other leaf. Lag/wallhack warning. If reversed, every other leaf has a portal to this one." [ - reverse(choices) : "Reversed" : "" = + reverse(choices) : "Reversed (3D skybox)" : "" = [ "": "No" 1: "Yes" ] ] -// info_room -// It makes all entities inside info_room_target visible inside the room where this entity is. -@PointClass color(255 255 255) = info_room : "Disable VIS in info_room_target for this room" +// info_portal +// TODO: vector for target so it can do a lot. Though doing the entity won't be as simple. +// That means we need to parse string and what not. +// For the time being, ONE target is good enough. +@PointClass color(255 200 200) = info_portal : "Create a portal to the selected info_leaf, from the leaf the info_portal is inside. Forces target leaf to be visible from the current one." [ - target(target_source) : "Name of info_room_target" - neighbor(interger) : "Layer of surrounding neighbor to be affected" : 1 + target(target_source) : "Name of info_leaf" + neighbor(integer) : "TODO: Layers of neighboring leaves to be affected" : 1 ] -// info_room_target -@PointClass color(255 255 255) = info_room_target : "Disable VIS in this room for info_room" +// info_leaf +@PointClass color(200 200 255) = info_leaf : "Works with info_portal. Used to select a leaf the info_leaf is inside." [ targetname(target_destination) : "Name" ]