renderer_opengl: Implement diffuse component of HW fragment lighting.
This commit is contained in:
parent
b003075570
commit
afbef52516
|
@ -662,17 +662,18 @@ struct Regs {
|
||||||
LN = 3, // Cosine of the angle between the light and the normal vectors
|
LN = 3, // Cosine of the angle between the light and the normal vectors
|
||||||
};
|
};
|
||||||
|
|
||||||
struct {
|
|
||||||
union LightColor {
|
union LightColor {
|
||||||
BitField< 0, 10, u32> b;
|
BitField< 0, 10, u32> b;
|
||||||
BitField<10, 10, u32> g;
|
BitField<10, 10, u32> g;
|
||||||
BitField<20, 10, u32> r;
|
BitField<20, 10, u32> r;
|
||||||
|
|
||||||
Math::Vec3f ToVec3f() const {
|
Math::Vec3f ToVec3f() const {
|
||||||
|
// These fields are 10 bits wide, however 255 corresponds to 1.0f for each color component
|
||||||
return Math::MakeVec((f32)r / 255.f, (f32)g / 255.f, (f32)b / 255.f);
|
return Math::MakeVec((f32)r / 255.f, (f32)g / 255.f, (f32)b / 255.f);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct {
|
||||||
struct LightSrc {
|
struct LightSrc {
|
||||||
LightColor specular_0; // material.specular_0 * light.specular_0
|
LightColor specular_0; // material.specular_0 * light.specular_0
|
||||||
LightColor specular_1; // material.specular_1 * light.specular_1
|
LightColor specular_1; // material.specular_1 * light.specular_1
|
||||||
|
|
|
@ -75,6 +75,12 @@ void RasterizerOpenGL::InitObjects() {
|
||||||
glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD1);
|
glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD1);
|
||||||
glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD2);
|
glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD2);
|
||||||
|
|
||||||
|
glVertexAttribPointer(GLShader::ATTRIBUTE_NORMQUAT, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, normquat));
|
||||||
|
glEnableVertexAttribArray(GLShader::ATTRIBUTE_NORMQUAT);
|
||||||
|
|
||||||
|
glVertexAttribPointer(GLShader::ATTRIBUTE_VIEW, 3, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, view));
|
||||||
|
glEnableVertexAttribArray(GLShader::ATTRIBUTE_VIEW);
|
||||||
|
|
||||||
SetShader();
|
SetShader();
|
||||||
|
|
||||||
// Create textures for OGL framebuffer that will be rendered to, initially 1x1 to succeed in framebuffer creation
|
// Create textures for OGL framebuffer that will be rendered to, initially 1x1 to succeed in framebuffer creation
|
||||||
|
@ -283,6 +289,98 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
|
||||||
case PICA_REG_INDEX(tev_combiner_buffer_color):
|
case PICA_REG_INDEX(tev_combiner_buffer_color):
|
||||||
SyncCombinerColor();
|
SyncCombinerColor();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// Fragment lighting diffuse color
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[0].diffuse, 0x142 + 0 * 0x10):
|
||||||
|
SyncLightDiffuse(0);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[1].diffuse, 0x142 + 1 * 0x10):
|
||||||
|
SyncLightDiffuse(1);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[2].diffuse, 0x142 + 2 * 0x10):
|
||||||
|
SyncLightDiffuse(2);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[3].diffuse, 0x142 + 3 * 0x10):
|
||||||
|
SyncLightDiffuse(3);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[4].diffuse, 0x142 + 4 * 0x10):
|
||||||
|
SyncLightDiffuse(4);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[5].diffuse, 0x142 + 5 * 0x10):
|
||||||
|
SyncLightDiffuse(5);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[6].diffuse, 0x142 + 6 * 0x10):
|
||||||
|
SyncLightDiffuse(6);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[7].diffuse, 0x142 + 7 * 0x10):
|
||||||
|
SyncLightDiffuse(7);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Fragment lighting ambient color
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[0].ambient, 0x143 + 0 * 0x10):
|
||||||
|
SyncLightAmbient(0);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[1].ambient, 0x143 + 1 * 0x10):
|
||||||
|
SyncLightAmbient(1);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[2].ambient, 0x143 + 2 * 0x10):
|
||||||
|
SyncLightAmbient(2);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[3].ambient, 0x143 + 3 * 0x10):
|
||||||
|
SyncLightAmbient(3);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[4].ambient, 0x143 + 4 * 0x10):
|
||||||
|
SyncLightAmbient(4);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[5].ambient, 0x143 + 5 * 0x10):
|
||||||
|
SyncLightAmbient(5);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[6].ambient, 0x143 + 6 * 0x10):
|
||||||
|
SyncLightAmbient(6);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[7].ambient, 0x143 + 7 * 0x10):
|
||||||
|
SyncLightAmbient(7);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Fragment lighting position
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[0].x, 0x144 + 0 * 0x10):
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[0].z, 0x145 + 0 * 0x10):
|
||||||
|
SyncLightPosition(0);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[1].x, 0x144 + 1 * 0x10):
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[1].z, 0x145 + 1 * 0x10):
|
||||||
|
SyncLightPosition(1);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[2].x, 0x144 + 2 * 0x10):
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[2].z, 0x145 + 2 * 0x10):
|
||||||
|
SyncLightPosition(2);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[3].x, 0x144 + 3 * 0x10):
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[3].z, 0x145 + 3 * 0x10):
|
||||||
|
SyncLightPosition(3);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[4].x, 0x144 + 4 * 0x10):
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[4].z, 0x145 + 4 * 0x10):
|
||||||
|
SyncLightPosition(4);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[5].x, 0x144 + 5 * 0x10):
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[5].z, 0x145 + 5 * 0x10):
|
||||||
|
SyncLightPosition(5);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[6].x, 0x144 + 6 * 0x10):
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[6].z, 0x145 + 6 * 0x10):
|
||||||
|
SyncLightPosition(6);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[7].x, 0x144 + 7 * 0x10):
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.light[7].z, 0x145 + 7 * 0x10):
|
||||||
|
SyncLightPosition(7);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Fragment lighting global ambient color (emission + ambient * ambient)
|
||||||
|
case PICA_REG_INDEX_WORKAROUND(lighting.global_ambient, 0x1c0):
|
||||||
|
SyncGlobalAmbient();
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -503,6 +601,13 @@ void RasterizerOpenGL::SetShader() {
|
||||||
auto& tev_stages = Pica::g_state.regs.GetTevStages();
|
auto& tev_stages = Pica::g_state.regs.GetTevStages();
|
||||||
for (int index = 0; index < tev_stages.size(); ++index)
|
for (int index = 0; index < tev_stages.size(); ++index)
|
||||||
SyncTevConstColor(index, tev_stages[index]);
|
SyncTevConstColor(index, tev_stages[index]);
|
||||||
|
|
||||||
|
SyncGlobalAmbient();
|
||||||
|
for (int light_index = 0; light_index < 8; light_index++) {
|
||||||
|
SyncLightDiffuse(light_index);
|
||||||
|
SyncLightAmbient(light_index);
|
||||||
|
SyncLightPosition(light_index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncFramebuffer() {
|
void RasterizerOpenGL::SyncFramebuffer() {
|
||||||
|
@ -683,6 +788,42 @@ void RasterizerOpenGL::SyncTevConstColor(int stage_index, const Pica::Regs::TevS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RasterizerOpenGL::SyncGlobalAmbient() {
|
||||||
|
auto color = PicaToGL::LightColor(Pica::g_state.regs.lighting.global_ambient);
|
||||||
|
if (color != uniform_block_data.data.lighting_global_ambient) {
|
||||||
|
uniform_block_data.data.lighting_global_ambient = color;
|
||||||
|
uniform_block_data.dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerOpenGL::SyncLightDiffuse(int light_index) {
|
||||||
|
auto color = PicaToGL::LightColor(Pica::g_state.regs.lighting.light[light_index].diffuse);
|
||||||
|
if (color != uniform_block_data.data.light_src[light_index].diffuse) {
|
||||||
|
uniform_block_data.data.light_src[light_index].diffuse = color;
|
||||||
|
uniform_block_data.dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerOpenGL::SyncLightAmbient(int light_index) {
|
||||||
|
auto color = PicaToGL::LightColor(Pica::g_state.regs.lighting.light[light_index].ambient);
|
||||||
|
if (color != uniform_block_data.data.light_src[light_index].ambient) {
|
||||||
|
uniform_block_data.data.light_src[light_index].ambient = color;
|
||||||
|
uniform_block_data.dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerOpenGL::SyncLightPosition(int light_index) {
|
||||||
|
std::array<GLfloat, 3> position = {
|
||||||
|
Pica::float16::FromRawFloat16(Pica::g_state.regs.lighting.light[light_index].x).ToFloat32(),
|
||||||
|
Pica::float16::FromRawFloat16(Pica::g_state.regs.lighting.light[light_index].y).ToFloat32(),
|
||||||
|
Pica::float16::FromRawFloat16(Pica::g_state.regs.lighting.light[light_index].z).ToFloat32() };
|
||||||
|
|
||||||
|
if (position != uniform_block_data.data.light_src[light_index].position) {
|
||||||
|
uniform_block_data.data.light_src[light_index].position = position;
|
||||||
|
uniform_block_data.dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncDrawState() {
|
void RasterizerOpenGL::SyncDrawState() {
|
||||||
const auto& regs = Pica::g_state.regs;
|
const auto& regs = Pica::g_state.regs;
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,18 @@ struct PicaShaderConfig {
|
||||||
regs.tev_combiner_buffer_input.update_mask_rgb.Value() |
|
regs.tev_combiner_buffer_input.update_mask_rgb.Value() |
|
||||||
regs.tev_combiner_buffer_input.update_mask_a.Value() << 4;
|
regs.tev_combiner_buffer_input.update_mask_a.Value() << 4;
|
||||||
|
|
||||||
|
// Fragment lighting
|
||||||
|
|
||||||
|
res.lighting_enabled = !regs.lighting.disable;
|
||||||
|
res.num_lights = regs.lighting.src_num + 1;
|
||||||
|
|
||||||
|
for (unsigned light_index = 0; light_index < res.num_lights; ++light_index) {
|
||||||
|
unsigned num = regs.lighting.light_enable.GetNum(light_index);
|
||||||
|
res.light_src[light_index].num = num;
|
||||||
|
res.light_src[light_index].directional = regs.lighting.light[num].w;
|
||||||
|
res.light_src[light_index].two_sided_diffuse = regs.lighting.light[num].two_sided_diffuse;
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,6 +101,16 @@ struct PicaShaderConfig {
|
||||||
Pica::Regs::CompareFunc alpha_test_func;
|
Pica::Regs::CompareFunc alpha_test_func;
|
||||||
std::array<Pica::Regs::TevStageConfig, 6> tev_stages = {};
|
std::array<Pica::Regs::TevStageConfig, 6> tev_stages = {};
|
||||||
u8 combiner_buffer_input;
|
u8 combiner_buffer_input;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
unsigned num;
|
||||||
|
bool directional;
|
||||||
|
bool two_sided_diffuse;
|
||||||
|
bool dist_atten_enabled;
|
||||||
|
} light_src[8];
|
||||||
|
|
||||||
|
bool lighting_enabled;
|
||||||
|
unsigned num_lights;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
|
@ -182,6 +204,13 @@ private:
|
||||||
tex_coord1[1] = v.tc1.y.ToFloat32();
|
tex_coord1[1] = v.tc1.y.ToFloat32();
|
||||||
tex_coord2[0] = v.tc2.x.ToFloat32();
|
tex_coord2[0] = v.tc2.x.ToFloat32();
|
||||||
tex_coord2[1] = v.tc2.y.ToFloat32();
|
tex_coord2[1] = v.tc2.y.ToFloat32();
|
||||||
|
normquat[0] = v.quat.x.ToFloat32();
|
||||||
|
normquat[1] = v.quat.y.ToFloat32();
|
||||||
|
normquat[2] = v.quat.z.ToFloat32();
|
||||||
|
normquat[3] = v.quat.w.ToFloat32();
|
||||||
|
view[0] = v.view.x.ToFloat32();
|
||||||
|
view[1] = v.view.y.ToFloat32();
|
||||||
|
view[2] = v.view.z.ToFloat32();
|
||||||
}
|
}
|
||||||
|
|
||||||
GLfloat position[4];
|
GLfloat position[4];
|
||||||
|
@ -189,6 +218,17 @@ private:
|
||||||
GLfloat tex_coord0[2];
|
GLfloat tex_coord0[2];
|
||||||
GLfloat tex_coord1[2];
|
GLfloat tex_coord1[2];
|
||||||
GLfloat tex_coord2[2];
|
GLfloat tex_coord2[2];
|
||||||
|
GLfloat normquat[4];
|
||||||
|
GLfloat view[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LightSrc {
|
||||||
|
std::array<GLfloat, 3> diffuse;
|
||||||
|
INSERT_PADDING_WORDS(1);
|
||||||
|
std::array<GLfloat, 3> ambient;
|
||||||
|
INSERT_PADDING_WORDS(1);
|
||||||
|
std::array<GLfloat, 3> position;
|
||||||
|
INSERT_PADDING_WORDS(1);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Uniform structure for the Uniform Buffer Object, all members must be 16-byte aligned
|
/// Uniform structure for the Uniform Buffer Object, all members must be 16-byte aligned
|
||||||
|
@ -198,11 +238,14 @@ private:
|
||||||
std::array<GLfloat, 4> tev_combiner_buffer_color;
|
std::array<GLfloat, 4> tev_combiner_buffer_color;
|
||||||
GLint alphatest_ref;
|
GLint alphatest_ref;
|
||||||
GLfloat depth_offset;
|
GLfloat depth_offset;
|
||||||
INSERT_PADDING_BYTES(8);
|
INSERT_PADDING_WORDS(2);
|
||||||
|
std::array<GLfloat, 3> lighting_global_ambient;
|
||||||
|
INSERT_PADDING_WORDS(1);
|
||||||
|
LightSrc light_src[8];
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(UniformData) == 0x80, "The size of the UniformData structure has changed, update the structure in the shader");
|
static_assert(sizeof(UniformData) == 0x210, "The size of the UniformData structure has changed, update the structure in the shader");
|
||||||
static_assert(sizeof(UniformData) < 16000, "UniformData structure must be less than 16kb as per the OpenGL spec");
|
static_assert(sizeof(UniformData) < 16384, "UniformData structure must be less than 16kb as per the OpenGL spec");
|
||||||
|
|
||||||
/// Reconfigure the OpenGL color texture to use the given format and dimensions
|
/// Reconfigure the OpenGL color texture to use the given format and dimensions
|
||||||
void ReconfigureColorTexture(TextureInfo& texture, Pica::Regs::ColorFormat format, u32 width, u32 height);
|
void ReconfigureColorTexture(TextureInfo& texture, Pica::Regs::ColorFormat format, u32 width, u32 height);
|
||||||
|
@ -249,6 +292,18 @@ private:
|
||||||
/// Syncs the TEV combiner color buffer to match the PICA register
|
/// Syncs the TEV combiner color buffer to match the PICA register
|
||||||
void SyncCombinerColor();
|
void SyncCombinerColor();
|
||||||
|
|
||||||
|
/// Syncs the lighting global ambient color to match the PICA register
|
||||||
|
void SyncGlobalAmbient();
|
||||||
|
|
||||||
|
/// Syncs the specified light's diffuse color to match the PICA register
|
||||||
|
void SyncLightDiffuse(int light_index);
|
||||||
|
|
||||||
|
/// Syncs the specified light's ambient color to match the PICA register
|
||||||
|
void SyncLightAmbient(int light_index);
|
||||||
|
|
||||||
|
/// Syncs the specified light's position to match the PICA register
|
||||||
|
void SyncLightPosition(int light_index);
|
||||||
|
|
||||||
/// Syncs the remaining OpenGL drawing state to match the current PICA state
|
/// Syncs the remaining OpenGL drawing state to match the current PICA state
|
||||||
void SyncDrawState();
|
void SyncDrawState();
|
||||||
|
|
||||||
|
|
|
@ -32,8 +32,7 @@ static void AppendSource(std::string& out, TevStageConfig::Source source,
|
||||||
out += "primary_color";
|
out += "primary_color";
|
||||||
break;
|
break;
|
||||||
case Source::PrimaryFragmentColor:
|
case Source::PrimaryFragmentColor:
|
||||||
// HACK: Until we implement fragment lighting, use primary_color
|
out += "primary_fragment_color";
|
||||||
out += "primary_color";
|
|
||||||
break;
|
break;
|
||||||
case Source::SecondaryFragmentColor:
|
case Source::SecondaryFragmentColor:
|
||||||
// HACK: Until we implement fragment lighting, use zero
|
// HACK: Until we implement fragment lighting, use zero
|
||||||
|
@ -324,24 +323,67 @@ std::string GenerateFragmentShader(const PicaShaderConfig& config) {
|
||||||
std::string out = R"(
|
std::string out = R"(
|
||||||
#version 330 core
|
#version 330 core
|
||||||
#define NUM_TEV_STAGES 6
|
#define NUM_TEV_STAGES 6
|
||||||
|
#define NUM_LIGHTS 8
|
||||||
|
|
||||||
in vec4 primary_color;
|
in vec4 primary_color;
|
||||||
in vec2 texcoord[3];
|
in vec2 texcoord[3];
|
||||||
|
in vec4 normquat;
|
||||||
|
in vec3 view;
|
||||||
|
|
||||||
out vec4 color;
|
out vec4 color;
|
||||||
|
|
||||||
|
struct LightSrc {
|
||||||
|
vec3 diffuse;
|
||||||
|
vec3 ambient;
|
||||||
|
vec3 position;
|
||||||
|
};
|
||||||
|
|
||||||
layout (std140) uniform shader_data {
|
layout (std140) uniform shader_data {
|
||||||
vec4 const_color[NUM_TEV_STAGES];
|
vec4 const_color[NUM_TEV_STAGES];
|
||||||
vec4 tev_combiner_buffer_color;
|
vec4 tev_combiner_buffer_color;
|
||||||
int alphatest_ref;
|
int alphatest_ref;
|
||||||
float depth_offset;
|
float depth_offset;
|
||||||
|
vec3 lighting_global_ambient;
|
||||||
|
LightSrc light_src[NUM_LIGHTS];
|
||||||
};
|
};
|
||||||
|
|
||||||
uniform sampler2D tex[3];
|
uniform sampler2D tex[3];
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
vec4 primary_fragment_color = vec4(0.0);
|
||||||
)";
|
)";
|
||||||
|
|
||||||
|
if (config.lighting_enabled) {
|
||||||
|
out += "vec3 normal = normalize(vec3(\n";
|
||||||
|
out += " 2.f*(normquat.x*normquat.z + normquat.y*normquat.w),\n";
|
||||||
|
out += " 2.f*(normquat.y*normquat.z + normquat.x*normquat.w),\n";
|
||||||
|
out += " 1.f - 2.f*(normquat.x*normquat.x + normquat.y*normquat.y)));\n";
|
||||||
|
out += "vec4 secondary_color = vec4(0.0);\n";
|
||||||
|
out += "vec3 diffuse_sum = vec3(0.0);\n";
|
||||||
|
out += "vec3 fragment_position = -view;\n";
|
||||||
|
|
||||||
|
for (unsigned light_index = 0; light_index < config.num_lights; ++light_index) {
|
||||||
|
unsigned num = config.light_src[light_index].num;
|
||||||
|
|
||||||
|
std::string light_vector;
|
||||||
|
if (config.light_src[light_index].directional)
|
||||||
|
light_vector = "normalize(-light_src[" + std::to_string(num) + "].position)";
|
||||||
|
else
|
||||||
|
light_vector = "normalize(light_src[" + std::to_string(num) + "].position - fragment_position)";
|
||||||
|
|
||||||
|
std::string dot_product;
|
||||||
|
if (config.light_src[light_index].two_sided_diffuse)
|
||||||
|
dot_product = "abs(dot(" + light_vector + ", normal))";
|
||||||
|
else
|
||||||
|
dot_product = "max(dot(" + light_vector + ", normal), 0.0)";
|
||||||
|
|
||||||
|
out += "diffuse_sum += ((light_src[" + std::to_string(num) + "].diffuse * " + dot_product + ") + light_src[" + std::to_string(num) + "].ambient) * 1.0;\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
out += "diffuse_sum += lighting_global_ambient;\n";
|
||||||
|
out += "primary_fragment_color = vec4(clamp(diffuse_sum, vec3(0.0), vec3(1.0)), 1.0);\n";
|
||||||
|
}
|
||||||
|
|
||||||
// Do not do any sort of processing if it's obvious we're not going to pass the alpha test
|
// Do not do any sort of processing if it's obvious we're not going to pass the alpha test
|
||||||
if (config.alpha_test_func == Regs::CompareFunc::Never) {
|
if (config.alpha_test_func == Regs::CompareFunc::Never) {
|
||||||
out += "discard; }";
|
out += "discard; }";
|
||||||
|
@ -369,21 +411,28 @@ void main() {
|
||||||
|
|
||||||
std::string GenerateVertexShader() {
|
std::string GenerateVertexShader() {
|
||||||
std::string out = "#version 330 core\n";
|
std::string out = "#version 330 core\n";
|
||||||
|
|
||||||
out += "layout(location = " + std::to_string((int)ATTRIBUTE_POSITION) + ") in vec4 vert_position;\n";
|
out += "layout(location = " + std::to_string((int)ATTRIBUTE_POSITION) + ") in vec4 vert_position;\n";
|
||||||
out += "layout(location = " + std::to_string((int)ATTRIBUTE_COLOR) + ") in vec4 vert_color;\n";
|
out += "layout(location = " + std::to_string((int)ATTRIBUTE_COLOR) + ") in vec4 vert_color;\n";
|
||||||
out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0) + ") in vec2 vert_texcoord0;\n";
|
out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0) + ") in vec2 vert_texcoord0;\n";
|
||||||
out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD1) + ") in vec2 vert_texcoord1;\n";
|
out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD1) + ") in vec2 vert_texcoord1;\n";
|
||||||
out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD2) + ") in vec2 vert_texcoord2;\n";
|
out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD2) + ") in vec2 vert_texcoord2;\n";
|
||||||
|
out += "layout(location = " + std::to_string((int)ATTRIBUTE_NORMQUAT) + ") in vec4 vert_normquat;\n";
|
||||||
|
out += "layout(location = " + std::to_string((int)ATTRIBUTE_VIEW) + ") in vec3 vert_view;\n";
|
||||||
|
|
||||||
out += R"(
|
out += R"(
|
||||||
out vec4 primary_color;
|
out vec4 primary_color;
|
||||||
out vec2 texcoord[3];
|
out vec2 texcoord[3];
|
||||||
|
out vec4 normquat;
|
||||||
|
out vec3 view;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
primary_color = vert_color;
|
primary_color = vert_color;
|
||||||
texcoord[0] = vert_texcoord0;
|
texcoord[0] = vert_texcoord0;
|
||||||
texcoord[1] = vert_texcoord1;
|
texcoord[1] = vert_texcoord1;
|
||||||
texcoord[2] = vert_texcoord2;
|
texcoord[2] = vert_texcoord2;
|
||||||
|
normquat = vert_normquat;
|
||||||
|
view = vert_view;
|
||||||
gl_Position = vec4(vert_position.x, vert_position.y, -vert_position.z, vert_position.w);
|
gl_Position = vec4(vert_position.x, vert_position.y, -vert_position.z, vert_position.w);
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
|
|
@ -14,6 +14,8 @@ enum Attributes {
|
||||||
ATTRIBUTE_TEXCOORD0,
|
ATTRIBUTE_TEXCOORD0,
|
||||||
ATTRIBUTE_TEXCOORD1,
|
ATTRIBUTE_TEXCOORD1,
|
||||||
ATTRIBUTE_TEXCOORD2,
|
ATTRIBUTE_TEXCOORD2,
|
||||||
|
ATTRIBUTE_NORMQUAT,
|
||||||
|
ATTRIBUTE_VIEW,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -183,4 +183,11 @@ inline std::array<GLfloat, 4> ColorRGBA8(const u32 color) {
|
||||||
} };
|
} };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::array<GLfloat, 3> LightColor(const Pica::Regs::LightColor& color) {
|
||||||
|
return { { color.r / 255.0f,
|
||||||
|
color.g / 255.0f,
|
||||||
|
color.b / 255.0f
|
||||||
|
} };
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
Reference in New Issue