Implement line renderer (OpenGL only for now)

This commit is contained in:
Jack Andersen 2016-02-17 16:42:32 -10:00
parent cfee7b61bb
commit 365f6ac9e7
21 changed files with 779 additions and 83 deletions

View File

@ -54,6 +54,7 @@ target_link_libraries(urde
RuntimeCommonCharacter RuntimeCommonCharacter
RuntimeCommonInput RuntimeCommonInput
RuntimeCommonParticle RuntimeCommonParticle
RuntimeCommonGraphics
RuntimeCommon RuntimeCommon
DNAMP3 DNAMP2 DNAMP1 DNAMP3 DNAMP2 DNAMP1
DNACommon Specter SpecterFonts freetype ${DATA_SPEC_LIBS} DNACommon Specter SpecterFonts freetype ${DATA_SPEC_LIBS}

View File

@ -10,6 +10,7 @@
#include "Runtime/Particle/CElectricDescription.hpp" #include "Runtime/Particle/CElectricDescription.hpp"
#include "Runtime/Particle/CSwooshDescription.hpp" #include "Runtime/Particle/CSwooshDescription.hpp"
#include "Runtime/CModel.hpp" #include "Runtime/CModel.hpp"
#include "Runtime/CGraphics.hpp"
#include <cstdio> #include <cstdio>
using YAMLNode = Athena::io::YAMLNode; using YAMLNode = Athena::io::YAMLNode;
@ -17,6 +18,49 @@ using YAMLNode = Athena::io::YAMLNode;
namespace URDE namespace URDE
{ {
void ViewManager::BuildTestPART(pshag::IObjectStore& objStore)
{
m_partGenDesc = objStore.GetObj({HECL::FOURCC('PART'), 0x1E348530});
m_partGen.reset(new pshag::CElementGen(m_partGenDesc,
pshag::CElementGen::EModelOrientationType::Normal,
pshag::CElementGen::EOptionalSystemFlags::None));
m_particleView.reset(new ParticleView(*this, m_viewResources, *m_rootView));
m_lineRenderer.reset(new pshag::CLineRenderer(pshag::CLineRenderer::EPrimitiveMode::LineStrip, 4, nullptr, true));
m_rootView->accessContentViews().push_back(m_particleView.get());
m_rootView->updateSize();
}
void ViewManager::ParticleView::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub)
{
Specter::View::resized(root, sub);
pshag::CGraphics::SetViewportResolution({sub.size[0], sub.size[1]});
}
void ViewManager::ParticleView::draw(boo::IGraphicsCommandQueue *gfxQ)
{
if (m_vm.m_partGen)
{
m_vm.m_partGen->Update(1.0 / 60.0);
pshag::CGraphics::SetModelMatrix(Zeus::CTransform::Identity());
pshag::CGraphics::SetViewPointMatrix(Zeus::CTransform::Identity() + Zeus::CVector3f(0.f, -10.f, 0.f));
boo::SWindowRect windowRect = m_vm.m_mainWindow->getWindowFrame();
float aspect = windowRect.size[0] / float(windowRect.size[1]);
pshag::CGraphics::SetPerspective(55.0, aspect, 0.001f, 1000.f);
//gfxQ->clearTarget(false, true);
m_vm.m_partGen->Render();
/*
m_vm.m_lineRenderer->Reset();
m_vm.m_lineRenderer->AddVertex({-0.5f, 0.f, -0.5f}, Zeus::CColor::skBlue, 1.f);
m_vm.m_lineRenderer->AddVertex({-0.5f, 0.f, 0.5f}, Zeus::CColor::skBlue, 1.f);
m_vm.m_lineRenderer->AddVertex({0.5f, 10.f, 0.5f}, Zeus::CColor::skRed, 3.f);
m_vm.m_lineRenderer->AddVertex({0.5f, 0.f, -0.5f}, Zeus::CColor::skBlue, 1.f);
m_vm.m_lineRenderer->Render();
*/
}
}
Specter::View* ViewManager::BuildSpaceViews() Specter::View* ViewManager::BuildSpaceViews()
{ {
m_rootSpaceView = m_rootSpace->buildSpaceView(m_viewResources); m_rootSpaceView = m_rootSpace->buildSpaceView(m_viewResources);
@ -80,16 +124,6 @@ void ViewManager::DismissSplash()
m_splash->close(); m_splash->close();
} }
void ViewManager::BuildTestPART(pshag::IObjectStore& objStore)
{
m_partGenDesc = objStore.GetObj({HECL::FOURCC('PART'), 0x273375E3});
m_partGen.reset(new pshag::CElementGen(m_partGenDesc,
pshag::CElementGen::EModelOrientationType::Normal,
pshag::CElementGen::EOptionalSystemFlags::None));
m_particleView.reset(new ParticleView(*this, m_viewResources, *m_rootView));
m_rootView->accessContentViews().push_back(m_particleView.get());
}
ViewManager::ViewManager(HECL::Runtime::FileStoreManager& fileMgr, HECL::CVarManager& cvarMgr) ViewManager::ViewManager(HECL::Runtime::FileStoreManager& fileMgr, HECL::CVarManager& cvarMgr)
: m_fileStoreManager(fileMgr), m_cvarManager(cvarMgr), m_projManager(*this), : m_fileStoreManager(fileMgr), m_cvarManager(cvarMgr), m_projManager(*this),
m_fontCache(fileMgr), m_translator(URDE::SystemLocaleOrEnglish()), m_fontCache(fileMgr), m_translator(URDE::SystemLocaleOrEnglish()),
@ -185,6 +219,7 @@ void ViewManager::init(boo::IApplication* app)
pshag::CGraphics::InitializeBoo(gf, m_mainWindow->getCommandQueue()); pshag::CGraphics::InitializeBoo(gf, m_mainWindow->getCommandQueue());
pshag::CElementGen::Initialize(); pshag::CElementGen::Initialize();
pshag::CLineRenderer::Initialize();
} }
bool ViewManager::proc() bool ViewManager::proc()
@ -236,6 +271,7 @@ bool ViewManager::proc()
void ViewManager::stop() void ViewManager::stop()
{ {
pshag::CElementGen::Shutdown(); pshag::CElementGen::Shutdown();
pshag::CLineRenderer::Shutdown();
m_mainWindow->getCommandQueue()->stopRenderer(); m_mainWindow->getCommandQueue()->stopRenderer();
} }

View File

