Skip to content

Commit

Permalink
Added arithmetic operator metamethods to PVS
Browse files Browse the repository at this point in the history
For documentation on newest additions, please see the newly updated `README.md`.
  • Loading branch information
piqey committed Dec 21, 2023
1 parent 02e8993 commit 07f3b10
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 4 deletions.
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,24 @@ Determines whether `area1` flows into `area2` and vice versa. Result depends on
## Description
A `userdata` type representing a Potentially Visible Set (PVS) in the context of map visibility computations. Comes packaged with several methods for working with its associated visibility data.

Contains the following metamethods:
## Metamethods
### General
| Metamethod | Description | Syntax |
| :---: | :--- | :--- |
| __index | When passed number values, acts as an alias of `PVS:ContainsCluster`, returning a `boolean` | `pvs[147]` |
| __len | Returns the number of clusters visible in the PVS in question | `#pvs` |
| __tostring | Returns a string in the format of `"[PVS] X/Y clusters visible"` | `tostring(pvs)` |

### Arithmetic
`PVS` objects come complete with several arithmetic operator overloads for performing a number of basic bitwise operations on the byte buffers of said objects.
| Metamethod | Description | Bitwise | Syntax |
| :---: | :--- | :---: | :---: |
| __add | Returns a `PVS` with all the clusters from both of the two `PVS` objects provided | `A \| B` | `A + B` |
| __sub | Returns a copy of `A` with all clusters shared with `B` omitted | `A & ~B` | `A - B` |
| __mul | Returns a `PVS` containing only clusters `A` and `B` have in common | `A & B` | `A * B` |
| __div | Returns a `PVS` containing every cluster in the map *except* those `A` and `B` have in common | `~(A & B)` | `A / B` |
| __unm | Returns an *inversion* of the `PVS` provided, containing any clusters the former didn't and not containing any it did | `~A` | `-A` |

## Methods
### `boolean` PVS:CheckOrigin(`Vector` origin)
#### Description
Expand Down
151 changes: 150 additions & 1 deletion src/Types/PVS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@ namespace VisInfo::Types
}

PVSData::PVSData(int size, byte* buffer) :
size(size), total(engine_server->GetClusterCount()), buffer(buffer)
PVSData::PVSData(size, buffer, engine_server->GetClusterCount())
{

}

PVSData::PVSData(int size, byte* buffer, int total) :
size(size), buffer(buffer), total(total)
{
if (buffer == nullptr)
throw std::runtime_error("PVS byte buffer is a null pointer!");
Expand Down Expand Up @@ -76,6 +82,68 @@ namespace VisInfo::Types
delete[] bboxes;
}

PVSData PVSData::operator-() const
{
byte* newBuffer = new byte[this->size];

for (int i = 0; i < this->size; i++)
newBuffer[i] = ~this->buffer[i];

return PVSData(this->size, newBuffer, this->total);
}

PVSData PVSData::operator+(const PVSData& b) const
{
if (this->total != b.total)
throw std::runtime_error("Cannot add PVS objects with different total cluster counts!");

byte* newBuffer = new byte[this->size];

for (int i = 0; i < this->size; i++)
newBuffer[i] = this->buffer[i] | b.buffer[i];

return PVSData(this->size, newBuffer, this->total);
}

PVSData PVSData::operator-(const PVSData& b) const
{
if (this->total != b.total)
throw std::runtime_error("Cannot subtract PVS objects with different total cluster counts!");

byte* newBuffer = new byte[this->size];

for (int i = 0; i < this->size; i++)
newBuffer[i] = this->buffer[i] & ~b.buffer[i];

return PVSData(this->size, newBuffer, this->total);
}

PVSData PVSData::operator*(const PVSData& b) const
{
if (this->total != b.total)
throw std::runtime_error("Cannot intersect PVS objects with different total cluster counts!");

byte* newBuffer = new byte[this->size];

for (int i = 0; i < this->size; i++)
newBuffer[i] = this->buffer[i] & b.buffer[i];

return PVSData(this->size, newBuffer, this->total);
}

PVSData PVSData::operator/(const PVSData& b) const
{
if (this->total != b.total)
throw std::runtime_error("Cannot get symmetric difference of PVS objects with different total cluster counts!");

byte* newBuffer = new byte[this->size];

for (int i = 0; i < this->size; i++)
newBuffer[i] = this->buffer[i] & ~(this->buffer[i] & b.buffer[i]);

return PVSData(this->size, newBuffer, this->total);
}

// Lua UserType stuff

LUA_FUNCTION_STATIC(index)
Expand Down Expand Up @@ -129,6 +197,66 @@ namespace VisInfo::Types
return 1;
}

