-
Автор темы
- #1
enjoy
aimbot.cpp:
#include <vector>
#include <mutex>
#include <future>
#include <thread>
std::mutex points_mutex; // for thread-safe access to points.
// function to process a range of hitboxes.
void AimPlayer::process_hitbox_range(int start, int end, LagRecord* record, matrix3x4_t* record_matrix, float mindmg, bool force_baim_misses, std::vector<AimPoint_t>& points) {
const model_t* model = m_player->get_model();
if (!model) return;
studiohdr_t* hdr = model_info.get()->GetStudioModel(model);
if (!hdr) return;
mstudiohitboxset_t* set = hdr->GetHitboxSet(m_player->hitbox_set());
if (!set) return;
// thread-local storage for points.
std::vector<AimPoint_t> local_points;
const float head_scale = g_menu.main.aimbot.head_pointscale.get() / 100.f;
const float body_scale = g_menu.main.aimbot.body_pointscale.get() / 100.f;
for (int index = start; index < end; ++index) {
if (!g_aimbot.AllowHitbox(record->m_player, index, mindmg) || (index == HITBOX_HEAD && force_baim_misses))
continue;
mstudiobbox_t* bbox = set->GetHitbox(index);
if (!bbox) continue;
vec3_t center = (bbox->m_mins + bbox->m_maxs) / 2.f;
if (bbox->m_radius <= 0.f) {
if (!m_peek_data.m_filtered && g_menu.main.aimbot.aimbot_optimizations.get(1))
continue;
matrix3x4_t rot_matrix, matrix;
rot_matrix.AngleMatrix(bbox->m_angle);
math::ConcatTransforms(record_matrix[bbox->m_bone], rot_matrix, matrix);
vec3_t origin = matrix.GetOrigin();
if (index == HITBOX_R_FOOT || index == HITBOX_L_FOOT) {
float d1 = (bbox->m_mins.z - center.z) * 0.875f;
if (index == HITBOX_L_FOOT) d1 *= -1.f;
AimPoint_t point;
point.m_pos = vec3_t(center.x, center.y, center.z + d1);
point.m_hitbox = index;
point.m_hitbox_radius = bbox->m_radius;
point.m_point_safety = 1.f - ((center - bbox->m_maxs).length() / bbox->m_radius);
local_points.emplace_back(point);
if (g_menu.main.aimbot.multipoint.get(3)) {
float d2 = (bbox->m_mins.x - center.x) * body_scale;
float d3 = (bbox->m_maxs.x - center.x) * body_scale;
point.m_pos = vec3_t(center.x + d2, center.y, center.z);
local_points.emplace_back(point);
point.m_pos = vec3_t(center.x + d3, center.y, center.z);
local_points.emplace_back(point);
}
}
for (auto& p : local_points) {
if (!p.m_rotated) {
p.m_pos = vec3_t(p.m_pos.dot(matrix[0]), p.m_pos.dot(matrix[1]), p.m_pos.dot(matrix[2])) + origin;
p.m_rotated = true;
}
}
}
else {
float bs = bbox->m_radius * body_scale;
if (m_peek_data.m_filtered || !g_menu.main.aimbot.aimbot_optimizations.get(1)) {
if (g_menu.main.aimbot.multipoint.get(0) && index == HITBOX_HEAD) {
const float rotation = 0.70710678f;
for (int i = 0; i <= g_menu.main.aimbot.multipoint_intensity.get(); i++) {
float hs_width = bbox->m_radius * (head_scale * ((3.f - i) / 3.f));
float hs_height = bbox->m_radius * (60 * ((3.f - i) / 3.f));
AimPoint_t point;
point.m_pos = vec3_t(bbox->m_maxs.x, bbox->m_maxs.y, bbox->m_maxs.z - hs_width);
point.m_hitbox = index;
point.m_hitbox_radius = bbox->m_radius;
local_points.emplace_back(point);
point.m_pos = vec3_t(bbox->m_maxs.x, bbox->m_maxs.y, bbox->m_maxs.z + hs_width);
local_points.emplace_back(point);
point.m_pos = vec3_t(bbox->m_maxs.x + (rotation * hs_height), bbox->m_maxs.y + (-rotation * hs_width), bbox->m_maxs.z);
local_points.emplace_back(point);
}
}
else if (index == HITBOX_BODY || index == HITBOX_PELVIS) {
if (g_menu.main.aimbot.multipoint.get(2)) {
AimPoint_t point;
point.m_pos = vec3_t(center.x, center.y, center.z - bs);
point.m_hitbox = index;
point.m_hitbox_radius = bbox->m_radius;
local_points.emplace_back(point);
point.m_pos = vec3_t(center.x, center.y, center.z + bs);
local_points.emplace_back(point);
}
}
}
AimPoint_t point;
point.m_pos = center;
point.m_hitbox = index;
point.m_hitbox_radius = bbox->m_radius;
local_points.emplace_back(point);
vec3_t transformed_center = center;
math::VectorTransform(transformed_center, record_matrix[bbox->m_bone], transformed_center);
RayTracer::Hitbox box(bbox->m_mins, bbox->m_maxs, bbox->m_radius);
RayTracer::Trace trace;
vec3_t delta = (transformed_center - g_cl.m_shoot_pos).normalized();
vec3_t max_min = (bbox->m_maxs - bbox->m_mins).normalized();
if (index == HITBOX_HEAD) {
RayTracer::TraceFromCenter(RayTracer::Ray(g_cl.m_shoot_pos, transformed_center), box, trace, RayTracer::Flags_RETURNEND);
AimPoint_t point;
point.m_pos = trace.m_traceEnd;
point.m_hitbox = index;
point.m_hitbox_radius = bbox->m_radius;
point.m_point_safety = 1.f;
point.m_rotated = false;
local_points.emplace_back(point);
}
else {
RayTracer::TraceFromCenter(RayTracer::Ray(g_cl.m_shoot_pos, transformed_center + (max_min * 1000.f)), box, trace, RayTracer::Flags_RETURNEND);
AimPoint_t point;
point.m_pos = trace.m_traceEnd;
point.m_hitbox = index;
point.m_hitbox_radius = bbox->m_radius;
point.m_point_safety = 1.f;
point.m_rotated = false;
local_points.emplace_back(point);
}
for (auto& p : local_points) {
if (!p.m_rotated) {
math::VectorTransform(p.m_pos, record_matrix[bbox->m_bone], p.m_pos);
p.m_rotated = true;
}
}
}
}
// lock and merge results back into the shared points vector.
std::lock_guard<std::mutex> lock(points_mutex);
points.insert(points.end(), local_points.begin(), local_points.end());
}
void AimPlayer::SetupHitboxPoints(LagRecord* record, matrix3x4_t* record_matrix, float mindmg, bool force_baim_misses, std::vector<AimPoint_t>& points) {
// get number of hardware threads.
unsigned int num_threads = std::thread::hardware_concurrency();
if (num_threads == 0) num_threads = 2; // fallback to 2 if hardware_concurrency is unavailable.
// divide hitboxes into batches.
int hitbox_count = HITBOX_MAX;
int hitboxes_per_thread = hitbox_count / num_threads;
std::vector<std::future<void>> futures;
// launch threads to process hitbox ranges.
for (unsigned int i = 0; i < num_threads; ++i) {
int start = i * hitboxes_per_thread;
int end = (i == num_threads - 1) ? hitbox_count : start + hitboxes_per_thread;
// pass the current instance (this) to std::async to call member function.
futures.push_back(std::async(std::launch::async, &AimPlayer::process_hitbox_range, this, start, end, record, record_matrix, mindmg, force_baim_misses, std::ref(points)));
}
// wait for all threads to complete.
for (auto& future : futures) {
future.get();
}
}
raytracer.h:
#pragma once
class RayTracer {
public:
struct Ray {
Ray(const vec3_t& direction);
Ray(const vec3_t& startPoint, const vec3_t& endPoint);
vec3_t m_startPoint;
vec3_t m_direction;
float m_length;
};
struct Hitbox {
Hitbox();
Hitbox(const vec3_t& mins, const vec3_t& maxs, const float radius);
Hitbox(const std::tuple<vec3_t, vec3_t, float>& initTuple);
vec3_t m_mins;
vec3_t m_maxs;
float m_radius;
};
struct Trace {
Trace();
bool m_hit;
float m_fraction;
vec3_t m_traceEnd;
vec3_t m_traceOffset;
};
enum Flags {
Flags_NONE = 0,
Flags_RETURNEND = (1 << 0),
Flags_RETURNOFFSET = (1 << 1)
};
// this is a specialization that starts from the center, as calculations are much simpler from the center of the hitbox.
static void TraceFromCenter(const Ray& ray, const Hitbox& hitbox, Trace& trace, int flags = 0);
// this is for the general case, tracing against the hitbox.
static void TraceHitbox(const Ray& ray, const Hitbox& hitbox, Trace& trace, int flags = 0);
};
raytracer.cpp:
#include "includes.h"
RayTracer::Ray::Ray(const vec3_t& direction): m_startPoint(), m_direction(direction), m_length(0.f) {}
RayTracer::Ray::Ray(const vec3_t& startPoint, const vec3_t& endPoint): m_startPoint(startPoint) {
auto vec3_tDiff = endPoint - startPoint;
m_direction = vec3_tDiff.normalized();
m_length = vec3_tDiff.length();
}
RayTracer::Hitbox::Hitbox(): m_mins(), m_maxs(), m_radius() {}
RayTracer::Hitbox::Hitbox(const vec3_t& mins, const vec3_t& maxs, const float radius): m_mins(mins), m_maxs(maxs), m_radius(radius) {}
RayTracer::Hitbox::Hitbox(const std::tuple<vec3_t, vec3_t, float>& initTuple): m_mins(std::get<0>(initTuple)), m_maxs(std::get<1>(initTuple)), m_radius(std::get<2>(initTuple)) {}
RayTracer::Trace::Trace(): m_hit(false), m_fraction(0.f), m_traceEnd() {}
void RayTracer::TraceFromCenter(const Ray& ray, const Hitbox& hitbox, Trace& trace, int flags) {
// we are treating the cylinder as a cylinder y^2+z^2=r^2, in the x-direction, so we will make it the x direction.
const vec3_t unitDesired(1.f, 0.f, 0.f);
const matrix3x4_t identityMatrix(
1.f, 0.f, 0.f, 0.f,
0.f, 1.f, 0.f, 0.f,
0.f, 0.f, 1.f, 0.f
);
auto center = (hitbox.m_mins + hitbox.m_maxs) / 2.f;
auto minsOffset = hitbox.m_mins - center;
auto maxsOffset = hitbox.m_maxs - center;
auto vecHitbox = maxsOffset - minsOffset;
auto hitboxLength = vecHitbox.length();
// now we calculate the transformation matrix to get our normalized hitbox to center.
auto unitHitbox = vecHitbox / hitboxLength;
// dot == cos because they are both unit vec3_ts.
auto dot = unitHitbox.dot(unitDesired);
auto cross = unitHitbox.cross(unitDesired);
vec3_t rotatedDirection;
// if cross is 0, then we don't have to rotate because they are parallel.
if (cross.length() > 0.f) {
matrix3x4_t crossMatrix(
0.f, -cross.z, cross.y, 0.f,
cross.z, 0.f, -cross.x, 0.f,
-cross.y, cross.x, 0.f, 0.f
);
auto rotationMatrix = identityMatrix + crossMatrix +
(crossMatrix * crossMatrix) * (1.f / (1.f + dot));
rotatedDirection = rotationMatrix * ray.m_direction;
}
else {
// cross is 0, they are parallel, if dot is 1.f they are same, else they are opposite.
if (dot == 1.f)
rotatedDirection = ray.m_direction;
else
rotatedDirection = -ray.m_direction;
}
auto a = rotatedDirection.y * rotatedDirection.y +
rotatedDirection.z * rotatedDirection.z;
if (a == 0) {
// the ray goes through both caps, easy case because we don't actually need to trace the ray because they are circles.
if (rotatedDirection.x > 0) {
// through the right cap, scale by radius and call it a day.
auto newLength = minsOffset.length() + hitbox.m_radius;
auto offset = (minsOffset * (newLength) / minsOffset.length());
if (flags & Flags_RETURNEND)
trace.m_traceEnd = center + offset;
if (flags & Flags_RETURNOFFSET)
trace.m_traceOffset = offset;
}
else {
// through the left cap, scale by radius again
auto newLength = maxsOffset.length() + hitbox.m_radius;
auto offset = (maxsOffset * (newLength) / maxsOffset.length());
if (flags & Flags_RETURNEND)
trace.m_traceEnd = center + offset;
if (flags & Flags_RETURNOFFSET)
trace.m_traceOffset = offset;
}
trace.m_hit = true;
return;
}
// b is always 0 because we start at the origin.
auto c = -(hitbox.m_radius * hitbox.m_radius);
// we only care about t1 because we are inside of the surface that we are tracing, so t0 will always be negative.
// also -4*a*c will always be positive because c is always negative and a is always positive.
auto t = (sqrtf(-4.f * a * c)) / (2.f * a);
// virutal direction is in the 3-D plane of x.
auto virtualPos = rotatedDirection * t;
auto minsAdjusted = -hitboxLength / 2.f;
auto maxsAdjusted = hitboxLength / 2.f;
auto outOfMinsSide = virtualPos.x < minsAdjusted;
auto outOfMaxsSide = virtualPos.x > maxsAdjusted;
// we need to trace the spheres on the ends.
if (outOfMinsSide || outOfMaxsSide) {
// set our position offset to the opposite side to raytrace the sphere.
vec3_t offsetPosition(
(outOfMinsSide) ? -minsAdjusted : -maxsAdjusted, 0.f, 0.f
);
// we treat a_s as 1 because for a sphere, it is just the entire unit vec3_t's length, always 1.
auto b_s = 2.f * (offsetPosition.x * rotatedDirection.x);
auto c_s = offsetPosition.x * offsetPosition.x -
hitbox.m_radius * hitbox.m_radius;
auto operand = sqrtf(b_s * b_s - 4 * c_s);
t = (-b_s + operand) / 2.f;
}
auto offset = ray.m_direction * t;
if (flags & Flags_RETURNEND)
trace.m_traceEnd = center + offset;
if (flags & Flags_RETURNOFFSET)
trace.m_traceOffset = offset;
trace.m_hit = true;
}
void RayTracer::TraceHitbox(const Ray& ray, const Hitbox& hitbox, Trace& trace, int flags) {
trace.m_fraction = 1.f;
// we are treating the cylinder as a cylinder y^2+z^2=r^2, in the x-direction, so we will make it the x direction.
const vec3_t unitDesired(1.f, 0.f, 0.f);
const matrix3x4_t identityMatrix(
1.f, 0.f, 0.f, 0.f,
0.f, 1.f, 0.f, 0.f,
0.f, 0.f, 1.f, 0.f
);
auto center = (hitbox.m_mins + hitbox.m_maxs) / 2.f;
auto minsOffset = hitbox.m_mins - center;
auto maxsOffset = hitbox.m_maxs - center;
auto vecHitbox = maxsOffset - minsOffset;
auto hitboxLength = vecHitbox.length();
// now we calculate the transformation matrix to get our normalized hitbox to center.
auto unitHitbox = vecHitbox / hitboxLength;
// dot == cos because they are both unit vec3_ts.
auto dot = unitHitbox.dot(unitDesired);
auto cross = unitHitbox.cross(unitDesired);
vec3_t rotatedDirection;
vec3_t rotatedStart;
// offset the position.
auto adjustedStart = ray.m_startPoint - center;
// if cross is 0, then we don't have to rotate because they are parallel.
if (cross.length() > 0.f) {
matrix3x4_t crossMatrix(
0.f, -cross.z, cross.y, 0.f,
cross.z, 0.f, -cross.x, 0.f,
-cross.y, cross.x, 0.f, 0.f
);
auto rotationMatrix = identityMatrix + crossMatrix +
(crossMatrix * crossMatrix) * (1.f / (1.f + dot));
rotatedDirection = rotationMatrix * ray.m_direction;
rotatedStart = rotationMatrix * adjustedStart;
}
else {
// cross is 0, they are parallel, if dot is 1.f they are same, else they are opposite.
if (dot > 0.f) {
rotatedDirection = ray.m_direction;
rotatedStart = adjustedStart;
}
else {
rotatedDirection = -ray.m_direction;
rotatedStart = -adjustedStart;
}
}
auto a_c = rotatedDirection.y * rotatedDirection.y +
rotatedDirection.z * rotatedDirection.z;
// todo: simv0l - detect the plane!
// this is INCREDIBLY RARE.
if (a_c == 0.f) {
// the ray goes through both caps, easy case because we don't actually need to trace the ray because they are circles.
if (rotatedDirection.x > 0) {
// through the right cap, scale by radius and call it a day.
auto newLength = minsOffset.length() + hitbox.m_radius;
auto offset = (minsOffset * (newLength) / minsOffset.length());
if (flags & Flags_RETURNEND)
trace.m_traceEnd = center + offset;
if (flags & Flags_RETURNOFFSET)
trace.m_traceOffset = offset;
}
else {
// through the left cap, scale by radius again.
auto newLength = maxsOffset.length() + hitbox.m_radius;
auto offset = (maxsOffset * (newLength) / maxsOffset.length());
if (flags & Flags_RETURNEND)
trace.m_traceEnd = center + offset;
if (flags & Flags_RETURNOFFSET)
trace.m_traceOffset = offset;
}
trace.m_hit = true;
return;
}
constexpr auto a_s = 1.f;
auto minsAdjusted = -hitboxLength / 2.f;
auto maxsAdjusted = hitboxLength / 2.f;
auto minsStart = vec3_t(rotatedStart.x - minsAdjusted, rotatedStart.y, rotatedStart.z);
auto maxsStart = vec3_t(rotatedStart.x - maxsAdjusted, rotatedStart.y, rotatedStart.z);
auto b_c = 2.f * (rotatedStart.y * rotatedDirection.y + rotatedStart.z * rotatedDirection.z);
auto b_smins = 2.f * (minsStart.dot(rotatedDirection));
auto b_smaxs = 2.f * (maxsStart.dot(rotatedDirection));
auto c_c = rotatedStart.y * rotatedStart.y + rotatedStart.z * rotatedStart.z - hitbox.m_radius * hitbox.m_radius;
auto c_smins = minsStart.dot(minsStart) - hitbox.m_radius * hitbox.m_radius;
auto c_smaxs = maxsStart.dot(maxsStart) - hitbox.m_radius * hitbox.m_radius;
auto cylOperand = b_c * b_c - 4 * a_c * c_c;
auto sphMinsOperand = b_smins * b_smins - 4 * a_s * c_smins;
auto sphMaxsOperand = b_smaxs * b_smaxs - 4 * a_s * c_smaxs;
auto tCyl = 0.f;
auto tSphMins = 0.f;
auto tSphMaxs = 0.f;
auto cylHit = false;
auto sphMinsHit = false;
auto sphMaxsHit = false;
// if we don't hit, operand is negative.
if (cylOperand > 0.f) {
tCyl = (-b_c - sqrtf(cylOperand)) / (2.f * a_c);
if (tCyl - FLT_EPSILON > 0.f) {
// make sure we hit within our bounds, and not outside of the cylinder's bore.
auto virtualPos = rotatedDirection * tCyl;
auto outOfMinsSide = virtualPos.x < minsAdjusted;
auto outOfMaxsSide = virtualPos.x > maxsAdjusted;
if (!outOfMinsSide &&
!outOfMaxsSide)
cylHit = true;
}
}
if (sphMinsOperand > 0.f) {
tSphMins = (-b_smins - sqrtf(sphMinsOperand)) / (2.f * a_s);
if (tSphMins - FLT_EPSILON > 0.f)
sphMinsHit = true;
}
if (sphMaxsOperand > 0.f) {
tSphMaxs = (-b_smaxs - sqrtf(sphMaxsOperand)) / (2.f * a_s);
if (tSphMaxs - FLT_EPSILON > 0.f)
sphMaxsHit = true;
}
// see which one hit first, then return accordingly.
if (cylHit) {
trace.m_fraction = tCyl / ray.m_length;
trace.m_hit = true;
}
else if (sphMinsHit) {
trace.m_fraction = tSphMins / ray.m_length;
trace.m_hit = true;
}
else if (sphMaxsHit) {
trace.m_fraction = tSphMaxs / ray.m_length;
trace.m_hit = true;
}
}
matrix.h:
#pragma once
#include <cstring>
class matrix3x4_t {
public:
float m_flMatVal[3][4];
// default constructor.
__forceinline matrix3x4_t() {
memset(m_flMatVal, 0, sizeof(m_flMatVal));
}
// parameterized constructor.
__forceinline matrix3x4_t(float m00, float m01, float m02, float m03,
float m10, float m11, float m12, float m13,
float m20, float m21, float m22, float m23) {
m_flMatVal[0][0] = m00; m_flMatVal[0][1] = m01; m_flMatVal[0][2] = m02; m_flMatVal[0][3] = m03;
m_flMatVal[1][0] = m10; m_flMatVal[1][1] = m11; m_flMatVal[1][2] = m12; m_flMatVal[1][3] = m13;
m_flMatVal[2][0] = m20; m_flMatVal[2][1] = m21; m_flMatVal[2][2] = m22; m_flMatVal[2][3] = m23;
}
// copy constructor.
matrix3x4_t(const matrix3x4_t& other) {
memcpy(m_flMatVal, other.m_flMatVal, sizeof(m_flMatVal));
}
// copy assignment operator.
matrix3x4_t& operator=(const matrix3x4_t& other) {
if (this != &other) {
memcpy(m_flMatVal, other.m_flMatVal, sizeof(m_flMatVal));
}
return *this;
}
// set origin of the matrix.
__forceinline void SetOrigin(const vec3_t& p) {
m_flMatVal[0][3] = p.x;
m_flMatVal[1][3] = p.y;
m_flMatVal[2][3] = p.z;
}
// get origin of the matrix.
__forceinline vec3_t GetOrigin() const {
return {m_flMatVal[0][3], m_flMatVal[1][3], m_flMatVal[2][3]};
}
// matrix from angles.
void AngleMatrix(const ang_t& angles) {
float sr, sp, sy, cr, cp, cy;
DirectX::XMScalarSinCos(&sy, &cy, math::deg_to_rad(angles.y));
DirectX::XMScalarSinCos(&sp, &cp, math::deg_to_rad(angles.x));
DirectX::XMScalarSinCos(&sr, &cr, math::deg_to_rad(angles.z));
// matrix = (yaw * pitch) * roll.
m_flMatVal[0][0] = cp * cy;
m_flMatVal[1][0] = cp * sy;
m_flMatVal[2][0] = -sp;
float crcy = cr * cy;
float crsy = cr * sy;
float srcy = sr * cy;
float srsy = sr * sy;
m_flMatVal[0][1] = sp * srcy - crsy;
m_flMatVal[1][1] = sp * srsy + crcy;
m_flMatVal[2][1] = sr * cp;
m_flMatVal[0][2] = (sp * crcy + srsy);
m_flMatVal[1][2] = (sp * crsy - srcy);
m_flMatVal[2][2] = cr * cp;
m_flMatVal[0][3] = 0.0f;
m_flMatVal[1][3] = 0.0f;
m_flMatVal[2][3] = 0.0f;
}
// addition operator.
matrix3x4_t operator+(const matrix3x4_t& other) const {
matrix3x4_t result;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
result.m_flMatVal[i][j] = this->m_flMatVal[i][j] + other.m_flMatVal[i][j];
}
}
return result;
}
// multiplication by another matrix (for 3x4 matrices, we only multiply the 3x3 part).
matrix3x4_t operator*(const matrix3x4_t& other) const {
matrix3x4_t result;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
result.m_flMatVal[i][j] = 0;
for (int k = 0; k < 3; k++) {
result.m_flMatVal[i][j] += this->m_flMatVal[i][k] * other.m_flMatVal[k][j];
}
}
}
return result;
}
// multiplication by scalar.
matrix3x4_t operator*(float scalar) const {
matrix3x4_t result;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
result.m_flMatVal[i][j] = this->m_flMatVal[i][j] * scalar;
}
}
return result;
}
// multiply the matrix by a vector.
vec3_t operator*(const vec3_t& vec) const {
return vec3_t(
vec.x * m_flMatVal[0][0] + vec.y * m_flMatVal[0][1] + vec.z * m_flMatVal[0][2] + m_flMatVal[0][3],
vec.x * m_flMatVal[1][0] + vec.y * m_flMatVal[1][1] + vec.z * m_flMatVal[1][2] + m_flMatVal[1][3],
vec.x * m_flMatVal[2][0] + vec.y * m_flMatVal[2][1] + vec.z * m_flMatVal[2][2] + m_flMatVal[2][3]
);
}
// array access operator.
__forceinline float* operator[](int i) {
return m_flMatVal[i];
}
// array access operator (const version).
__forceinline const float* operator[](int i) const {
return m_flMatVal[i];
}
// base pointer access.
__forceinline float* Base() {
return &m_flMatVal[0][0];
}
// base pointer access (const version).
__forceinline const float* Base() const {
return &m_flMatVal[0][0];
}
// get bone position.
bool get_bone(vec3_t& out, int bone = 0) {
if (bone < 0 || bone >= 128)
return false;
matrix3x4_t* bone_matrix = &this[bone];
if (!bone_matrix)
return false;
out = {bone_matrix->m_flMatVal[0][3], bone_matrix->m_flMatVal[1][3], bone_matrix->m_flMatVal[2][3]};
return true;
}
};
// aligned version of matrix3x4_t for specific cases.
class __declspec(align(16)) matrix3x4a_t: public matrix3x4_t {
public:
__forceinline matrix3x4a_t& operator=(const matrix3x4_t& src) {
std::memcpy(Base(), src.Base(), sizeof(float) * 3 * 4);
return *this;
}
};
// VMatrix class.
class VMatrix {
public:
float m[4][4];
// array access operator.
__forceinline float* operator[](int i) {
return m[i];
}
// array access operator (const version).
__forceinline const float* operator[](int i) const {
return m[i];
}
// base pointer access.
__forceinline float* Base() {
return &m[0][0];
}
// base pointer access (const version).
__forceinline const float* Base() const {
return &m[0][0];
}
};