@ -6,6 +6,7 @@
#include "Space.hpp" #include "Space.hpp"
#include "Runtime/Particle/CElementGen.hpp" #include "Runtime/Particle/CElementGen.hpp"
#include "Runtime/Graphics/CLineRenderer.hpp"
namespace URDE namespace URDE
{ {
@ -39,24 +40,13 @@ class ViewManager : public Specter::IViewManager
public: public:
ParticleView(ViewManager& vm, Specter::ViewResources& res, Specter::View& parent) ParticleView(ViewManager& vm, Specter::ViewResources& res, Specter::View& parent)
: View(res, parent), m_vm(vm) {} : View(res, parent), m_vm(vm) {}
void draw(boo::IGraphicsCommandQueue* gfxQ) void resized(const boo::SWindowRect& root, const boo::SWindowRect& sub);
{ void draw(boo::IGraphicsCommandQueue* gfxQ);
if (m_vm.m_partGen)
{
m_vm.m_partGen->Update(1.0 / 60.0);
pshag::CGraphics::SetModelMatrix(Zeus::CTransform::Identity());
pshag::CGraphics::SetViewPointMatrix(Zeus::CTransform::Identity() + Zeus::CVector3f(0.f, -10.f, 0.f));
boo::SWindowRect windowRect = m_vm.m_mainWindow->getWindowFrame();
float aspect = windowRect.size[0] / float(windowRect.size[1]);
pshag::CGraphics::SetPerspective(55.0, aspect, 0.001f, 1000.f);
//gfxQ->clearTarget(false, true);
m_vm.m_partGen->Render();
}
}
}; };
std::unique_ptr<ParticleView> m_particleView; std::unique_ptr<ParticleView> m_particleView;
pshag::TLockedToken<pshag::CGenDescription> m_partGenDesc; pshag::TLockedToken<pshag::CGenDescription> m_partGenDesc;
std::unique_ptr<pshag::CElementGen> m_partGen; std::unique_ptr<pshag::CElementGen> m_partGen;
std::unique_ptr<pshag::CLineRenderer> m_lineRenderer;
HECL::SystemString m_recentProjectsPath; HECL::SystemString m_recentProjectsPath;
std::vector<HECL::SystemString> m_recentProjects; std::vector<HECL::SystemString> m_recentProjects;

View File

@ -8,6 +8,7 @@ namespace pshag
{ {
CGraphics::CProjectionState CGraphics::g_Proj; CGraphics::CProjectionState CGraphics::g_Proj;
float CGraphics::g_ProjAspect = 1.f;
u32 CGraphics::g_NumLightsActive = 0; u32 CGraphics::g_NumLightsActive = 0;
ERglLight CGraphics::g_LightActive = ERglLight::None; ERglLight CGraphics::g_LightActive = ERglLight::None;
ERglLight CGraphics::g_LightsWereOn = ERglLight::None; ERglLight CGraphics::g_LightsWereOn = ERglLight::None;
@ -119,6 +120,8 @@ void CGraphics::SetProjectionState(const CGraphics::CProjectionState& proj)
void CGraphics::SetPerspective(float fovy, float aspect, float near, float far) void CGraphics::SetPerspective(float fovy, float aspect, float near, float far)
{ {
g_ProjAspect = aspect;
float tfov = tanf(fovy * 0.5f * M_PI / 180.f); float tfov = tanf(fovy * 0.5f * M_PI / 180.f);
g_Proj.x0_persp = true; g_Proj.x0_persp = true;
g_Proj.x14_near = near; g_Proj.x14_near = near;
@ -151,11 +154,11 @@ Zeus::CVector2i CGraphics::ProjectPoint(const Zeus::CVector3f& point)
SClipScreenRect CGraphics::ClipScreenRectFromMS(const Zeus::CVector3f& p1, SClipScreenRect CGraphics::ClipScreenRectFromMS(const Zeus::CVector3f& p1,
const Zeus::CVector3f& p2) const Zeus::CVector3f& p2)
{ {
Zeus::CVector3f xfExt = (g_GXModelMatrix * p2) - g_ViewMatrix.m_origin; Zeus::CVector3f xf2 = (g_GXModelMatrix * p2) - g_ViewMatrix.m_origin;
xfExt = g_ViewMatrix.transposeRotate(xfExt); xf2 = g_ViewMatrix.transposeRotate(xf2);
Zeus::CVector3f xfPos = (g_GXModelMatrix * p1) - g_ViewMatrix.m_origin; Zeus::CVector3f xf1 = (g_GXModelMatrix * p1) - g_ViewMatrix.m_origin;
xfPos = g_ViewMatrix.transposeRotate(xfPos); xf1 = g_ViewMatrix.transposeRotate(xf1);
return ClipScreenRectFromVS(xfPos, xfExt); return ClipScreenRectFromVS(xf1, xf2);
} }
SClipScreenRect CGraphics::ClipScreenRectFromVS(const Zeus::CVector3f& p1, SClipScreenRect CGraphics::ClipScreenRectFromVS(const Zeus::CVector3f& p1,
@ -210,6 +213,19 @@ SClipScreenRect CGraphics::ClipScreenRectFromVS(const Zeus::CVector3f& p1,
} }
Zeus::CVector3f CGraphics::ProjectModelPointToViewportSpace(const Zeus::CVector3f& point)
{
CProjectionState& pst = g_Proj;
Zeus::CVector3f pt = g_GXModelView * point;
return GetPerspectiveProjectionMatrix().multiplyOneOverW(pt);
}
void CGraphics::SetViewportResolution(const Zeus::CVector2i& res)
{
g_ViewportResolution = res;
g_ViewportResolutionHalf = {res.x / 2, res.y / 2};
}
boo::IGraphicsDataFactory* CGraphics::g_BooFactory = nullptr; boo::IGraphicsDataFactory* CGraphics::g_BooFactory = nullptr;
boo::IGraphicsCommandQueue* CGraphics::g_BooMainCommandQueue = nullptr; boo::IGraphicsCommandQueue* CGraphics::g_BooMainCommandQueue = nullptr;
boo::ITextureR* CGraphics::g_SpareTexture = nullptr; boo::ITextureR* CGraphics::g_SpareTexture = nullptr;

View File

@ -148,6 +148,7 @@ public:
float x18_far; float x18_far;
}; };
static CProjectionState g_Proj; static CProjectionState g_Proj;
static float g_ProjAspect;
static u32 g_NumLightsActive; static u32 g_NumLightsActive;
static ERglLight g_LightActive; static ERglLight g_LightActive;
static ERglLight g_LightsWereOn; static ERglLight g_LightsWereOn;
@ -180,6 +181,8 @@ public:
static Zeus::CVector2i ProjectPoint(const Zeus::CVector3f& point); static Zeus::CVector2i ProjectPoint(const Zeus::CVector3f& point);
static SClipScreenRect ClipScreenRectFromMS(const Zeus::CVector3f& p1, const Zeus::CVector3f& p2); static SClipScreenRect ClipScreenRectFromMS(const Zeus::CVector3f& p1, const Zeus::CVector3f& p2);
static SClipScreenRect ClipScreenRectFromVS(const Zeus::CVector3f& p1, const Zeus::CVector3f& p2); static SClipScreenRect ClipScreenRectFromVS(const Zeus::CVector3f& p1, const Zeus::CVector3f& p2);
static Zeus::CVector3f ProjectModelPointToViewportSpace(const Zeus::CVector3f& point);
static void SetViewportResolution(const Zeus::CVector2i& res);
static boo::IGraphicsDataFactory* g_BooFactory; static boo::IGraphicsDataFactory* g_BooFactory;
static boo::IGraphicsCommandQueue* g_BooMainCommandQueue; static boo::IGraphicsCommandQueue* g_BooMainCommandQueue;
@ -208,6 +211,11 @@ public:
g_BooMainCommandQueue->setDrawPrimitive(prim); g_BooMainCommandQueue->setDrawPrimitive(prim);
g_BooMainCommandQueue->drawInstances(start, count, instCount); g_BooMainCommandQueue->drawInstances(start, count, instCount);
} }
static void DrawArray(boo::Primitive prim, size_t start, size_t count)
{
g_BooMainCommandQueue->setDrawPrimitive(prim);
g_BooMainCommandQueue->draw(start, count);
}
}; };
} }

