mirror of
https://github.com/mitch030504/Wiicompiled_VR_Frame.git
synced 2026-10-06 06:00:25 +02:00
The VR first-person camera will animate the local vehicle's steering wheel by handing Aurora a rotated copy of one of the vehicle's position arrays. A draw picks up the copy only when it binds that exact array with the local vehicle's position matrix (per-position ownership for indexed-matrix draws), so opponents sharing the asset keep the original vertices. The copy takes the same padded upload path as the original and never touches the shared array cache. Ported from heurazy's mario-kart-wii-VR-port (GPL-3.0-or-later).
137 lines
4.8 KiB
C++
137 lines
4.8 KiB
C++
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
// Native steering wheel: indexed-matrix ownership and array matching. The
|
|
// ownership cases come from heurazy's mario-kart-wii-VR-port test set.
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <array>
|
|
|
|
#include "gx/native_wheel.hpp"
|
|
|
|
namespace {
|
|
|
|
// Three positions, 12 bytes each. Position 1 is on the wheel; 0 and 2 belong to
|
|
// the body/wing.
|
|
struct OwnershipFixture {
|
|
std::array<uint8_t, 36> original{};
|
|
std::array<uint8_t, 36> replacement{};
|
|
// PN matrix byte, texture matrix byte, big-endian position index.
|
|
std::array<uint8_t, 12> vertices{0, 30, 0, 0, 0, 30, 0, 1, 3, 30, 0, 2};
|
|
OwnershipFixture() { replacement[12] = 7; }
|
|
bool matches(uint16_t mask) const {
|
|
return aurora::NativeWheelDrawMatches(original, replacement, 12, vertices, 4, 2, 2, mask);
|
|
}
|
|
};
|
|
|
|
TEST(NativeWheelMatch, MixedBodyAndWingDrawAcceptsWheelPositionsOnLocalBody) {
|
|
OwnershipFixture f;
|
|
EXPECT_TRUE(f.matches(1));
|
|
}
|
|
|
|
TEST(NativeWheelMatch, UnrelatedWingJointCannotAnimateWheel) {
|
|
OwnershipFixture f;
|
|
EXPECT_FALSE(f.matches(2));
|
|
}
|
|
|
|
TEST(NativeWheelMatch, OpponentWithoutLocalMatrixIsRejected) {
|
|
OwnershipFixture f;
|
|
EXPECT_FALSE(f.matches(0));
|
|
}
|
|
|
|
TEST(NativeWheelMatch, WheelPositionUnderAnotherMatrixIsRejected) {
|
|
OwnershipFixture f;
|
|
f.vertices[4] = 6;
|
|
EXPECT_FALSE(f.matches(1));
|
|
EXPECT_TRUE(f.matches(4)) << "local body can occupy a different palette slot";
|
|
}
|
|
|
|
TEST(NativeWheelMatch, MalformedMatrixSelectorRejected) {
|
|
OwnershipFixture f;
|
|
f.vertices[4] = 1;
|
|
EXPECT_FALSE(f.matches(1));
|
|
}
|
|
|
|
TEST(NativeWheelMatch, OutOfRangePositionIndexRejected) {
|
|
OwnershipFixture f;
|
|
f.vertices[11] = 3;
|
|
EXPECT_FALSE(f.matches(1));
|
|
}
|
|
|
|
TEST(NativeWheelMatch, SelectionTouchingAnotherJointCannotDeformIt) {
|
|
OwnershipFixture f;
|
|
f.replacement[24] = 1;
|
|
EXPECT_FALSE(f.matches(1));
|
|
}
|
|
|
|
TEST(NativeWheelMatch, EightBitIndicesAndLayoutValidation) {
|
|
OwnershipFixture f;
|
|
std::array<uint8_t, 4> indexed8{0, 1, 3, 2};
|
|
EXPECT_TRUE(aurora::NativeWheelDrawMatches(f.original, f.replacement, 12, indexed8, 2, 1, 1, 1));
|
|
EXPECT_FALSE(aurora::NativeWheelDrawMatches(f.original, f.replacement, 12, indexed8, 2, 2, 1, 1))
|
|
<< "invalid vertex layout rejected";
|
|
EXPECT_FALSE(aurora::NativeWheelDrawMatches(f.original, f.original, 12, indexed8, 2, 1, 1, 1))
|
|
<< "unchanged positions are not counted as animation";
|
|
}
|
|
|
|
// Draw-time matching against the GX position-matrix palette.
|
|
class NativeWheelArrayTest : public ::testing::Test {
|
|
protected:
|
|
void SetUp() override {
|
|
aurora::gx::g_gxState = {};
|
|
aurora::gx::nativeWheelArrays.clear();
|
|
aurora::gx::nativeWheelMatches = 0;
|
|
aurora::gx::NativeWheelArray replacement;
|
|
replacement.source = source.data();
|
|
replacement.bytes.assign(36, 0);
|
|
replacement.bytes[12] = 1;
|
|
aurora::gx::nativeWheelArrays.push_back(replacement);
|
|
array.data = source.data();
|
|
array.size = 36;
|
|
array.stride = 12;
|
|
}
|
|
void TearDown() override {
|
|
aurora::gx::g_gxState = {};
|
|
aurora::gx::nativeWheelArrays.clear();
|
|
}
|
|
static float* pos(uint32_t slot) { return reinterpret_cast<float*>(&aurora::gx::g_gxState.pnMtx[slot].pos); }
|
|
std::array<uint8_t, 36> source{};
|
|
aurora::gx::AttrArray array{};
|
|
};
|
|
|
|
TEST_F(NativeWheelArrayTest, MatchesLocalVehicleMatrixOnly) {
|
|
EXPECT_NE(aurora::gx::native_wheel_array(array, nullptr, 0, 0, 0), nullptr);
|
|
EXPECT_EQ(aurora::gx::nativeWheelMatches, 1u);
|
|
// Same asset drawn by an opponent: a translated matrix.
|
|
pos(0)[3] = 100;
|
|
EXPECT_EQ(aurora::gx::native_wheel_array(array, nullptr, 0, 0, 0), nullptr);
|
|
EXPECT_EQ(aurora::gx::nativeWheelMatches, 1u);
|
|
}
|
|
|
|
TEST_F(NativeWheelArrayTest, UnboundSourceIsNotAWheelArray) {
|
|
std::array<uint8_t, 36> other{};
|
|
aurora::gx::AttrArray unrelated = array;
|
|
unrelated.data = other.data();
|
|
EXPECT_EQ(aurora::gx::native_wheel_array(unrelated, nullptr, 0, 0, 0), nullptr);
|
|
EXPECT_TRUE(aurora::gx::native_wheel_source(source.data()));
|
|
EXPECT_FALSE(aurora::gx::native_wheel_source(other.data()));
|
|
}
|
|
|
|
TEST_F(NativeWheelArrayTest, MultiJointBodyChecksPerPositionOwnership) {
|
|
// Multi-joint body with an independently animated wing, as in Mario's
|
|
// mb/mc kart models. Only the wheel position uses the matching body slot.
|
|
aurora::gx::g_gxState.vtxDesc[GX_VA_PNMTXIDX] = GX_DIRECT;
|
|
aurora::gx::g_gxState.vtxDesc[GX_VA_POS] = GX_INDEX16;
|
|
for (uint32_t slot = 0; slot < aurora::gx::MaxPnMtx; ++slot) pos(slot)[3] = 100;
|
|
pos(2)[3] = 0;
|
|
uint8_t vertices[]{6, 0, 1, 3, 0, 2};
|
|
EXPECT_NE(aurora::gx::native_wheel_array(array, vertices, sizeof(vertices), 3, 1), nullptr);
|
|
vertices[0] = 0; // opponent wheel while an unrelated palette slot still matches
|
|
EXPECT_EQ(aurora::gx::native_wheel_array(array, vertices, sizeof(vertices), 3, 1), nullptr);
|
|
}
|
|
|
|
TEST_F(NativeWheelArrayTest, NonFiniteMatrixNeverMatches) {
|
|
pos(0)[0] = __builtin_nanf("");
|
|
EXPECT_EQ(aurora::gx::native_wheel_array(array, nullptr, 0, 0, 0), nullptr);
|
|
}
|
|
|
|
} // namespace
|