LUA_FUNCTION_STATIC(unm)
{
LUA->CheckType(1, PVSData::meta);
LUA->PushUserType(new PVSData(-*LUA->GetUserType<PVSData>(1, PVSData::meta)), PVSData::meta);

return 1;
}

LUA_FUNCTION_STATIC(add)
{
LUA->CheckType(1, PVSData::meta);
LUA->CheckType(2, PVSData::meta);

PVSData* pvs_A = LUA->GetUserType<PVSData>(1, PVSData::meta);
PVSData* pvs_B = LUA->GetUserType<PVSData>(2, PVSData::meta);

LUA->PushUserType(new PVSData(*pvs_A + *pvs_B), PVSData::meta);

return 1;
}

LUA_FUNCTION_STATIC(sub)
{
LUA->CheckType(1, PVSData::meta);
LUA->CheckType(2, PVSData::meta);

PVSData* pvs_A = LUA->GetUserType<PVSData>(1, PVSData::meta);
PVSData* pvs_B = LUA->GetUserType<PVSData>(2, PVSData::meta);

LUA->PushUserType(new PVSData(*pvs_A - *pvs_B), PVSData::meta);

return 1;
}

LUA_FUNCTION_STATIC(mul)
{
LUA->CheckType(1, PVSData::meta);
LUA->CheckType(2, PVSData::meta);

PVSData* pvs_A = LUA->GetUserType<PVSData>(1, PVSData::meta);
PVSData* pvs_B = LUA->GetUserType<PVSData>(2, PVSData::meta);

LUA->PushUserType(new PVSData(*pvs_A * *pvs_B), PVSData::meta);

return 1;
}

LUA_FUNCTION_STATIC(div)
{
LUA->CheckType(1, PVSData::meta);
LUA->CheckType(2, PVSData::meta);

PVSData* pvs_A = LUA->GetUserType<PVSData>(1, PVSData::meta);
PVSData* pvs_B = LUA->GetUserType<PVSData>(2, PVSData::meta);

LUA->PushUserType(new PVSData(*pvs_A / *pvs_B), PVSData::meta);

return 1;
}

LUA_FUNCTION_STATIC(CheckOrigin)
{
LUA->CheckType(1, PVSData::meta);
Expand Down Expand Up @@ -222,6 +350,8 @@ namespace VisInfo::Types
{
meta = L->CreateMetaTable(typeName);

// General Metamethods

L->PushCFunction(index);
L->SetField(-2, "__index");

Expand All @@ -231,6 +361,25 @@ namespace VisInfo::Types
L->PushCFunction(tostring);
L->SetField(-2, "__tostring");

// Arithmetic Metamethods

L->PushCFunction(unm);
L->SetField(-2, "__unm");

L->PushCFunction(add);
L->SetField(-2, "__add");

L->PushCFunction(sub);
L->SetField(-2, "__sub");

L->PushCFunction(mul);
L->SetField(-2, "__mul");

L->PushCFunction(div);
L->SetField(-2, "__div");

// Methods

L->PushCFunction(VisInfo::Types::CheckOrigin);
L->SetField(-2, "CheckOrigin");

Expand Down
13 changes: 11 additions & 2 deletions src/Types/PVS.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ extern IVDebugOverlay* debug_overlay;

const QAngle qZero; // I don't know why vec3_angle is unresolved

// extern inline void LuaPrint(GarrysMod::Lua::ILuaBase* L, char* msg);
// extern inline void LuaPrint(GarrysMod::Lua::ILuaBase* L, char* msg, int num);
extern inline void LuaPrint(GarrysMod::Lua::ILuaBase* L, char* msg);
extern inline void LuaPrint(GarrysMod::Lua::ILuaBase* L, char* msg, int num);

namespace VisInfo::Types
{
Expand All @@ -28,6 +28,8 @@ namespace VisInfo::Types
int visible = 0;

PVSData(int size, byte* buffer);
PVSData(int size, byte* buffer, int total);

PVSData(PVSData&& pvs) noexcept;

~PVSData();
Expand All @@ -38,6 +40,13 @@ namespace VisInfo::Types

void DebugOverlay(int r, int g, int b, int a, float duration) const;

PVSData operator-() const;

PVSData operator+(const PVSData& b) const;
PVSData operator-(const PVSData& b) const;
PVSData operator*(const PVSData& b) const;
PVSData operator/(const PVSData& b) const;

// Lua UserType stuff

static const char* typeName;
Expand Down

0 comments on commit 07f3b10

Please sign in to comment.