View File

@ -0,0 +1,398 @@
#include "CLineRenderer.hpp"
#include "CLineRendererShaders.hpp"
namespace pshag
{
boo::IShaderPipeline* CLineRendererShaders::m_texAlpha = nullptr;
boo::IShaderPipeline* CLineRendererShaders::m_texAdditive = nullptr;
boo::IShaderPipeline* CLineRendererShaders::m_noTexAlpha = nullptr;
boo::IShaderPipeline* CLineRendererShaders::m_noTexAdditive = nullptr;
std::unique_ptr<CLineRendererShaders::IDataBindingFactory> CLineRendererShaders::m_bindFactory;
boo::GraphicsDataToken CLineRendererShaders::m_gfxToken;
void CLineRendererShaders::Initialize()
{
if (!CGraphics::g_BooFactory)
return;
switch (CGraphics::g_BooFactory->platform())
{
case boo::IGraphicsDataFactory::Platform::OGL:
m_bindFactory.reset(Initialize(*static_cast<boo::GLDataFactory*>(CGraphics::g_BooFactory)));
break;
#if _WIN32
case boo::IGraphicsDataFactory::Platform::D3D11:
case boo::IGraphicsDataFactory::Platform::D3D12:
m_bindFactory.reset(Initialize(*static_cast<boo::ID3DDataFactory*>(CGraphics::g_BooFactory)));
break;
#elif BOO_HAS_METAL
case boo::IGraphicsDataFactory::Platform::Metal:
m_bindFactory.reset(Initialize(*static_cast<boo::MetalDataFactory*>(CGraphics::g_BooFactory)));
break;
#endif
default: break;
}
m_gfxToken = CGraphics::CommitResources();
}
void CLineRenderer::Initialize()
{
CLineRendererShaders::Initialize();
}
void CLineRendererShaders::Shutdown()
{
m_gfxToken.doDestroy();
}
void CLineRenderer::Shutdown()
{
CLineRendererShaders::Shutdown();
}
struct SDrawVertTex
{
Zeus::CVector4f pos;
Zeus::CColor color;
Zeus::CVector2f uv;
};
struct SDrawVertNoTex
{
Zeus::CVector4f pos;
Zeus::CColor color;
};
struct SDrawUniform
{
Zeus::CColor moduColor;
};
void CLineRendererShaders::BuildShaderDataBinding(CLineRenderer& renderer,
boo::ITexture* texture, bool additive)
{
boo::IShaderPipeline* pipeline = nullptr;
if (texture)
{
if (additive)
pipeline = m_texAdditive;
else
pipeline = m_texAlpha;
}
else
{
if (additive)
pipeline = m_noTexAdditive;
else
pipeline = m_noTexAlpha;
}
m_bindFactory->BuildShaderDataBinding(renderer, pipeline, texture);
}
CLineRenderer::CLineRenderer(EPrimitiveMode mode, u32 maxVerts, boo::ITexture* texture, bool additive)
: m_mode(mode), m_maxVerts(maxVerts)
{
if (maxVerts < 2)
return;
m_textured = texture != nullptr;
u32 maxTriVerts;
switch (mode)
{
case EPrimitiveMode::Lines:
maxTriVerts = maxVerts * 3;
break;
case EPrimitiveMode::LineStrip:
maxTriVerts = maxVerts * 2;
break;
case EPrimitiveMode::LineLoop:
maxTriVerts = maxVerts * 2 + 2;
break;
}
m_vertBuf = CGraphics::NewDynamicGPUBuffer(boo::BufferUse::Vertex,
texture ? sizeof(SDrawVertTex) : sizeof(SDrawVertNoTex),
maxTriVerts);
m_uniformBuf = CGraphics::NewDynamicGPUBuffer(boo::BufferUse::Uniform, sizeof(SDrawUniform), 1);
CLineRendererShaders::BuildShaderDataBinding(*this, texture, additive);
m_gfxToken = CGraphics::CommitResources();
}
static rstl::reserved_vector<SDrawVertTex, 256> g_StaticLineVertsTex;
static rstl::reserved_vector<SDrawVertNoTex, 256> g_StaticLineVertsNoTex;
static Zeus::CVector2f IntersectLines(const Zeus::CVector2f& pa1, const Zeus::CVector2f& pa2,
const Zeus::CVector2f& pb1, const Zeus::CVector2f& pb2)
{
Zeus::CVector2f pa1mpa2 = pa1 - pa2;
Zeus::CVector2f pb1mpb2 = pb1 - pb2;
float denom = pa1mpa2.x * pb1mpb2.y - pa1mpa2.y * pb1mpb2.x;
float numt1 = pa1.x * pa2.y - pa1.y * pa2.x;
float numt2 = pb1.x * pb2.y - pb1.y * pb2.x;
return {(numt1 * pb1mpb2.x - pa1mpa2.x * numt2) / denom,
(numt1 * pb1mpb2.y - pa1mpa2.y * numt2) / denom};
}
void CLineRenderer::Reset()
{
m_nextVert = 0;
m_final = false;
if (m_textured)
g_StaticLineVertsTex.clear();
else
g_StaticLineVertsNoTex.clear();
}
void CLineRenderer::AddVertex(const Zeus::CVector3f& position, const Zeus::CColor& color, float width,
const Zeus::CVector2f& uv)
{
if (!m_shaderBind || m_nextVert >= m_maxVerts)
return;
float adjWidth = width / 480.f;
Zeus::CVector3f projPt = CGraphics::ProjectModelPointToViewportSpace(position);
if (m_mode == EPrimitiveMode::LineLoop)
{
if (m_nextVert == 0)
{
m_firstPos = projPt;
m_secondPos = projPt;
m_firstUV = uv;
m_firstColor = color;
m_firstWidth = adjWidth;
}
else if (m_nextVert == 1)
{
m_secondPos = projPt;
}
}
if (m_nextVert > 1)
{
Zeus::CVector2f dva = (m_lastPos - m_lastPos2).toVec2f();
if (!dva.canBeNormalized())
dva = {0.f, 1.f};
dva = dva.normalized().perpendicularVector() * m_lastWidth;
dva.x /= CGraphics::g_ProjAspect;
Zeus::CVector2f dvb = (projPt - m_lastPos).toVec2f();
if (!dvb.canBeNormalized())
dvb = {0.f, 1.f};
dvb = dvb.normalized().perpendicularVector() * m_lastWidth;
dvb.x /= CGraphics::g_ProjAspect;
if (m_textured)
{
if (m_mode == EPrimitiveMode::Lines)
{
if (m_nextVert & 1)
{
g_StaticLineVertsTex.push_back(g_StaticLineVertsTex.back());
g_StaticLineVertsTex.push_back({m_lastPos + dvb, m_lastColor, m_lastUV});
g_StaticLineVertsTex.push_back(g_StaticLineVertsTex.back());
g_StaticLineVertsTex.push_back({m_lastPos - dvb, m_lastColor, m_lastUV});
}
else
{
g_StaticLineVertsTex.push_back({m_lastPos + dva, m_lastColor, m_lastUV});
g_StaticLineVertsTex.push_back({m_lastPos - dva, m_lastColor, m_lastUV});
}
}
else
{
Zeus::CVector3f intersect1 = IntersectLines(m_lastPos2.toVec2f() + dva, m_lastPos.toVec2f() + dva,
m_lastPos.toVec2f() + dvb, projPt.toVec2f() + dvb);
intersect1.z = m_lastPos.z;
Zeus::CVector3f intersect2 = IntersectLines(m_lastPos2.toVec2f() - dva, m_lastPos.toVec2f() - dva,
m_lastPos.toVec2f() - dvb, projPt.toVec2f() - dvb);
intersect2.z = m_lastPos.z;
g_StaticLineVertsTex.push_back({intersect1, m_lastColor, m_lastUV});
g_StaticLineVertsTex.push_back({intersect2, m_lastColor, m_lastUV});
}
}
else
{
if (m_mode == EPrimitiveMode::Lines)
{
if (m_nextVert & 1)
{
g_StaticLineVertsNoTex.push_back(g_StaticLineVertsNoTex.back());
g_StaticLineVertsNoTex.push_back({m_lastPos + dvb, m_lastColor});
g_StaticLineVertsNoTex.push_back(g_StaticLineVertsNoTex.back());
g_StaticLineVertsNoTex.push_back({m_lastPos - dvb, m_lastColor});
}
else
{
g_StaticLineVertsNoTex.push_back({m_lastPos + dva, m_lastColor});
g_StaticLineVertsNoTex.push_back({m_lastPos - dva, m_lastColor});
}
}
else
{
Zeus::CVector3f intersect1 = IntersectLines(m_lastPos2.toVec2f() + dva, m_lastPos.toVec2f() + dva,
m_lastPos.toVec2f() + dvb, projPt.toVec2f() + dvb);
intersect1.z = m_lastPos.z;
Zeus::CVector3f intersect2 = IntersectLines(m_lastPos2.toVec2f() - dva, m_lastPos.toVec2f() - dva,
m_lastPos.toVec2f() - dvb, projPt.toVec2f() - dvb);
intersect2.z = m_lastPos.z;
g_StaticLineVertsNoTex.push_back({intersect1, m_lastColor});
g_StaticLineVertsNoTex.push_back({intersect2, m_lastColor});
}
}
}
else if (m_nextVert == 1)
{
Zeus::CVector2f dv = (projPt - m_lastPos).toVec2f();
if (!dv.canBeNormalized())
dv = {0.f, 1.f};
dv = dv.normalized().perpendicularVector() * m_lastWidth;
dv.x /= CGraphics::g_ProjAspect;
if (m_textured)
{
g_StaticLineVertsTex.push_back({m_lastPos + dv, m_lastColor, m_lastUV});
g_StaticLineVertsTex.push_back({m_lastPos - dv, m_lastColor, m_lastUV});
}
else
{
g_StaticLineVertsNoTex.push_back({m_lastPos + dv, m_lastColor});
g_StaticLineVertsNoTex.push_back({m_lastPos - dv, m_lastColor});
}
}
m_lastPos2 = m_lastPos;
m_lastPos = projPt;
m_lastUV = uv;
m_lastColor = color;
m_lastWidth = adjWidth;
++m_nextVert;
}
void CLineRenderer::Render(const Zeus::CColor& moduColor)
{
if (!m_final && m_nextVert > 1)
{
if (m_mode == EPrimitiveMode::LineLoop)
{
{
Zeus::CVector2f dva = (m_lastPos - m_lastPos2).toVec2f();
if (!dva.canBeNormalized())
dva = {0.f, 1.f};
dva = dva.normalized().perpendicularVector() * m_lastWidth;
dva.x /= CGraphics::g_ProjAspect;
Zeus::CVector2f dvb = (m_firstPos - m_lastPos).toVec2f();
if (!dvb.canBeNormalized())
dvb = {0.f, 1.f};
dvb = dvb.normalized().perpendicularVector() * m_lastWidth;
dvb.x /= CGraphics::g_ProjAspect;
Zeus::CVector3f intersect1 = IntersectLines(m_lastPos2.toVec2f() + dva, m_lastPos.toVec2f() + dva,
m_lastPos.toVec2f() + dvb, m_firstPos.toVec2f() + dvb);
intersect1.z = m_lastPos.z;
Zeus::CVector3f intersect2 = IntersectLines(m_lastPos2.toVec2f() - dva, m_lastPos.toVec2f() - dva,
m_lastPos.toVec2f() - dvb, m_firstPos.toVec2f() - dvb);
intersect2.z = m_lastPos.z;
if (m_textured)
{
g_StaticLineVertsTex.push_back({intersect1, m_lastColor, m_lastUV});
g_StaticLineVertsTex.push_back({intersect2, m_lastColor, m_lastUV});
}
else
{
g_StaticLineVertsNoTex.push_back({intersect1, m_lastColor});
g_StaticLineVertsNoTex.push_back({intersect2, m_lastColor});
}
}
{
Zeus::CVector2f dva = (m_firstPos - m_lastPos).toVec2f();
if (!dva.canBeNormalized())
dva = {0.f, 1.f};
dva = dva.normalized().perpendicularVector() * m_firstWidth;
dva.x /= CGraphics::g_ProjAspect;
Zeus::CVector2f dvb = (m_secondPos - m_firstPos).toVec2f();
if (!dvb.canBeNormalized())
dvb = {0.f, 1.f};
dvb = dvb.normalized().perpendicularVector() * m_firstWidth;
dvb.x /= CGraphics::g_ProjAspect;
Zeus::CVector3f intersect1 = IntersectLines(m_lastPos.toVec2f() + dva, m_firstPos.toVec2f() + dva,
m_firstPos.toVec2f() + dvb, m_secondPos.toVec2f() + dvb);
intersect1.z = m_firstPos.z;
Zeus::CVector3f intersect2 = IntersectLines(m_lastPos.toVec2f() - dva, m_firstPos.toVec2f() - dva,
m_firstPos.toVec2f() - dvb, m_secondPos.toVec2f() - dvb);
intersect2.z = m_firstPos.z;
if (m_textured)
{
g_StaticLineVertsTex.push_back({intersect1, m_firstColor, m_firstUV});
g_StaticLineVertsTex.push_back({intersect2, m_firstColor, m_firstUV});
}
else
{
g_StaticLineVertsNoTex.push_back({intersect1, m_firstColor});
g_StaticLineVertsNoTex.push_back({intersect2, m_firstColor});
}
}
}
else
{
Zeus::CVector2f dv = (m_lastPos - m_lastPos2).toVec2f();
if (!dv.canBeNormalized())
dv = {0.f, 1.f};
dv = dv.normalized().perpendicularVector() * m_lastWidth;
dv.x /= CGraphics::g_ProjAspect;
if (m_textured)
{
if (m_mode == EPrimitiveMode::Lines && (m_nextVert & 1))
{}
else
{
g_StaticLineVertsTex.push_back({m_lastPos + dv, m_lastColor, m_lastUV});
g_StaticLineVertsTex.push_back({m_lastPos - dv, m_lastColor, m_lastUV});
}
}
else
{
if (m_mode == EPrimitiveMode::Lines && (m_nextVert & 1))
{}
else
{
g_StaticLineVertsNoTex.push_back({m_lastPos + dv, m_lastColor});
g_StaticLineVertsNoTex.push_back({m_lastPos - dv, m_lastColor});
}
}
}
m_final = true;
}
SDrawUniform uniformData = {moduColor};
m_uniformBuf->load(&uniformData, sizeof(SDrawUniform));
CGraphics::SetShaderDataBinding(m_shaderBind);
if (m_textured)
{
m_vertBuf->load(g_StaticLineVertsTex.data(), sizeof(SDrawVertTex) * g_StaticLineVertsTex.size());
CGraphics::DrawArray(boo::Primitive::TriStrips, 0, g_StaticLineVertsTex.size());
}
else
{
m_vertBuf->load(g_StaticLineVertsNoTex.data(), sizeof(SDrawVertNoTex) * g_StaticLineVertsNoTex.size());
CGraphics::DrawArray(boo::Primitive::TriStrips, 0, g_StaticLineVertsNoTex.size());
}
}
}

