mirror of https://github.com/AxioDL/metaforce.git
CModelShaders vertex & uniform buffers (WIP)
This commit is contained in:
parent
7bffc621b8
commit
07c90c894a
|
@ -739,8 +739,8 @@ void CBooRenderer::AddStaticGeometry(const std::vector<CMetroidModelInstance>* g
|
||||||
if (search == x1c_areaListItems.end()) {
|
if (search == x1c_areaListItems.end()) {
|
||||||
std::unordered_map<CAssetId, TCachedToken<CTexture>> textures;
|
std::unordered_map<CAssetId, TCachedToken<CTexture>> textures;
|
||||||
std::vector<CBooModel*> models;
|
std::vector<CBooModel*> models;
|
||||||
if (geometry->size()) {
|
if (!geometry->empty()) {
|
||||||
(*geometry)[0].m_instance->MakeTexturesFromMats(textures, xc_store);
|
geometry->at(0).m_instance->MakeTexturesFromMats(textures, xc_store);
|
||||||
models.reserve(geometry->size());
|
models.reserve(geometry->size());
|
||||||
int instIdx = 0;
|
int instIdx = 0;
|
||||||
for (const CMetroidModelInstance& inst : *geometry) {
|
for (const CMetroidModelInstance& inst : *geometry) {
|
||||||
|
@ -764,29 +764,11 @@ void CBooRenderer::UpdateAreaUniforms(int areaIdx, EWorldShadowMode shadowMode,
|
||||||
SetupRendererStates();
|
SetupRendererStates();
|
||||||
|
|
||||||
CModelFlags flags;
|
CModelFlags flags;
|
||||||
int bufIdx;
|
int bufIdx = 0;
|
||||||
if (shadowMode == EWorldShadowMode::WorldOnActorShadow) {
|
|
||||||
flags.m_extendedShader = EExtendedShader::SolidColor;
|
|
||||||
flags.x4_color = zeus::skBlack;
|
|
||||||
bufIdx = 1;
|
|
||||||
} else if (shadowMode == EWorldShadowMode::BallOnWorldShadow) {
|
|
||||||
flags = *ballShadowFlags;
|
|
||||||
bufIdx = 2;
|
|
||||||
} else if (shadowMode == EWorldShadowMode::BallOnWorldIds) {
|
|
||||||
flags.m_extendedShader = EExtendedShader::SolidColor;
|
|
||||||
bufIdx = 3;
|
|
||||||
} else {
|
|
||||||
flags.m_extendedShader = EExtendedShader::Lighting;
|
|
||||||
bufIdx = cubeFace == -1 ? 0 : 4 + cubeFace;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (CAreaListItem& item : x1c_areaListItems) {
|
for (CAreaListItem& item : x1c_areaListItems) {
|
||||||
if (areaIdx != -1 && item.x18_areaIdx != areaIdx)
|
if (areaIdx != -1 && item.x18_areaIdx != areaIdx)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
item.m_shaderSet->m_geomLayout->Update(flags, nullptr, nullptr, &item.m_shaderSet->m_matSet,
|
|
||||||
item.m_shaderSet->m_geomLayout->GetSharedBuffer(bufIdx), nullptr);
|
|
||||||
|
|
||||||
if (shadowMode == EWorldShadowMode::BallOnWorldShadow || shadowMode == EWorldShadowMode::BallOnWorldIds)
|
if (shadowMode == EWorldShadowMode::BallOnWorldShadow || shadowMode == EWorldShadowMode::BallOnWorldIds)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -1107,13 +1089,10 @@ void CBooRenderer::CacheReflection(TReflectionCallback cb, void* ctx, bool clear
|
||||||
x2dc_reflectionAge = 0;
|
x2dc_reflectionAge = 0;
|
||||||
|
|
||||||
BindReflectionDrawTarget();
|
BindReflectionDrawTarget();
|
||||||
SViewport backupVp = g_Viewport;
|
|
||||||
SetViewport(0, 0, 256, 256);
|
|
||||||
hsh::clear_attachments(true, false);
|
hsh::clear_attachments(true, false);
|
||||||
cb(ctx, CBooModel::g_ReflectViewPos);
|
cb(ctx, CBooModel::g_ReflectViewPos);
|
||||||
x14c_reflectionTex.resolve_color_binding(0, {{}, {256, 256}}, false);
|
ResolveReflectionDrawTarget();
|
||||||
BindMainDrawTarget();
|
BindMainDrawTarget();
|
||||||
SetViewport(backupVp.x0_left, backupVp.x4_top, backupVp.x8_width, backupVp.xc_height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBooRenderer::DrawSpaceWarp(const zeus::CVector3f& pt, float strength) {
|
void CBooRenderer::DrawSpaceWarp(const zeus::CVector3f& pt, float strength) {
|
||||||
|
@ -1421,4 +1400,22 @@ void CBooRenderer::DrawOverlappingWorldModelShadows(int alphaVal, const std::vec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CBooRenderer::BindMainDrawTarget() {
|
||||||
|
CGraphics::g_SpareTexture.attach();
|
||||||
|
hsh::set_blend_constants(0.f, 0.f, 0.f, gx_DstAlphaValue);
|
||||||
|
CachedVP.x0_left = 0;
|
||||||
|
CachedVP.x4_top = 0;
|
||||||
|
#ifdef __SWITCH__
|
||||||
|
hsh::extent2d extent{1280, 720};
|
||||||
|
#else
|
||||||
|
hsh::extent2d extent = CGraphics::g_SpareTexture.Owner._VULKAN_SPIRV.Allocation->GetExtent();
|
||||||
|
#endif
|
||||||
|
CachedVP.x8_width = extent.w;
|
||||||
|
CachedVP.xc_height = extent.h;
|
||||||
|
CachedVP.x10_halfWidth = extent.w / 2.f;
|
||||||
|
CachedVP.x14_halfHeight = extent.h / 2.f;
|
||||||
|
CachedVP.aspect = extent.w / float(extent.h);
|
||||||
|
g_Viewport = CachedVP;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace urde
|
} // namespace urde
|
||||||
|
|
|
@ -51,6 +51,7 @@ class CBooRenderer final : public IRenderer {
|
||||||
friend class CModel;
|
friend class CModel;
|
||||||
friend class CMorphBallShadow;
|
friend class CMorphBallShadow;
|
||||||
friend class CWorldTransManager;
|
friend class CWorldTransManager;
|
||||||
|
friend class CModelShaders;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct ScanlinesVert {
|
struct ScanlinesVert {
|
||||||
|
|
|
@ -62,6 +62,7 @@ runtime_add_hsh(Graphics
|
||||||
Shaders/CFogVolumePlaneShader.cpp
|
Shaders/CFogVolumePlaneShader.cpp
|
||||||
Shaders/CLineRendererShaders.cpp
|
Shaders/CLineRendererShaders.cpp
|
||||||
Shaders/CMapSurfaceShader.cpp
|
Shaders/CMapSurfaceShader.cpp
|
||||||
|
Shaders/CModelShaders.cpp
|
||||||
Shaders/CParticleSwooshShaders.cpp
|
Shaders/CParticleSwooshShaders.cpp
|
||||||
Shaders/CPhazonSuitFilter.cpp
|
Shaders/CPhazonSuitFilter.cpp
|
||||||
Shaders/CRadarPaintShader.cpp
|
Shaders/CRadarPaintShader.cpp
|
||||||
|
|
|
@ -21,12 +21,15 @@ class CMetroidModelInstance {
|
||||||
friend class CBooRenderer;
|
friend class CBooRenderer;
|
||||||
friend class CGameArea;
|
friend class CGameArea;
|
||||||
|
|
||||||
|
public:
|
||||||
int x0_visorFlags;
|
int x0_visorFlags;
|
||||||
zeus::CTransform x4_xf;
|
zeus::CTransform x4_xf;
|
||||||
zeus::CAABox x34_aabb;
|
zeus::CAABox x34_aabb;
|
||||||
std::vector<CBooSurface> m_surfaces;
|
std::vector<CBooSurface> m_surfaces;
|
||||||
std::unique_ptr<CBooModel> m_instance;
|
std::unique_ptr<CBooModel> m_instance;
|
||||||
hecl::HMDLMeta m_hmdlMeta;
|
hecl::HMDLMeta m_hmdlMeta;
|
||||||
|
hsh::owner<hsh::vertex_buffer_typeless> m_staticVbo;
|
||||||
|
hsh::owner<hsh::index_buffer<u32>> m_staticIbo;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CMetroidModelInstance() = default;
|
CMetroidModelInstance() = default;
|
||||||
|
|
|
@ -74,25 +74,15 @@ struct CBooSurface {
|
||||||
using MaterialSet = DataSpec::DNAMP1::HMDLMaterialSet;
|
using MaterialSet = DataSpec::DNAMP1::HMDLMaterialSet;
|
||||||
|
|
||||||
struct GeometryUniformLayout {
|
struct GeometryUniformLayout {
|
||||||
mutable std::vector<hsh::dynamic_owner<hsh::uniform_buffer_typeless>> m_sharedBuffer;
|
|
||||||
size_t m_geomBufferSize = 0;
|
|
||||||
size_t m_skinBankCount = 0;
|
size_t m_skinBankCount = 0;
|
||||||
size_t m_weightVecCount = 0;
|
size_t m_weightVecCount = 0;
|
||||||
|
|
||||||
std::vector<size_t> m_skinOffs;
|
|
||||||
std::vector<size_t> m_skinSizes;
|
|
||||||
|
|
||||||
std::vector<size_t> m_uvOffs;
|
|
||||||
std::vector<size_t> m_uvSizes;
|
|
||||||
|
|
||||||
GeometryUniformLayout(const CModel* model, const MaterialSet* matSet);
|
GeometryUniformLayout(const CModel* model, const MaterialSet* matSet);
|
||||||
void Update(const CModelFlags& flags, const CSkinRules* cskr, const CPoseAsTransforms* pose,
|
void Update(const CModelFlags& flags, const CSkinRules* cskr, const CPoseAsTransforms* pose,
|
||||||
const MaterialSet* matSet, hsh::dynamic_owner<hsh::uniform_buffer_typeless>& buf,
|
const MaterialSet* matSet, std::vector<hsh::dynamic_owner<hsh::uniform_buffer_typeless>>& buf,
|
||||||
const CBooModel* parent) const;
|
const CBooModel* parent) const;
|
||||||
|
|
||||||
hsh::dynamic_owner<hsh::uniform_buffer_typeless> AllocateVertUniformBuffer() const;
|
hsh::dynamic_owner<hsh::uniform_buffer_typeless> AllocateVertUniformBuffer() const;
|
||||||
void ReserveSharedBuffers(size_t size);
|
|
||||||
hsh::dynamic_owner<hsh::uniform_buffer_typeless>& GetSharedBuffer(size_t idx) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SShader {
|
struct SShader {
|
||||||
|
@ -100,9 +90,7 @@ struct SShader {
|
||||||
MaterialSet m_matSet;
|
MaterialSet m_matSet;
|
||||||
std::optional<GeometryUniformLayout> m_geomLayout;
|
std::optional<GeometryUniformLayout> m_geomLayout;
|
||||||
int m_matSetIdx;
|
int m_matSetIdx;
|
||||||
explicit SShader(int idx) : m_matSetIdx(idx) {
|
explicit SShader(int idx) : m_matSetIdx(idx) { x0_textures.clear(); }
|
||||||
x0_textures.clear();
|
|
||||||
}
|
|
||||||
void InitializeLayout(const CModel* model) { m_geomLayout.emplace(model, &m_matSet); }
|
void InitializeLayout(const CModel* model) { m_geomLayout.emplace(model, &m_matSet); }
|
||||||
void UnlockTextures();
|
void UnlockTextures();
|
||||||
};
|
};
|
||||||
|
@ -124,6 +112,7 @@ class CBooModel {
|
||||||
friend class CSkinnedModel;
|
friend class CSkinnedModel;
|
||||||
friend struct GeometryUniformLayout;
|
friend struct GeometryUniformLayout;
|
||||||
friend class CModelShaders;
|
friend class CModelShaders;
|
||||||
|
friend struct ModelInstance;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum class ESurfaceSelection { UnsortedOnly, SortedOnly, All };
|
enum class ESurfaceSelection { UnsortedOnly, SortedOnly, All };
|
||||||
|
@ -149,23 +138,16 @@ private:
|
||||||
u32 x44_areaInstanceIdx = UINT32_MAX;
|
u32 x44_areaInstanceIdx = UINT32_MAX;
|
||||||
|
|
||||||
struct UVAnimationBuffer {
|
struct UVAnimationBuffer {
|
||||||
static void ProcessAnimation(u8*& bufOut, const MaterialSet::Material::PASS& anim);
|
static void ProcessAnimation(CModelShaders::TCGMatrix& tcg, const MaterialSet::Material::PASS& anim);
|
||||||
static void PadOutBuffer(u8*& bufStart, u8*& bufOut);
|
static void Update(std::vector<hsh::dynamic_owner<hsh::uniform_buffer<CModelShaders::TCGMatrixUniform>>>& uniforms,
|
||||||
static void Update(u8*& bufOut, const MaterialSet* matSet, const CModelFlags& flags, const CBooModel* parent);
|
const MaterialSet* matSet, const CModelFlags& flags, const CBooModel* parent);
|
||||||
};
|
};
|
||||||
|
|
||||||
CModelShaders::LightingUniform m_lightingData;
|
CModelShaders::FragmentUniform m_lightingData{};
|
||||||
|
bool m_lightsActive = false;
|
||||||
|
|
||||||
/* urde addition: boo! */
|
/* urde addition: boo! */
|
||||||
size_t m_uniformDataSize = 0;
|
size_t m_uniformDataSize = 0;
|
||||||
struct ModelInstance {
|
|
||||||
hsh::dynamic_owner<hsh::uniform_buffer_typeless> m_geomUniformBuffer;
|
|
||||||
hsh::dynamic_owner<hsh::uniform_buffer_typeless> m_uniformBuffer;
|
|
||||||
std::vector<std::vector<hsh::binding>> m_shaderDataBindings;
|
|
||||||
hsh::dynamic_owner<hsh::vertex_buffer_typeless> m_dynamicVbo;
|
|
||||||
|
|
||||||
hsh::vertex_buffer_typeless GetBooVBO(const CBooModel& model);
|
|
||||||
};
|
|
||||||
std::vector<ModelInstance> m_instances;
|
std::vector<ModelInstance> m_instances;
|
||||||
ModelInstance m_ballShadowInstance;
|
ModelInstance m_ballShadowInstance;
|
||||||
|
|
||||||
|
@ -181,8 +163,7 @@ private:
|
||||||
void DrawNormalSurfaces(const CModelFlags& flags) const;
|
void DrawNormalSurfaces(const CModelFlags& flags) const;
|
||||||
void DrawSurfaces(const CModelFlags& flags) const;
|
void DrawSurfaces(const CModelFlags& flags) const;
|
||||||
void DrawSurface(const CBooSurface& surf, const CModelFlags& flags) const;
|
void DrawSurface(const CBooSurface& surf, const CModelFlags& flags) const;
|
||||||
void WarmupDrawSurfaces() const;
|
void WarmupDrawSurface(const CBooSurface& surf, const CModelFlags& flags) const;
|
||||||
void WarmupDrawSurface(const CBooSurface& surf) const;
|
|
||||||
|
|
||||||
static inline zeus::CVector3f g_PlayerPosition;
|
static inline zeus::CVector3f g_PlayerPosition;
|
||||||
static inline float g_ModSeconds = 0.0f;
|
static inline float g_ModSeconds = 0.0f;
|
||||||
|
@ -196,13 +177,11 @@ private:
|
||||||
public:
|
public:
|
||||||
~CBooModel();
|
~CBooModel();
|
||||||
CBooModel(TToken<CModel>& token, CModel* parent, std::vector<CBooSurface>* surfaces, SShader& shader,
|
CBooModel(TToken<CModel>& token, CModel* parent, std::vector<CBooSurface>* surfaces, SShader& shader,
|
||||||
hsh::vertex_buffer_typeless vbo,
|
hsh::vertex_buffer_typeless vbo, hsh::index_buffer<u32> ibo, const zeus::CAABox& aabb, u8 renderMask,
|
||||||
hsh::index_buffer_typeless ibo,
|
int numInsts, VertexFormat vtxFmt);
|
||||||
const zeus::CAABox& aabb, u8 renderMask, int numInsts);
|
|
||||||
|
|
||||||
static void MakeTexturesFromMats(const MaterialSet& matSet,
|
static void MakeTexturesFromMats(const MaterialSet& matSet,
|
||||||
std::unordered_map<CAssetId, TCachedToken<CTexture>>& toksOut,
|
std::unordered_map<CAssetId, TCachedToken<CTexture>>& toksOut, IObjectStore& store);
|
||||||
IObjectStore& store);
|
|
||||||
void MakeTexturesFromMats(std::unordered_map<CAssetId, TCachedToken<CTexture>>& toksOut, IObjectStore& store);
|
void MakeTexturesFromMats(std::unordered_map<CAssetId, TCachedToken<CTexture>>& toksOut, IObjectStore& store);
|
||||||
|
|
||||||
bool IsOpaque() const { return x3c_firstSortedSurface == nullptr; }
|
bool IsOpaque() const { return x3c_firstSortedSurface == nullptr; }
|
||||||
|
@ -216,7 +195,8 @@ public:
|
||||||
void Touch(int shaderIdx);
|
void Touch(int shaderIdx);
|
||||||
void VerifyCurrentShader(int shaderIdx);
|
void VerifyCurrentShader(int shaderIdx);
|
||||||
hsh::dynamic_owner<hsh::vertex_buffer_typeless>* UpdateUniformData(const CModelFlags& flags, const CSkinRules* cskr,
|
hsh::dynamic_owner<hsh::vertex_buffer_typeless>* UpdateUniformData(const CModelFlags& flags, const CSkinRules* cskr,
|
||||||
const CPoseAsTransforms* pose, int sharedLayoutBuf = -1);
|
const CPoseAsTransforms* pose,
|
||||||
|
int sharedLayoutBuf = -1);
|
||||||
void DrawAlpha(const CModelFlags& flags, const CSkinRules* cskr, const CPoseAsTransforms* pose);
|
void DrawAlpha(const CModelFlags& flags, const CSkinRules* cskr, const CPoseAsTransforms* pose);
|
||||||
void DrawNormal(const CModelFlags& flags, const CSkinRules* cskr, const CPoseAsTransforms* pose);
|
void DrawNormal(const CModelFlags& flags, const CSkinRules* cskr, const CPoseAsTransforms* pose);
|
||||||
void Draw(const CModelFlags& flags, const CSkinRules* cskr, const CPoseAsTransforms* pose);
|
void Draw(const CModelFlags& flags, const CSkinRules* cskr, const CPoseAsTransforms* pose);
|
||||||
|
@ -237,8 +217,8 @@ public:
|
||||||
|
|
||||||
static inline zeus::CVector3f g_ReflectViewPos;
|
static inline zeus::CVector3f g_ReflectViewPos;
|
||||||
static void KillCachedViewDepState();
|
static void KillCachedViewDepState();
|
||||||
static void EnsureViewDepStateCached(const CBooModel& model, const CBooSurface* surf, zeus::CMatrix4f* mtxsOut,
|
static void EnsureViewDepStateCached(const CBooModel& model, const CBooSurface* surf,
|
||||||
float& alphaOut);
|
hsh::dynamic_owner<hsh::uniform_buffer<CModelShaders::ReflectMtx>>& buf);
|
||||||
|
|
||||||
static hsh::texture2d g_shadowMap;
|
static hsh::texture2d g_shadowMap;
|
||||||
static zeus::CTransform g_shadowTexXf;
|
static zeus::CTransform g_shadowTexXf;
|
||||||
|
@ -257,6 +237,7 @@ public:
|
||||||
static void Shutdown();
|
static void Shutdown();
|
||||||
|
|
||||||
const zeus::CAABox& GetAABB() const { return x20_aabb; }
|
const zeus::CAABox& GetAABB() const { return x20_aabb; }
|
||||||
|
void WarmupDrawSurfaces(const CModelFlags& unsortedFlags, const CModelFlags& sortedFlags) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CModel {
|
class CModel {
|
||||||
|
@ -297,9 +278,7 @@ public:
|
||||||
void UpdateLastFrame() const { const_cast<CModel&>(*this).x38_lastFrame = CGraphics::GetFrameCounter(); }
|
void UpdateLastFrame() const { const_cast<CModel&>(*this).x38_lastFrame = CGraphics::GetFrameCounter(); }
|
||||||
u32 GetNumMaterialSets() const { return x18_matSets.size(); }
|
u32 GetNumMaterialSets() const { return x18_matSets.size(); }
|
||||||
|
|
||||||
size_t GetPoolVertexOffset(size_t idx) const;
|
|
||||||
zeus::CVector3f GetPoolVertex(size_t idx) const;
|
zeus::CVector3f GetPoolVertex(size_t idx) const;
|
||||||
size_t GetPoolNormalOffset(size_t idx) const;
|
|
||||||
zeus::CVector3f GetPoolNormal(size_t idx) const;
|
zeus::CVector3f GetPoolNormal(size_t idx) const;
|
||||||
void ApplyVerticesCPU(hsh::dynamic_owner<hsh::vertex_buffer_typeless>& vertBuf,
|
void ApplyVerticesCPU(hsh::dynamic_owner<hsh::vertex_buffer_typeless>& vertBuf,
|
||||||
const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn) const;
|
const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn) const;
|
||||||
|
@ -315,4 +294,42 @@ public:
|
||||||
CFactoryFnReturn FModelFactory(const urde::SObjectTag& tag, std::unique_ptr<u8[]>&& in, u32 len,
|
CFactoryFnReturn FModelFactory(const urde::SObjectTag& tag, std::unique_ptr<u8[]>&& in, u32 len,
|
||||||
const urde::CVParamTransfer& vparms, CObjectReference* selfRef);
|
const urde::CVParamTransfer& vparms, CObjectReference* selfRef);
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
constexpr auto MapVertData(const hecl::HMDLMeta& meta, F&& Func) {
|
||||||
|
#define WEIGHT_COUNT(uvs, weights) \
|
||||||
|
case weights: { \
|
||||||
|
using VertData = CModelShaders::VertData<0, uvs, weights>; \
|
||||||
|
assert(sizeof(VertData) == meta.vertStride && "Vert data stride mismatch"); \
|
||||||
|
return Func.template operator()<VertData>(); \
|
||||||
|
break; \
|
||||||
|
}
|
||||||
|
#define UV_COUNT(uvs) \
|
||||||
|
case uvs: \
|
||||||
|
switch (meta.weightCount) { \
|
||||||
|
WEIGHT_COUNT(uvs, 0); \
|
||||||
|
WEIGHT_COUNT(uvs, 1); \
|
||||||
|
WEIGHT_COUNT(uvs, 2); \
|
||||||
|
WEIGHT_COUNT(uvs, 3); \
|
||||||
|
WEIGHT_COUNT(uvs, 4); \
|
||||||
|
WEIGHT_COUNT(uvs, 5); \
|
||||||
|
default: \
|
||||||
|
assert(false && "Unhandled weight count"); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
break;
|
||||||
|
switch (meta.uvCount) {
|
||||||
|
UV_COUNT(0)
|
||||||
|
UV_COUNT(1)
|
||||||
|
UV_COUNT(2)
|
||||||
|
UV_COUNT(3)
|
||||||
|
UV_COUNT(4)
|
||||||
|
UV_COUNT(5)
|
||||||
|
#undef UV_COUNT
|
||||||
|
#undef WEIGHT_COUNT
|
||||||
|
default:
|
||||||
|
assert(false && "Unhandled UV count");
|
||||||
|
}
|
||||||
|
// fallback
|
||||||
|
return Func.template operator()<CModelShaders::VertData<0, 0, 0>>();
|
||||||
|
}
|
||||||
} // namespace urde
|
} // namespace urde
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue