mirror of https://github.com/AxioDL/metaforce.git
GLSL refactors to support Vulkan
This commit is contained in:
parent
442068306f
commit
952b96fa79
|
@ -21,25 +21,24 @@ namespace urde
|
|||
|
||||
void ViewManager::BuildTestPART(urde::IObjectStore& objStore)
|
||||
{
|
||||
TToken<CSkinRules>
|
||||
m_modelTest = objStore.GetObj("MP1/SamusGun/CMDL_0EF58656.blend");
|
||||
m_modelTest = objStore.GetObj("gun_cmdl");
|
||||
//m_modelTest = objStore.GetObj("CMDL_GameCube");
|
||||
m_modelTest.Lock();
|
||||
|
||||
//m_partGenDesc = objStore.GetObj({hecl::FOURCC('PART'), 0x972A5CD2});
|
||||
m_partGenDesc = objStore.GetObj("PowerCharge");
|
||||
m_partGenDesc.Lock();
|
||||
m_partGen.reset(new urde::CElementGen(m_partGenDesc,
|
||||
urde::CElementGen::EModelOrientationType::Normal,
|
||||
urde::CElementGen::EOptionalSystemFlags::None));
|
||||
m_partGen->SetGlobalScale({5.f, 5.f, 5.f});
|
||||
//m_partGen.reset(new urde::CElementGen(m_partGenDesc,
|
||||
// urde::CElementGen::EModelOrientationType::Normal,
|
||||
// urde::CElementGen::EOptionalSystemFlags::None));
|
||||
//m_partGen->SetGlobalScale({5.f, 5.f, 5.f});
|
||||
m_lineRenderer.reset(new urde::CLineRenderer(urde::CLineRenderer::EPrimitiveMode::LineStrip, 4, nullptr, true));
|
||||
|
||||
m_particleView.reset(new ParticleView(*this, m_viewResources, *m_rootView));
|
||||
|
||||
//m_moviePlayer.reset(new CMoviePlayer("Video/SpecialEnding.thp", 1.f, false, true));
|
||||
//m_moviePlayer->SetFrame({-1.0f, 1.0f, 0.f}, {-1.0f, -1.0f, 0.f}, {1.0f, -1.0f, 0.f}, {1.0f, 1.0f, 0.f});
|
||||
/*
|
||||
m_moviePlayer.reset(new CMoviePlayer("Video/SpecialEnding.thp", 1.f, false, true));
|
||||
m_moviePlayer->SetFrame({-1.0f, 1.0f, 0.f}, {-1.0f, -1.0f, 0.f}, {1.0f, -1.0f, 0.f}, {1.0f, 1.0f, 0.f});
|
||||
CDvdFile testRSF("Audio/frontend_1.rsf");
|
||||
u64 rsfLen = testRSF.Length();
|
||||
m_rsfBuf.reset(new u8[rsfLen]);
|
||||
|
|
|
@ -136,6 +136,11 @@ static const zeus::CMatrix4f PlusOneZ(1.f, 0.f, 0.f, 0.f,
|
|||
0.f, 0.f, 1.f, 1.f,
|
||||
0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
static const zeus::CMatrix4f PlusOneZFlip(1.f, 0.f, 0.f, 0.f,
|
||||
0.f, -1.f, 0.f, 0.f,
|
||||
0.f, 0.f, 1.f, 1.f,
|
||||
0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
zeus::CMatrix4f CGraphics::CalculatePerspectiveMatrix(float fovy, float aspect,
|
||||
float near, float far,
|
||||
bool forRenderer)
|
||||
|
@ -184,6 +189,14 @@ zeus::CMatrix4f CGraphics::CalculatePerspectiveMatrix(float fovy, float aspect,
|
|||
0.f, 0.f, -1.f, 0.f);
|
||||
return PlusOneZ * mat2;
|
||||
}
|
||||
case boo::IGraphicsDataFactory::Platform::Vulkan:
|
||||
{
|
||||
zeus::CMatrix4f mat2(2.f * st.x14_near / rml, 0.f, rpl / rml, 0.f,
|
||||
0.f, 2.f * st.x14_near / tmb, tpb / tmb, 0.f,
|
||||
0.f, 0.f, st.x18_far / fmn, st.x14_near * st.x18_far / fmn,
|
||||
0.f, 0.f, -1.f, 0.f);
|
||||
return PlusOneZFlip * mat2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,6 +237,14 @@ zeus::CMatrix4f CGraphics::GetPerspectiveProjectionMatrix(bool forRenderer)
|
|||
0.f, 0.f, -1.f, 0.f);
|
||||
return PlusOneZ * mat2;
|
||||
}
|
||||
case boo::IGraphicsDataFactory::Platform::Vulkan:
|
||||
{
|
||||
zeus::CMatrix4f mat2(2.f * g_Proj.x14_near / rml, 0.f, rpl / rml, 0.f,
|
||||
0.f, 2.f * g_Proj.x14_near / tmb, tpb / tmb, 0.f,
|
||||
0.f, 0.f, g_Proj.x18_far / fmn, g_Proj.x14_near * g_Proj.x18_far / fmn,
|
||||
0.f, 0.f, -1.f, 0.f);
|
||||
return PlusOneZFlip * mat2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,10 +41,10 @@ BOO_GLSL_BINDING_HEAD
|
|||
"\n"
|
||||
"SBINDING(0) in VertToFrag vtf;\n"
|
||||
"layout(location=0) out vec4 colorOut;\n"
|
||||
"TBINDING0 uniform sampler2D texs[1];\n"
|
||||
"TBINDING0 uniform sampler2D tex;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" colorOut = vtf.color * texture(texs[0], vtf.uv);\n"
|
||||
" colorOut = vtf.color * texture(tex, vtf.uv);\n"
|
||||
"}\n";
|
||||
|
||||
static const char* VS_GLSL_NOTEX =
|
||||
|
@ -127,11 +127,12 @@ struct OGLLineDataBindingFactory : CLineRendererShaders::IDataBindingFactory
|
|||
CLineRendererShaders::IDataBindingFactory* CLineRendererShaders::Initialize(boo::GLDataFactory::Context& ctx)
|
||||
{
|
||||
static const char* UniNames[] = {"LineUniform"};
|
||||
static const char* TexNames[] = {"tex"};
|
||||
|
||||
m_texAlpha = ctx.newShaderPipeline(VS_GLSL_TEX, FS_GLSL_TEX, 1, "texs", 1, UniNames,
|
||||
m_texAlpha = ctx.newShaderPipeline(VS_GLSL_TEX, FS_GLSL_TEX, 1, TexNames, 1, UniNames,
|
||||
boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha,
|
||||
boo::Primitive::TriStrips, false, true, false);
|
||||
m_texAdditive = ctx.newShaderPipeline(VS_GLSL_TEX, FS_GLSL_TEX, 1, "texs", 1, UniNames,
|
||||
m_texAdditive = ctx.newShaderPipeline(VS_GLSL_TEX, FS_GLSL_TEX, 1, TexNames, 1, UniNames,
|
||||
boo::BlendFactor::SrcAlpha, boo::BlendFactor::One,
|
||||
boo::Primitive::TriStrips, false, false, false);
|
||||
m_noTexAlpha = ctx.newShaderPipeline(VS_GLSL_NOTEX, FS_GLSL_NOTEX, 1, nullptr, 1, UniNames,
|
||||
|
|
|
@ -39,14 +39,16 @@ BOO_GLSL_BINDING_HEAD
|
|||
" vec2 uv;\n"
|
||||
"};\n"
|
||||
"SBINDING(0) in VertToFrag vtf;\n"
|
||||
"TBINDING0 uniform sampler2D texs[3];\n"
|
||||
"TBINDING0 uniform sampler2D texY;\n"
|
||||
"TBINDING1 uniform sampler2D texU;\n"
|
||||
"TBINDING2 uniform sampler2D texV;\n"
|
||||
"layout(location=0) out vec4 colorOut;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec3 yuv;\n"
|
||||
" yuv.r = texture(texs[0], vtf.uv).r;\n"
|
||||
" yuv.g = texture(texs[1], vtf.uv).r;\n"
|
||||
" yuv.b = texture(texs[2], vtf.uv).r;\n"
|
||||
" yuv.r = texture(texY, vtf.uv).r;\n"
|
||||
" yuv.g = texture(texU, vtf.uv).r;\n"
|
||||
" yuv.b = texture(texV, vtf.uv).r;\n"
|
||||
" yuv.r = 1.1643*(yuv.r-0.0625);\n"
|
||||
" yuv.g = yuv.g-0.5;\n"
|
||||
" yuv.b = yuv.b-0.5;\n"
|
||||
|
@ -190,6 +192,7 @@ static g72x_state StaticStateLeft = {};
|
|||
static g72x_state StaticStateRight = {};
|
||||
|
||||
static const char* BlockNames[] = {"SpecterViewBlock"};
|
||||
static const char* TexNames[] = {"texY", "texU", "texV"};
|
||||
|
||||
void CMoviePlayer::Initialize()
|
||||
{
|
||||
|
@ -209,7 +212,7 @@ void CMoviePlayer::Initialize()
|
|||
{
|
||||
case boo::IGraphicsDataFactory::Platform::OGL:
|
||||
YUVShaderPipeline = static_cast<boo::GLDataFactory::Context&>(ctx).newShaderPipeline
|
||||
(VS_GLSL_YUV, FS_GLSL_YUV, 3, "texs", 1, BlockNames,
|
||||
(VS_GLSL_YUV, FS_GLSL_YUV, 3, TexNames, 1, BlockNames,
|
||||
boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha,
|
||||
boo::Primitive::TriStrips, false, false, false);
|
||||
break;
|
||||
|
|
|
@ -450,6 +450,7 @@ CElementGen::CElementGen(const TToken<CGenDescription>& gen,
|
|||
{
|
||||
m_shaderClass = CElementGenShaders::GetShaderClass(*this);
|
||||
size_t maxInsts = x224_29_MBLR ? (m_maxMBSP * x70_MAXP) : x70_MAXP;
|
||||
maxInsts = (maxInsts == 0 ? 256 : maxInsts);
|
||||
m_gfxToken = CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) -> bool
|
||||
{
|
||||
m_instBuf = ctx.newDynamicBuffer(boo::BufferUse::Vertex, ShadClsSizes[int(m_shaderClass)], maxInsts);
|
||||
|
|
|
@ -46,10 +46,10 @@ BOO_GLSL_BINDING_HEAD
|
|||
"\n"
|
||||
"SBINDING(0) in VertToFrag vtf;\n"
|
||||
"layout(location=0) out vec4 colorOut;\n"
|
||||
"TBINDING0 uniform sampler2D texs[1];\n"
|
||||
"TBINDING0 uniform sampler2D tex;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" colorOut = vtf.color * texture(texs[0], vtf.uv);\n"
|
||||
" colorOut = vtf.color * texture(tex, vtf.uv);\n"
|
||||
"}\n";
|
||||
|
||||
static const char* FS_GLSL_TEX_REDTOALPHA =
|
||||
|
@ -63,10 +63,10 @@ BOO_GLSL_BINDING_HEAD
|
|||
"\n"
|
||||
"SBINDING(0) in VertToFrag vtf;\n"
|
||||
"layout(location=0) out vec4 colorOut;\n"
|
||||
"TBINDING0 uniform sampler2D texs[1];\n"
|
||||
"TBINDING0 uniform sampler2D tex;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" colorOut = vtf.color * texture(texs[0], vtf.uv);\n"
|
||||
" colorOut = vtf.color * texture(tex, vtf.uv);\n"
|
||||
" colorOut.a = colorOut.r;\n"
|
||||
"}\n";
|
||||
|
||||
|
@ -116,12 +116,14 @@ BOO_GLSL_BINDING_HEAD
|
|||
"\n"
|
||||
"SBINDING(0) in VertToFrag vtf;\n"
|
||||
"layout(location=0) out vec4 colorOut;\n"
|
||||
"TBINDING0 uniform sampler2D texs[3];\n"
|
||||
"TBINDING0 uniform sampler2D texrMap;\n"
|
||||
"TBINDING1 uniform sampler2D sceneMap;\n"
|
||||
"TBINDING2 uniform sampler2D tindMap;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec2 tindTexel = texture(texs[2], vtf.uvTind).zw;\n"
|
||||
" vec4 sceneTexel = texture(texs[1], mix(vtf.uvScene.xy, vtf.uvScene.zw, tindTexel));\n"
|
||||
" vec4 texrTexel = texture(texs[0], vtf.uvTexr);\n"
|
||||
" vec2 tindTexel = texture(tindMap, vtf.uvTind).zw;\n"
|
||||
" vec4 sceneTexel = texture(sceneMap, mix(vtf.uvScene.xy, vtf.uvScene.zw, tindTexel));\n"
|
||||
" vec4 texrTexel = texture(texrMap, vtf.uvTexr);\n"
|
||||
" colorOut = vtf.color * sceneTexel + texrTexel;\n"
|
||||
" colorOut.a = vtf.color.a * texrTexel.a;\n"
|
||||
"}\n";
|
||||
|
@ -139,12 +141,14 @@ BOO_GLSL_BINDING_HEAD
|
|||
"\n"
|
||||
"SBINDING(0) in VertToFrag vtf;\n"
|
||||
"layout(location=0) out vec4 colorOut;\n"
|
||||
"TBINDING0 uniform sampler2D texs[3];\n"
|
||||
"TBINDING0 uniform sampler2D texrMap;\n"
|
||||
"TBINDING1 uniform sampler2D sceneMap;\n"
|
||||
"TBINDING2 uniform sampler2D tindMap;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec2 tindTexel = texture(texs[2], vtf.uvTind).zw;\n"
|
||||
" vec4 sceneTexel = texture(texs[1], mix(vtf.uvScene.xy, vtf.uvScene.zw, tindTexel));\n"
|
||||
" colorOut = vtf.color * sceneTexel * texture(texs[0], vtf.uvTexr);\n"
|
||||
" vec2 tindTexel = texture(tindMap, vtf.uvTind).zw;\n"
|
||||
" vec4 sceneTexel = texture(sceneMap, mix(vtf.uvScene.xy, vtf.uvScene.zw, tindTexel));\n"
|
||||
" colorOut = vtf.color * sceneTexel * texture(texrMap, vtf.uvTexr);\n"
|
||||
"}\n";
|
||||
|
||||
static const char* VS_GLSL_NOTEX =
|
||||
|
@ -270,53 +274,55 @@ struct OGLElementDataBindingFactory : CElementGenShaders::IDataBindingFactory
|
|||
};
|
||||
|
||||
static const char* UniNames[] = {"ParticleUniform"};
|
||||
static const char* TexNames[] = {"tex"};
|
||||
static const char* TindTexNames[] = {"texrMap", "sceneMap", "tindMap"};
|
||||
|
||||
CElementGenShaders::IDataBindingFactory* CElementGenShaders::Initialize(boo::GLDataFactory::Context& ctx)
|
||||
{
|
||||
m_texZTestZWrite = ctx.newShaderPipeline(VS_GLSL_TEX, FS_GLSL_TEX, 1, "texs", 1, UniNames,
|
||||
m_texZTestZWrite = ctx.newShaderPipeline(VS_GLSL_TEX, FS_GLSL_TEX, 1, TexNames, 1, UniNames,
|
||||
boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha,
|
||||
boo::Primitive::TriStrips, true, true, false);
|
||||
m_texNoZTestZWrite = ctx.newShaderPipeline(VS_GLSL_TEX, FS_GLSL_TEX, 1, "texs", 1, UniNames,
|
||||
m_texNoZTestZWrite = ctx.newShaderPipeline(VS_GLSL_TEX, FS_GLSL_TEX, 1, TexNames, 1, UniNames,
|
||||
boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha,
|
||||
boo::Primitive::TriStrips, false, true, false);
|
||||
m_texZTestNoZWrite = ctx.newShaderPipeline(VS_GLSL_TEX, FS_GLSL_TEX, 1, "texs", 1, UniNames,
|
||||
m_texZTestNoZWrite = ctx.newShaderPipeline(VS_GLSL_TEX, FS_GLSL_TEX, 1, TexNames, 1, UniNames,
|
||||
boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha,
|
||||
boo::Primitive::TriStrips, true, false, false);
|
||||
m_texNoZTestNoZWrite = ctx.newShaderPipeline(VS_GLSL_TEX, FS_GLSL_TEX, 1, "texs", 1, UniNames,
|
||||
m_texNoZTestNoZWrite = ctx.newShaderPipeline(VS_GLSL_TEX, FS_GLSL_TEX, 1, TexNames, 1, UniNames,
|
||||
boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha,
|
||||
boo::Primitive::TriStrips, false, false, false);
|
||||
|
||||
m_texAdditiveZTest = ctx.newShaderPipeline(VS_GLSL_TEX, FS_GLSL_TEX, 1, "texs", 1, UniNames,
|
||||
m_texAdditiveZTest = ctx.newShaderPipeline(VS_GLSL_TEX, FS_GLSL_TEX, 1, TexNames, 1, UniNames,
|
||||
boo::BlendFactor::SrcAlpha, boo::BlendFactor::One,
|
||||
boo::Primitive::TriStrips, true, false, false);
|
||||
m_texAdditiveNoZTest = ctx.newShaderPipeline(VS_GLSL_TEX, FS_GLSL_TEX, 1, "texs", 1, UniNames,
|
||||
m_texAdditiveNoZTest = ctx.newShaderPipeline(VS_GLSL_TEX, FS_GLSL_TEX, 1, TexNames, 1, UniNames,
|
||||
boo::BlendFactor::SrcAlpha, boo::BlendFactor::One,
|
||||
boo::Primitive::TriStrips, false, false, false);
|
||||
|
||||
m_texRedToAlphaZTest = ctx.newShaderPipeline(VS_GLSL_TEX, FS_GLSL_TEX_REDTOALPHA, 1, "texs", 1, UniNames,
|
||||
m_texRedToAlphaZTest = ctx.newShaderPipeline(VS_GLSL_TEX, FS_GLSL_TEX_REDTOALPHA, 1, TexNames, 1, UniNames,
|
||||
boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha,
|
||||
boo::Primitive::TriStrips, true, false, false);
|
||||
m_texRedToAlphaNoZTest = ctx.newShaderPipeline(VS_GLSL_TEX, FS_GLSL_TEX_REDTOALPHA, 1, "texs", 1, UniNames,
|
||||
m_texRedToAlphaNoZTest = ctx.newShaderPipeline(VS_GLSL_TEX, FS_GLSL_TEX_REDTOALPHA, 1, TexNames, 1, UniNames,
|
||||
boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha,
|
||||
boo::Primitive::TriStrips, false, false, false);
|
||||
|
||||
m_indTexZWrite = ctx.newShaderPipeline(VS_GLSL_INDTEX, FS_GLSL_INDTEX, 3, "texs", 1, UniNames,
|
||||
m_indTexZWrite = ctx.newShaderPipeline(VS_GLSL_INDTEX, FS_GLSL_INDTEX, 3, TindTexNames, 1, UniNames,
|
||||
boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha,
|
||||
boo::Primitive::TriStrips, false, true, false);
|
||||
m_indTexNoZWrite = ctx.newShaderPipeline(VS_GLSL_INDTEX, FS_GLSL_INDTEX, 3, "texs", 1, UniNames,
|
||||
m_indTexNoZWrite = ctx.newShaderPipeline(VS_GLSL_INDTEX, FS_GLSL_INDTEX, 3, TindTexNames, 1, UniNames,
|
||||
boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha,
|
||||
boo::Primitive::TriStrips, false, false, false);
|
||||
m_indTexAdditive = ctx.newShaderPipeline(VS_GLSL_INDTEX, FS_GLSL_INDTEX, 3, "texs", 1, UniNames,
|
||||
m_indTexAdditive = ctx.newShaderPipeline(VS_GLSL_INDTEX, FS_GLSL_INDTEX, 3, TindTexNames, 1, UniNames,
|
||||
boo::BlendFactor::SrcAlpha, boo::BlendFactor::One,
|
||||
boo::Primitive::TriStrips, false, true, false);
|
||||
|
||||
m_cindTexZWrite = ctx.newShaderPipeline(VS_GLSL_INDTEX, FS_GLSL_CINDTEX, 3, "texs", 1, UniNames,
|
||||
m_cindTexZWrite = ctx.newShaderPipeline(VS_GLSL_INDTEX, FS_GLSL_CINDTEX, 3, TindTexNames, 1, UniNames,
|
||||
boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha,
|
||||
boo::Primitive::TriStrips, false, true, false);
|
||||
m_cindTexNoZWrite = ctx.newShaderPipeline(VS_GLSL_INDTEX, FS_GLSL_CINDTEX, 3, "texs", 1, UniNames,
|
||||
m_cindTexNoZWrite = ctx.newShaderPipeline(VS_GLSL_INDTEX, FS_GLSL_CINDTEX, 3, TindTexNames, 1, UniNames,
|
||||
boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha,
|
||||
boo::Primitive::TriStrips, false, false, false);
|
||||
m_cindTexAdditive = ctx.newShaderPipeline(VS_GLSL_INDTEX, FS_GLSL_CINDTEX, 3, "texs", 1, UniNames,
|
||||
m_cindTexAdditive = ctx.newShaderPipeline(VS_GLSL_INDTEX, FS_GLSL_CINDTEX, 3, TindTexNames, 1, UniNames,
|
||||
boo::BlendFactor::SrcAlpha, boo::BlendFactor::One,
|
||||
boo::Primitive::TriStrips, false, true, false);
|
||||
|
||||
|
|
|
@ -1157,7 +1157,7 @@ void CParticleDataFactory::LoadGPSMTokens(CGenDescription* desc)
|
|||
}
|
||||
|
||||
CFactoryFnReturn FParticleFactory(const SObjectTag& tag, CInputStream& in,
|
||||
const CVParamTransfer& vparms)
|
||||
const CVParamTransfer& vparms)
|
||||
{
|
||||
CSimplePool* sp = static_cast<CSimplePool*>(static_cast<TObjOwnerParam<IObjectStore*>*>(vparms.GetObj())->GetParam());
|
||||
return TToken<CGenDescription>::GetIObjObjectFor(std::unique_ptr<CGenDescription>(CParticleDataFactory::GetGeneratorDesc(in, sp)));
|
||||
|
|
2
amuse
2
amuse
|
@ -1 +1 @@
|
|||
Subproject commit 3a7b43a63a0fdb20f2d9b53f2d39ef91e891bde0
|
||||
Subproject commit 596bc66ce62220bc5bca55ec3eae768ae9f6b333
|
2
hecl
2
hecl
|
@ -1 +1 @@
|
|||
Subproject commit eeb595c4e1bfb67a7fecc24086fbae1a4c627df9
|
||||
Subproject commit cbb9c25db86a5ff36afc1391f2f4e37a2b96db47
|
2
specter
2
specter
|
@ -1 +1 @@
|
|||
Subproject commit 2eb988f115ec75e6f39ae95bb702ca9ca7632092
|
||||
Subproject commit 53432805c7e12472f3b66f10eeaf9415003bae1a
|
Loading…
Reference in New Issue