View File

@ -0,0 +1,60 @@
#ifndef __PSHAG_CLINERENDERER_HPP__
#define __PSHAG_CLINERENDERER_HPP__
#include "RetroTypes.hpp"
#include "CVector3f.hpp"
#include "CColor.hpp"
#include "boo/graphicsdev/IGraphicsDataFactory.hpp"
namespace pshag
{
class CLineRenderer
{
public:
enum class EPrimitiveMode
{
Lines,
LineStrip,
LineLoop
};
public:
EPrimitiveMode m_mode;
u32 m_maxVerts;
u32 m_nextVert = 0;
bool m_final = false;
bool m_textured;
Zeus::CVector3f m_firstPos;
Zeus::CVector3f m_secondPos;
Zeus::CVector2f m_firstUV;
Zeus::CColor m_firstColor;
float m_firstWidth;
Zeus::CVector3f m_lastPos;
Zeus::CVector3f m_lastPos2;
Zeus::CVector2f m_lastUV;
Zeus::CColor m_lastColor;
float m_lastWidth;
public:
boo::GraphicsDataToken m_gfxToken;
boo::IGraphicsBufferD* m_vertBuf;
boo::IGraphicsBufferD* m_uniformBuf;
boo::IShaderDataBinding* m_shaderBind = nullptr;
CLineRenderer(EPrimitiveMode mode, u32 maxVerts, boo::ITexture* texture, bool additive);
void Reset();
void AddVertex(const Zeus::CVector3f& position, const Zeus::CColor& color, float width,
const Zeus::CVector2f& uv=Zeus::CVector2f::skZero);
void Render(const Zeus::CColor& moduColor=Zeus::CColor::skWhite);
static void Initialize();
static void Shutdown();
};
}
#endif // __PSHAG_CLINERENDERER_HPP__

