Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ set(SPT_SOURCES
FetchContent_Declare(
monocle
GIT_REPOSITORY https://github.com/UncraftedName/Monocle
GIT_TAG 3ff422cc2a7d4048369c1cae7b1315155e9afa08
GIT_TAG cf2d275f0b63c9294ec217141f9e5e19492f3192
)

FetchContent_MakeAvailable(monocle)
Expand Down
12 changes: 3 additions & 9 deletions spt/features/visualizations/monocle/mon_feature.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "spt\feature.hpp"

#include "thirdparty\monocle_implicit_conversions.hpp"
#include "teleport_chain\generate.hpp"

#include <d3d9.h>
Expand Down Expand Up @@ -84,13 +85,7 @@ struct WorkerMonocleData
mon::PlacementOrder order,
mon::GameVersion gv,
const mon::TeleportChainParams& paramsTemplate)
: pp(*(mon::Vector*)&bluePos,
*(mon::QAngle*)&blueAng,
*(mon::Vector*)&orangePos,
*(mon::QAngle*)&orangeAng,
order,
gv)
, paramsTemplate(paramsTemplate)
: pp(bluePos, blueAng, orangePos, orangeAng, order, gv), paramsTemplate(paramsTemplate)
{
this->paramsTemplate.pp = &pp;
}
Expand Down Expand Up @@ -220,8 +215,7 @@ class MonocleWorker
return img.size;
}

mon::Vector PixelToWorldCoordinates(WorkerPixel px,
const mon::TeleportChainParams* paramsOverride = nullptr) const;
Vector PixelToWorldCoordinates(WorkerPixel px, const mon::TeleportChainParams* paramsOverride = nullptr) const;

std::optional<WorkerPixelData> GetPixelResult(WorkerPixel px) const
{
Expand Down
10 changes: 5 additions & 5 deletions spt/features/visualizations/monocle/mon_imgui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -616,10 +616,10 @@ bool MonocleFeature::CheckPortalsChanged(const utils::PortalInfo* newEntryPortal

auto& oldEntry = oldMonData->paramsTemplate.EntryPortal();
auto& oldExit = oldMonData->paramsTemplate.ExitPortal();
auto vec_match = [](auto& a, auto& b) { return *(Vector*)&a == *(Vector*)&b; };

return !vec_match(oldEntry.pos, newEntryPortal->pos) || !vec_match(oldExit.pos, newLinkedPortal->pos)
|| !vec_match(oldEntry.ang, newEntryPortal->ang) || !vec_match(oldExit.ang, newLinkedPortal->ang);
return (const Vector&)oldEntry.pos != newEntryPortal->pos || (const Vector&)oldExit.pos != newLinkedPortal->pos
|| (const QAngle&)oldEntry.ang != newEntryPortal->ang
|| (const QAngle&)oldExit.ang != newLinkedPortal->ang;
}

void MonocleFeature::RestartWorkers(const utils::PortalInfo* newEntryPortal)
Expand All @@ -639,10 +639,10 @@ void MonocleFeature::RestartWorkers(const utils::PortalInfo* newEntryPortal)

mon::TeleportChainParams paramsTemplate;

mon::Vector entCenter = *(mon::Vector*)&newEntryPortal->pos;
auto& entCenter = newEntryPortal->pos;
paramsTemplate.ent =
imguiPersist.usePlayer
? mon::Entity::CreatePlayerFromCenter(entCenter, imguiPersist.combos.playerCrouched.Grab())
? mon::Entity::CreatePlayerFromCenter(newEntryPortal->pos, imguiPersist.combos.playerCrouched.Grab())
: mon::Entity::CreateBall(entCenter, imguiPersist.nonPlayerRadius);
paramsTemplate.first_tp_from_blue = !newEntryPortal->isOrange;
paramsTemplate.record_flags = mon::TCRF_NONE;
Expand Down
61 changes: 30 additions & 31 deletions spt/features/visualizations/monocle/mon_worker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ MonocleWorker::~MonocleWorker()
thread.join();
}

mon::Vector MonocleWorker::PixelToWorldCoordinates(WorkerPixel px, const mon::TeleportChainParams* paramsOverride) const
Vector MonocleWorker::PixelToWorldCoordinates(WorkerPixel px, const mon::TeleportChainParams* paramsOverride) const
{
Assert(!!monocleData);
const mon::TeleportChainParams* params = paramsOverride ? paramsOverride : &monocleData->paramsTemplate;
const mon::Portal& p = params->EntryPortal();
// center on each pixel and orient as if we're looking at the portal
mon::Vector uShift = p.u * (mon::PORTAL_HALF_HEIGHT * ((2 * px.y + 1) / (float)img.size.y - 1));
mon::Vector rShift = p.r * (mon::PORTAL_HALF_WIDTH * ((2 * px.x + 1) / (float)img.size.x - 1));
Vector uShift = p.u * (mon::PORTAL_HALF_HEIGHT * ((2 * px.y + 1) / (float)img.size.y - 1));
Vector rShift = p.r * (mon::PORTAL_HALF_WIDTH * ((2 * px.x + 1) / (float)img.size.x - 1));
return (p.pos - uShift) - rShift;
}

Expand Down Expand Up @@ -229,53 +229,52 @@ void MonocleWorker::RecomputeEffectiveTpSpace()
* The player will always be teleported when their center is on the portal plane. To figure
* out the effective teleport space:
* - slice the player using the portal plane to create a 2D polygon
* - create an AABB of that polygon
* - create a 2D AABB of that polygon
* - "subtract" that AABB from the portal rectangle
*/

matrix3x4_t portalToWorld;
AngleIMatrix(*(QAngle*)&p.ang, *(Vector*)&p.pos, portalToWorld);
AngleIMatrix(p.ang, p.pos, portalToWorld);

