// Copyright 2008 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "VideoCommon/VertexLoader_Normal.h" #include #include #include "Common/CommonTypes.h" #include "Common/EnumMap.h" #include "VideoCommon/VertexLoader.h" #include "VideoCommon/VertexLoaderManager.h" #include "VideoCommon/VertexLoaderUtils.h" // warning: mapping buffer should be disabled to use this #define LOG_NORM() // PRIM_LOG("norm: {} {} {}, ", ((float*)g_vertex_manager_write_ptr)[-3], // ((float*)g_vertex_manager_write_ptr)[-2], // ((float*)g_vertex_manager_write_ptr)[-1]); namespace { template constexpr float FracAdjust(T val) { // auto const S8FRAC = 1.f / (1u << 6); // auto const U8FRAC = 1.f / (1u << 7); // auto const S16FRAC = 1.f / (1u << 14); // auto const U16FRAC = 1.f / (1u << 15); // TODO: is this right? return val / float(1u << (sizeof(T) * 8 - std::is_signed_v - 1)); } template <> constexpr float FracAdjust(float val) { return val; } template void ReadIndirect(VertexLoader* loader, const T* data) { static_assert(3 == N || 9 == N, "N is only sane as 3 or 9!"); static_assert(!(Offset != 0 && 9 == N), "N == 9 only makes sense if offset == 0"); for (u32 i = Offset; i < N + Offset; ++i) { const float value = FracAdjust(Common::FromBigEndian(data[i])); if (loader->m_remaining == 0) { if (i >= 3 && i < 6) VertexLoaderManager::tangent_cache[i - 3] = value; else if (i >= 6 && i < 9) VertexLoaderManager::binormal_cache[i - 6] = value; } DataWrite(value); } LOG_NORM(); } template void Normal_ReadDirect(VertexLoader* loader) { const auto source = reinterpret_cast(DataGetPosition()); ReadIndirect(loader, source); DataSkip(); } template void Normal_ReadIndex_Offset(VertexLoader* loader) { static_assert(std::is_unsigned_v, "Only unsigned I is sane!"); const auto index = DataRead(); const auto data = reinterpret_cast(VertexLoaderManager::cached_arraybases[CPArray::Normal] + (index * g_main_cp_state.array_strides[CPArray::Normal])); ReadIndirect(loader, data); } template void Normal_ReadIndex(VertexLoader* loader) { Normal_ReadIndex_Offset(loader); } template void Normal_ReadIndex_Indices3(VertexLoader* loader) { Normal_ReadIndex_Offset(loader); Normal_ReadIndex_Offset(loader); Normal_ReadIndex_Offset(loader); } using Common::EnumMap; using Formats = EnumMap; using Elements = EnumMap; using Indices = std::array; using Types = EnumMap; consteval Types InitializeTable() { Types table{}; using VCF = VertexComponentFormat; using NCC = NormalComponentCount; using FMT = ComponentFormat; table[VCF::Direct][false][NCC::N][FMT::UByte] = Normal_ReadDirect; table[VCF::Direct][false][NCC::N][FMT::Byte] = Normal_ReadDirect; table[VCF::Direct][false][NCC::N][FMT::UShort] = Normal_ReadDirect; table[VCF::Direct][false][NCC::N][FMT::Short] = Normal_ReadDirect; table[VCF::Direct][false][NCC::N][FMT::Float] = Normal_ReadDirect; table[VCF::Direct][false][NCC::N][FMT::InvalidFloat5] = Normal_ReadDirect; table[VCF::Direct][false][NCC::N][FMT::InvalidFloat6] = Normal_ReadDirect; table[VCF::Direct][false][NCC::N][FMT::InvalidFloat7] = Normal_ReadDirect; table[VCF::Direct][false][NCC::NTB][FMT::UByte] = Normal_ReadDirect; table[VCF::Direct][false][NCC::NTB][FMT::Byte] = Normal_ReadDirect; table[VCF::Direct][false][NCC::NTB][FMT::UShort] = Normal_ReadDirect; table[VCF::Direct][false][NCC::NTB][FMT::Short] = Normal_ReadDirect; table[VCF::Direct][false][NCC::NTB][FMT::Float] = Normal_ReadDirect; table[VCF::Direct][false][NCC::NTB][FMT::InvalidFloat5] = Normal_ReadDirect; table[VCF::Direct][false][NCC::NTB][FMT::InvalidFloat6] = Normal_ReadDirect; table[VCF::Direct][false][NCC::NTB][FMT::InvalidFloat7] = Normal_ReadDirect; // Same as above, since there are no indices table[VCF::Direct][true][NCC::N][FMT::UByte] = Normal_ReadDirect; table[VCF::Direct][true][NCC::N][FMT::Byte] = Normal_ReadDirect; table[VCF::Direct][true][NCC::N][FMT::UShort] = Normal_ReadDirect; table[VCF::Direct][true][NCC::N][FMT::Short] = Normal_ReadDirect; table[VCF::Direct][true][NCC::N][FMT::Float] = Normal_ReadDirect; table[VCF::Direct][true][NCC::N][FMT::InvalidFloat5] = Normal_ReadDirect; table[VCF::Direct][true][NCC::N][FMT::InvalidFloat6] = Normal_ReadDirect; table[VCF::Direct][true][NCC::N][FMT::InvalidFloat7] = Normal_ReadDirect; table[VCF::Direct][true][NCC::NTB][FMT::UByte] = Normal_ReadDirect; table[VCF::Direct][true][NCC::NTB][FMT::Byte] = Normal_ReadDirect; table[VCF::Direct][true][NCC::NTB][FMT::UShort] = Normal_ReadDirect; table[VCF::Direct][true][NCC::NTB][FMT::Short] = Normal_ReadDirect; table[VCF::Direct][true][NCC::NTB][FMT::Float] = Normal_ReadDirect; table[VCF::Direct][true][NCC::NTB][FMT::InvalidFloat5] = Normal_ReadDirect; table[VCF::Direct][true][NCC::NTB][FMT::InvalidFloat6] = Normal_ReadDirect; table[VCF::Direct][true][NCC::NTB][FMT::InvalidFloat7] = Normal_ReadDirect; table[VCF::Index8][false][NCC::N][FMT::UByte] = Normal_ReadIndex; table[VCF::Index8][false][NCC::N][FMT::Byte] = Normal_ReadIndex; table[VCF::Index8][false][NCC::N][FMT::UShort] = Normal_ReadIndex; table[VCF::Index8][false][NCC::N][FMT::Short] = Normal_ReadIndex; table[VCF::Index8][false][NCC::N][FMT::Float] = Normal_ReadIndex; table[VCF::Index8][false][NCC::N][FMT::InvalidFloat5] = Normal_ReadIndex; table[VCF::Index8][false][NCC::N][FMT::InvalidFloat6] = Normal_ReadIndex; table[VCF::Index8][false][NCC::N][FMT::InvalidFloat7] = Normal_ReadIndex; table[VCF::Index8][false][NCC::NTB][FMT::UByte] = Normal_ReadIndex; table[VCF::Index8][false][NCC::NTB][FMT::Byte] = Normal_ReadIndex; table[VCF::Index8][false][NCC::NTB][FMT::UShort] = Normal_ReadIndex; table[VCF::Index8][false][NCC::NTB][FMT::Short] = Normal_ReadIndex; table[VCF::Index8][false][NCC::NTB][FMT::Float] = Normal_ReadIndex; table[VCF::Index8][false][NCC::NTB][FMT::InvalidFloat5] = Normal_ReadIndex; table[VCF::Index8][false][NCC::NTB][FMT::InvalidFloat6] = Normal_ReadIndex; table[VCF::Index8][false][NCC::NTB][FMT::InvalidFloat7] = Normal_ReadIndex; // Same for NormalComponentCount::N; differs for NTB table[VCF::Index8][true][NCC::N][FMT::UByte] = Normal_ReadIndex; table[VCF::Index8][true][NCC::N][FMT::Byte] = Normal_ReadIndex; table[VCF::Index8][true][NCC::N][FMT::UShort] = Normal_ReadIndex; table[VCF::Index8][true][NCC::N][FMT::Short] = Normal_ReadIndex; table[VCF::Index8][true][NCC::N][FMT::Float] = Normal_ReadIndex; table[VCF::Index8][true][NCC::N][FMT::InvalidFloat5] = Normal_ReadIndex; table[VCF::Index8][true][NCC::N][FMT::InvalidFloat6] = Normal_ReadIndex; table[VCF::Index8][true][NCC::N][FMT::InvalidFloat7] = Normal_ReadIndex; table[VCF::Index8][true][NCC::NTB][FMT::UByte] = Normal_ReadIndex_Indices3; table[VCF::Index8][true][NCC::NTB][FMT::Byte] = Normal_ReadIndex_Indices3; table[VCF::Index8][true][NCC::NTB][FMT::UShort] = Normal_ReadIndex_Indices3; table[VCF::Index8][true][NCC::NTB][FMT::Short] = Normal_ReadIndex_Indices3; table[VCF::Index8][true][NCC::NTB][FMT::Float] = Normal_ReadIndex_Indices3; table[VCF::Index8][true][NCC::NTB][FMT::InvalidFloat5] = Normal_ReadIndex_Indices3; table[VCF::Index8][true][NCC::NTB][FMT::InvalidFloat6] = Normal_ReadIndex_Indices3; table[VCF::Index8][true][NCC::NTB][FMT::InvalidFloat7] = Normal_ReadIndex_Indices3; table[VCF::Index16][false][NCC::N][FMT::UByte] = Normal_ReadIndex; table[VCF::Index16][false][NCC::N][FMT::Byte] = Normal_ReadIndex; table[VCF::Index16][false][NCC::N][FMT::UShort] = Normal_ReadIndex; table[VCF::Index16][false][NCC::N][FMT::Short] = Normal_ReadIndex; table[VCF::Index16][false][NCC::N][FMT::Float] = Normal_ReadIndex; table[VCF::Index16][false][NCC::N][FMT::InvalidFloat5] = Normal_ReadIndex; table[VCF::Index16][false][NCC::N][FMT::InvalidFloat6] = Normal_ReadIndex; table[VCF::Index16][false][NCC::N][FMT::InvalidFloat7] = Normal_ReadIndex; table[VCF::Index16][false][NCC::NTB][FMT::UByte] = Normal_ReadIndex; table[VCF::Index16][false][NCC::NTB][FMT::Byte] = Normal_ReadIndex; table[VCF::Index16][false][NCC::NTB][FMT::UShort] = Normal_ReadIndex; table[VCF::Index16][false][NCC::NTB][FMT::Short] = Normal_ReadIndex; table[VCF::Index16][false][NCC::NTB][FMT::Float] = Normal_ReadIndex; table[VCF::Index16][false][NCC::NTB][FMT::InvalidFloat5] = Normal_ReadIndex; table[VCF::Index16][false][NCC::NTB][FMT::InvalidFloat6] = Normal_ReadIndex; table[VCF::Index16][false][NCC::NTB][FMT::InvalidFloat7] = Normal_ReadIndex; // Same for NormalComponentCount::N; differs for NTB table[VCF::Index16][true][NCC::N][FMT::UByte] = Normal_ReadIndex; table[VCF::Index16][true][NCC::N][FMT::Byte] = Normal_ReadIndex; table[VCF::Index16][true][NCC::N][FMT::UShort] = Normal_ReadIndex; table[VCF::Index16][true][NCC::N][FMT::Short] = Normal_ReadIndex; table[VCF::Index16][true][NCC::N][FMT::Float] = Normal_ReadIndex; table[VCF::Index16][true][NCC::N][FMT::InvalidFloat5] = Normal_ReadIndex; table[VCF::Index16][true][NCC::N][FMT::InvalidFloat6] = Normal_ReadIndex; table[VCF::Index16][true][NCC::N][FMT::InvalidFloat7] = Normal_ReadIndex; table[VCF::Index16][true][NCC::NTB][FMT::UByte] = Normal_ReadIndex_Indices3; table[VCF::Index16][true][NCC::NTB][FMT::Byte] = Normal_ReadIndex_Indices3; table[VCF::Index16][true][NCC::NTB][FMT::UShort] = Normal_ReadIndex_Indices3; table[VCF::Index16][true][NCC::NTB][FMT::Short] = Normal_ReadIndex_Indices3; table[VCF::Index16][true][NCC::NTB][FMT::Float] = Normal_ReadIndex_Indices3; table[VCF::Index16][true][NCC::NTB][FMT::InvalidFloat5] = Normal_ReadIndex_Indices3; table[VCF::Index16][true][NCC::NTB][FMT::InvalidFloat6] = Normal_ReadIndex_Indices3; table[VCF::Index16][true][NCC::NTB][FMT::InvalidFloat7] = Normal_ReadIndex_Indices3; return table; } constexpr Types s_table_read_normal = InitializeTable(); } // Anonymous namespace TPipelineFunction VertexLoader_Normal::GetFunction(VertexComponentFormat type, ComponentFormat format, NormalComponentCount elements, bool index3) { return s_table_read_normal[type][index3][elements][format]; }