View File

@ -0,0 +1,47 @@
#ifndef __PSHAG_CLINERENDERERSHADERS_HPP__
#define __PSHAG_CLINERENDERERSHADERS_HPP__
#include "CGraphics.hpp"
#include "boo/graphicsdev/GL.hpp"
#include "boo/graphicsdev/D3D.hpp"
#include "boo/graphicsdev/Metal.hpp"
namespace pshag
{
class CLineRenderer;
class CLineRendererShaders
{
public:
struct IDataBindingFactory
{
virtual void BuildShaderDataBinding(CLineRenderer& renderer, boo::IShaderPipeline* pipeline,
boo::ITexture* texture)=0;
};
private:
static boo::IShaderPipeline* m_texAlpha;
static boo::IShaderPipeline* m_texAdditive;
static boo::IShaderPipeline* m_noTexAlpha;
static boo::IShaderPipeline* m_noTexAdditive;
static std::unique_ptr<IDataBindingFactory> m_bindFactory;
static boo::GraphicsDataToken m_gfxToken;
public:
static IDataBindingFactory* Initialize(boo::GLDataFactory& factory);
#if _WIN32
static IDataBindingFactory* Initialize(boo::ID3DDataFactory& factory);
#elif BOO_HAS_METAL
static IDataBindingFactory* Initialize(boo::MetalDataFactory& factory);
#endif
static void Initialize();
static void Shutdown();
static void BuildShaderDataBinding(CLineRenderer& renderer, boo::ITexture* texture, bool additive);
};
}
#endif // __PSHAG_CLINERENDERERSHADERS_HPP__

