diff --git a/.gitignore b/.gitignore index d2bcfb5c..ae0d3acd 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ Build/ imgui.ini *.aps *.vcxproj* -*.sln \ No newline at end of file +*.sln +*.vcxitems* \ No newline at end of file diff --git a/Resources/Editor/Icons/puzzle.png b/Resources/Editor/Icons/puzzle.png new file mode 100644 index 00000000..8b014d0c Binary files /dev/null and b/Resources/Editor/Icons/puzzle.png differ diff --git a/Resources/Editor/Shaders/Billboard.glsl b/Resources/Editor/Shaders/Billboard.ovfx similarity index 100% rename from Resources/Editor/Shaders/Billboard.glsl rename to Resources/Editor/Shaders/Billboard.ovfx diff --git a/Resources/Editor/Shaders/Gizmo.glsl b/Resources/Editor/Shaders/Gizmo.ovfx similarity index 100% rename from Resources/Editor/Shaders/Gizmo.glsl rename to Resources/Editor/Shaders/Gizmo.ovfx diff --git a/Resources/Editor/Shaders/Grid.glsl b/Resources/Editor/Shaders/Grid.ovfx similarity index 100% rename from Resources/Editor/Shaders/Grid.glsl rename to Resources/Editor/Shaders/Grid.ovfx diff --git a/Resources/Engine/Materials/Default.ovmat b/Resources/Engine/Materials/Default.ovmat index 92306d74..74058ed2 100644 --- a/Resources/Engine/Materials/Default.ovmat +++ b/Resources/Engine/Materials/Default.ovmat @@ -1,5 +1,5 @@ - :Shaders\Standard.glsl + :Shaders\Standard.ovfx false true diff --git a/Resources/Engine/Shaders/Common/Buffers/EngineUBO.ovfxh b/Resources/Engine/Shaders/Common/Buffers/EngineUBO.ovfxh new file mode 100644 index 00000000..fd9f776b --- /dev/null +++ b/Resources/Engine/Shaders/Common/Buffers/EngineUBO.ovfxh @@ -0,0 +1,9 @@ +layout (std140) uniform EngineUBO +{ + mat4 ubo_Model; + mat4 ubo_View; + mat4 ubo_Projection; + vec3 ubo_ViewPos; + float ubo_Time; + mat4 ubo_UserMatrix; +}; diff --git a/Resources/Engine/Shaders/Common/Buffers/LightsSSBO.ovfxh b/Resources/Engine/Shaders/Common/Buffers/LightsSSBO.ovfxh new file mode 100644 index 00000000..77e94946 --- /dev/null +++ b/Resources/Engine/Shaders/Common/Buffers/LightsSSBO.ovfxh @@ -0,0 +1,4 @@ +layout(std430, binding = 0) buffer LightSSBO +{ + mat4 ssbo_Lights[]; +}; diff --git a/Resources/Engine/Shaders/Common/Constants.ovfxh b/Resources/Engine/Shaders/Common/Constants.ovfxh new file mode 100644 index 00000000..a3a5308e --- /dev/null +++ b/Resources/Engine/Shaders/Common/Constants.ovfxh @@ -0,0 +1 @@ +const float PI = 3.14159265359; diff --git a/Resources/Engine/Shaders/Common/Physics.ovfxh b/Resources/Engine/Shaders/Common/Physics.ovfxh new file mode 100644 index 00000000..66d55996 --- /dev/null +++ b/Resources/Engine/Shaders/Common/Physics.ovfxh @@ -0,0 +1,12 @@ +bool IsPointInAABB(vec3 point, vec3 aabbCenter, vec3 aabbHalfSize) +{ + return + point.x > aabbCenter.x - aabbHalfSize.x && point.x < aabbCenter.x + aabbHalfSize.x && + point.y > aabbCenter.y - aabbHalfSize.y && point.y < aabbCenter.y + aabbHalfSize.y && + point.z > aabbCenter.z - aabbHalfSize.z && point.z < aabbCenter.z + aabbHalfSize.z; +} + +bool IsPointInSphere(vec3 point, vec3 sphereCenter, float sphereRadius) +{ + return distance(point, sphereCenter) <= sphereRadius; +} \ No newline at end of file diff --git a/Resources/Engine/Shaders/Common/Utils.ovfxh b/Resources/Engine/Shaders/Common/Utils.ovfxh new file mode 100644 index 00000000..1ed35a10 --- /dev/null +++ b/Resources/Engine/Shaders/Common/Utils.ovfxh @@ -0,0 +1,54 @@ +vec3 UnPack(float target) +{ + return vec3 ( + float((uint(target) >> 24) & 0xff) * 0.003921568627451, + float((uint(target) >> 16) & 0xff) * 0.003921568627451, + float((uint(target) >> 8) & 0xff) * 0.003921568627451 + ); +} + +vec2 TileAndOffsetTexCoords(vec2 texCoords, vec2 tiling, vec2 offset) +{ + return vec2(mod(texCoords.x * tiling.x, 1), mod(texCoords.y * tiling.y, 1)) + offset; +} + +vec2 ApplyParallaxMapping(vec2 texCoords, sampler2D heightMap, vec3 tangentViewPos, vec3 tangentFragPos, float heightScale) +{ + if (heightScale > 0) + { + const vec3 viewDir = normalize(tangentViewPos - tangentFragPos); + const vec2 parallax = viewDir.xy * heightScale * texture(heightMap, texCoords).r; + return texCoords - vec2(parallax.x, 1.0 - parallax.y); + } + + return texCoords; +} + +bool IsMasked(sampler2D maskMap, vec2 texCoords) +{ + return texture(maskMap, texCoords).r == 0.0; +} + +mat3 ConstructTBN(mat4 model, vec3 normal, vec3 tangent, vec3 bitangent) +{ + return mat3( + normalize(vec3(model * vec4(tangent, 0.0))), + normalize(vec3(model * vec4(bitangent, 0.0))), + normalize(vec3(model * vec4(normal, 0.0))) + ); +} + +vec3 ComputeNormal(bool enableNormalMapping, vec2 texCoords, vec3 normal, sampler2D normalMap, mat3 TBN) +{ + if (enableNormalMapping) + { + normal = texture(normalMap, texCoords).rgb; + normal = normalize(normal * 2.0 - 1.0); + normal = normalize(TBN * normal); + return normal; + } + else + { + return normalize(normal); + } +} diff --git a/Resources/Engine/Shaders/Lambert.glsl b/Resources/Engine/Shaders/Lambert.glsl deleted file mode 100644 index debb5ba4..00000000 --- a/Resources/Engine/Shaders/Lambert.glsl +++ /dev/null @@ -1,64 +0,0 @@ -#shader vertex -#version 430 core - -layout (location = 0) in vec3 geo_Pos; -layout (location = 1) in vec2 geo_TexCoords; -layout (location = 2) in vec3 geo_Normal; - -layout (std140) uniform EngineUBO -{ - mat4 ubo_Model; - mat4 ubo_View; - mat4 ubo_Projection; - vec3 ubo_ViewPos; - float ubo_Time; -}; - -out VS_OUT -{ - vec3 FragPos; - vec3 Normal; - vec2 TexCoords; -} vs_out; - -void main() -{ - vs_out.FragPos = vec3(ubo_Model * vec4(geo_Pos, 1.0)); - vs_out.Normal = normalize(mat3(transpose(inverse(ubo_Model))) * geo_Normal); - vs_out.TexCoords = geo_TexCoords; - - gl_Position = ubo_Projection * ubo_View * vec4(vs_out.FragPos, 1.0); -} - -#shader fragment -#version 430 core - -out vec4 FRAGMENT_COLOR; - -in VS_OUT -{ - vec3 FragPos; - vec3 Normal; - vec2 TexCoords; -} fs_in; - -uniform vec4 u_Diffuse = vec4(1.0, 1.0, 1.0, 1.0); -uniform sampler2D u_DiffuseMap; -uniform vec2 u_TextureTiling = vec2(1.0, 1.0); -uniform vec2 u_TextureOffset = vec2(0.0, 0.0); - -const vec3 c_lightPosition = vec3(-9000.0, 10000.0, 11000.0); -const vec3 c_lightDiffuse = vec3(1.0, 1.0, 1.0); -const vec3 c_lightAmbient = vec3(0.3, 0.3, 0.3); - -vec3 Lambert(vec3 p_fragPos, vec3 p_normal) -{ - const float diffuse = max(dot(p_normal, normalize(c_lightPosition - p_fragPos)), 0.0); - return clamp(c_lightDiffuse * diffuse + c_lightAmbient, 0.0, 1.0); -} - -void main() -{ - const vec4 diffuse = texture(u_DiffuseMap, u_TextureOffset + vec2(mod(fs_in.TexCoords.x * u_TextureTiling.x, 1), mod(fs_in.TexCoords.y * u_TextureTiling.y, 1))) * u_Diffuse; - FRAGMENT_COLOR = vec4(Lambert(fs_in.FragPos, fs_in.Normal) * diffuse.rgb, diffuse.a); -} \ No newline at end of file diff --git a/Resources/Engine/Shaders/Lambert.ovfx b/Resources/Engine/Shaders/Lambert.ovfx new file mode 100644 index 00000000..4a65a625 --- /dev/null +++ b/Resources/Engine/Shaders/Lambert.ovfx @@ -0,0 +1,58 @@ +#shader vertex +#version 430 core + +#include ":Shaders/Common/Buffers/EngineUBO.ovfxh" +#include ":Shaders/Common/Utils.ovfxh" + +layout (location = 0) in vec3 geo_Pos; +layout (location = 1) in vec2 geo_TexCoords; +layout (location = 2) in vec3 geo_Normal; + +out VS_OUT +{ + vec3 FragPos; + vec2 TexCoords; + vec3 Normal; +} vs_out; + +void main() +{ + vs_out.FragPos = vec3(ubo_Model * vec4(geo_Pos, 1.0)); + vs_out.TexCoords = geo_TexCoords; + vs_out.Normal = normalize(mat3(transpose(inverse(ubo_Model))) * geo_Normal); + + gl_Position = ubo_Projection * ubo_View * vec4(vs_out.FragPos, 1.0); +} + +#shader fragment +#version 430 core + +#include ":Shaders/Common/Buffers/EngineUBO.ovfxh" +#include ":Shaders/Common/Utils.ovfxh" +#include ":Shaders/Lighting/Lambert.ovfxh" + +in VS_OUT +{ + vec3 FragPos; + vec2 TexCoords; + vec3 Normal; +} fs_in; + +uniform vec4 u_Diffuse = vec4(1.0, 1.0, 1.0, 1.0); +uniform sampler2D u_DiffuseMap; +uniform vec2 u_TextureTiling = vec2(1.0, 1.0); +uniform vec2 u_TextureOffset = vec2(0.0, 0.0); + +out vec4 FRAGMENT_COLOR; + +void main() +{ + vec2 texCoords = TileAndOffsetTexCoords(fs_in.TexCoords, u_TextureTiling, u_TextureOffset); + + const vec3 kLightPosition = vec3(-9000.0, 10000.0, 11000.0); + const vec3 kLightDiffuse = vec3(1.0); + const vec3 kLightAmbient = vec3(0.3); + const vec3 lambert = ComputeLambertLighting(fs_in.FragPos, fs_in.Normal, kLightPosition, kLightDiffuse, kLightAmbient); + + FRAGMENT_COLOR = texture(u_DiffuseMap, texCoords) * u_Diffuse * vec4(lambert, 1.0); +} diff --git a/Resources/Engine/Shaders/Lighting/BlinnPhong.ovfxh b/Resources/Engine/Shaders/Lighting/BlinnPhong.ovfxh new file mode 100644 index 00000000..f62ccdb4 --- /dev/null +++ b/Resources/Engine/Shaders/Lighting/BlinnPhong.ovfxh @@ -0,0 +1,98 @@ +#include ":Shaders/Common/Physics.ovfxh" +#include ":Shaders/Common/Utils.ovfxh" +#include ":Shaders/Lighting/Shared.ovfxh" +#include ":Shaders/Common/Buffers/LightsSSBO.ovfxh" + +vec3 BlinnPhong(vec3 lightDir, vec3 lightColor, float luminosity, vec4 diffuseTexel, vec4 specularTexel, vec3 normal, vec3 viewDir, float shininess) +{ + const vec3 halfwayDir = normalize(lightDir + viewDir); + const float diffuseCoefficient = max(dot(normal, lightDir), 0.0); + const float specularCoefficient = pow(max(dot(normal, halfwayDir), 0.0), shininess * 2.0); + + return lightColor * diffuseTexel.rgb * diffuseCoefficient * luminosity + ((luminosity > 0.0) ? (lightColor * specularTexel.rgb * specularCoefficient * luminosity) : vec3(0.0)); +} + +vec3 ComputePointLight(mat4 light, vec3 fragPos, vec4 diffuseTexel, vec4 specularTexel, vec3 normal, vec3 viewDir, float shininess) +{ + /* Extract light information from light mat4 */ + const vec3 lightPosition = light[0].rgb; + const vec3 lightColor = UnPack(light[2][0]); + const float intensity = light[3][3]; + + const vec3 lightDirection = normalize(lightPosition - fragPos); + const float luminosity = LuminosityFromAttenuation(light, fragPos); + + return BlinnPhong(lightDirection, lightColor, intensity * luminosity, diffuseTexel, specularTexel, normal, viewDir, shininess); +} + +vec3 ComputeDirectionalLight(mat4 light, vec4 diffuseTexel, vec4 specularTexel, vec3 normal, vec3 viewDir, float shininess) +{ + return BlinnPhong(-light[1].rgb, UnPack(light[2][0]), light[3][3], diffuseTexel, specularTexel, normal, viewDir, shininess); +} + +vec3 ComputeSpotLight(mat4 light, vec3 fragPos, vec4 diffuseTexel, vec4 specularTexel, vec3 normal, vec3 viewDir, float shininess) +{ + /* Extract light information from light mat4 */ + const vec3 lightPosition = light[0].rgb; + const vec3 lightForward = light[1].rgb; + const vec3 lightColor = UnPack(light[2][0]); + const float intensity = light[3][3]; + const float cutOff = cos(radians(light[3][1])); + const float outerCutOff = cos(radians(light[3][1] + light[3][2])); + + const vec3 lightDirection = normalize(lightPosition - fragPos); + const float luminosity = LuminosityFromAttenuation(light, fragPos); + + /* Calculate the spot intensity */ + const float theta = dot(lightDirection, normalize(-lightForward)); + const float epsilon = cutOff - outerCutOff; + const float spotIntensity = clamp((theta - outerCutOff) / epsilon, 0.0, 1.0); + + return BlinnPhong(lightDirection, lightColor, intensity * spotIntensity * luminosity, diffuseTexel, specularTexel, normal, viewDir, shininess); +} + +vec3 ComputeAmbientBoxLight(mat4 light, vec3 fragPos, vec4 diffuseTexel) +{ + const vec3 lightPosition = light[0].rgb; + const vec3 lightColor = UnPack(light[2][0]); + const float intensity = light[3][3]; + const vec3 size = vec3(light[0][3], light[1][3], light[2][3]); + + return IsPointInAABB(fragPos, lightPosition, size) ? diffuseTexel.rgb * lightColor * intensity : vec3(0.0); +} + +vec3 ComputeAmbientSphereLight(mat4 light, vec3 fragPos, vec4 diffuseTexel) +{ + const vec3 lightPosition = light[0].rgb; + const vec3 lightColor = UnPack(light[2][0]); + const float intensity = light[3][3]; + const float radius = light[0][3]; + + return IsPointInSphere(fragPos, lightPosition, radius) ? diffuseTexel.rgb * lightColor * intensity : vec3(0.0); +} + +vec4 ComputeBlinnPhongLighting(vec2 texCoords, vec3 normal, vec3 viewPos, vec3 fragPos, vec4 diffuse, vec3 specular, sampler2D diffuseMap, sampler2D specularMap, float shininess) +{ + vec3 viewDir = normalize(viewPos - fragPos); + vec4 diffuseTexel = texture(diffuseMap, texCoords) * diffuse; + vec4 specularTexel = texture(specularMap, texCoords) * vec4(specular, 1.0); + + vec3 lightAccumulation = vec3(0.0); + + for (int i = 0; i < ssbo_Lights.length(); ++i) + { + const mat4 light = ssbo_Lights[i]; + const int lightType = int(light[3][0]); + + switch(lightType) + { + case 0: lightAccumulation += ComputePointLight(light, fragPos, diffuseTexel, specularTexel, normal, viewDir, shininess); break; + case 1: lightAccumulation += ComputeDirectionalLight(light, diffuseTexel, specularTexel, normal, viewDir, shininess); break; + case 2: lightAccumulation += ComputeSpotLight(light, fragPos, diffuseTexel, specularTexel, normal, viewDir, shininess); break; + case 3: lightAccumulation += ComputeAmbientBoxLight(light, fragPos, diffuseTexel); break; + case 4: lightAccumulation += ComputeAmbientSphereLight(light, fragPos, diffuseTexel); break; + } + } + + return vec4(lightAccumulation, diffuseTexel.a); +} diff --git a/Resources/Engine/Shaders/Lighting/Lambert.ovfxh b/Resources/Engine/Shaders/Lighting/Lambert.ovfxh new file mode 100644 index 00000000..223c5280 --- /dev/null +++ b/Resources/Engine/Shaders/Lighting/Lambert.ovfxh @@ -0,0 +1,5 @@ +vec3 ComputeLambertLighting(vec3 fragPos, vec3 normal, vec3 lightPos, vec3 lightDiffuse, vec3 lightAmbient) +{ + const float diffuse = max(dot(normal, normalize(lightPos - fragPos)), 0.0); + return clamp(lightDiffuse * diffuse + lightAmbient, 0.0, 1.0); +} diff --git a/Resources/Engine/Shaders/Lighting/PBR.ovfxh b/Resources/Engine/Shaders/Lighting/PBR.ovfxh new file mode 100644 index 00000000..4df6c21b --- /dev/null +++ b/Resources/Engine/Shaders/Lighting/PBR.ovfxh @@ -0,0 +1,160 @@ +#include ":Shaders/Common/Physics.ovfxh" +#include ":Shaders/Common/Utils.ovfxh" +#include ":Shaders/Common/Constants.ovfxh" +#include ":Shaders/Common/Buffers/LightsSSBO.ovfxh" +#include ":Shaders/Lighting/Shared.ovfxh" + +float DistributionGGX(vec3 N, vec3 H, float roughness) +{ + float a = roughness * roughness; + float a2 = a * a; + float NdotH = max(dot(N, H), 0.0); + float NdotH2 = NdotH * NdotH; + + float num = a2; + float denom = (NdotH2 * (a2 - 1.0) + 1.0); + denom = PI * denom * denom; + + return num / denom; +} + +float GeometrySchlickGGX(float NdotV, float roughness) +{ + float r = (roughness + 1.0); + float k = (r * r) / 8.0; + + float num = NdotV; + float denom = NdotV * (1.0 - k) + k; + + return num / denom; +} +float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) +{ + float NdotV = max(dot(N, V), 0.0); + float NdotL = max(dot(N, L), 0.0); + float ggx2 = GeometrySchlickGGX(NdotV, roughness); + float ggx1 = GeometrySchlickGGX(NdotL, roughness); + + return ggx1 * ggx2; +} + +vec3 FresnelSchlick(float cosTheta, vec3 F0) +{ + return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); +} + +vec3 ComputeAmbientBoxLight(mat4 light, vec3 fragPos) +{ + const vec3 lightPosition = light[0].rgb; + const vec3 lightColor = UnPack(light[2][0]); + const float intensity = light[3][3]; + const vec3 size = vec3(light[0][3], light[1][3], light[2][3]); + + return IsPointInAABB(fragPos, lightPosition, size) ? lightColor * intensity : vec3(0.0); +} + +vec3 ComputeAmbientSphereLight(mat4 light, vec3 fragPos) +{ + const vec3 lightPosition = light[0].rgb; + const vec3 lightColor = UnPack(light[2][0]); + const float intensity = light[3][3]; + const float radius = light[0][3]; + + return IsPointInSphere(fragPos, lightPosition, radius) ? lightColor * intensity : vec3(0.0); +} + +vec4 ComputePBRLighting(vec2 texCoords, vec3 normal, vec3 viewPos, vec3 fragPos, vec4 inAlbedo, float inMetallic, float inRoughness, sampler2D albedoMap, sampler2D metallicMap, sampler2D roughnessMap, sampler2D aoMap) +{ + vec4 albedoRGBA = texture(albedoMap, texCoords) * inAlbedo; + vec3 albedo = pow(albedoRGBA.rgb, vec3(2.2)); + float metallic = texture(metallicMap, texCoords).r * inMetallic; + float roughness = texture(roughnessMap, texCoords).r * inRoughness; + float ao = texture(aoMap, texCoords).r; + + vec3 N = normalize(normal); + vec3 V = normalize(viewPos - fragPos); + + vec3 F0 = vec3(0.04); + F0 = mix(F0, albedo, metallic); + + // reflectance equation + vec3 Lo = vec3(0.0); + vec3 ambientSum = vec3(0.0); + + for (int i = 0; i < ssbo_Lights.length(); ++i) + { + const mat4 light = ssbo_Lights[i]; + const int lightType = int(light[3][0]); + + if (lightType == 3) + { + ambientSum += ComputeAmbientBoxLight(light, fragPos); + } + else if (lightType == 4) + { + ambientSum += ComputeAmbientSphereLight(light, fragPos); + } + else + { + // calculate per-light radiance + vec3 L = lightType == 1 ? -light[1].rgb : normalize(light[0].rgb - fragPos); + vec3 H = normalize(V + L); + float distance = length(light[0].rgb - fragPos); + float lightCoeff = 0.0; + + switch(int(light[3][0])) + { + case 0: + lightCoeff = LuminosityFromAttenuation(light, fragPos) * light[3][3]; + break; + + case 1: + lightCoeff = light[3][3]; + break; + + case 2: + const vec3 lightForward = light[1].rgb; + const float cutOff = cos(radians(light[3][1])); + const float outerCutOff = cos(radians(light[3][1] + light[3][2])); + + const vec3 lightDirection = normalize(light[0].rgb - fragPos); + const float luminosity = LuminosityFromAttenuation(light, fragPos); + + /* Calculate the spot intensity */ + const float theta = dot(lightDirection, normalize(-lightForward)); + const float epsilon = cutOff - outerCutOff; + const float spotIntensity = clamp((theta - outerCutOff) / epsilon, 0.0, 1.0); + + lightCoeff = luminosity * spotIntensity * light[3][3]; + break; + } + + vec3 radiance = UnPack(light[2][0]) * lightCoeff; + + // cook-torrance brdf + float NDF = DistributionGGX(N, H, roughness); + float G = GeometrySmith(N, V, L, roughness); + vec3 F = FresnelSchlick(max(dot(H, V), 0.0), F0); + + vec3 kS = F; + vec3 kD = vec3(1.0) - kS; + kD *= 1.0 - metallic; + + vec3 numerator = NDF * G * F; + float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0); + vec3 specular = numerator / max(denominator, 0.001); + + // add to outgoing radiance Lo + float NdotL = max(dot(N, L), 0.0); + Lo += (kD * albedo / PI + specular) * radiance * NdotL; + } + } + + vec3 ambient = ambientSum * albedo * ao; + vec3 color = ambient + Lo; + + color = color / (color + vec3(1.0)); + color = pow(color, vec3(1.0/2.2)); + + return vec4(color, albedoRGBA.a); +} \ No newline at end of file diff --git a/Resources/Engine/Shaders/Lighting/Shared.ovfxh b/Resources/Engine/Shaders/Lighting/Shared.ovfxh new file mode 100644 index 00000000..7c8dd53e --- /dev/null +++ b/Resources/Engine/Shaders/Lighting/Shared.ovfxh @@ -0,0 +1,12 @@ +float LuminosityFromAttenuation(mat4 light, vec3 fragPos) +{ + const vec3 lightPosition = light[0].rgb; + const float constant = light[0][3]; + const float linear = light[1][3]; + const float quadratic = light[2][3]; + + const float distanceToLight = length(lightPosition - fragPos); + const float attenuation = (constant + linear * distanceToLight + quadratic * (distanceToLight * distanceToLight)); + + return 1.0 / attenuation; +} diff --git a/Resources/Engine/Shaders/Standard.glsl b/Resources/Engine/Shaders/Standard.glsl deleted file mode 100644 index 36ba7843..00000000 --- a/Resources/Engine/Shaders/Standard.glsl +++ /dev/null @@ -1,258 +0,0 @@ -#shader vertex -#version 430 core - -layout (location = 0) in vec3 geo_Pos; -layout (location = 1) in vec2 geo_TexCoords; -layout (location = 2) in vec3 geo_Normal; -layout (location = 3) in vec3 geo_Tangent; -layout (location = 4) in vec3 geo_Bitangent; - -/* Global information sent by the engine */ -layout (std140) uniform EngineUBO -{ - mat4 ubo_Model; - mat4 ubo_View; - mat4 ubo_Projection; - vec3 ubo_ViewPos; - float ubo_Time; -}; - -/* Information passed to the fragment shader */ -out VS_OUT -{ - vec3 FragPos; - vec3 Normal; - vec2 TexCoords; - mat3 TBN; - flat vec3 TangentViewPos; - vec3 TangentFragPos; -} vs_out; - -void main() -{ - vs_out.TBN = mat3 - ( - normalize(vec3(ubo_Model * vec4(geo_Tangent, 0.0))), - normalize(vec3(ubo_Model * vec4(geo_Bitangent, 0.0))), - normalize(vec3(ubo_Model * vec4(geo_Normal, 0.0))) - ); - - mat3 TBNi = transpose(vs_out.TBN); - - vs_out.FragPos = vec3(ubo_Model * vec4(geo_Pos, 1.0)); - vs_out.Normal = normalize(mat3(transpose(inverse(ubo_Model))) * geo_Normal); - vs_out.TexCoords = geo_TexCoords; - vs_out.TangentViewPos = TBNi * ubo_ViewPos; - vs_out.TangentFragPos = TBNi * vs_out.FragPos; - - gl_Position = ubo_Projection * ubo_View * vec4(vs_out.FragPos, 1.0); -} - -#shader fragment -#version 430 core - -/* Global information sent by the engine */ -layout (std140) uniform EngineUBO -{ - mat4 ubo_Model; - mat4 ubo_View; - mat4 ubo_Projection; - vec3 ubo_ViewPos; - float ubo_Time; -}; - -/* Information passed from the fragment shader */ -in VS_OUT -{ - vec3 FragPos; - vec3 Normal; - vec2 TexCoords; - mat3 TBN; - flat vec3 TangentViewPos; - vec3 TangentFragPos; -} fs_in; - -/* Light information sent by the engine */ -layout(std430, binding = 0) buffer LightSSBO -{ - mat4 ssbo_Lights[]; -}; - -/* Uniforms (Tweakable from the material editor) */ -uniform vec2 u_TextureTiling = vec2(1.0, 1.0); -uniform vec2 u_TextureOffset = vec2(0.0, 0.0); -uniform vec4 u_Diffuse = vec4(1.0, 1.0, 1.0, 1.0); -uniform vec3 u_Specular = vec3(1.0, 1.0, 1.0); -uniform float u_Shininess = 100.0; -uniform float u_HeightScale = 0.0; -uniform bool u_EnableNormalMapping = false; -uniform sampler2D u_DiffuseMap; -uniform sampler2D u_SpecularMap; -uniform sampler2D u_NormalMap; -uniform sampler2D u_HeightMap; -uniform sampler2D u_MaskMap; - -/* Global variables */ -vec3 g_Normal; -vec2 g_TexCoords; -vec3 g_ViewDir; -vec4 g_DiffuseTexel; -vec4 g_SpecularTexel; -vec4 g_HeightTexel; -vec4 g_NormalTexel; - -out vec4 FRAGMENT_COLOR; - -vec3 UnPack(float p_Target) -{ - return vec3 - ( - float((uint(p_Target) >> 24) & 0xff) * 0.003921568627451, - float((uint(p_Target) >> 16) & 0xff) * 0.003921568627451, - float((uint(p_Target) >> 8) & 0xff) * 0.003921568627451 - ); -} - -bool PointInAABB(vec3 p_Point, vec3 p_AabbCenter, vec3 p_AabbHalfSize) -{ - return - ( - p_Point.x > p_AabbCenter.x - p_AabbHalfSize.x && p_Point.x < p_AabbCenter.x + p_AabbHalfSize.x && - p_Point.y > p_AabbCenter.y - p_AabbHalfSize.y && p_Point.y < p_AabbCenter.y + p_AabbHalfSize.y && - p_Point.z > p_AabbCenter.z - p_AabbHalfSize.z && p_Point.z < p_AabbCenter.z + p_AabbHalfSize.z - ); -} - -vec2 ParallaxMapping(vec3 p_ViewDir) -{ - const vec2 parallax = p_ViewDir.xy * u_HeightScale * texture(u_HeightMap, g_TexCoords).r; - return g_TexCoords - vec2(parallax.x, 1.0 - parallax.y); -} - -vec3 BlinnPhong(vec3 p_LightDir, vec3 p_LightColor, float p_Luminosity) -{ - const vec3 halfwayDir = normalize(p_LightDir + g_ViewDir); - const float diffuseCoefficient = max(dot(g_Normal, p_LightDir), 0.0); - const float specularCoefficient = pow(max(dot(g_Normal, halfwayDir), 0.0), u_Shininess * 2.0); - - return p_LightColor * g_DiffuseTexel.rgb * diffuseCoefficient * p_Luminosity + ((p_Luminosity > 0.0) ? (p_LightColor * g_SpecularTexel.rgb * specularCoefficient * p_Luminosity) : vec3(0.0)); -} - -float LuminosityFromAttenuation(mat4 p_Light) -{ - const vec3 lightPosition = p_Light[0].rgb; - const float constant = p_Light[0][3]; - const float linear = p_Light[1][3]; - const float quadratic = p_Light[2][3]; - - const float distanceToLight = length(lightPosition - fs_in.FragPos); - const float attenuation = (constant + linear * distanceToLight + quadratic * (distanceToLight * distanceToLight)); - return 1.0 / attenuation; -} - -vec3 CalcPointLight(mat4 p_Light) -{ - /* Extract light information from light mat4 */ - const vec3 lightPosition = p_Light[0].rgb; - const vec3 lightColor = UnPack(p_Light[2][0]); - const float intensity = p_Light[3][3]; - - const vec3 lightDirection = normalize(lightPosition - fs_in.FragPos); - const float luminosity = LuminosityFromAttenuation(p_Light); - - return BlinnPhong(lightDirection, lightColor, intensity * luminosity); -} - -vec3 CalcDirectionalLight(mat4 light) -{ - return BlinnPhong(-light[1].rgb, UnPack(light[2][0]), light[3][3]); -} - -vec3 CalcSpotLight(mat4 p_Light) -{ - /* Extract light information from light mat4 */ - const vec3 lightPosition = p_Light[0].rgb; - const vec3 lightForward = p_Light[1].rgb; - const vec3 lightColor = UnPack(p_Light[2][0]); - const float intensity = p_Light[3][3]; - const float cutOff = cos(radians(p_Light[3][1])); - const float outerCutOff = cos(radians(p_Light[3][1] + p_Light[3][2])); - - const vec3 lightDirection = normalize(lightPosition - fs_in.FragPos); - const float luminosity = LuminosityFromAttenuation(p_Light); - - /* Calculate the spot intensity */ - const float theta = dot(lightDirection, normalize(-lightForward)); - const float epsilon = cutOff - outerCutOff; - const float spotIntensity = clamp((theta - outerCutOff) / epsilon, 0.0, 1.0); - - return BlinnPhong(lightDirection, lightColor, intensity * spotIntensity * luminosity); -} - -vec3 CalcAmbientBoxLight(mat4 p_Light) -{ - const vec3 lightPosition = p_Light[0].rgb; - const vec3 lightColor = UnPack(p_Light[2][0]); - const float intensity = p_Light[3][3]; - const vec3 size = vec3(p_Light[0][3], p_Light[1][3], p_Light[2][3]); - - return PointInAABB(fs_in.FragPos, lightPosition, size) ? g_DiffuseTexel.rgb * lightColor * intensity : vec3(0.0); -} - -vec3 CalcAmbientSphereLight(mat4 p_Light) -{ - const vec3 lightPosition = p_Light[0].rgb; - const vec3 lightColor = UnPack(p_Light[2][0]); - const float intensity = p_Light[3][3]; - const float radius = p_Light[0][3]; - - return distance(lightPosition, fs_in.FragPos) <= radius ? g_DiffuseTexel.rgb * lightColor * intensity : vec3(0.0); -} - -void main() -{ - g_TexCoords = u_TextureOffset + vec2(mod(fs_in.TexCoords.x * u_TextureTiling.x, 1), mod(fs_in.TexCoords.y * u_TextureTiling.y, 1)); - - /* Apply parallax mapping */ - if (u_HeightScale > 0) - g_TexCoords = ParallaxMapping(normalize(fs_in.TangentViewPos - fs_in.TangentFragPos)); - - /* Apply color mask */ - if (texture(u_MaskMap, g_TexCoords).r != 0.0) - { - g_ViewDir = normalize(ubo_ViewPos - fs_in.FragPos); - g_DiffuseTexel = texture(u_DiffuseMap, g_TexCoords) * u_Diffuse; - g_SpecularTexel = texture(u_SpecularMap, g_TexCoords) * vec4(u_Specular, 1.0); - - if (u_EnableNormalMapping) - { - g_Normal = texture(u_NormalMap, g_TexCoords).rgb; - g_Normal = normalize(g_Normal * 2.0 - 1.0); - g_Normal = normalize(fs_in.TBN * g_Normal); - } - else - { - g_Normal = normalize(fs_in.Normal); - } - - vec3 lightSum = vec3(0.0); - - for (int i = 0; i < ssbo_Lights.length(); ++i) - { - switch(int(ssbo_Lights[i][3][0])) - { - case 0: lightSum += CalcPointLight(ssbo_Lights[i]); break; - case 1: lightSum += CalcDirectionalLight(ssbo_Lights[i]); break; - case 2: lightSum += CalcSpotLight(ssbo_Lights[i]); break; - case 3: lightSum += CalcAmbientBoxLight(ssbo_Lights[i]); break; - case 4: lightSum += CalcAmbientSphereLight(ssbo_Lights[i]); break; - } - } - - FRAGMENT_COLOR = vec4(lightSum, g_DiffuseTexel.a); - } - else - { - FRAGMENT_COLOR = vec4(0.0); - } -} \ No newline at end of file diff --git a/Resources/Engine/Shaders/Standard.ovfx b/Resources/Engine/Shaders/Standard.ovfx new file mode 100644 index 00000000..7cfdd69f --- /dev/null +++ b/Resources/Engine/Shaders/Standard.ovfx @@ -0,0 +1,80 @@ +#shader vertex +#version 430 core + +#include ":Shaders/Common/Buffers/EngineUBO.ovfxh" +#include ":Shaders/Common/Utils.ovfxh" + +layout (location = 0) in vec3 geo_Pos; +layout (location = 1) in vec2 geo_TexCoords; +layout (location = 2) in vec3 geo_Normal; +layout (location = 3) in vec3 geo_Tangent; +layout (location = 4) in vec3 geo_Bitangent; + +out VS_OUT +{ + vec3 FragPos; + vec2 TexCoords; + vec3 Normal; + mat3 TBN; + flat vec3 TangentViewPos; + vec3 TangentFragPos; +} vs_out; + +void main() +{ + vs_out.FragPos = vec3(ubo_Model * vec4(geo_Pos, 1.0)); + vs_out.TexCoords = geo_TexCoords; + vs_out.Normal = normalize(mat3(transpose(inverse(ubo_Model))) * geo_Normal); + vs_out.TBN = ConstructTBN(ubo_Model, geo_Normal, geo_Tangent, geo_Bitangent); + vs_out.TangentViewPos = transpose(vs_out.TBN) * ubo_ViewPos; + vs_out.TangentFragPos = transpose(vs_out.TBN) * vs_out.FragPos; + + gl_Position = ubo_Projection * ubo_View * vec4(vs_out.FragPos, 1.0); +} + +#shader fragment +#version 430 core + +#include ":Shaders/Common/Buffers/EngineUBO.ovfxh" +#include ":Shaders/Lighting/BlinnPhong.ovfxh" + +in VS_OUT +{ + vec3 FragPos; + vec2 TexCoords; + vec3 Normal; + mat3 TBN; + flat vec3 TangentViewPos; + vec3 TangentFragPos; +} fs_in; + +uniform vec2 u_TextureTiling = vec2(1.0, 1.0); +uniform vec2 u_TextureOffset = vec2(0.0, 0.0); +uniform vec4 u_Diffuse = vec4(1.0, 1.0, 1.0, 1.0); +uniform vec3 u_Specular = vec3(1.0, 1.0, 1.0); +uniform float u_Shininess = 100.0; +uniform float u_HeightScale = 0.0; +uniform bool u_EnableNormalMapping = false; +uniform sampler2D u_DiffuseMap; +uniform sampler2D u_SpecularMap; +uniform sampler2D u_NormalMap; +uniform sampler2D u_HeightMap; +uniform sampler2D u_MaskMap; + +out vec4 FRAGMENT_COLOR; + +void main() +{ + vec2 texCoords = TileAndOffsetTexCoords(fs_in.TexCoords, u_TextureTiling, u_TextureOffset); + texCoords = ApplyParallaxMapping(texCoords, u_HeightMap, fs_in.TangentViewPos, fs_in.TangentFragPos, u_HeightScale); + + if (!IsMasked(u_MaskMap, texCoords)) + { + vec3 normal = ComputeNormal(u_EnableNormalMapping, texCoords, fs_in.Normal, u_NormalMap, fs_in.TBN); + FRAGMENT_COLOR = ComputeBlinnPhongLighting(texCoords, normal, ubo_ViewPos, fs_in.FragPos, u_Diffuse, u_Specular, u_DiffuseMap, u_SpecularMap, u_Shininess); + } + else + { + FRAGMENT_COLOR = vec4(0.0); + } +} diff --git a/Resources/Engine/Shaders/StandardPBR.glsl b/Resources/Engine/Shaders/StandardPBR.glsl deleted file mode 100644 index c0bd2e7d..00000000 --- a/Resources/Engine/Shaders/StandardPBR.glsl +++ /dev/null @@ -1,294 +0,0 @@ -#shader vertex -#version 430 core - -layout (location = 0) in vec3 geo_Pos; -layout (location = 1) in vec2 geo_TexCoords; -layout (location = 2) in vec3 geo_Normal; -layout (location = 3) in vec3 geo_Tangent; -layout (location = 4) in vec3 geo_Bitangent; - -/* Global information sent by the engine */ -layout (std140) uniform EngineUBO -{ - mat4 ubo_Model; - mat4 ubo_View; - mat4 ubo_Projection; - vec3 ubo_ViewPos; - float ubo_Time; -}; - -/* Information passed to the fragment shader */ -out VS_OUT -{ - vec3 FragPos; - vec3 Normal; - vec2 TexCoords; - mat3 TBN; - flat vec3 TangentViewPos; - vec3 TangentFragPos; -} vs_out; - -void main() -{ - vs_out.TBN = mat3 - ( - normalize(vec3(ubo_Model * vec4(geo_Tangent, 0.0))), - normalize(vec3(ubo_Model * vec4(geo_Bitangent, 0.0))), - normalize(vec3(ubo_Model * vec4(geo_Normal, 0.0))) - ); - - mat3 TBNi = transpose(vs_out.TBN); - - vs_out.FragPos = vec3(ubo_Model * vec4(geo_Pos, 1.0)); - vs_out.Normal = normalize(mat3(transpose(inverse(ubo_Model))) * geo_Normal); - vs_out.TexCoords = geo_TexCoords; - vs_out.TangentViewPos = TBNi * ubo_ViewPos; - vs_out.TangentFragPos = TBNi * vs_out.FragPos; - - gl_Position = ubo_Projection * ubo_View * vec4(vs_out.FragPos, 1.0); -} - -#shader fragment -#version 430 core - -/* Global information sent by the engine */ -layout (std140) uniform EngineUBO -{ - mat4 ubo_Model; - mat4 ubo_View; - mat4 ubo_Projection; - vec3 ubo_ViewPos; - float ubo_Time; -}; - -/* Information passed from the fragment shader */ -in VS_OUT -{ - vec3 FragPos; - vec3 Normal; - vec2 TexCoords; - mat3 TBN; - flat vec3 TangentViewPos; - vec3 TangentFragPos; -} fs_in; - -/* Light information sent by the engine */ -layout(std430, binding = 0) buffer LightSSBO -{ - mat4 ssbo_Lights[]; -}; - -out vec4 FRAGMENT_COLOR; - -uniform sampler2D u_AlbedoMap; -uniform sampler2D u_MetallicMap; -uniform sampler2D u_RoughnessMap; -uniform sampler2D u_AmbientOcclusionMap; -uniform sampler2D u_NormalMap; -uniform vec4 u_Albedo = vec4(1.0); -uniform vec2 u_TextureTiling = vec2(1.0, 1.0); -uniform vec2 u_TextureOffset = vec2(0.0, 0.0); -uniform bool u_EnableNormalMapping = false; -uniform float u_HeightScale = 0.0; -uniform float u_Metallic = 1.0; -uniform float u_Roughness = 1.0; - -const float PI = 3.14159265359; - -float DistributionGGX(vec3 N, vec3 H, float roughness) -{ - float a = roughness*roughness; - float a2 = a*a; - float NdotH = max(dot(N, H), 0.0); - float NdotH2 = NdotH*NdotH; - - float num = a2; - float denom = (NdotH2 * (a2 - 1.0) + 1.0); - denom = PI * denom * denom; - - return num / denom; -} - -float GeometrySchlickGGX(float NdotV, float roughness) -{ - float r = (roughness + 1.0); - float k = (r*r) / 8.0; - - float num = NdotV; - float denom = NdotV * (1.0 - k) + k; - - return num / denom; -} -float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) -{ - float NdotV = max(dot(N, V), 0.0); - float NdotL = max(dot(N, L), 0.0); - float ggx2 = GeometrySchlickGGX(NdotV, roughness); - float ggx1 = GeometrySchlickGGX(NdotL, roughness); - - return ggx1 * ggx2; -} - -vec3 fresnelSchlick(float cosTheta, vec3 F0) -{ - return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); -} - -vec3 UnPack(float p_Target) -{ - return vec3 - ( - float((uint(p_Target) >> 24) & 0xff) * 0.003921568627451, - float((uint(p_Target) >> 16) & 0xff) * 0.003921568627451, - float((uint(p_Target) >> 8) & 0xff) * 0.003921568627451 - ); -} - -bool PointInAABB(vec3 p_Point, vec3 p_AabbCenter, vec3 p_AabbHalfSize) -{ - return - ( - p_Point.x > p_AabbCenter.x - p_AabbHalfSize.x && p_Point.x < p_AabbCenter.x + p_AabbHalfSize.x && - p_Point.y > p_AabbCenter.y - p_AabbHalfSize.y && p_Point.y < p_AabbCenter.y + p_AabbHalfSize.y && - p_Point.z > p_AabbCenter.z - p_AabbHalfSize.z && p_Point.z < p_AabbCenter.z + p_AabbHalfSize.z - ); -} - -float LuminosityFromAttenuation(mat4 p_Light) -{ - const vec3 lightPosition = p_Light[0].rgb; - const float constant = p_Light[0][3]; - const float linear = p_Light[1][3]; - const float quadratic = p_Light[2][3]; - - const float distanceToLight = length(lightPosition - fs_in.FragPos); - const float attenuation = (constant + linear * distanceToLight + quadratic * (distanceToLight * distanceToLight)); - return 1.0 / attenuation; -} - -vec3 CalcAmbientBoxLight(mat4 p_Light) -{ - const vec3 lightPosition = p_Light[0].rgb; - const vec3 lightColor = UnPack(p_Light[2][0]); - const float intensity = p_Light[3][3]; - const vec3 size = vec3(p_Light[0][3], p_Light[1][3], p_Light[2][3]); - - return PointInAABB(fs_in.FragPos, lightPosition, size) ? lightColor * intensity : vec3(0.0); -} - -vec3 CalcAmbientSphereLight(mat4 p_Light) -{ - const vec3 lightPosition = p_Light[0].rgb; - const vec3 lightColor = UnPack(p_Light[2][0]); - const float intensity = p_Light[3][3]; - const float radius = p_Light[0][3]; - - return distance(lightPosition, fs_in.FragPos) <= radius ? lightColor * intensity : vec3(0.0); -} - -void main() -{ - vec2 texCoords = u_TextureOffset + vec2(mod(fs_in.TexCoords.x * u_TextureTiling.x, 1), mod(fs_in.TexCoords.y * u_TextureTiling.y, 1)); - - vec4 albedoRGBA = texture(u_AlbedoMap, texCoords) * u_Albedo; - vec3 albedo = pow(albedoRGBA.rgb, vec3(2.2)); - float metallic = texture(u_MetallicMap, texCoords).r * u_Metallic; - float roughness = texture(u_RoughnessMap, texCoords).r * u_Roughness; - float ao = texture(u_AmbientOcclusionMap, texCoords).r; - vec3 normal; - - if (u_EnableNormalMapping) - { - normal = texture(u_NormalMap, texCoords).rgb; - normal = normalize(normal * 2.0 - 1.0); - normal = normalize(fs_in.TBN * normal); - } - else - { - normal = normalize(fs_in.Normal); - } - - vec3 N = normalize(normal); - vec3 V = normalize(ubo_ViewPos - fs_in.FragPos); - - vec3 F0 = vec3(0.04); - F0 = mix(F0, albedo, metallic); - - // reflectance equation - vec3 Lo = vec3(0.0); - vec3 ambientSum = vec3(0.0); - - for (int i = 0; i < ssbo_Lights.length(); ++i) - { - if (int(ssbo_Lights[i][3][0]) == 3) - { - ambientSum += CalcAmbientBoxLight(ssbo_Lights[i]); - } - else if (int(ssbo_Lights[i][3][0]) == 4) - { - ambientSum += CalcAmbientSphereLight(ssbo_Lights[i]); - } - else - { - // calculate per-light radiance - vec3 L = int(ssbo_Lights[i][3][0]) == 1 ? -ssbo_Lights[i][1].rgb : normalize(ssbo_Lights[i][0].rgb - fs_in.FragPos); - vec3 H = normalize(V + L); - float distance = length(ssbo_Lights[i][0].rgb - fs_in.FragPos); - float lightCoeff = 0.0; - - switch(int(ssbo_Lights[i][3][0])) - { - case 0: - lightCoeff = LuminosityFromAttenuation(ssbo_Lights[i]) * ssbo_Lights[i][3][3]; - break; - - case 1: - lightCoeff = ssbo_Lights[i][3][3]; - break; - - case 2: - const vec3 lightForward = ssbo_Lights[i][1].rgb; - const float cutOff = cos(radians(ssbo_Lights[i][3][1])); - const float outerCutOff = cos(radians(ssbo_Lights[i][3][1] + ssbo_Lights[i][3][2])); - - const vec3 lightDirection = normalize(ssbo_Lights[i][0].rgb - fs_in.FragPos); - const float luminosity = LuminosityFromAttenuation(ssbo_Lights[i]); - - /* Calculate the spot intensity */ - const float theta = dot(lightDirection, normalize(-lightForward)); - const float epsilon = cutOff - outerCutOff; - const float spotIntensity = clamp((theta - outerCutOff) / epsilon, 0.0, 1.0); - - lightCoeff = luminosity * spotIntensity * ssbo_Lights[i][3][3]; - break; - } - - vec3 radiance = UnPack(ssbo_Lights[i][2][0]) * lightCoeff; - - // cook-torrance brdf - float NDF = DistributionGGX(N, H, roughness); - float G = GeometrySmith(N, V, L, roughness); - vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0); - - vec3 kS = F; - vec3 kD = vec3(1.0) - kS; - kD *= 1.0 - metallic; - - vec3 numerator = NDF * G * F; - float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0); - vec3 specular = numerator / max(denominator, 0.001); - - // add to outgoing radiance Lo - float NdotL = max(dot(N, L), 0.0); - Lo += (kD * albedo / PI + specular) * radiance * NdotL; - } - } - - vec3 ambient = ambientSum * albedo * ao; - vec3 color = ambient + Lo; - - color = color / (color + vec3(1.0)); - color = pow(color, vec3(1.0/2.2)); - - FRAGMENT_COLOR = vec4(color, albedoRGBA.a); -} \ No newline at end of file diff --git a/Resources/Engine/Shaders/StandardPBR.ovfx b/Resources/Engine/Shaders/StandardPBR.ovfx new file mode 100644 index 00000000..28862cae --- /dev/null +++ b/Resources/Engine/Shaders/StandardPBR.ovfx @@ -0,0 +1,82 @@ +#shader vertex +#version 430 core + +#include ":Shaders/Common/Buffers/EngineUBO.ovfxh" +#include ":Shaders/Common/Utils.ovfxh" + +layout (location = 0) in vec3 geo_Pos; +layout (location = 1) in vec2 geo_TexCoords; +layout (location = 2) in vec3 geo_Normal; +layout (location = 3) in vec3 geo_Tangent; +layout (location = 4) in vec3 geo_Bitangent; + +out VS_OUT +{ + vec3 FragPos; + vec2 TexCoords; + vec3 Normal; + mat3 TBN; + flat vec3 TangentViewPos; + vec3 TangentFragPos; +} vs_out; + +void main() +{ + vs_out.FragPos = vec3(ubo_Model * vec4(geo_Pos, 1.0)); + vs_out.TexCoords = geo_TexCoords; + vs_out.Normal = normalize(mat3(transpose(inverse(ubo_Model))) * geo_Normal); + vs_out.TBN = ConstructTBN(ubo_Model, geo_Normal, geo_Tangent, geo_Bitangent); + vs_out.TangentViewPos = transpose(vs_out.TBN) * ubo_ViewPos; + vs_out.TangentFragPos = transpose(vs_out.TBN) * vs_out.FragPos; + + gl_Position = ubo_Projection * ubo_View * vec4(vs_out.FragPos, 1.0); +} + +#shader fragment +#version 430 core + +#include ":Shaders/Common/Buffers/EngineUBO.ovfxh" +#include ":Shaders/Lighting/PBR.ovfxh" + +in VS_OUT +{ + vec3 FragPos; + vec2 TexCoords; + vec3 Normal; + mat3 TBN; + flat vec3 TangentViewPos; + vec3 TangentFragPos; +} fs_in; + +uniform sampler2D u_AlbedoMap; +uniform sampler2D u_MetallicMap; +uniform sampler2D u_RoughnessMap; +uniform sampler2D u_AmbientOcclusionMap; +uniform sampler2D u_NormalMap; +uniform vec4 u_Albedo = vec4(1.0); +uniform vec2 u_TextureTiling = vec2(1.0, 1.0); +uniform vec2 u_TextureOffset = vec2(0.0, 0.0); +uniform bool u_EnableNormalMapping = false; +uniform float u_HeightScale = 0.0; +uniform float u_Metallic = 1.0; +uniform float u_Roughness = 1.0; +uniform sampler2D u_HeightMap; +uniform sampler2D u_MaskMap; + +out vec4 FRAGMENT_COLOR; + +void main() +{ + vec2 texCoords = TileAndOffsetTexCoords(fs_in.TexCoords, u_TextureTiling, u_TextureOffset); + texCoords = ApplyParallaxMapping(texCoords, u_HeightMap, fs_in.TangentViewPos, fs_in.TangentFragPos, u_HeightScale); + + if (!IsMasked(u_MaskMap, texCoords)) + { + vec3 normal = ComputeNormal(u_EnableNormalMapping, texCoords, fs_in.Normal, u_NormalMap, fs_in.TBN); + FRAGMENT_COLOR = ComputePBRLighting(texCoords, normal, ubo_ViewPos, fs_in.FragPos, u_Albedo, u_Metallic, u_Roughness, u_AlbedoMap, u_MetallicMap, u_RoughnessMap, u_AmbientOcclusionMap); + } + else + { + FRAGMENT_COLOR = vec4(0.0); + } +} diff --git a/Resources/Engine/Shaders/Unlit.glsl b/Resources/Engine/Shaders/Unlit.glsl deleted file mode 100644 index e734b649..00000000 --- a/Resources/Engine/Shaders/Unlit.glsl +++ /dev/null @@ -1,47 +0,0 @@ -#shader vertex -#version 430 core - -layout (location = 0) in vec3 geo_Pos; -layout (location = 1) in vec2 geo_TexCoords; -layout (location = 2) in vec3 geo_Normal; - -layout (std140) uniform EngineUBO -{ - mat4 ubo_Model; - mat4 ubo_View; - mat4 ubo_Projection; - vec3 ubo_ViewPos; - float ubo_Time; -}; - -out VS_OUT -{ - vec2 TexCoords; -} vs_out; - -void main() -{ - vs_out.TexCoords = geo_TexCoords; - - gl_Position = ubo_Projection * ubo_View * ubo_Model * vec4(geo_Pos, 1.0); -} - -#shader fragment -#version 430 core - -out vec4 FRAGMENT_COLOR; - -in VS_OUT -{ - vec2 TexCoords; -} fs_in; - -uniform vec4 u_Diffuse = vec4(1.0, 1.0, 1.0, 1.0); -uniform sampler2D u_DiffuseMap; -uniform vec2 u_TextureTiling = vec2(1.0, 1.0); -uniform vec2 u_TextureOffset = vec2(0.0, 0.0); - -void main() -{ - FRAGMENT_COLOR = texture(u_DiffuseMap, u_TextureOffset + vec2(mod(fs_in.TexCoords.x * u_TextureTiling.x, 1), mod(fs_in.TexCoords.y * u_TextureTiling.y, 1))) * u_Diffuse; -} \ No newline at end of file diff --git a/Resources/Engine/Shaders/Unlit.ovfx b/Resources/Engine/Shaders/Unlit.ovfx new file mode 100644 index 00000000..a01db0ca --- /dev/null +++ b/Resources/Engine/Shaders/Unlit.ovfx @@ -0,0 +1,47 @@ +#shader vertex +#version 430 core + +#include ":Shaders/Common/Buffers/EngineUBO.ovfxh" +#include ":Shaders/Common/Utils.ovfxh" + +layout (location = 0) in vec3 geo_Pos; +layout (location = 1) in vec2 geo_TexCoords; + +out VS_OUT +{ + vec3 FragPos; + vec2 TexCoords; +} vs_out; + +void main() +{ + vs_out.FragPos = vec3(ubo_Model * vec4(geo_Pos, 1.0)); + vs_out.TexCoords = geo_TexCoords; + + gl_Position = ubo_Projection * ubo_View * vec4(vs_out.FragPos, 1.0); +} + +#shader fragment +#version 430 core + +#include ":Shaders/Common/Buffers/EngineUBO.ovfxh" +#include ":Shaders/Common/Utils.ovfxh" + +in VS_OUT +{ + vec3 FragPos; + vec2 TexCoords; +} fs_in; + +uniform vec4 u_Diffuse = vec4(1.0); +uniform sampler2D u_DiffuseMap; +uniform vec2 u_TextureTiling = vec2(1.0); +uniform vec2 u_TextureOffset = vec2(0.0); + +out vec4 FRAGMENT_COLOR; + +void main() +{ + vec2 texCoords = TileAndOffsetTexCoords(fs_in.TexCoords, u_TextureTiling, u_TextureOffset); + FRAGMENT_COLOR = texture(u_DiffuseMap, texCoords) * u_Diffuse; +} diff --git a/Resources/premake5.lua b/Resources/premake5.lua new file mode 100644 index 00000000..86373146 --- /dev/null +++ b/Resources/premake5.lua @@ -0,0 +1,3 @@ +project "Resources" + kind "SharedItems" + files { "Editor/**", "Engine/**", "**.lua" } diff --git a/Sources/Overload/OvAnalytics/premake5.lua b/Sources/Overload/OvAnalytics/premake5.lua index 3aaf8437..ed0b17f8 100644 --- a/Sources/Overload/OvAnalytics/premake5.lua +++ b/Sources/Overload/OvAnalytics/premake5.lua @@ -2,7 +2,7 @@ project "OvAnalytics" kind "StaticLib" language "C++" cppdialect "C++17" - files { "**.h", "**.inl", "**.cpp" } + files { "**.h", "**.inl", "**.cpp", "**.lua" } includedirs { "include" } targetdir (outputdir .. "%{cfg.buildcfg}/%{prj.name}") objdir (objoutdir .. "%{cfg.buildcfg}/%{prj.name}") diff --git a/Sources/Overload/OvAudio/premake5.lua b/Sources/Overload/OvAudio/premake5.lua index 8c80333c..8c9976e4 100644 --- a/Sources/Overload/OvAudio/premake5.lua +++ b/Sources/Overload/OvAudio/premake5.lua @@ -2,7 +2,7 @@ project "OvAudio" kind "StaticLib" language "C++" cppdialect "C++17" - files { "**.h", "**.inl", "**.cpp" } + files { "**.h", "**.inl", "**.cpp", "**.lua" } includedirs { "include", dependdir .. "irrklang/include", "%{wks.location}/OvDebug/include", "%{wks.location}/OvMaths/include", "%{wks.location}/OvTools/include" } targetdir (outputdir .. "%{cfg.buildcfg}/%{prj.name}") objdir (objoutdir .. "%{cfg.buildcfg}/%{prj.name}") diff --git a/Sources/Overload/OvCore/premake5.lua b/Sources/Overload/OvCore/premake5.lua index 3c8bd69b..8f749ff9 100644 --- a/Sources/Overload/OvCore/premake5.lua +++ b/Sources/Overload/OvCore/premake5.lua @@ -2,7 +2,7 @@ project "OvCore" kind "StaticLib" language "C++" cppdialect "C++17" - files { "**.h", "**.inl", "**.cpp" } + files { "**.h", "**.inl", "**.cpp", "**.lua" } includedirs { "include", dependdir .. "glfw/include", dependdir .. "stb_image/include", dependdir .. "lua/include", dependdir .. "bullet3/include", dependdir .. "glew/include", dependdir .. "irrklang/include", "%{wks.location}/OvAnalytics/include", "%{wks.location}/OvAudio/include", "%{wks.location}/OvDebug/include", "%{wks.location}/OvMaths/include", "%{wks.location}/OvPhysics/include", "%{wks.location}/OvRendering/include", "%{wks.location}/OvTools/include", "%{wks.location}/OvUI/include", "%{wks.location}/OvWindowing/include" } diff --git a/Sources/Overload/OvCore/src/OvCore/ResourceManagement/ShaderManager.cpp b/Sources/Overload/OvCore/src/OvCore/ResourceManagement/ShaderManager.cpp index 3e06beff..546610a3 100644 --- a/Sources/Overload/OvCore/src/OvCore/ResourceManagement/ShaderManager.cpp +++ b/Sources/Overload/OvCore/src/OvCore/ResourceManagement/ShaderManager.cpp @@ -9,7 +9,8 @@ OvRendering::Resources::Shader* OvCore::ResourceManagement::ShaderManager::CreateResource(const std::string & p_path) { std::string realPath = GetRealPath(p_path); - OvRendering::Resources::Shader* shader = OvRendering::Resources::Loaders::ShaderLoader::Create(realPath); + auto pathParserCallback = std::bind(&OvCore::ResourceManagement::ShaderManager::GetRealPath, this, std::placeholders::_1); + OvRendering::Resources::Shader* shader = OvRendering::Resources::Loaders::ShaderLoader::Create(realPath, pathParserCallback); if (shader) *reinterpret_cast(reinterpret_cast(shader) + offsetof(OvRendering::Resources::Shader, path)) = p_path; // Force the resource path to fit the given path @@ -23,5 +24,6 @@ void OvCore::ResourceManagement::ShaderManager::DestroyResource(OvRendering::Res void OvCore::ResourceManagement::ShaderManager::ReloadResource(OvRendering::Resources::Shader* p_resource, const std::string& p_path) { - OvRendering::Resources::Loaders::ShaderLoader::Recompile(*p_resource, p_path); + auto pathParserCallback = std::bind(&OvCore::ResourceManagement::ShaderManager::GetRealPath, this, std::placeholders::_1); + OvRendering::Resources::Loaders::ShaderLoader::Recompile(*p_resource, p_path, pathParserCallback); } diff --git a/Sources/Overload/OvDebug/premake5.lua b/Sources/Overload/OvDebug/premake5.lua index f5841999..c599b58c 100644 --- a/Sources/Overload/OvDebug/premake5.lua +++ b/Sources/Overload/OvDebug/premake5.lua @@ -2,7 +2,7 @@ project "OvDebug" kind "StaticLib" language "C++" cppdialect "C++17" - files { "**.h", "**.inl", "**.cpp" } + files { "**.h", "**.inl", "**.cpp", "**.lua" } includedirs { "include", "%{wks.location}/OvTools/include" } targetdir (outputdir .. "%{cfg.buildcfg}/%{prj.name}") objdir (objoutdir .. "%{cfg.buildcfg}/%{prj.name}") diff --git a/Sources/Overload/OvEditor/premake5.lua b/Sources/Overload/OvEditor/premake5.lua index 2722061c..37a2a20a 100644 --- a/Sources/Overload/OvEditor/premake5.lua +++ b/Sources/Overload/OvEditor/premake5.lua @@ -1,7 +1,7 @@ project "OvEditor" language "C++" cppdialect "C++17" - files { "**.h", "**.inl","**.cpp", "**.rc" } + files { "**.h", "**.inl","**.cpp", "**.lua", "**.rc" } includedirs { "include", dependdir .. "glfw/include", dependdir .. "stb_image/include", dependdir .. "lua/include", dependdir .. "bullet3/include", dependdir .. "glew/include", dependdir .. "irrklang/include", "%{wks.location}/OvAnalytics/include", "%{wks.location}/OvAudio/include", "%{wks.location}/OvCore/include", "%{wks.location}/OvDebug/include", "%{wks.location}/OvMaths/include", "%{wks.location}/OvPhysics/include", @@ -17,19 +17,21 @@ project "OvEditor" debugdir "%{wks.location}/../../Build/%{cfg.buildcfg}" postbuildcommands { - "for /f \"delims=|\" %%i in ('dir /B /S \"%{wks.location}..\\..\\Dependencies\\*.dll\"') do xcopy /Q /Y \"%%i\" \"%{wks.location}..\\..\\Bin\\%{cfg.buildcfg}\\%{prj.name}\"", + "for /f \"delims=|\" %%i in ('dir /B /S \"%{dependdir}\\*.dll\"') do xcopy /Q /Y \"%%i\" \"%{outputdir}%{cfg.buildcfg}\\%{prj.name}\"", - "xcopy \"%{wks.location}\\..\\..\\Resources\\Engine\\*\" \"%{wks.location}\\..\\..\\Build\\%{cfg.buildcfg}\\Data\\Engine\" /y /i /r /e /q", - "xcopy \"%{wks.location}\\..\\..\\Resources\\Editor\\*\" \"%{wks.location}\\..\\..\\Build\\%{cfg.buildcfg}\\Data\\Editor\" /y /i /r /e /q", - "xcopy \"%{prj.location}\\Layout.ini\" \"%{wks.location}\\..\\..\\Build\\%{cfg.buildcfg}\\Config\\\" /y /i", + "rmdir /s /q \"%{builddir}%{cfg.buildcfg}\\Data\"", - "xcopy /Y /I /Q /D \"%{wks.location}\\..\\..\\Bin\\Debug\\%{prj.name}\\*.exe\" \"%{wks.location}\\..\\..\\Build\\%{cfg.buildcfg}\\\"", - "xcopy /Y /I /Q /D \"%{wks.location}\\..\\..\\Bin\\Debug\\%{prj.name}\\*.dll\" \"%{wks.location}\\..\\..\\Build\\%{cfg.buildcfg}\\\"", - "xcopy /Y /I /Q /D \"%{wks.location}\\..\\..\\Bin\\Release\\%{prj.name}\\*.exe\" \"%{wks.location}\\..\\..\\Build\\%{cfg.buildcfg}\\\"", - "xcopy /Y /I /Q /D \"%{wks.location}\\..\\..\\Bin\\Release\\%{prj.name}\\*.dll\" \"%{wks.location}\\..\\..\\Build\\%{cfg.buildcfg}\\\"", + "xcopy \"%{resdir}Engine\\*\" \"%{builddir}%{cfg.buildcfg}\\Data\\Engine\" /y /i /r /e /q", + "xcopy \"%{resdir}Editor\\*\" \"%{builddir}%{cfg.buildcfg}\\Data\\Editor\" /y /i /r /e /q", + "xcopy \"%{prj.location}\\Layout.ini\" \"%{builddir}%{cfg.buildcfg}\\Config\\\" /y /i", - "xcopy \"%{wks.location}..\\..\\Bin\\Debug\\OvGame\\*.exe\" \"%{wks.location}..\\..\\Build\\%{cfg.buildcfg}\\Builder\\Development\" /y /i /c", - "xcopy \"%{wks.location}..\\..\\Bin\\Release\\OvGame\\*.exe\" \"%{wks.location}..\\..\\Build\\%{cfg.buildcfg}\\Builder\\Shipping\" /y /i /c", + "xcopy /Y /I /Q /D \"%{outputdir}Debug\\%{prj.name}\\*.exe\" \"%{builddir}%{cfg.buildcfg}\\\"", + "xcopy /Y /I /Q /D \"%{outputdir}Debug\\%{prj.name}\\*.dll\" \"%{builddir}%{cfg.buildcfg}\\\"", + "xcopy /Y /I /Q /D \"%{outputdir}Release\\%{prj.name}\\*.exe\" \"%{builddir}%{cfg.buildcfg}\\\"", + "xcopy /Y /I /Q /D \"%{outputdir}Release\\%{prj.name}\\*.dll\" \"%{builddir}%{cfg.buildcfg}\\\"", + + "xcopy \"%{outputdir}Debug\\OvGame\\*.exe\" \"%{builddir}%{cfg.buildcfg}\\Builder\\Development\" /y /i /c", + "xcopy \"%{outputdir}Release\\OvGame\\*.exe\" \"%{builddir}%{cfg.buildcfg}\\Builder\\Shipping\" /y /i /c", "EXIT /B 0" } diff --git a/Sources/Overload/OvEditor/src/OvEditor/Core/EditorActions.cpp b/Sources/Overload/OvEditor/src/OvEditor/Core/EditorActions.cpp index 1afcbde3..d1441e34 100644 --- a/Sources/Overload/OvEditor/src/OvEditor/Core/EditorActions.cpp +++ b/Sources/Overload/OvEditor/src/OvEditor/Core/EditorActions.cpp @@ -625,14 +625,16 @@ bool OvEditor::Core::EditorActions::ImportAsset(const std::string& p_initialDest std::string modelFormats = "*.fbx;*.obj;"; std::string textureFormats = "*.png;*.jpeg;*.jpg;*.tga"; - std::string shaderFormats = "*.glsl;"; + std::string shaderFormats = "*.ovfx"; + std::string shaderPartFormats = "*.ovfxh"; std::string soundFormats = "*.mp3;*.ogg;*.wav;"; OpenFileDialog selectAssetDialog("Select an asset to import"); selectAssetDialog.AddFileType("Any supported format", modelFormats + textureFormats + shaderFormats + soundFormats); selectAssetDialog.AddFileType("Model (.fbx, .obj)", modelFormats); selectAssetDialog.AddFileType("Texture (.png, .jpeg, .jpg, .tga)", textureFormats); - selectAssetDialog.AddFileType("Shader (.glsl)", shaderFormats); + selectAssetDialog.AddFileType("Shader (.ovfx)", shaderFormats); + selectAssetDialog.AddFileType("Shader Parts (.ovfxh)", shaderPartFormats); selectAssetDialog.AddFileType("Sound (.mp3, .ogg, .wav)", soundFormats); selectAssetDialog.Show(); @@ -669,14 +671,16 @@ bool OvEditor::Core::EditorActions::ImportAssetAtLocation(const std::string& p_d std::string modelFormats = "*.fbx;*.obj;"; std::string textureFormats = "*.png;*.jpeg;*.jpg;*.tga;"; - std::string shaderFormats = "*.glsl;"; + std::string shaderFormats = "*.ovfx"; + std::string shaderPartFormats = "*.ovfxh"; std::string soundFormats = "*.mp3;*.ogg;*.wav;"; OpenFileDialog selectAssetDialog("Select an asset to import"); selectAssetDialog.AddFileType("Any supported format", modelFormats + textureFormats + shaderFormats + soundFormats); selectAssetDialog.AddFileType("Model (.fbx, .obj)", modelFormats); selectAssetDialog.AddFileType("Texture (.png, .jpeg, .jpg, .tga)", textureFormats); - selectAssetDialog.AddFileType("Shader (.glsl)", shaderFormats); + selectAssetDialog.AddFileType("Shader (.ovfx)", shaderFormats); + selectAssetDialog.AddFileType("Shader Parts (.ovfxh)", shaderPartFormats); selectAssetDialog.AddFileType("Sound (.mp3, .ogg, .wav)", soundFormats); selectAssetDialog.Show(); diff --git a/Sources/Overload/OvEditor/src/OvEditor/Core/EditorResources.cpp b/Sources/Overload/OvEditor/src/OvEditor/Core/EditorResources.cpp index b07161ad..ff784c5e 100644 --- a/Sources/Overload/OvEditor/src/OvEditor/Core/EditorResources.cpp +++ b/Sources/Overload/OvEditor/src/OvEditor/Core/EditorResources.cpp @@ -17,8 +17,7 @@ OvEditor::Core::EditorResources::EditorResources(const std::string& p_editorAsse { using namespace OvRendering::Resources::Loaders; - std::string buttonsFolder = p_editorAssetsPath + "Textures\\Buttons\\"; - std::string iconsFolder = p_editorAssetsPath + "Textures\\Icons\\"; + std::string iconsFolder = p_editorAssetsPath + "Icons\\"; std::string modelsFolder = p_editorAssetsPath + "Models\\"; std::string shadersFolder = p_editorAssetsPath + "Shaders\\"; @@ -147,6 +146,8 @@ OvEditor::Core::EditorResources::EditorResources(const std::string& p_editorAsse m_textures["Bill_Ambient_Sphere_Light"] = TextureLoader::CreateFromMemory(reinterpret_cast(raw.data()), 128, 128, firstFilterBillboard, secondFilterBillboard, false); } + m_textures["Icon_Shader_Part"] = TextureLoader::Create(iconsFolder + "puzzle.png", firstFilterEditor, secondFilterEditor, false); + /* Models */ m_models["Cube"] = ModelLoader::Create(modelsFolder + "Cube.fbx", modelParserFlags); m_models["Cylinder"] = ModelLoader::Create(modelsFolder + "Cylinder.fbx", modelParserFlags); @@ -161,9 +162,9 @@ OvEditor::Core::EditorResources::EditorResources(const std::string& p_editorAsse m_models["Camera"] = ModelLoader::Create(modelsFolder + "Camera.fbx", modelParserFlags); /* Shaders */ - m_shaders["Grid"] = ShaderLoader::Create(shadersFolder + "Grid.glsl"); - m_shaders["Gizmo"] = ShaderLoader::Create(shadersFolder + "Gizmo.glsl"); - m_shaders["Billboard"] = ShaderLoader::Create(shadersFolder + "Billboard.glsl"); + m_shaders["Grid"] = ShaderLoader::Create(shadersFolder + "Grid.ovfx"); + m_shaders["Gizmo"] = ShaderLoader::Create(shadersFolder + "Gizmo.ovfx"); + m_shaders["Billboard"] = ShaderLoader::Create(shadersFolder + "Billboard.ovfx"); /* From memory */ { diff --git a/Sources/Overload/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp b/Sources/Overload/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp index 02daf4b5..3d984008 100644 --- a/Sources/Overload/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp +++ b/Sources/Overload/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp @@ -206,6 +206,8 @@ class FolderContextualMenu : public BrowserItemContextualMenu auto& createShaderMenu = createMenu.CreateWidget("Shader"); auto& createMaterialMenu = createMenu.CreateWidget("Material"); + auto& createEmptyShaderMenu = createShaderMenu.CreateWidget("Empty"); + auto& createPartialShaderMenu = createShaderMenu.CreateWidget("Partial"); auto& createStandardShaderMenu = createShaderMenu.CreateWidget("Standard template"); auto& createStandardPBRShaderMenu = createShaderMenu.CreateWidget("Standard PBR template"); auto& createUnlitShaderMenu = createShaderMenu.CreateWidget("Unlit template"); @@ -226,6 +228,8 @@ class FolderContextualMenu : public BrowserItemContextualMenu auto& createUnlitMaterial = createUnlitMaterialMenu.CreateWidget(""); auto& createLambertMaterial = createLambertMaterialMenu.CreateWidget(""); + auto& createEmptyShader = createEmptyShaderMenu.CreateWidget(""); + auto& createPartialShader = createPartialShaderMenu.CreateWidget(""); auto& createStandardShader = createStandardShaderMenu.CreateWidget(""); auto& createStandardPBRShader = createStandardPBRShaderMenu.CreateWidget(""); auto& createUnlitShader = createUnlitShaderMenu.CreateWidget(""); @@ -238,6 +242,8 @@ class FolderContextualMenu : public BrowserItemContextualMenu createUnlitShaderMenu.ClickedEvent += [&createUnlitShader] { createUnlitShader.content = ""; }; createLambertShaderMenu.ClickedEvent += [&createLambertShader] { createLambertShader.content = ""; }; createEmptyMaterialMenu.ClickedEvent += [&createEmptyMaterial] { createEmptyMaterial.content = ""; }; + createEmptyShaderMenu.ClickedEvent += [&createEmptyShader] { createEmptyShader.content = ""; }; + createPartialShaderMenu.ClickedEvent += [&createPartialShader] { createPartialShader.content = ""; }; createStandardMaterialMenu.ClickedEvent += [&createStandardMaterial] { createStandardMaterial.content = ""; }; createStandardPBRMaterialMenu.ClickedEvent += [&createStandardPBRMaterial] { createStandardPBRMaterial.content = ""; }; createUnlitMaterialMenu.ClickedEvent += [&createUnlitMaterial] { createUnlitMaterial.content = ""; }; @@ -280,6 +286,46 @@ class FolderContextualMenu : public BrowserItemContextualMenu Close(); }; + createEmptyShader.EnterPressedEvent += [this](std::string newShaderName) + { + size_t fails = 0; + std::string finalPath; + + do + { + finalPath = filePath + '\\' + (!fails ? newShaderName : newShaderName + " (" + std::to_string(fails) + ')') + ".ovfx"; + + ++fails; + } while (std::filesystem::exists(finalPath)); + + { + std::ofstream outfile(finalPath); + } + + ItemAddedEvent.Invoke(finalPath); + Close(); + }; + + createPartialShader.EnterPressedEvent += [this](std::string newShaderName) + { + size_t fails = 0; + std::string finalPath; + + do + { + finalPath = filePath + '\\' + (!fails ? newShaderName : newShaderName + " (" + std::to_string(fails) + ')') + ".ovfxh"; + + ++fails; + } while (std::filesystem::exists(finalPath)); + + { + std::ofstream outfile(finalPath); + } + + ItemAddedEvent.Invoke(finalPath); + Close(); + }; + createStandardShader.EnterPressedEvent += [this](std::string newShaderName) { size_t fails = 0; @@ -287,12 +333,12 @@ class FolderContextualMenu : public BrowserItemContextualMenu do { - finalPath = filePath + '\\' + (!fails ? newShaderName : newShaderName + " (" + std::to_string(fails) + ')') + ".glsl"; + finalPath = filePath + '\\' + (!fails ? newShaderName : newShaderName + " (" + std::to_string(fails) + ')') + ".ovfx"; ++fails; } while (std::filesystem::exists(finalPath)); - std::filesystem::copy_file(EDITOR_CONTEXT(engineAssetsPath) + "Shaders\\Standard.glsl", finalPath); + std::filesystem::copy_file(EDITOR_CONTEXT(engineAssetsPath) + "Shaders\\Standard.ovfx", finalPath); ItemAddedEvent.Invoke(finalPath); Close(); }; @@ -304,12 +350,12 @@ class FolderContextualMenu : public BrowserItemContextualMenu do { - finalPath = filePath + '\\' + (!fails ? newShaderName : newShaderName + " (" + std::to_string(fails) + ')') + ".glsl"; + finalPath = filePath + '\\' + (!fails ? newShaderName : newShaderName + " (" + std::to_string(fails) + ')') + ".ovfx"; ++fails; } while (std::filesystem::exists(finalPath)); - std::filesystem::copy_file(EDITOR_CONTEXT(engineAssetsPath) + "Shaders\\StandardPBR.glsl", finalPath); + std::filesystem::copy_file(EDITOR_CONTEXT(engineAssetsPath) + "Shaders\\StandardPBR.ovfx", finalPath); ItemAddedEvent.Invoke(finalPath); Close(); }; @@ -321,12 +367,12 @@ class FolderContextualMenu : public BrowserItemContextualMenu do { - finalPath = filePath + '\\' + (!fails ? newShaderName : newShaderName + " (" + std::to_string(fails) + ')') + ".glsl"; + finalPath = filePath + '\\' + (!fails ? newShaderName : newShaderName + " (" + std::to_string(fails) + ')') + ".ovfx"; ++fails; } while (std::filesystem::exists(finalPath)); - std::filesystem::copy_file(EDITOR_CONTEXT(engineAssetsPath) + "Shaders\\Unlit.glsl", finalPath); + std::filesystem::copy_file(EDITOR_CONTEXT(engineAssetsPath) + "Shaders\\Unlit.ovfx", finalPath); ItemAddedEvent.Invoke(finalPath); Close(); }; @@ -338,12 +384,12 @@ class FolderContextualMenu : public BrowserItemContextualMenu do { - finalPath = filePath + '\\' + (!fails ? newShaderName : newShaderName + " (" + std::to_string(fails) + ')') + ".glsl"; + finalPath = filePath + '\\' + (!fails ? newShaderName : newShaderName + " (" + std::to_string(fails) + ')') + ".ovfx"; ++fails; } while (std::filesystem::exists(finalPath)); - std::filesystem::copy_file(EDITOR_CONTEXT(engineAssetsPath) + "Shaders\\Lambert.glsl", finalPath); + std::filesystem::copy_file(EDITOR_CONTEXT(engineAssetsPath) + "Shaders\\Lambert.ovfx", finalPath); ItemAddedEvent.Invoke(finalPath); Close(); }; @@ -392,7 +438,7 @@ class FolderContextualMenu : public BrowserItemContextualMenu { std::ofstream outfile(finalPath); - outfile << ":Shaders\\Standard.glsl" << std::endl; // Empty standard material content + outfile << ":Shaders\\Standard.ovfx" << std::endl; // Empty standard material content } ItemAddedEvent.Invoke(finalPath); @@ -422,7 +468,7 @@ class FolderContextualMenu : public BrowserItemContextualMenu { std::ofstream outfile(finalPath); - outfile << ":Shaders\\StandardPBR.glsl" << std::endl; // Empty standard material content + outfile << ":Shaders\\StandardPBR.ovfx" << std::endl; // Empty standard material content } ItemAddedEvent.Invoke(finalPath); @@ -453,7 +499,7 @@ class FolderContextualMenu : public BrowserItemContextualMenu { std::ofstream outfile(finalPath); - outfile << ":Shaders\\Unlit.glsl" << std::endl; // Empty unlit material content + outfile << ":Shaders\\Unlit.ovfx" << std::endl; // Empty unlit material content } ItemAddedEvent.Invoke(finalPath); @@ -483,7 +529,7 @@ class FolderContextualMenu : public BrowserItemContextualMenu { std::ofstream outfile(finalPath); - outfile << ":Shaders\\Lambert.glsl" << std::endl; // Empty unlit material content + outfile << ":Shaders\\Lambert.ovfx" << std::endl; // Empty unlit material content } ItemAddedEvent.Invoke(finalPath); @@ -683,7 +729,7 @@ class ShaderContextualMenu : public FileContextualMenu if (shaderManager.IsResourceRegistered(resourcePath)) { /* Trying to recompile */ - OvRendering::Resources::Loaders::ShaderLoader::Recompile(*shaderManager[resourcePath], filePath); + shaderManager.ReloadResource(shaderManager[resourcePath], filePath); } else { @@ -697,6 +743,17 @@ class ShaderContextualMenu : public FileContextualMenu } }; +class ShaderPartContextualMenu : public FileContextualMenu +{ +public: + ShaderPartContextualMenu(const std::string& p_filePath, bool p_protected = false) : FileContextualMenu(p_filePath, p_protected) {} + + virtual void CreateList() override + { + FileContextualMenu::CreateList(); + } +}; + class ModelContextualMenu : public PreviewableContextualMenu { public: @@ -740,7 +797,7 @@ class ModelContextualMenu : public PreviewableContextualMenu:Shaders\\Standard.glsl" << std::endl; // Empty standard material content + outfile << ":Shaders\\Standard.ovfx" << std::endl; // Empty standard material content } DuplicateEvent.Invoke(finalPath); @@ -768,7 +825,7 @@ class ModelContextualMenu : public PreviewableContextualMenu:Shaders\\StandardPBR.glsl" << std::endl; // Empty standard material content + outfile << ":Shaders\\StandardPBR.ovfx" << std::endl; // Empty standard material content } DuplicateEvent.Invoke(finalPath); @@ -796,7 +853,7 @@ class ModelContextualMenu : public PreviewableContextualMenu:Shaders\\Unlit.glsl" << std::endl; // Empty standard material content + outfile << ":Shaders\\Unlit.ovfx" << std::endl; // Empty standard material content } DuplicateEvent.Invoke(finalPath); @@ -824,7 +881,7 @@ class ModelContextualMenu : public PreviewableContextualMenu:Shaders\\Lambert.glsl" << std::endl; // Empty standard material content + outfile << ":Shaders\\Lambert.ovfx" << std::endl; // Empty standard material content } DuplicateEvent.Invoke(finalPath); @@ -1222,6 +1279,7 @@ void OvEditor::Panels::AssetBrowser::ConsiderItem(OvUI::Widgets::Layout::TreeNod case OvTools::Utils::PathParser::EFileType::MODEL: contextMenu = &clickableText.AddPlugin(path, protectedItem); break; case OvTools::Utils::PathParser::EFileType::TEXTURE: contextMenu = &clickableText.AddPlugin(path, protectedItem); break; case OvTools::Utils::PathParser::EFileType::SHADER: contextMenu = &clickableText.AddPlugin(path, protectedItem); break; + case OvTools::Utils::PathParser::EFileType::SHADER_PART:contextMenu = &clickableText.AddPlugin(path, protectedItem); break; case OvTools::Utils::PathParser::EFileType::MATERIAL: contextMenu = &clickableText.AddPlugin(path, protectedItem); break; case OvTools::Utils::PathParser::EFileType::SCENE: contextMenu = &clickableText.AddPlugin(path, protectedItem); break; default: contextMenu = &clickableText.AddPlugin(path, protectedItem); break; diff --git a/Sources/Overload/OvEditor/src/OvEditor/Panels/AssetView.cpp b/Sources/Overload/OvEditor/src/OvEditor/Panels/AssetView.cpp index 919d86c8..63c1583e 100644 --- a/Sources/Overload/OvEditor/src/OvEditor/Panels/AssetView.cpp +++ b/Sources/Overload/OvEditor/src/OvEditor/Panels/AssetView.cpp @@ -50,13 +50,13 @@ OvEditor::Panels::AssetView::AssetView m_cameraController.LockTargetActor(*m_assetActor); /* Default Material */ - m_defaultMaterial.SetShader(EDITOR_CONTEXT(shaderManager)[":Shaders\\Standard.glsl"]); + m_defaultMaterial.SetShader(EDITOR_CONTEXT(shaderManager)[":Shaders\\Standard.ovfx"]); m_defaultMaterial.Set("u_Diffuse", OvMaths::FVector4(1.f, 1.f, 1.f, 1.f)); m_defaultMaterial.Set("u_Shininess", 100.0f); m_defaultMaterial.Set("u_DiffuseMap", nullptr); /* Texture Material */ - m_textureMaterial.SetShader(EDITOR_CONTEXT(shaderManager)[":Shaders\\Unlit.glsl"]); + m_textureMaterial.SetShader(EDITOR_CONTEXT(shaderManager)[":Shaders\\Unlit.ovfx"]); m_textureMaterial.Set("u_Diffuse", OvMaths::FVector4(1.f, 1.f, 1.f, 1.f)); m_textureMaterial.SetBackfaceCulling(false); m_textureMaterial.SetBlendable(true); diff --git a/Sources/Overload/OvEditor/src/OvEditor/Panels/SceneView.cpp b/Sources/Overload/OvEditor/src/OvEditor/Panels/SceneView.cpp index c4033ee9..81403e78 100644 --- a/Sources/Overload/OvEditor/src/OvEditor/Panels/SceneView.cpp +++ b/Sources/Overload/OvEditor/src/OvEditor/Panels/SceneView.cpp @@ -25,7 +25,7 @@ OvEditor::Panels::SceneView::SceneView m_camera.SetFar(5000.0f); - m_fallbackMaterial.SetShader(EDITOR_CONTEXT(shaderManager)[":Shaders\\Unlit.glsl"]); + m_fallbackMaterial.SetShader(EDITOR_CONTEXT(shaderManager)[":Shaders\\Unlit.ovfx"]); m_fallbackMaterial.Set("u_Diffuse", { 1.f, 0.f, 1.f, 1.0f }); m_fallbackMaterial.Set("u_DiffuseMap", nullptr); diff --git a/Sources/Overload/OvEditor/src/OvEditor/Rendering/DebugSceneRenderer.cpp b/Sources/Overload/OvEditor/src/OvEditor/Rendering/DebugSceneRenderer.cpp index f21778fd..73c8f700 100644 --- a/Sources/Overload/OvEditor/src/OvEditor/Rendering/DebugSceneRenderer.cpp +++ b/Sources/Overload/OvEditor/src/OvEditor/Rendering/DebugSceneRenderer.cpp @@ -77,7 +77,7 @@ class DebugCamerasRenderPass : public OvRendering::Core::ARenderPass public: DebugCamerasRenderPass(OvRendering::Core::CompositeRenderer& p_renderer) : OvRendering::Core::ARenderPass(p_renderer) { - m_cameraMaterial.SetShader(EDITOR_CONTEXT(shaderManager)[":Shaders\\Lambert.glsl"]); + m_cameraMaterial.SetShader(EDITOR_CONTEXT(shaderManager)[":Shaders\\Lambert.ovfx"]); m_cameraMaterial.Set("u_Diffuse", FVector4(0.0f, 0.3f, 0.7f, 1.0f)); m_cameraMaterial.Set("u_DiffuseMap", nullptr); } diff --git a/Sources/Overload/OvEditor/src/OvEditor/Rendering/OutlineRenderFeature.cpp b/Sources/Overload/OvEditor/src/OvEditor/Rendering/OutlineRenderFeature.cpp index 13d56fa2..c115c8f2 100644 --- a/Sources/Overload/OvEditor/src/OvEditor/Rendering/OutlineRenderFeature.cpp +++ b/Sources/Overload/OvEditor/src/OvEditor/Rendering/OutlineRenderFeature.cpp @@ -20,14 +20,14 @@ OvEditor::Rendering::OutlineRenderFeature::OutlineRenderFeature(OvRendering::Cor OvRendering::Features::ARenderFeature(p_renderer) { /* Stencil Fill Material */ - m_stencilFillMaterial.SetShader(EDITOR_CONTEXT(shaderManager)[":Shaders\\Unlit.glsl"]); + m_stencilFillMaterial.SetShader(EDITOR_CONTEXT(shaderManager)[":Shaders\\Unlit.ovfx"]); m_stencilFillMaterial.SetBackfaceCulling(true); m_stencilFillMaterial.SetDepthTest(false); m_stencilFillMaterial.SetColorWriting(false); m_stencilFillMaterial.Set("u_DiffuseMap", nullptr); /* Outline Material */ - m_outlineMaterial.SetShader(EDITOR_CONTEXT(shaderManager)[":Shaders\\Unlit.glsl"]); + m_outlineMaterial.SetShader(EDITOR_CONTEXT(shaderManager)[":Shaders\\Unlit.ovfx"]); m_outlineMaterial.Set("u_DiffuseMap", nullptr); m_outlineMaterial.SetDepthTest(false); } diff --git a/Sources/Overload/OvEditor/src/OvEditor/Rendering/PickingRenderPass.cpp b/Sources/Overload/OvEditor/src/OvEditor/Rendering/PickingRenderPass.cpp index c1ba0ba8..d04363f6 100644 --- a/Sources/Overload/OvEditor/src/OvEditor/Rendering/PickingRenderPass.cpp +++ b/Sources/Overload/OvEditor/src/OvEditor/Rendering/PickingRenderPass.cpp @@ -27,7 +27,7 @@ OvEditor::Rendering::PickingRenderPass::PickingRenderPass(OvRendering::Core::Com m_gizmoPickingMaterial.Set("u_IsPickable", true); /* Picking Material */ - m_actorPickingMaterial.SetShader(EDITOR_CONTEXT(shaderManager)[":Shaders\\Unlit.glsl"]); + m_actorPickingMaterial.SetShader(EDITOR_CONTEXT(shaderManager)[":Shaders\\Unlit.ovfx"]); m_actorPickingMaterial.Set("u_Diffuse", OvMaths::FVector4(1.f, 1.f, 1.f, 1.0f)); m_actorPickingMaterial.Set("u_DiffuseMap", nullptr); m_actorPickingMaterial.SetFrontfaceCulling(false); diff --git a/Sources/Overload/OvGame/premake5.lua b/Sources/Overload/OvGame/premake5.lua index 4ac3a9cc..5dd43e6d 100644 --- a/Sources/Overload/OvGame/premake5.lua +++ b/Sources/Overload/OvGame/premake5.lua @@ -1,7 +1,7 @@ project "OvGame" language "C++" cppdialect "C++17" - files { "**.h", "**.inl","**.cpp", "**.rc" } + files { "**.h", "**.inl","**.cpp", "**.lua", "**.rc" } includedirs { "include", dependdir .. "glfw/include", dependdir .. "stb_image/include", dependdir .. "lua/include", dependdir .. "bullet3/include", dependdir .. "glew/include", dependdir .. "irrklang/include", "%{wks.location}/OvAnalytics/include", "%{wks.location}/OvAudio/include", "%{wks.location}/OvCore/include", "%{wks.location}/OvDebug/include", "%{wks.location}/OvMaths/include", "%{wks.location}/OvPhysics/include", @@ -16,12 +16,12 @@ project "OvGame" characterset ("MBCS") postbuildcommands { - "for /f \"delims=|\" %%i in ('dir /B /S \"%{wks.location}..\\..\\Dependencies\\*.dll\"') do xcopy /Q /Y \"%%i\" \"%{wks.location}..\\..\\Bin\\%{cfg.buildcfg}\\%{prj.name}\"", + "for /f \"delims=|\" %%i in ('dir /B /S \"%{dependdir}\\*.dll\"') do xcopy /Q /Y \"%%i\" \"%{builddir}%{cfg.buildcfg}\\%{prj.name}\"", - "xcopy /Y /I /Q /D \"%{wks.location}\\..\\..\\Bin\\Debug\\%{prj.name}\\*.exe\" \"%{wks.location}\\..\\..\\Build\\%{cfg.buildcfg}\\Builder\\Development\"", - "xcopy /Y /I /Q /D \"%{wks.location}\\..\\..\\Bin\\Debug\\%{prj.name}\\*.dll\" \"%{wks.location}\\..\\..\\Build\\%{cfg.buildcfg}\\Builder\\Development\"", - "xcopy /Y /I /Q /D \"%{wks.location}\\..\\..\\Bin\\Release\\%{prj.name}\\*.exe\" \"%{wks.location}\\..\\..\\Build\\%{cfg.buildcfg}\\Builder\\Shipping\"", - "xcopy /Y /I /Q /D \"%{wks.location}\\..\\..\\Bin\\Release\\%{prj.name}\\*.dll\" \"%{wks.location}\\..\\..\\Build\\%{cfg.buildcfg}\\Builder\\Shipping\"", + "xcopy /Y /I /Q /D \"%{outputdir}Debug\\%{prj.name}\\*.exe\" \"%{builddir}%{cfg.buildcfg}\\Builder\\Development\"", + "xcopy /Y /I /Q /D \"%{outputdir}Debug\\%{prj.name}\\*.dll\" \"%{builddir}%{cfg.buildcfg}\\Builder\\Development\"", + "xcopy /Y /I /Q /D \"%{outputdir}Release\\%{prj.name}\\*.exe\" \"%{builddir}%{cfg.buildcfg}\\Builder\\Shipping\"", + "xcopy /Y /I /Q /D \"%{outputdir}Release\\%{prj.name}\\*.dll\" \"%{builddir}%{cfg.buildcfg}\\Builder\\Shipping\"", "EXIT /B 0" } diff --git a/Sources/Overload/OvGame/src/OvGame/Core/Game.cpp b/Sources/Overload/OvGame/src/OvGame/Core/Game.cpp index 7ed2f6c6..694ba975 100644 --- a/Sources/Overload/OvGame/src/OvGame/Core/Game.cpp +++ b/Sources/Overload/OvGame/src/OvGame/Core/Game.cpp @@ -119,11 +119,6 @@ void OvGame::Core::Game::Update(float p_deltaTime) if (m_context.inputManager->IsKeyPressed(OvWindowing::Inputs::EKey::KEY_F12)) m_showDebugInformation = !m_showDebugInformation; - #ifdef _DEBUG - if (m_context.inputManager->IsKeyPressed(OvWindowing::Inputs::EKey::KEY_R)) - OvRendering::Resources::Loaders::ShaderLoader::Recompile(*m_context.shaderManager[":Shaders\\Standard.glsl"], "Data\\Engine\\Shaders\\Standard.glsl"); - #endif - if (m_showDebugInformation) { m_fpsCounter.Update(p_deltaTime); diff --git a/Sources/Overload/OvMaths/premake5.lua b/Sources/Overload/OvMaths/premake5.lua index 1d646ff8..aa14650a 100644 --- a/Sources/Overload/OvMaths/premake5.lua +++ b/Sources/Overload/OvMaths/premake5.lua @@ -2,7 +2,7 @@ project "OvMaths" kind "StaticLib" language "C++" cppdialect "C++17" - files { "**.h", "**.inl", "**.cpp" } + files { "**.h", "**.inl", "**.cpp", "**.lua" } includedirs { "include" } targetdir (outputdir .. "%{cfg.buildcfg}/%{prj.name}") objdir (objoutdir .. "%{cfg.buildcfg}/%{prj.name}") diff --git a/Sources/Overload/OvPhysics/premake5.lua b/Sources/Overload/OvPhysics/premake5.lua index f04bdc87..f538013c 100644 --- a/Sources/Overload/OvPhysics/premake5.lua +++ b/Sources/Overload/OvPhysics/premake5.lua @@ -2,7 +2,7 @@ project "OvPhysics" kind "StaticLib" language "C++" cppdialect "C++17" - files { "**.h", "**.inl", "**.cpp" } + files { "**.h", "**.inl", "**.cpp", "**.lua" } includedirs { "include", dependdir .. "bullet3/include", "%{wks.location}/OvDebug/include", "%{wks.location}/OvMaths/include", "%{wks.location}/OvTools/include" } targetdir (outputdir .. "%{cfg.buildcfg}/%{prj.name}") objdir (objoutdir .. "%{cfg.buildcfg}/%{prj.name}") diff --git a/Sources/Overload/OvRendering/include/OvRendering/Resources/Loaders/ShaderLoader.h b/Sources/Overload/OvRendering/include/OvRendering/Resources/Loaders/ShaderLoader.h index 5aeb9607..f07f2a1b 100644 --- a/Sources/Overload/OvRendering/include/OvRendering/Resources/Loaders/ShaderLoader.h +++ b/Sources/Overload/OvRendering/include/OvRendering/Resources/Loaders/ShaderLoader.h @@ -6,6 +6,8 @@ #pragma once +#include + #include "OvRendering/Resources/Shader.h" namespace OvRendering::Resources::Loaders @@ -16,6 +18,8 @@ namespace OvRendering::Resources::Loaders class ShaderLoader { public: + using FilePathParserCallback = std::function; + /** * Disabled constructor */ @@ -24,13 +28,15 @@ namespace OvRendering::Resources::Loaders /** * Create a shader * @param p_filePath + * @param p_pathParser */ - static Shader* Create(const std::string& p_filePath); + static Shader* Create(const std::string& p_filePath, FilePathParserCallback p_pathParser = nullptr); /** * Create a shader from source * @param p_vertexShader * @param p_fragmentShader + * @note Doesn't support path parsing/resolving */ static Shader* CreateFromSource(const std::string& p_vertexShader, const std::string& p_fragmentShader); @@ -39,7 +45,7 @@ namespace OvRendering::Resources::Loaders * @param p_shader * @param p_filePath */ - static void Recompile(Shader& p_shader, const std::string& p_filePath); + static void Recompile(Shader& p_shader, const std::string& p_filePath, FilePathParserCallback p_pathParser = nullptr); /** * Destroy a shader @@ -48,7 +54,9 @@ namespace OvRendering::Resources::Loaders static bool Destroy(Shader*& p_shader); private: - static std::pair ParseShader(const std::string& p_filePath); + static bool ParseIncludeDirective(const std::string& line, std::string& includeFilePath); + static std::string LoadShader(const std::string& p_filePath, FilePathParserCallback p_pathParser); + static std::pair ParseShader(const std::string& p_filePath, FilePathParserCallback p_pathParser); static uint32_t CreateProgram(const std::string& p_vertexShader, const std::string& p_fragmentShader); static uint32_t CompileShader(uint32_t p_type, const std::string& p_source); diff --git a/Sources/Overload/OvRendering/include/OvRendering/Resources/Shader.h b/Sources/Overload/OvRendering/include/OvRendering/Resources/Shader.h index 5ddd44fe..8d309083 100644 --- a/Sources/Overload/OvRendering/include/OvRendering/Resources/Shader.h +++ b/Sources/Overload/OvRendering/include/OvRendering/Resources/Shader.h @@ -15,8 +15,6 @@ #include "OvRendering/Resources/UniformInfo.h" - - namespace OvRendering::Resources { namespace Loaders { class ShaderLoader; } diff --git a/Sources/Overload/OvRendering/premake5.lua b/Sources/Overload/OvRendering/premake5.lua index ab201217..cc1f0aaa 100644 --- a/Sources/Overload/OvRendering/premake5.lua +++ b/Sources/Overload/OvRendering/premake5.lua @@ -2,7 +2,7 @@ project "OvRendering" kind "StaticLib" language "C++" cppdialect "C++17" - files { "**.h", "**.inl", "**.cpp" } + files { "**.h", "**.inl", "**.cpp", "**.lua" } includedirs { "include", dependdir .. "glew/include", dependdir .. "stb_image/include", dependdir .. "assimp/include", "%{wks.location}/OvDebug/include", "%{wks.location}/OvMaths/include", "%{wks.location}/OvTools/include" } targetdir (outputdir .. "%{cfg.buildcfg}/%{prj.name}") objdir (objoutdir .. "%{cfg.buildcfg}/%{prj.name}") diff --git a/Sources/Overload/OvRendering/src/OvRendering/Resources/Loaders/ShaderLoader.cpp b/Sources/Overload/OvRendering/src/OvRendering/Resources/Loaders/ShaderLoader.cpp index 5c25dab9..429a5147 100644 --- a/Sources/Overload/OvRendering/src/OvRendering/Resources/Loaders/ShaderLoader.cpp +++ b/Sources/Overload/OvRendering/src/OvRendering/Resources/Loaders/ShaderLoader.cpp @@ -15,11 +15,11 @@ std::string OvRendering::Resources::Loaders::ShaderLoader::__FILE_TRACE; -OvRendering::Resources::Shader* OvRendering::Resources::Loaders::ShaderLoader::Create(const std::string& p_filePath) +OvRendering::Resources::Shader* OvRendering::Resources::Loaders::ShaderLoader::Create(const std::string& p_filePath, FilePathParserCallback p_pathParser) { __FILE_TRACE = p_filePath; - std::pair source = ParseShader(p_filePath); + std::pair source = ParseShader(p_filePath, p_pathParser); uint32_t programID = CreateProgram(source.first, source.second); @@ -39,11 +39,11 @@ OvRendering::Resources::Shader* OvRendering::Resources::Loaders::ShaderLoader::C return nullptr; } -void OvRendering::Resources::Loaders::ShaderLoader::Recompile(Shader& p_shader, const std::string& p_filePath) +void OvRendering::Resources::Loaders::ShaderLoader::Recompile(Shader& p_shader, const std::string& p_filePath, FilePathParserCallback p_pathParser) { __FILE_TRACE = p_filePath; - std::pair source = ParseShader(p_filePath); + std::pair source = ParseShader(p_filePath, p_pathParser); /* Create the new program */ uint32_t newProgram = CreateProgram(source.first, source.second); @@ -82,24 +82,85 @@ bool OvRendering::Resources::Loaders::ShaderLoader::Destroy(Shader*& p_shader) return false; } -std::pair OvRendering::Resources::Loaders::ShaderLoader::ParseShader(const std::string& p_filePath) +bool OvRendering::Resources::Loaders::ShaderLoader::ParseIncludeDirective(const std::string& line, std::string& includeFilePath) { - std::ifstream stream(p_filePath); + // Find the position of the opening and closing quotes + size_t start = line.find("\""); + size_t end = line.find("\"", start + 1); - enum class ShaderType { NONE = -1, VERTEX = 0, FRAGMENT = 1 }; + // Check if both quotes are found + if (start != std::string::npos && end != std::string::npos && end > start) + { + // Extract the included file path + includeFilePath = line.substr(start + 1, end - start - 1); + return true; + } + else + { + return false; + } +} + +std::string OvRendering::Resources::Loaders::ShaderLoader::LoadShader(const std::string& p_filePath, FilePathParserCallback p_pathParser) +{ + std::ifstream file(p_filePath); + if (!file.is_open()) + { + OVLOG_ERROR("Error: Could not open shader file - " + p_filePath); + return ""; + } + + std::stringstream buffer; std::string line; + while (std::getline(file, line)) + { + if (line.find("#include") != std::string::npos) + { + // If the line contains #include, process the included file + std::string includeFilePath; + if (ParseIncludeDirective(line, includeFilePath)) + { + // Recursively load the included file + const std::string realIncludeFilePath = p_pathParser ? p_pathParser(includeFilePath) : includeFilePath; + std::string includedShader = LoadShader(realIncludeFilePath, p_pathParser); + buffer << includedShader << std::endl; + } + else + { + OVLOG_ERROR("Error: Invalid #include directive in file - " + p_filePath); + } + } + else { + // If the line does not contain #include, just append it to the buffer + buffer << line << std::endl; + } + } + + return buffer.str(); +} + +std::pair OvRendering::Resources::Loaders::ShaderLoader::ParseShader(const std::string& p_filePath, FilePathParserCallback p_pathParser) +{ + const std::string shaderCode = LoadShader(p_filePath, p_pathParser); + + std::istringstream stream(shaderCode); // Add this line to create a stringstream from shaderCode + std::string line; std::stringstream ss[2]; + enum class ShaderType { NONE = -1, VERTEX = 0, FRAGMENT = 1 }; + ShaderType type = ShaderType::NONE; while (std::getline(stream, line)) { if (line.find("#shader") != std::string::npos) { - if (line.find("vertex") != std::string::npos) type = ShaderType::VERTEX; - else if (line.find("fragment") != std::string::npos) type = ShaderType::FRAGMENT; + if (line.find("vertex") != std::string::npos) + type = ShaderType::VERTEX; + else if (line.find("fragment") != std::string::npos) + type = ShaderType::FRAGMENT; } else if (type != ShaderType::NONE) { @@ -107,8 +168,8 @@ std::pair OvRendering::Resources::Loaders::ShaderLoade } } - return - { + return + { ss[static_cast(ShaderType::VERTEX)].str(), ss[static_cast(ShaderType::FRAGMENT)].str() }; diff --git a/Sources/Overload/OvTools/include/OvTools/Utils/PathParser.h b/Sources/Overload/OvTools/include/OvTools/Utils/PathParser.h index 6fc60c99..758d21fb 100644 --- a/Sources/Overload/OvTools/include/OvTools/Utils/PathParser.h +++ b/Sources/Overload/OvTools/include/OvTools/Utils/PathParser.h @@ -23,6 +23,7 @@ namespace OvTools::Utils MODEL, TEXTURE, SHADER, + SHADER_PART, MATERIAL, SOUND, SCENE, diff --git a/Sources/Overload/OvTools/premake5.lua b/Sources/Overload/OvTools/premake5.lua index f31b1e9c..f6631c31 100644 --- a/Sources/Overload/OvTools/premake5.lua +++ b/Sources/Overload/OvTools/premake5.lua @@ -2,7 +2,7 @@ project "OvTools" kind "StaticLib" language "C++" cppdialect "C++17" - files { "**.h", "**.inl", "**.cpp" } + files { "**.h", "**.inl", "**.cpp", "**.lua" } includedirs { "include" } targetdir (outputdir .. "%{cfg.buildcfg}/%{prj.name}") objdir (objoutdir .. "%{cfg.buildcfg}/%{prj.name}") diff --git a/Sources/Overload/OvTools/src/OvTools/Utils/PathParser.cpp b/Sources/Overload/OvTools/src/OvTools/Utils/PathParser.cpp index 5969e235..4a0da637 100644 --- a/Sources/Overload/OvTools/src/OvTools/Utils/PathParser.cpp +++ b/Sources/Overload/OvTools/src/OvTools/Utils/PathParser.cpp @@ -88,6 +88,7 @@ std::string OvTools::Utils::PathParser::FileTypeToString(EFileType p_fileType) case OvTools::Utils::PathParser::EFileType::MODEL: return "Model"; case OvTools::Utils::PathParser::EFileType::TEXTURE: return "Texture"; case OvTools::Utils::PathParser::EFileType::SHADER: return "Shader"; + case OvTools::Utils::PathParser::EFileType::SHADER_PART:return "Shader_Part"; case OvTools::Utils::PathParser::EFileType::MATERIAL: return "Material"; case OvTools::Utils::PathParser::EFileType::SOUND: return "Sound"; case OvTools::Utils::PathParser::EFileType::SCENE: return "Scene"; @@ -105,7 +106,8 @@ OvTools::Utils::PathParser::EFileType OvTools::Utils::PathParser::GetFileType(co if (ext == "fbx" || ext == "obj") return EFileType::MODEL; else if (ext == "png" || ext == "jpeg" || ext == "jpg" || ext == "tga") return EFileType::TEXTURE; - else if (ext == "glsl") return EFileType::SHADER; + else if (ext == "ovfx") return EFileType::SHADER; + else if (ext == "ovfxh") return EFileType::SHADER_PART; else if (ext == "ovmat") return EFileType::MATERIAL; else if (ext == "wav" || ext == "mp3" || ext == "ogg") return EFileType::SOUND; else if (ext == "ovscene") return EFileType::SCENE; diff --git a/Sources/Overload/OvUI/premake5.lua b/Sources/Overload/OvUI/premake5.lua index d1e6c121..f826271e 100644 --- a/Sources/Overload/OvUI/premake5.lua +++ b/Sources/Overload/OvUI/premake5.lua @@ -2,7 +2,7 @@ project "OvUI" kind "StaticLib" language "C++" cppdialect "C++17" - files { "**.h", "**.inl", "**.cpp" } + files { "**.h", "**.inl", "**.cpp", "**.lua" } includedirs { "include", dependdir .. "glfw/include", dependdir .. "glew/include", "%{wks.location}/OvMaths/include", "%{wks.location}/OvTools/include" } targetdir (outputdir .. "%{cfg.buildcfg}/%{prj.name}") objdir (objoutdir .. "%{cfg.buildcfg}/%{prj.name}") diff --git a/Sources/Overload/OvWindowing/premake5.lua b/Sources/Overload/OvWindowing/premake5.lua index f4d1a7fb..0fb15a7f 100644 --- a/Sources/Overload/OvWindowing/premake5.lua +++ b/Sources/Overload/OvWindowing/premake5.lua @@ -2,7 +2,7 @@ project "OvWindowing" kind "StaticLib" language "C++" cppdialect "C++17" - files { "**.h", "**.inl", "**.cpp" } + files { "**.h", "**.inl", "**.cpp", "**.lua" } includedirs { "include", dependdir .. "glfw/include", dependdir .. "stb_image/include", "%{wks.location}/OvTools/include" } targetdir (outputdir .. "%{cfg.buildcfg}/%{prj.name}") objdir (objoutdir .. "%{cfg.buildcfg}/%{prj.name}") diff --git a/Sources/Overload/premake5.lua b/Sources/Overload/premake5.lua index 65a20524..dbac74c4 100644 --- a/Sources/Overload/premake5.lua +++ b/Sources/Overload/premake5.lua @@ -6,6 +6,8 @@ workspace "Overload" outputdir = "%{wks.location}/../../Bin/" objoutdir = "%{wks.location}/../../Bin-Int/" dependdir = "%{wks.location}/../../Dependencies/" +builddir = "%{wks.location}/../../Build/" +resdir = "%{wks.location}/../../Resources/" include "OvAnalytics" include "OvAudio" @@ -19,4 +21,6 @@ include "OvUI" include "OvWindowing" include "OvEditor" -include "OvGame" \ No newline at end of file +include "OvGame" + +include "../../Resources"