// create an AABB centered at the portal
mon::Entity centeredEnt = ent.WithNewCenter(p.pos);
mon::Vector mins = centeredEnt.GetWorldMins();
mon::Vector maxs = centeredEnt.GetWorldMaxs();

// get a cross section of the player sliced by the portal plane (world space)
std::array<Vector, 10> edgeIntersectionsWorldSpace;
size_t intersectionCount = 0;

auto checkPlaneIntersectLine = [&](const Vector& a, const Vector& b)
auto checkPortalPlaneIntersectLineSegment = [&](const Vector& a, const Vector& b)
{
const VPlane& portalPlane = *(VPlane*)&p.plane;
float aDotN = a.Dot(portalPlane.m_Normal);
float bDotN = b.Dot(portalPlane.m_Normal);
float aDotN = a.Dot(p.plane.n);
float bDotN = b.Dot(p.plane.n);
// t is the fraction at which the line segment a->b intersects the portal plane
float t = (portalPlane.m_Dist - aDotN) / (bDotN - aDotN);
float t = (p.plane.d - aDotN) / (bDotN - aDotN);
// because of this epsilon, we may sometimes get false positives and include more edges than necessary (up to 10)
if (t >= -0.0001f && t <= 1.0001f)
edgeIntersectionsWorldSpace[intersectionCount++] = Lerp(t, a, b);
};

// iterate over all player AABB edges

// edges from the mins corner
checkPlaneIntersectLine(*(Vector*)&mins, {maxs.x, mins.y, mins.z});
checkPlaneIntersectLine(*(Vector*)&mins, {mins.x, maxs.y, mins.z});
checkPlaneIntersectLine(*(Vector*)&mins, {mins.x, mins.y, maxs.z});

// the other 9 edges :)
for (size_t r = 0; r < 3; r++)
{
Vector from = *(Vector*)&maxs;
from[r] = mins[r];
for (size_t flipAx = 0; flipAx < 3; flipAx++)
{
Vector to = from;
to[flipAx] = r == flipAx ? maxs[flipAx] : mins[flipAx];
checkPlaneIntersectLine(from, to);
}
}
// iterate over all player AABB edges - pick 4 reference corners and change each of the 3 axes one at a time (mins<->maxs) to get an adjacent corner

Vector a = centeredEnt.GetWorldMins();
Vector b = centeredEnt.GetWorldMaxs();

Vector ref = {a.x, a.y, a.z};
checkPortalPlaneIntersectLineSegment(ref, {b.x, a.y, a.z});
checkPortalPlaneIntersectLineSegment(ref, {a.x, b.y, a.z});
checkPortalPlaneIntersectLineSegment(ref, {a.x, a.y, b.z});
ref = {a.x, b.y, b.z};
checkPortalPlaneIntersectLineSegment(ref, {b.x, b.y, b.z});
checkPortalPlaneIntersectLineSegment(ref, {a.x, a.y, b.z});
checkPortalPlaneIntersectLineSegment(ref, {a.x, b.y, a.z});
ref = {b.x, a.y, b.z};
checkPortalPlaneIntersectLineSegment(ref, {a.x, a.y, b.z});
checkPortalPlaneIntersectLineSegment(ref, {b.x, b.y, b.z});
checkPortalPlaneIntersectLineSegment(ref, {b.x, a.y, a.z});
ref = {b.x, b.y, a.z};
checkPortalPlaneIntersectLineSegment(ref, {a.x, b.y, a.z});
checkPortalPlaneIntersectLineSegment(ref, {b.x, a.y, a.z});
checkPortalPlaneIntersectLineSegment(ref, {b.x, b.y, b.z});

// convert the intersections to a local space AABB (+z is up, +y is left)
Vector localMins(666, 666, 666);
Expand Down
53 changes: 53 additions & 0 deletions thirdparty/monocle_implicit_conversions.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#pragma once

// include this file before any monocle files to allow implicit conversions between monocle/SDK

#include "mathlib/vector.h"
#include "mathlib/mathlib.h"
#include "mathlib/vmatrix.h"
#include "mathlib/vplane.h"

#include <bit>

#define MON_VECTOR_CLASS_EXTRA \
constexpr Vector(const ::Vector& v) : x(v.x), y(v.y), z(v.z) {} \
operator const ::Vector&() const \
{ \
return reinterpret_cast<const ::Vector&>(*this); \
}

#define MON_QANGLE_CLASS_EXTRA \
constexpr QAngle(const ::QAngle& v) : x(v.x), y(v.y), z(v.z) {} \
operator const ::QAngle&() const \
{ \
return reinterpret_cast<const ::QAngle&>(*this); \
}

#define MON_MATRIX3X4_CLASS_EXTRA \
constexpr matrix3x4_t(const ::matrix3x4_t& m) \
{ \
*this = std::bit_cast<matrix3x4_t>(m); \
} \
operator const ::matrix3x4_t&() const \
{ \
return reinterpret_cast<const ::matrix3x4_t&>(*this); \
}

#define MON_VMATRIX_CLASS_EXTRA \
constexpr VMatrix(const ::VMatrix& vm) \
{ \
for (int i = 0; i < 4; ++i) \
for (int j = 0; j < 4; ++j) \
m[i][j] = vm.m[i][j]; \
} \
operator const ::VMatrix&() const \
{ \
return reinterpret_cast<const ::VMatrix&>(*this); \
}

#define MON_VPLANE_CLASS_EXTRA \
constexpr VPlane(const ::VPlane& plane) : n(plane.m_Normal), d(plane.m_Dist) {} \
operator const ::VPlane&() const \
{ \
return reinterpret_cast<const ::VPlane&>(*this); \
}