View File

@ -0,0 +1,142 @@
#include "CLineRendererShaders.hpp"
#include "CLineRenderer.hpp"
namespace pshag
{
static const char* VS_GLSL_TEX =
"#version 330\n"
"layout(location=0) in vec4 posIn;\n"
"layout(location=1) in vec4 colorIn;\n"
"layout(location=2) in vec4 uvIn;\n"
"\n"
"uniform LineUniform\n"
"{\n"
" vec4 moduColor;\n"
"};\n"
"\n"
"struct VertToFrag\n"
"{\n"
" vec4 color;\n"
" vec2 uv;\n"
"};\n"
"\n"
"out VertToFrag vtf;\n"
"void main()\n"
"{\n"
" vtf.color = colorIn * moduColor;\n"
" vtf.uv = uvIn.xy;\n"
" gl_Position = posIn;\n"
"}\n";
static const char* FS_GLSL_TEX =
"#version 330\n"
"struct VertToFrag\n"
"{\n"
" vec4 color;\n"
" vec2 uv;\n"
"};\n"
"\n"
"in VertToFrag vtf;\n"
"layout(location=0) out vec4 colorOut;\n"
"uniform sampler2D texs[1];\n"
"void main()\n"
"{\n"
" colorOut = vtf.color * texture(texs[0], vtf.uv);\n"
"}\n";
static const char* VS_GLSL_NOTEX =
"#version 330\n"
"layout(location=0) in vec4 posIn;\n"
"layout(location=1) in vec4 colorIn;\n"
"\n"
"uniform LineUniform\n"
"{\n"
" vec4 moduColor;\n"
"};\n"
"\n"
"struct VertToFrag\n"
"{\n"
" vec4 color;\n"
"};\n"
"\n"
"out VertToFrag vtf;\n"
"void main()\n"
"{\n"
" vtf.color = colorIn * moduColor;\n"
" gl_Position = posIn;\n"
"}\n";
static const char* FS_GLSL_NOTEX =
"#version 330\n"
"struct VertToFrag\n"
"{\n"
" vec4 color;\n"
"};\n"
"\n"
"in VertToFrag vtf;\n"
"layout(location=0) out vec4 colorOut;\n"
"void main()\n"
"{\n"
" colorOut = vtf.color;\n"
"}\n";
struct GLSLLineDataBindingFactory : CLineRendererShaders::IDataBindingFactory
{
void BuildShaderDataBinding(CLineRenderer& renderer, boo::IShaderPipeline* pipeline, boo::ITexture* texture)
{
boo::IVertexFormat* vtxFmt = nullptr;
int texCount = 0;
boo::ITexture* textures[1];
if (texture)
{
textures[0] = texture;
texCount = 1;
const boo::VertexElementDescriptor TexFmtTex[] =
{
{renderer.m_vertBuf, nullptr, boo::VertexSemantic::Position4},
{renderer.m_vertBuf, nullptr, boo::VertexSemantic::Color},
{renderer.m_vertBuf, nullptr, boo::VertexSemantic::UV4}
};
vtxFmt = CGraphics::g_BooFactory->newVertexFormat(3, TexFmtTex);
}
else
{
const boo::VertexElementDescriptor TexFmtNoTex[] =
{
{renderer.m_vertBuf, nullptr, boo::VertexSemantic::Position4},
{renderer.m_vertBuf, nullptr, boo::VertexSemantic::Color}
};
vtxFmt = CGraphics::g_BooFactory->newVertexFormat(2, TexFmtNoTex);
}
boo::IGraphicsBuffer* uniforms[] = {renderer.m_uniformBuf};
renderer.m_shaderBind = CGraphics::g_BooFactory->newShaderDataBinding(pipeline, vtxFmt, renderer.m_vertBuf,
nullptr, nullptr, 1, uniforms,
texCount, textures);
}
};
CLineRendererShaders::IDataBindingFactory* CLineRendererShaders::Initialize(boo::GLDataFactory& factory)
{
static const char* UniNames[] = {"LineUniform"};
m_texAlpha = factory.newShaderPipeline(VS_GLSL_TEX, FS_GLSL_TEX, 1, "texs", 1, UniNames,
boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha,
false, true, false);
m_texAdditive = factory.newShaderPipeline(VS_GLSL_TEX, FS_GLSL_TEX, 1, "texs", 1, UniNames,
boo::BlendFactor::SrcAlpha, boo::BlendFactor::One,
false, false, false);
m_noTexAlpha = factory.newShaderPipeline(VS_GLSL_NOTEX, FS_GLSL_NOTEX, 1, nullptr, 1, UniNames,
boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha,
false, true, false);
m_noTexAdditive = factory.newShaderPipeline(VS_GLSL_NOTEX, FS_GLSL_NOTEX, 1, nullptr, 1, UniNames,
boo::BlendFactor::SrcAlpha, boo::BlendFactor::One,
false, false, false);
return new struct GLSLLineDataBindingFactory;
}
}

View File

@ -1,5 +1,7 @@
add_library(RuntimeCommonGraphics add_library(RuntimeCommonGraphics
IRenderer.hpp IRenderer.hpp
CBooRenderer.hpp CBooRenderer.cpp CBooRenderer.hpp CBooRenderer.cpp
CLineRenderer.hpp CLineRenderer.cpp
CLineRendererShaders.hpp CLineRendererShadersGLSL.cpp
CMetroidModelInstance.hpp CMetroidModelInstance.hpp
CLight.hpp) CLight.hpp)

View File

@ -12,6 +12,7 @@ target_link_libraries(mp1
RuntimeCommonCharacter RuntimeCommonCharacter
RuntimeCommonInput RuntimeCommonInput
RuntimeCommonParticle RuntimeCommonParticle
RuntimeCommonGraphics
RuntimeCommon RuntimeCommon
DNAMP1 DNAMP1
DNACommon DNACommon

View File

@ -13,7 +13,7 @@
namespace pshag namespace pshag
{ {
static LogVisor::LogModule Log("Retro::CElementGen"); static LogVisor::LogModule Log("pshag::CElementGen");
static bool s_inCreateNewParticles = false; static bool s_inCreateNewParticles = false;
@ -413,18 +413,30 @@ CElementGen::CElementGen(const TToken<CGenDescription>& gen,
} }
} }
m_shaderClass = CElementGenShaders::GetShaderClass(*this); if (x225_26_LINE)
static const size_t ShadClsSizes[] =
{ {
sizeof(SParticleInstanceTex), CUVElement* texr = desc->x54_TEXR.get();
sizeof(SParticleInstanceIndTex), boo::ITexture* tex = nullptr;
sizeof(SParticleInstanceNoTex) if (texr)
}; tex = texr->GetValueTexture(0).GetObj()->GetBooTexture();
size_t maxInsts = x224_29_MBLR ? (m_maxMBSP * x70_MAXP) : x70_MAXP; m_lineRenderer.reset(new CLineRenderer(CLineRenderer::EPrimitiveMode::Lines,
m_instBuf = CGraphics::NewDynamicGPUBuffer(boo::BufferUse::Vertex, ShadClsSizes[int(m_shaderClass)], maxInsts); x70_MAXP * 2, tex, x224_26_AAPH));
m_uniformBuf = CGraphics::NewDynamicGPUBuffer(boo::BufferUse::Uniform, sizeof(SParticleUniforms), 1); }
CElementGenShaders::BuildShaderDataBinding(*this); else
m_gfxToken = CGraphics::CommitResources(); {
m_shaderClass = CElementGenShaders::GetShaderClass(*this);
static const size_t ShadClsSizes[] =
{
sizeof(SParticleInstanceTex),
sizeof(SParticleInstanceIndTex),
sizeof(SParticleInstanceNoTex)
};
size_t maxInsts = x224_29_MBLR ? (m_maxMBSP * x70_MAXP) : x70_MAXP;
m_instBuf = CGraphics::NewDynamicGPUBuffer(boo::BufferUse::Vertex, ShadClsSizes[int(m_shaderClass)], maxInsts);
m_uniformBuf = CGraphics::NewDynamicGPUBuffer(boo::BufferUse::Uniform, sizeof(SParticleUniforms), 1);
CElementGenShaders::BuildShaderDataBinding(*this);
m_gfxToken = CGraphics::CommitResources();
}
} }
CElementGen::~CElementGen() CElementGen::~CElementGen()
@ -1378,7 +1390,6 @@ void CElementGen::RenderModels()
void CElementGen::RenderLines() void CElementGen::RenderLines()
{ {
return;
CGenDescription* desc = x1c_genDesc.GetObj(); CGenDescription* desc = x1c_genDesc.GetObj();
CGlobalRandom gr(x230_randState); CGlobalRandom gr(x230_randState);
@ -1411,6 +1422,7 @@ void CElementGen::RenderLines()
bool constTexr = true; bool constTexr = true;
bool constUVs = true; bool constUVs = true;
CTexture* cachedTex = nullptr; CTexture* cachedTex = nullptr;
Zeus::CColor moduColor = Zeus::CColor::skWhite;
if (texr) if (texr)
{ {
CParticle& target = g_StaticParticleList[x2c_particleLists[0].x0_partIdx]; CParticle& target = g_StaticParticleList[x2c_particleLists[0].x0_partIdx];
@ -1423,30 +1435,23 @@ void CElementGen::RenderLines()
if (x30c_moduColor != Zeus::CColor::skBlack) if (x30c_moduColor != Zeus::CColor::skBlack)
{ {
/* Add RASC * PREVC pass for MODU color loaded into channel mat-color */ /* Add RASC * PREVC pass for MODU color loaded into channel mat-color */
} moduColor = x30c_moduColor;
else
{
/* Pass-thru */
} }
constTexr = texr->HasConstantTexture(); constTexr = texr->HasConstantTexture();
texr->GetValueUV(partFrame, uvs); texr->GetValueUV(partFrame, uvs);
constUVs = texr->HasConstantUV(); constUVs = texr->HasConstantUV();
} }
else
{
/* Pass-thru */
}
float constWidth = 1.f;
if (widtConst) if (widtConst)
{ {
float width = 1.f; widt->GetValue(0, constWidth);
widt->GetValue(0, width); constWidth = std::max(0.f, std::min(constWidth, 42.5f));
width = std::max(0.f, std::min(width, 42.5f));
/* Set line width */
/* Start line draw of x2c_particleLists.size() * 2 */
} }
m_lineRenderer->Reset();
for (CParticleListItem& item : x2c_particleLists) for (CParticleListItem& item : x2c_particleLists)
{ {
CParticle& particle = g_StaticParticleList[item.x0_partIdx]; CParticle& particle = g_StaticParticleList[item.x0_partIdx];
@ -1475,32 +1480,20 @@ void CElementGen::RenderLines()
if (widtConst) if (widtConst)
{ {
/* Draw: */ m_lineRenderer->AddVertex(p1, particle.x34_color, constWidth, {uvs.xMin, uvs.yMin});
/* Pos: p1 Color: particle.color UV0: {uv[0], uv[1]} */ m_lineRenderer->AddVertex(p2, particle.x34_color, constWidth, {uvs.xMax, uvs.yMax});
/* Pos: p2 Color: particle.color UV0: {uv[2], uv[3]} */
} }
else else
{ {
float width = 1.f; float width = 1.f;
widt->GetValue(0, width); widt->GetValue(0, width);
width = std::max(0.f, std::min(width, 42.5f)); width = std::max(0.f, std::min(width, 42.5f));
/* Set line width */ m_lineRenderer->AddVertex(p1, particle.x34_color, width, {uvs.xMin, uvs.yMin});
/* Start line draw of 2 */ m_lineRenderer->AddVertex(p2, particle.x34_color, width, {uvs.xMax, uvs.yMax});
/* Draw: */
/* Pos: p1 Color: particle.color UV0: {uv[0], uv[1]} */
/* Pos: p2 Color: particle.color UV0: {uv[2], uv[3]} */
/* EndDraw */
} }
} }
if (widtConst) m_lineRenderer->Render(moduColor);
{
/* EndDraw */
}
/* Restore line-width to 1.0 */
} }
void CElementGen::RenderParticles() void CElementGen::RenderParticles()

View File

@ -12,6 +12,7 @@
#include "CRandom16.hpp" #include "CRandom16.hpp"
#include "CParticleGen.hpp" #include "CParticleGen.hpp"
#include "CElementGenShaders.hpp" #include "CElementGenShaders.hpp"
#include "Graphics/CLineRenderer.hpp"
namespace pshag namespace pshag
{ {
@ -149,6 +150,7 @@ private:
float x308_LSLA = 45.f; float x308_LSLA = 45.f;
Zeus::CColor x30c_moduColor = {1.f, 1.f, 1.f, 1.f}; Zeus::CColor x30c_moduColor = {1.f, 1.f, 1.f, 1.f};
std::unique_ptr<CLineRenderer> m_lineRenderer;
CElementGenShaders::EShaderClass m_shaderClass; CElementGenShaders::EShaderClass m_shaderClass;
void AccumulateBounds(Zeus::CVector3f& pos, float size); void AccumulateBounds(Zeus::CVector3f& pos, float size);

View File

@ -177,7 +177,7 @@ static const char* FS_GLSL_NOTEX =
" colorOut = vtf.color;\n" " colorOut = vtf.color;\n"
"}\n"; "}\n";
struct GLSLDataBindingFactory : CElementGenShaders::IDataBindingFactory struct GLSLElementDataBindingFactory : CElementGenShaders::IDataBindingFactory
{ {
void BuildShaderDataBinding(CElementGen& gen, void BuildShaderDataBinding(CElementGen& gen,
boo::IShaderPipeline* regPipeline, boo::IShaderPipeline* regPipeline,
@ -333,7 +333,7 @@ CElementGenShaders::IDataBindingFactory* CElementGenShaders::Initialize(boo::GLD
boo::BlendFactor::SrcAlpha, boo::BlendFactor::One, boo::BlendFactor::SrcAlpha, boo::BlendFactor::One,
false, false, false); false, false, false);
return new struct GLSLDataBindingFactory; return new struct GLSLElementDataBindingFactory;
} }
} }

View File

@ -187,7 +187,7 @@ static const char* FS_HLSL_NOTEX =
" return vtf.color;\n" " return vtf.color;\n"
"}\n"; "}\n";
struct D3DDataBindingFactory : CElementGenShaders::IDataBindingFactory struct D3DElementDataBindingFactory : CElementGenShaders::IDataBindingFactory
{ {
void BuildShaderDataBinding(CElementGen& gen, void BuildShaderDataBinding(CElementGen& gen,
boo::IShaderPipeline* regPipeline, boo::IShaderPipeline* regPipeline,
@ -356,7 +356,7 @@ CElementGenShaders::IDataBindingFactory* CElementGenShaders::Initialize(boo::ID3
boo::BlendFactor::SrcAlpha, boo::BlendFactor::One, boo::BlendFactor::SrcAlpha, boo::BlendFactor::One,
false, false, false); false, false, false);
return new struct D3DDataBindingFactory; return new struct D3DElementDataBindingFactory;
} }
} }

View File

@ -209,7 +209,7 @@ static const char* FS_METAL_NOTEX =
" return vtf.color;\n" " return vtf.color;\n"
"}\n"; "}\n";
struct MetalDataBindingFactory : CElementGenShaders::IDataBindingFactory struct MetalElementDataBindingFactory : CElementGenShaders::IDataBindingFactory
{ {
void BuildShaderDataBinding(CElementGen& gen, void BuildShaderDataBinding(CElementGen& gen,
boo::IShaderPipeline* regPipeline, boo::IShaderPipeline* regPipeline,
@ -378,7 +378,7 @@ CElementGenShaders::IDataBindingFactory* CElementGenShaders::Initialize(boo::Met
boo::BlendFactor::SrcAlpha, boo::BlendFactor::One, boo::BlendFactor::SrcAlpha, boo::BlendFactor::One,
false, false, false); false, false, false);
return new struct MetalDataBindingFactory; return new struct MetalElementDataBindingFactory;
} }
} }

View File

@ -9,7 +9,7 @@
namespace pshag namespace pshag
{ {
static LogVisor::LogModule Log("Retro::CParticleDataFactory"); static LogVisor::LogModule Log("pshag::CParticleDataFactory");
float CParticleDataFactory::GetReal(CInputStream& in) float CParticleDataFactory::GetReal(CInputStream& in)
{ {

View File

@ -9,7 +9,7 @@
namespace pshag namespace pshag
{ {
static LogVisor::LogModule Log("Retro::CParticleElectricDataFactory"); static LogVisor::LogModule Log("pshag::CParticleElectricDataFactory");
using CPF = CParticleDataFactory; using CPF = CParticleDataFactory;

View File

@ -8,7 +8,7 @@
namespace pshag namespace pshag
{ {
static LogVisor::LogModule Log("Retro::CParticleSwooshDataFactory"); static LogVisor::LogModule Log("pshag::CParticleSwooshDataFactory");
using CPF = CParticleDataFactory; using CPF = CParticleDataFactory;

View File

@ -10,7 +10,7 @@
namespace pshag namespace pshag
{ {
static LogVisor::LogModule Log("Retro::CProjectileWeaponDataFactory"); static LogVisor::LogModule Log("pshag::CProjectileWeaponDataFactory");
using CPF = CParticleDataFactory; using CPF = CParticleDataFactory;

@ -1 +1 @@
Subproject commit a5d6f9f2624d86a92f1438dda89695f47789995c Subproject commit 38b3396e0853e9bf446859a9d8b042044d9fd78e