From 31b5eccbb92776ea6f67cd64db867010db97d8bb Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Tue, 12 Sep 2023 18:48:29 -0400 Subject: [PATCH] Initial attempt: use lightmap in the object shader To apply terrain lightmap additive color (from environmental point lights / effects) to objects. For appearances, decrease how much this is applied based on the height above the terrain. --- data/base/shaders/tcmask_depth_instanced.vert | 9 +++- data/base/shaders/tcmask_instanced.frag | 18 +++++-- data/base/shaders/tcmask_instanced.vert | 15 +++++- .../shaders/vk/tcmask_depth_instanced.vert | 9 +++- data/base/shaders/vk/tcmask_instanced.frag | 20 ++++++-- data/base/shaders/vk/tcmask_instanced.glsl | 1 + data/base/shaders/vk/tcmask_instanced.vert | 15 +++++- lib/ivis_opengl/gfx_api.h | 4 +- lib/ivis_opengl/gfx_api_gl.cpp | 42 +++++++++-------- lib/ivis_opengl/piedraw.cpp | 47 ++++++++++++------- lib/ivis_opengl/piedraw.h | 6 +++ src/component.cpp | 37 +++++++++------ src/component.h | 2 +- src/display3d.cpp | 10 ++-- src/droid.cpp | 1 + src/droiddef.h | 1 + src/move.cpp | 1 + src/terrain.cpp | 10 ++++ src/terrain.h | 8 ++++ 19 files changed, 188 insertions(+), 68 deletions(-) diff --git a/data/base/shaders/tcmask_depth_instanced.vert b/data/base/shaders/tcmask_depth_instanced.vert index 5069001c967..0ace2ed2014 100644 --- a/data/base/shaders/tcmask_depth_instanced.vert +++ b/data/base/shaders/tcmask_depth_instanced.vert @@ -35,6 +35,10 @@ VERTEX_INPUT vec4 instancePackedValues; // shaderStretch_ecmState_alphaTest_anim VERTEX_INPUT vec4 instanceColour; VERTEX_INPUT vec4 instanceTeamColour; +float when_gt(float x, float y) { + return max(sign(x - y), 0.0); +} + void main() { // unpack inputs @@ -45,7 +49,10 @@ void main() vec4 position = vertex; if (vertex.y <= 0.0) // use vertex here directly to help shader compiler optimization { - position.y -= stretch; + // NOTE: 'stretch' may be: + // - if positive: building stretching + // - if negative: the height above the terrain of the model intance overall + position.y -= (stretch * when_gt(stretch, 0.f)); } // Translate every vertex according to the Model View and Projection Matrix diff --git a/data/base/shaders/tcmask_instanced.frag b/data/base/shaders/tcmask_instanced.frag index 61434b91872..aeaea7cf261 100644 --- a/data/base/shaders/tcmask_instanced.frag +++ b/data/base/shaders/tcmask_instanced.frag @@ -17,6 +17,7 @@ uniform sampler2D TextureTcmask; // tcmask uniform sampler2D TextureNormal; // normal map uniform sampler2D TextureSpecular; // specular map uniform sampler2DArrayShadow shadowMap; // shadow map +uniform sampler2D lightmap_tex; uniform mat4 ViewMatrix; @@ -56,6 +57,7 @@ FRAGMENT_INPUT mat4 NormalMatrix; FRAGMENT_INPUT vec4 colour; FRAGMENT_INPUT vec4 teamcolour; FRAGMENT_INPUT vec4 packed_ecmState_alphaTest; +FRAGMENT_INPUT vec3 uvLightmap; // uvLightmap in .xy, heightAboveTerrain in .z // For Shadows FRAGMENT_INPUT vec3 fragPos; @@ -289,6 +291,10 @@ float getShadowVisibility() #endif } +vec3 blendAddEffectLighting(vec3 a, vec3 b) { + return min(a + b, vec3(1.0)); +} + void main() { // unpack inputs @@ -327,6 +333,9 @@ void main() vec3 L = normalize(lightDir); float lambertTerm = max(dot(N, L), 0.0); //diffuse light float visibility = getShadowVisibility(); + vec4 lightmap_vec4 = texture(lightmap_tex, uvLightmap.xy, 0.f); + float distanceAboveTerrain = uvLightmap.z; + float lightmapFactor = 1.0f - (clamp(distanceAboveTerrain, 0.f, 300.f) / 300.f); if (lambertTerm > 0.0) { @@ -350,7 +359,10 @@ void main() light += diffuse * lambertTerm * diffuseMap * vanillaFactor; } // ambient light maxed for classic models to keep results similar to original - light += ambient * diffuseMap * (1.0 + (1.0 - float(specularmap))); + light += vec4(blendAddEffectLighting(ambient.rgb, ((lightmap_vec4.rgb * lightmapFactor) / 3.f)), ambient.a) * diffuseMap * (1.0 + (1.0 - float(specularmap))); + + light.rgb *= visibility; + light.a = 1.0f; vec4 fragColour; if (tcmask != 0) @@ -359,11 +371,11 @@ void main() float maskAlpha = texture(TextureTcmask, texCoord, WZ_MIP_LOAD_BIAS).r; // Apply color using grain merge with tcmask - fragColour = visibility * (light + (teamcolour - 0.5) * maskAlpha) * colour; + fragColour = (light + (teamcolour - 0.5) * maskAlpha) * colour; } else { - fragColour = visibility * light * colour; + fragColour = light * colour; } if (ecmEffect) diff --git a/data/base/shaders/tcmask_instanced.vert b/data/base/shaders/tcmask_instanced.vert index 5da44fc7db7..460f8f2339f 100644 --- a/data/base/shaders/tcmask_instanced.vert +++ b/data/base/shaders/tcmask_instanced.vert @@ -13,6 +13,8 @@ uniform mat4 ProjectionMatrix; uniform mat4 ViewMatrix; +uniform mat4 ModelUVLightmapMatrix; + uniform int hasTangents; // whether tangents were calculated for model uniform vec4 lightPosition; @@ -45,11 +47,16 @@ VERTEX_OUTPUT mat4 NormalMatrix; VERTEX_OUTPUT vec4 colour; VERTEX_OUTPUT vec4 teamcolour; VERTEX_OUTPUT vec4 packed_ecmState_alphaTest; +VERTEX_OUTPUT vec3 uvLightmap; // uvLightmap in .xy, heightAboveTerrain in .z // for Shadows VERTEX_OUTPUT vec3 fragPos; VERTEX_OUTPUT vec3 fragNormal; +float when_gt(float x, float y) { + return max(sign(x - y), 0.0); +} + void main() { // unpack inputs @@ -93,13 +100,19 @@ void main() vec4 position = vertex; if (vertex.y <= 0.0) // use vertex here directly to help shader compiler optimization { - position.y -= stretch; + // NOTE: 'stretch' may be: + // - if positive: building stretching + // - if negative: the height above the terrain of the model intance overall + position.y -= (stretch * when_gt(stretch, 0.f)); } vec4 positionModelSpace = instanceModelMatrix * position; fragPos = positionModelSpace.xyz; fragNormal = vertexNormal; + float heightAboveTerrain = abs(clamp(sign(stretch), -1.f, 0.f)) * abs(stretch); + uvLightmap = vec3((ModelUVLightmapMatrix * positionModelSpace).xy, position.y + heightAboveTerrain); + // Translate every vertex according to the Model View and Projection Matrix mat4 ModelViewProjectionMatrix = ProjectionMatrix * ModelViewMatrix; vec4 gposition = ModelViewProjectionMatrix * position; diff --git a/data/base/shaders/vk/tcmask_depth_instanced.vert b/data/base/shaders/vk/tcmask_depth_instanced.vert index e05ba82c883..6b587a875c1 100644 --- a/data/base/shaders/vk/tcmask_depth_instanced.vert +++ b/data/base/shaders/vk/tcmask_depth_instanced.vert @@ -16,6 +16,10 @@ layout(location = 9) in vec4 instancePackedValues; // shaderStretch_ecmState_alp layout(location = 10) in vec4 instanceColour; layout(location = 11) in vec4 instanceTeamColour; +float when_gt(float x, float y) { + return max(sign(x - y), 0.0); +} + void main() { // unpack inputs @@ -26,7 +30,10 @@ void main() vec4 position = vertex; if (vertex.y <= 0.0) // use vertex here directly to help shader compiler optimization { - position.y -= stretch; + // NOTE: 'stretch' may be: + // - if positive: building stretching + // - if negative: the height above the terrain of the model intance overall + position.y -= (stretch * when_gt(stretch, 0.f)); } // Translate every vertex according to the Model View and Projection Matrix diff --git a/data/base/shaders/vk/tcmask_instanced.frag b/data/base/shaders/vk/tcmask_instanced.frag index 48d49c586e2..39d5921590d 100644 --- a/data/base/shaders/vk/tcmask_instanced.frag +++ b/data/base/shaders/vk/tcmask_instanced.frag @@ -13,6 +13,7 @@ layout(set = 2, binding = 1) uniform sampler2D TextureTcmask; // tcmask layout(set = 2, binding = 2) uniform sampler2D TextureNormal; // normal map layout(set = 2, binding = 3) uniform sampler2D TextureSpecular; // specular map layout(set = 2, binding = 4) uniform sampler2DArrayShadow shadowMap; // shadow map +layout(set = 2, binding = 5) uniform sampler2D lightmap_tex; layout(location = 0) in vec4 texCoord_vertexDistance; // vec(2) texCoord, float vertexDistance, (unused float) layout(location = 1) in vec3 normal; @@ -22,8 +23,9 @@ layout(location = 4) in mat4 NormalMatrix; layout(location = 8) in vec4 colour; layout(location = 9) in vec4 teamcolour; layout(location = 10) in vec4 packed_ecmState_alphaTest; +layout(location = 11) in vec3 uvLightmap; // uvLightmap in .xy, heightAboveTerrain in .z // For Shadows -layout(location = 11) in vec3 fragPos; +layout(location = 12) in vec3 fragPos; //layout(location = 13) in vec3 fragNormal; layout(location = 0) out vec4 FragColor; @@ -259,6 +261,10 @@ float getShadowVisibility() } } +vec3 blendAddEffectLighting(vec3 a, vec3 b) { + return min(a + b, vec3(1.0)); +} + void main() { // unpack inputs @@ -297,6 +303,9 @@ void main() vec3 L = normalize(lightDir); float lambertTerm = max(dot(N, L), 0.0); //diffuse light float visibility = getShadowVisibility(); + vec4 lightmap_vec4 = texture(lightmap_tex, uvLightmap.xy, 0.f); + float distanceAboveTerrain = uvLightmap.z; + float lightmapFactor = 1.0f - (clamp(distanceAboveTerrain, 0.f, 300.f) / 300.f); if (lambertTerm > 0.0) { @@ -320,7 +329,10 @@ void main() light += diffuse * lambertTerm * diffuseMap * vanillaFactor; } // ambient light maxed for classic models to keep results similar to original - light += ambient * diffuseMap * (1.0 + (1.0 - float(specularmap))); + light += vec4(blendAddEffectLighting(ambient.rgb, ((lightmap_vec4.rgb * lightmapFactor) / 3.f)), ambient.a) * diffuseMap * (1.0 + (1.0 - float(specularmap))); + + light.rgb *= visibility; + light.a = 1.0f; vec4 fragColour; if (tcmask != 0) @@ -329,11 +341,11 @@ void main() float maskAlpha = texture(TextureTcmask, texCoord, WZ_MIP_LOAD_BIAS).r; // Apply color using grain merge with tcmask - fragColour = visibility * (light + (teamcolour - 0.5) * maskAlpha) * colour; + fragColour = (light + (teamcolour - 0.5) * maskAlpha) * colour; } else { - fragColour = visibility * light * colour; + fragColour = light * colour; } if (ecmEffect) diff --git a/data/base/shaders/vk/tcmask_instanced.glsl b/data/base/shaders/vk/tcmask_instanced.glsl index 82e48119d58..caf6db92347 100644 --- a/data/base/shaders/vk/tcmask_instanced.glsl +++ b/data/base/shaders/vk/tcmask_instanced.glsl @@ -6,6 +6,7 @@ layout(std140, set = 0, binding = 0) uniform globaluniforms { mat4 ProjectionMatrix; mat4 ViewMatrix; + mat4 ModelUVLightmapMatrix; mat4 ShadowMapMVPMatrix[WZ_MAX_SHADOW_CASCADES]; vec4 lightPosition; vec4 sceneColor; diff --git a/data/base/shaders/vk/tcmask_instanced.vert b/data/base/shaders/vk/tcmask_instanced.vert index 4684ba4e378..3f23f2cf1fa 100644 --- a/data/base/shaders/vk/tcmask_instanced.vert +++ b/data/base/shaders/vk/tcmask_instanced.vert @@ -20,10 +20,15 @@ layout(location = 4) out mat4 NormalMatrix; layout(location = 8) out vec4 colour; layout(location = 9) out vec4 teamcolour; layout(location = 10) out vec4 packed_ecmState_alphaTest; +layout(location = 11) out vec3 uvLightmap; // uvLightmap in .xy, heightAboveTerrain in .z // For Shadows -layout(location = 11) out vec3 fragPos; +layout(location = 12) out vec3 fragPos; //layout(location = 13) out vec3 fragNormal; +float when_gt(float x, float y) { + return max(sign(x - y), 0.0); +} + void main() { // unpack inputs @@ -67,13 +72,19 @@ void main() vec4 position = vertex; if (vertex.y <= 0.0) // use vertex here directly to help shader compiler optimization { - position.y -= stretch; + // NOTE: 'stretch' may be: + // - if positive: building stretching + // - if negative: the height above the terrain of the model intance overall + position.y -= (stretch * when_gt(stretch, 0.f)); } vec4 positionModelSpace = instanceModelMatrix * position; fragPos = positionModelSpace.xyz; // fragNormal = vertexNormal; + float heightAboveTerrain = abs(clamp(sign(stretch), -1.f, 0.f)) * abs(stretch); + uvLightmap = vec3((ModelUVLightmapMatrix * positionModelSpace).xy, position.y + heightAboveTerrain); + // Translate every vertex according to the Model View and Projection Matrix mat4 ModelViewProjectionMatrix = ProjectionMatrix * ModelViewMatrix; vec4 gposition = ModelViewProjectionMatrix * position; diff --git a/lib/ivis_opengl/gfx_api.h b/lib/ivis_opengl/gfx_api.h index 0c8a358356c..8fd7f868545 100644 --- a/lib/ivis_opengl/gfx_api.h +++ b/lib/ivis_opengl/gfx_api.h @@ -730,6 +730,7 @@ namespace gfx_api { glm::mat4 ProjectionMatrix; glm::mat4 ViewMatrix; + glm::mat4 ModelUVLightmapMatrix; glm::mat4 ShadowMapMVPMatrix[WZ_MAX_SHADOW_CASCADES]; glm::vec4 sunPos; glm::vec4 sceneColor; @@ -797,7 +798,8 @@ namespace gfx_api texture_description<1, sampler_type::bilinear>, // team color mask texture_description<2, sampler_type::anisotropic>, // normal map texture_description<3, sampler_type::anisotropic>, // specular map - texture_description<4, sampler_type::bilinear_border, pixel_format_target::depth_map, border_color::opaque_white> // depth / shadow map + texture_description<4, sampler_type::bilinear_border, pixel_format_target::depth_map, border_color::opaque_white>, // depth / shadow map + texture_description<5, sampler_type::bilinear> // lightmap >, shader>; using Draw3DShapeOpaque_Instanced = Draw3DShapeInstanced; diff --git a/lib/ivis_opengl/gfx_api_gl.cpp b/lib/ivis_opengl/gfx_api_gl.cpp index 034a49eefec..aa5eaaf8a16 100644 --- a/lib/ivis_opengl/gfx_api_gl.cpp +++ b/lib/ivis_opengl/gfx_api_gl.cpp @@ -647,12 +647,13 @@ static const std::map shader_to_file_table = std::make_pair(SHADER_COMPONENT_INSTANCED, program_data{ "Component program", "shaders/tcmask_instanced.vert", "shaders/tcmask_instanced.frag", { // per-frame global uniforms - "ProjectionMatrix", "ViewMatrix", "ShadowMapMVPMatrix", "lightPosition", "sceneColor", "ambient", "diffuse", "specular", "fogColor", "ShadowMapCascadeSplits", "ShadowMapSize", "fogEnd", "fogStart", "graphicsCycle", "fogEnabled", + "ProjectionMatrix", "ViewMatrix", "ModelUVLightmapMatrix", "ShadowMapMVPMatrix", "lightPosition", "sceneColor", "ambient", "diffuse", "specular", "fogColor", "ShadowMapCascadeSplits", "ShadowMapSize", "fogEnd", "fogStart", "graphicsCycle", "fogEnabled", // per-mesh uniforms "tcmask", "normalmap", "specularmap", "hasTangents" }, { - {"shadowMap", 4} + {"shadowMap", 4}, + {"lightmap_tex", 5} } }), std::make_pair(SHADER_COMPONENT_DEPTH_INSTANCED, program_data{ "Component program", "shaders/tcmask_depth_instanced.vert", "shaders/tcmask_depth_instanced.frag", { @@ -671,7 +672,7 @@ static const std::map shader_to_file_table = std::make_pair(SHADER_NOLIGHT_INSTANCED, program_data{ "Plain program", "shaders/nolight_instanced.vert", "shaders/nolight_instanced.frag", { // per-frame global uniforms - "ProjectionMatrix", "ViewMatrix", "ShadowMapMVPMatrix", "lightPosition", "sceneColor", "ambient", "diffuse", "specular", "fogColor", "ShadowMapCascadeSplits", "ShadowMapSize", "fogEnd", "fogStart", "graphicsCycle", "fogEnabled", + "ProjectionMatrix", "ViewMatrix", "ModelUVLightmapMatrix", "ShadowMapMVPMatrix", "lightPosition", "sceneColor", "ambient", "diffuse", "specular", "fogColor", "ShadowMapCascadeSplits", "ShadowMapSize", "fogEnd", "fogStart", "graphicsCycle", "fogEnabled", // per-mesh uniforms "tcmask", "normalmap", "specularmap", "hasTangents", }, @@ -1862,27 +1863,28 @@ void gl_pipeline_state_object::set_constants(const gfx_api::Draw3DShapeInstanced { setUniforms(0, cbuf.ProjectionMatrix); setUniforms(1, cbuf.ViewMatrix); - setUniforms(2, cbuf.ShadowMapMVPMatrix, WZ_MAX_SHADOW_CASCADES); - setUniforms(3, cbuf.sunPos); - setUniforms(4, cbuf.sceneColor); - setUniforms(5, cbuf.ambient); - setUniforms(6, cbuf.diffuse); - setUniforms(7, cbuf.specular); - setUniforms(8, cbuf.fogColour); - setUniforms(9, cbuf.ShadowMapCascadeSplits); - setUniforms(10, cbuf.ShadowMapSize); - setUniforms(11, cbuf.fogEnd); - setUniforms(12, cbuf.fogBegin); - setUniforms(13, cbuf.timeState); - setUniforms(14, cbuf.fogEnabled); + setUniforms(2, cbuf.ModelUVLightmapMatrix); + setUniforms(3, cbuf.ShadowMapMVPMatrix, WZ_MAX_SHADOW_CASCADES); + setUniforms(4, cbuf.sunPos); + setUniforms(5, cbuf.sceneColor); + setUniforms(6, cbuf.ambient); + setUniforms(7, cbuf.diffuse); + setUniforms(8, cbuf.specular); + setUniforms(9, cbuf.fogColour); + setUniforms(10, cbuf.ShadowMapCascadeSplits); + setUniforms(11, cbuf.ShadowMapSize); + setUniforms(12, cbuf.fogEnd); + setUniforms(13, cbuf.fogBegin); + setUniforms(14, cbuf.timeState); + setUniforms(15, cbuf.fogEnabled); } void gl_pipeline_state_object::set_constants(const gfx_api::Draw3DShapeInstancedPerMeshUniforms& cbuf) { - setUniforms(15, cbuf.tcmask); - setUniforms(16, cbuf.normalMap); - setUniforms(17, cbuf.specularMap); - setUniforms(18, cbuf.hasTangents); + setUniforms(16, cbuf.tcmask); + setUniforms(17, cbuf.normalMap); + setUniforms(18, cbuf.specularMap); + setUniforms(19, cbuf.hasTangents); } void gl_pipeline_state_object::set_constants(const gfx_api::Draw3DShapeInstancedDepthOnlyGlobalUniforms& cbuf) diff --git a/lib/ivis_opengl/piedraw.cpp b/lib/ivis_opengl/piedraw.cpp index 12b538a2466..cf2ceb1994b 100644 --- a/lib/ivis_opengl/piedraw.cpp +++ b/lib/ivis_opengl/piedraw.cpp @@ -896,6 +896,11 @@ class InstancedMeshRenderer bool initialize(); void clear(); void reset(); + void setLightmap(gfx_api::texture* _lightmapTexture, const glm::mat4& _modelUVLightmapMatrix) + { + lightmapTexture = _lightmapTexture; + modelUVLightmapMatrix = _modelUVLightmapMatrix; + } private: bool useInstancedRendering = false; @@ -912,6 +917,9 @@ class InstancedMeshRenderer std::vector instanceDataBuffers; size_t currInstanceBufferIdx = 0; + gfx_api::texture* lightmapTexture = nullptr; + glm::mat4 modelUVLightmapMatrix = glm::mat4(); + private: struct InstancedDrawCall { @@ -943,7 +951,7 @@ bool InstancedMeshRenderer::initialize() int32_t max_vertex_attribs = gfx_api::context::get().get_context_value(gfx_api::context::context_value::MAX_VERTEX_ATTRIBS); int32_t max_vertex_output_components = gfx_api::context::get().get_context_value(gfx_api::context::context_value::MAX_VERTEX_OUTPUT_COMPONENTS); size_t maxInstancedMeshShaderVertexAttribs = std::max({gfx_api::instance_modelMatrix, gfx_api::instance_packedValues, gfx_api::instance_Colour, gfx_api::instance_TeamColour}) + 1; - constexpr size_t min_required_vertex_output_components = 11 * 4; // from the shaders - see tcmask_instanced.vert / nolight_instanced.vert + constexpr size_t min_required_vertex_output_components = 12 * 4; // from the shaders - see tcmask_instanced.vert / nolight_instanced.vert if (max_vertex_attribs < maxInstancedMeshShaderVertexAttribs) { debug(LOG_INFO, "Disabling instanced rendering - Insufficient MAX_VERTEX_ATTRIBS (%" PRIi32 "; need: %zu)", max_vertex_attribs, maxInstancedMeshShaderVertexAttribs); @@ -974,6 +982,8 @@ void InstancedMeshRenderer::clear() translucentInstancesCount = 0; tshapes.clear(); shapes.clear(); + lightmapTexture = nullptr; + modelUVLightmapMatrix = glm::mat4(); } void InstancedMeshRenderer::reset() @@ -1216,6 +1226,11 @@ void pie_StartMeshes() instancedMeshRenderer.clear(); } +void pie_UpdateLightmap(gfx_api::texture* lightmapTexture, const glm::mat4& modelUVLightmapMatrix) +{ + instancedMeshRenderer.setLightmap(lightmapTexture, modelUVLightmapMatrix); +} + void pie_FinalizeMeshes(uint64_t currentGameFrame) { instancedMeshRenderer.FinalizeInstances(); @@ -1321,7 +1336,7 @@ bool InstancedMeshRenderer::DrawAll(uint64_t currentGameFrame, const glm::mat4& if (useInstancedRendering) { gfx_api::Draw3DShapeInstancedGlobalUniforms globalUniforms { - projectionMatrix, viewMatrix, {shadowCascades.shadowMVPMatrix[0], shadowCascades.shadowMVPMatrix[1], shadowCascades.shadowMVPMatrix[2]}, + projectionMatrix, viewMatrix, modelUVLightmapMatrix, {shadowCascades.shadowMVPMatrix[0], shadowCascades.shadowMVPMatrix[1], shadowCascades.shadowMVPMatrix[2]}, glm::vec4(currentSunPosition, 0.f), sceneColor, ambient, diffuse, specular, fogColor, {shadowCascades.shadowCascadeSplit[0], shadowCascades.shadowCascadeSplit[1], shadowCascades.shadowCascadeSplit[2], pie_getPerspectiveZFar()}, shadowCascades.shadowMapSize, renderState.fogBegin, renderState.fogEnd, pie_GetShaderTime(), renderState.fogEnabled @@ -1342,7 +1357,7 @@ bool InstancedMeshRenderer::DrawAll(uint64_t currentGameFrame, const glm::mat4& } template -static void drawInstanced3dShapeTemplated_Inner(ShaderOnce& globalsOnce, const gfx_api::Draw3DShapeInstancedGlobalUniforms& globalUniforms, const iIMDShape * shape, gfx_api::buffer* instanceDataBuffer, size_t instanceBufferOffset, size_t instance_count) +static void drawInstanced3dShapeTemplated_Inner(ShaderOnce& globalsOnce, const gfx_api::Draw3DShapeInstancedGlobalUniforms& globalUniforms, const iIMDShape * shape, gfx_api::buffer* instanceDataBuffer, size_t instanceBufferOffset, size_t instance_count, gfx_api::texture* lightmapTexture) { const auto& textures = shape->getTextures(); auto* tcmask = textures.tcmaskpage != iV_TEX_INVALID ? &pie_Texture(textures.tcmaskpage) : nullptr; @@ -1368,7 +1383,7 @@ static void drawInstanced3dShapeTemplated_Inner(ShaderOnce& globalsOnce, const g std::make_tuple(shape->buffers[VBO_TEXCOORD], 0), std::make_tuple(pTangentBuffer, 0), std::make_tuple(instanceDataBuffer, instanceBufferOffset) }); - Draw3DInstancedPSO::get().bind_textures(&pie_Texture(textures.texpage), tcmask, normalmap, specularmap, gfx_api::context::get().getDepthTexture()); + Draw3DInstancedPSO::get().bind_textures(&pie_Texture(textures.texpage), tcmask, normalmap, specularmap, gfx_api::context::get().getDepthTexture(), lightmapTexture); Draw3DInstancedPSO::get().draw_elements_instanced(shape->polys.size() * 3, 0, instance_count); // Draw3DInstancedPSO::get().unbind_vertex_buffers(shape->buffers[VBO_VERTEX], shape->buffers[VBO_NORMAL], shape->buffers[VBO_TEXCOORD]); @@ -1402,42 +1417,42 @@ static void drawInstanced3dShapeDepthOnly(ShaderOnce& globalsOnce, const gfx_api } template -static void drawInstanced3dShapeTemplated(ShaderOnce& globalsOnce, const gfx_api::Draw3DShapeInstancedGlobalUniforms& globalUniforms, const iIMDShape * shape, int pieFlag, gfx_api::buffer* instanceDataBuffer, size_t instanceBufferOffset, size_t instance_count) +static void drawInstanced3dShapeTemplated(ShaderOnce& globalsOnce, const gfx_api::Draw3DShapeInstancedGlobalUniforms& globalUniforms, const iIMDShape * shape, int pieFlag, gfx_api::buffer* instanceDataBuffer, size_t instanceBufferOffset, size_t instance_count, gfx_api::texture* lightmapTexture) { /* Set tranlucency */ if (pieFlag & pie_ADDITIVE) { if (!(pieFlag & pie_NODEPTHWRITE)) { - return drawInstanced3dShapeTemplated_Inner(globalsOnce, globalUniforms, shape, instanceDataBuffer, instanceBufferOffset, instance_count); + return drawInstanced3dShapeTemplated_Inner(globalsOnce, globalUniforms, shape, instanceDataBuffer, instanceBufferOffset, instance_count, lightmapTexture); } else { - return drawInstanced3dShapeTemplated_Inner(globalsOnce, globalUniforms, shape, instanceDataBuffer, instanceBufferOffset, instance_count); + return drawInstanced3dShapeTemplated_Inner(globalsOnce, globalUniforms, shape, instanceDataBuffer, instanceBufferOffset, instance_count, lightmapTexture); } } else if (pieFlag & pie_TRANSLUCENT) { if (!(pieFlag & pie_NODEPTHWRITE)) { - return drawInstanced3dShapeTemplated_Inner(globalsOnce, globalUniforms, shape, instanceDataBuffer, instanceBufferOffset, instance_count); + return drawInstanced3dShapeTemplated_Inner(globalsOnce, globalUniforms, shape, instanceDataBuffer, instanceBufferOffset, instance_count, lightmapTexture); } else { - return drawInstanced3dShapeTemplated_Inner(globalsOnce, globalUniforms, shape, instanceDataBuffer, instanceBufferOffset, instance_count); + return drawInstanced3dShapeTemplated_Inner(globalsOnce, globalUniforms, shape, instanceDataBuffer, instanceBufferOffset, instance_count, lightmapTexture); } } else if (pieFlag & pie_PREMULTIPLIED) { - return drawInstanced3dShapeTemplated_Inner(globalsOnce, globalUniforms, shape, instanceDataBuffer, instanceBufferOffset, instance_count); + return drawInstanced3dShapeTemplated_Inner(globalsOnce, globalUniforms, shape, instanceDataBuffer, instanceBufferOffset, instance_count, lightmapTexture); } else { - return drawInstanced3dShapeTemplated_Inner(globalsOnce, globalUniforms, shape, instanceDataBuffer, instanceBufferOffset, instance_count); + return drawInstanced3dShapeTemplated_Inner(globalsOnce, globalUniforms, shape, instanceDataBuffer, instanceBufferOffset, instance_count, lightmapTexture); } } -static void pie_Draw3DShape2_Instanced(ShaderOnce& globalsOnce, const gfx_api::Draw3DShapeInstancedGlobalUniforms& globalUniforms, const iIMDShape *shape, int pieFlag, gfx_api::buffer* instanceDataBuffer, size_t instanceBufferOffset, size_t instance_count, bool depthPass) +static void pie_Draw3DShape2_Instanced(ShaderOnce& globalsOnce, const gfx_api::Draw3DShapeInstancedGlobalUniforms& globalUniforms, const iIMDShape *shape, int pieFlag, gfx_api::buffer* instanceDataBuffer, size_t instanceBufferOffset, size_t instance_count, bool depthPass, gfx_api::texture* lightmapTexture) { bool light = true; @@ -1485,11 +1500,11 @@ static void pie_Draw3DShape2_Instanced(ShaderOnce& globalsOnce, const gfx_api::D } else if (light) { - drawInstanced3dShapeTemplated(globalsOnce, globalUniforms, shape, pieFlag, instanceDataBuffer, instanceBufferOffset, instance_count); + drawInstanced3dShapeTemplated(globalsOnce, globalUniforms, shape, pieFlag, instanceDataBuffer, instanceBufferOffset, instance_count, lightmapTexture); } else { - drawInstanced3dShapeTemplated(globalsOnce, globalUniforms, shape, pieFlag, instanceDataBuffer, instanceBufferOffset, instance_count); + drawInstanced3dShapeTemplated(globalsOnce, globalUniforms, shape, pieFlag, instanceDataBuffer, instanceBufferOffset, instance_count, lightmapTexture); } polyCount += shape->polys.size(); @@ -1516,7 +1531,7 @@ void InstancedMeshRenderer::Draw3DShapes_Instanced(uint64_t currentGameFrame, Sh continue; } size_t instanceBufferOffset = static_cast(sizeof(gfx_api::Draw3DShapePerInstanceInterleavedData) * call.startingIdxInInstancesBuffer); - pie_Draw3DShape2_Instanced(perFrameUniformsShaderOnce, globalUniforms, shape, call.state.pieFlag, instanceDataBuffers[currInstanceBufferIdx], instanceBufferOffset, call.instance_count, depthPass); + pie_Draw3DShape2_Instanced(perFrameUniformsShaderOnce, globalUniforms, shape, call.state.pieFlag, instanceDataBuffers[currInstanceBufferIdx], instanceBufferOffset, call.instance_count, depthPass, lightmapTexture); } if (startIdxTranslucentDrawCalls > 0) { @@ -1544,7 +1559,7 @@ void InstancedMeshRenderer::Draw3DShapes_Instanced(uint64_t currentGameFrame, Sh const auto& call = finalizedDrawCalls[i]; const iIMDShape * shape = call.state.shape; size_t instanceBufferOffset = static_cast(sizeof(gfx_api::Draw3DShapePerInstanceInterleavedData) * call.startingIdxInInstancesBuffer); - pie_Draw3DShape2_Instanced(perFrameUniformsShaderOnce, globalUniforms, shape, call.state.pieFlag, instanceDataBuffers[currInstanceBufferIdx], instanceBufferOffset, call.instance_count, depthPass); + pie_Draw3DShape2_Instanced(perFrameUniformsShaderOnce, globalUniforms, shape, call.state.pieFlag, instanceDataBuffers[currInstanceBufferIdx], instanceBufferOffset, call.instance_count, depthPass, lightmapTexture); } if (startIdxTranslucentDrawCalls < finalizedDrawCalls.size()) { diff --git a/lib/ivis_opengl/piedraw.h b/lib/ivis_opengl/piedraw.h index 7ee3cc18f23..c752d50cf2f 100644 --- a/lib/ivis_opengl/piedraw.h +++ b/lib/ivis_opengl/piedraw.h @@ -25,6 +25,12 @@ #include "pietypes.h" #include "shadows.h" +namespace gfx_api +{ + struct texture; // forward-declare +} + void pie_StartMeshes(); +void pie_UpdateLightmap(gfx_api::texture* lightmapTexture, const glm::mat4& modelUVLightmapMatrix); void pie_FinalizeMeshes(uint64_t currentGameFrame); void pie_DrawAllMeshes(uint64_t currentGameFrame, const glm::mat4 &projectionMatrix, const glm::mat4 &viewMatrix, const ShadowCascadesInfo& shadowMVPMatrix, bool depthPass); diff --git a/src/component.cpp b/src/component.cpp index cdbd13ee04e..73f5b791b34 100644 --- a/src/component.cpp +++ b/src/component.cpp @@ -372,7 +372,7 @@ static inline iIMDBaseShape *getRightPropulsionIMD(DROID *psDroid) return asBodyStats[bodyStat].ppIMDList[propStat * NUM_PROP_SIDES + RIGHT_PROP]; } -void drawMuzzleFlash(WEAPON sWeap, iIMDShape *weaponImd, iIMDShape *flashImd, PIELIGHT buildingBrightness, int pieFlag, int iPieData, glm::mat4 modelMatrix, const glm::mat4 &viewMatrix, UBYTE colour) +void drawMuzzleFlash(WEAPON sWeap, iIMDShape *weaponImd, iIMDShape *flashImd, PIELIGHT buildingBrightness, int pieFlag, int iPieData, glm::mat4 modelMatrix, const glm::mat4 &viewMatrix, float heightAboveTerrain, UBYTE colour) { if (!weaponImd || !flashImd || weaponImd->connectors.empty() || graphicsTime < sWeap.lastFired) { @@ -390,6 +390,7 @@ void drawMuzzleFlash(WEAPON sWeap, iIMDShape *weaponImd, iIMDShape *flashImd, PI /* Now we need to move to the end of the firing barrel */ modelMatrix *= glm::translate(glm::vec3(weaponImd->connectors[connector_num].xzy())); + heightAboveTerrain += weaponImd->connectors[connector_num].z; // assume no clan colours for muzzle effects if (flashImd->numFrames == 0 || flashImd->animInterval <= 0) @@ -397,7 +398,7 @@ void drawMuzzleFlash(WEAPON sWeap, iIMDShape *weaponImd, iIMDShape *flashImd, PI // no anim so display one frame for a fixed time if (graphicsTime >= sWeap.lastFired && graphicsTime < sWeap.lastFired + BASE_MUZZLE_FLASH_DURATION) { - pie_Draw3DShape(flashImd, 0, colour, buildingBrightness, pieFlag | pie_ADDITIVE, EFFECT_MUZZLE_ADDITIVE, modelMatrix, viewMatrix); + pie_Draw3DShape(flashImd, 0, colour, buildingBrightness, pieFlag | pie_ADDITIVE, EFFECT_MUZZLE_ADDITIVE, modelMatrix, viewMatrix, -heightAboveTerrain); } } else if (graphicsTime >= sWeap.lastFired) @@ -408,7 +409,7 @@ void drawMuzzleFlash(WEAPON sWeap, iIMDShape *weaponImd, iIMDShape *flashImd, PI int frame = (graphicsTime - sWeap.lastFired) / animRate; if (frame < flashImd->numFrames) { - pie_Draw3DShape(flashImd, frame, colour, buildingBrightness, pieFlag | pie_ADDITIVE, EFFECT_MUZZLE_ADDITIVE, modelMatrix, viewMatrix); + pie_Draw3DShape(flashImd, frame, colour, buildingBrightness, pieFlag | pie_ADDITIVE, EFFECT_MUZZLE_ADDITIVE, modelMatrix, viewMatrix, -heightAboveTerrain); } } } @@ -483,7 +484,7 @@ static bool displayCompObj(DROID *psDroid, bool bButton, const glm::mat4& modelM iIMDBaseShape *psShapeProp = (leftFirst ? getLeftPropulsionIMD(psDroid) : getRightPropulsionIMD(psDroid)); if (psShapeProp) { - if (pie_Draw3DShape(psShapeProp->displayModel(), 0, colour, brightness, pieFlag, iPieData, modifiedModelMatrix, viewMatrix)) + if (pie_Draw3DShape(psShapeProp->displayModel(), 0, colour, brightness, pieFlag, iPieData, modifiedModelMatrix, viewMatrix, -(psDroid->heightAboveMap))) { didDrawSomething = true; } @@ -517,7 +518,7 @@ static bool displayCompObj(DROID *psDroid, bool bButton, const glm::mat4& modelM } while (strImd) { - if (drawShape(strImd, psDroid->timeAnimationStarted, colour, brightness, pieFlag, iPieData, modifiedModelMatrix, viewMatrix)) + if (drawShape(strImd, psDroid->timeAnimationStarted, colour, brightness, pieFlag, iPieData, modifiedModelMatrix, viewMatrix, -(psDroid->heightAboveMap))) { didDrawSomething = true; } @@ -531,7 +532,7 @@ static bool displayCompObj(DROID *psDroid, bool bButton, const glm::mat4& modelM if (!bButton && psMoveAnim && psDroid->sMove.Status != MOVEINACTIVE) { iIMDShape *displayModel = psMoveAnim->displayModel(); - if (pie_Draw3DShape(displayModel, getModularScaledGraphicsTime(displayModel->animInterval, displayModel->numFrames), colour, brightness, pie_ADDITIVE, 200, modifiedModelMatrix, viewMatrix)) + if (pie_Draw3DShape(displayModel, getModularScaledGraphicsTime(displayModel->animInterval, displayModel->numFrames), colour, brightness, pie_ADDITIVE, 200, modifiedModelMatrix, viewMatrix, -(psDroid->heightAboveMap))) { didDrawSomething = true; } @@ -539,7 +540,7 @@ static bool displayCompObj(DROID *psDroid, bool bButton, const glm::mat4& modelM else if (!bButton && psStillAnim) // standing still { iIMDShape *displayModel = psStillAnim->displayModel(); - if (pie_Draw3DShape(displayModel, getModularScaledGraphicsTime(displayModel->animInterval, displayModel->numFrames), colour, brightness, 0, 0, modifiedModelMatrix, viewMatrix)) + if (pie_Draw3DShape(displayModel, getModularScaledGraphicsTime(displayModel->animInterval, displayModel->numFrames), colour, brightness, 0, 0, modifiedModelMatrix, viewMatrix, -(psDroid->heightAboveMap))) { didDrawSomething = true; } @@ -598,15 +599,18 @@ static bool displayCompObj(DROID *psDroid, bool bButton, const glm::mat4& modelM Rotation rot = getInterpolatedWeaponRotation(psDroid, i, graphicsTime); glm::mat4 localModelMatrix = modifiedModelMatrix; + float localHeightAboveTerrain = psDroid->heightAboveMap; //to skip number of VTOL_CONNECTOR_START ground unit connectors if (iConnector < VTOL_CONNECTOR_START) { localModelMatrix *= glm::translate(glm::vec3(psShapeBody->connectors[i].xzy())); + localHeightAboveTerrain += psShapeBody->connectors[i].z; } else { localModelMatrix *= glm::translate(glm::vec3(psShapeBody->connectors[iConnector + i].xzy())); + localHeightAboveTerrain += (psShapeBody->connectors[iConnector + i]).z; } localModelMatrix *= glm::rotate(UNDEG(-rot.direction), glm::vec3(0.f, 1.f, 0.f)); @@ -627,7 +631,7 @@ static bool displayCompObj(DROID *psDroid, bool bButton, const glm::mat4& modelM /* Draw it */ if (psShape) { - if (pie_Draw3DShape(psShape, 0, colour, brightness, pieFlag, iPieData, localModelMatrix, viewMatrix)) + if (pie_Draw3DShape(psShape, 0, colour, brightness, pieFlag, iPieData, localModelMatrix, viewMatrix, -localHeightAboveTerrain)) { didDrawSomething = true; } @@ -638,6 +642,7 @@ static bool displayCompObj(DROID *psDroid, bool bButton, const glm::mat4& modelM if (psShape && !psShape->connectors.empty()) { localModelMatrix *= glm::translate(glm::vec3(psShape->connectors[0].xzy())); + localHeightAboveTerrain += psShape->connectors[0].z; } /* vtol weapons inverted */ @@ -659,13 +664,13 @@ static bool displayCompObj(DROID *psDroid, bool bButton, const glm::mat4& modelM // We have a weapon so we draw it and a muzzle flash from weapon connector if (psShape) { - if (pie_Draw3DShape(psShape, 0, colour, brightness, pieFlag, iPieData, localModelMatrix, viewMatrix)) + if (pie_Draw3DShape(psShape, 0, colour, brightness, pieFlag, iPieData, localModelMatrix, viewMatrix, -localHeightAboveTerrain)) { didDrawSomething = true; } auto flashBaseModel = MUZZLE_FLASH_PIE(psDroid, i); iIMDShape *pMuzzleFlash = (flashBaseModel) ? flashBaseModel->displayModel() : nullptr; - drawMuzzleFlash(psDroid->asWeaps[i], psShape, pMuzzleFlash, brightness, pieFlag, iPieData, localModelMatrix, viewMatrix); + drawMuzzleFlash(psDroid->asWeaps[i], psShape, pMuzzleFlash, brightness, pieFlag, iPieData, localModelMatrix, viewMatrix, localHeightAboveTerrain); } } } @@ -720,6 +725,7 @@ static bool displayCompObj(DROID *psDroid, bool bButton, const glm::mat4& modelM //sensor and cyborg and ecm uses connectors[0] glm::mat4 localModelMatrix = modifiedModelMatrix; + float localHeightAboveTerrain = psDroid->heightAboveMap; /* vtol weapons inverted */ if (iConnector >= VTOL_CONNECTOR_START) { @@ -728,12 +734,13 @@ static bool displayCompObj(DROID *psDroid, bool bButton, const glm::mat4& modelM } localModelMatrix *= glm::translate(glm::vec3(psShapeBody->connectors[0].xzy())); + localHeightAboveTerrain += psShapeBody->connectors[0].z; localModelMatrix *= glm::rotate(UNDEG(-rot.direction), glm::vec3(0.f, 1.f, 0.f)); /* Draw it */ if (psMountShape) { - if (pie_Draw3DShape(psMountShape, 0, colour, brightness, pieFlag, iPieData, localModelMatrix, viewMatrix)) + if (pie_Draw3DShape(psMountShape, 0, colour, brightness, pieFlag, iPieData, localModelMatrix, viewMatrix, -localHeightAboveTerrain)) { didDrawSomething = true; } @@ -743,12 +750,13 @@ static bool displayCompObj(DROID *psDroid, bool bButton, const glm::mat4& modelM if (cyborgDroid(psDroid) && psMountShape && !psMountShape->connectors.empty()) { localModelMatrix *= glm::translate(glm::vec3(psMountShape->connectors[0].xzy())); + localHeightAboveTerrain += psMountShape->connectors[0].z; } /* Draw it */ if (psShape) { - if (pie_Draw3DShape(psShape, 0, colour, brightness, pieFlag, iPieData, localModelMatrix, viewMatrix)) + if (pie_Draw3DShape(psShape, 0, colour, brightness, pieFlag, iPieData, localModelMatrix, viewMatrix, -localHeightAboveTerrain)) { didDrawSomething = true; } @@ -759,6 +767,7 @@ static bool displayCompObj(DROID *psDroid, bool bButton, const glm::mat4& modelM { Spacetime st = interpolateObjectSpacetime(psDroid, graphicsTime); localModelMatrix *= glm::translate(glm::vec3(psShape->connectors[0].xzy())); + localHeightAboveTerrain += psShape->connectors[0].z; localModelMatrix *= glm::translate(glm::vec3(0.f, -20.f, 0.f)); psShape = getImdFromIndex(MI_FLAME)->displayModel(); @@ -773,7 +782,7 @@ static bool displayCompObj(DROID *psDroid, bool bButton, const glm::mat4& modelM localModelMatrix *= glm::rotate(UNDEG(-playerPos.r.y), glm::vec3(0.f, 1.f, 0.f)); localModelMatrix *= glm::rotate(UNDEG(-playerPos.r.x), glm::vec3(1.f, 0.f, 0.f)); - if (pie_Draw3DShape(psShape, getModularScaledGraphicsTime(psShape->animInterval, psShape->numFrames), 0, brightness, pie_ADDITIVE, 140, localModelMatrix, viewMatrix)) + if (pie_Draw3DShape(psShape, getModularScaledGraphicsTime(psShape->animInterval, psShape->numFrames), 0, brightness, pie_ADDITIVE, 140, localModelMatrix, viewMatrix, -localHeightAboveTerrain)) { didDrawSomething = true; } @@ -809,7 +818,7 @@ static bool displayCompObj(DROID *psDroid, bool bButton, const glm::mat4& modelM psShapeProp = (leftFirst ? getRightPropulsionIMD(psDroid) : getLeftPropulsionIMD(psDroid)); if (psShapeProp) { - if (pie_Draw3DShape(psShapeProp->displayModel(), 0, colour, brightness, pieFlag, iPieData, modifiedModelMatrix, viewMatrix)) + if (pie_Draw3DShape(psShapeProp->displayModel(), 0, colour, brightness, pieFlag, iPieData, modifiedModelMatrix, viewMatrix, -(psDroid->heightAboveMap))) { didDrawSomething = true; } diff --git a/src/component.h b/src/component.h index 62d7344d4f4..4da06a4dfa6 100644 --- a/src/component.h +++ b/src/component.h @@ -77,7 +77,7 @@ void compPersonToBits(DROID *psDroid); SDWORD rescaleButtonObject(SDWORD radius, SDWORD baseScale, SDWORD baseRadius); void destroyFXDroid(DROID *psDroid, unsigned impactTime); -void drawMuzzleFlash(WEAPON sWeap, iIMDShape *weaponImd, iIMDShape *flashImd, PIELIGHT buildingBrightness, int pieFlag, int pieFlagData, glm::mat4 modelMatrix, const glm::mat4 &viewMatrix, UBYTE colour = 0); +void drawMuzzleFlash(WEAPON sWeap, iIMDShape *weaponImd, iIMDShape *flashImd, PIELIGHT buildingBrightness, int pieFlag, int pieFlagData, glm::mat4 modelMatrix, const glm::mat4 &viewMatrix, float heightAboveTerrain, UBYTE colour = 0); /* Pass in the stats you're interested in and the COMPONENT - double reference, but works. NOTE: Unused!*/ #define PART_IMD(STATS,DROID,COMPONENT,PLAYER) (STATS[DROID->asBits[COMPONENT]].pIMD) diff --git a/src/display3d.cpp b/src/display3d.cpp index 9b90dc6c72d..1cf7e3a11a7 100644 --- a/src/display3d.cpp +++ b/src/display3d.cpp @@ -1448,6 +1448,7 @@ static void drawTiles(iView *player) /* Actually render / draw everything */ /* ---------------------------------------------------------------- */ + pie_UpdateLightmap(getTerrainLightmapTexture(), getModelUVLightmapMatrix()); pie_FinalizeMeshes(currentGameFrame); // shadow/depth-mapping passes @@ -2586,6 +2587,7 @@ static void renderStructureTurrets(STRUCTURE *psStructure, iIMDShape *strImd, PI if (weaponImd[i] != nullptr) { glm::mat4 matrix = glm::translate(glm::vec3(strImd->connectors[i].xzy())) * glm::rotate(UNDEG(-rot.direction), glm::vec3(0.f, 1.f, 0.f)); + float heightAboveTerrain = strImd->connectors[i].z; int recoilValue = noRecoil ? 0 : getRecoil(psStructure->asWeaps[i]); if (mountImd[i] != nullptr) { @@ -2596,7 +2598,7 @@ static void renderStructureTurrets(STRUCTURE *psStructure, iIMDShape *strImd, PI { animFrame = getModularScaledGraphicsTime(pMountDisplayIMD->animInterval, pMountDisplayIMD->numFrames); } - pie_Draw3DShape(pMountDisplayIMD, animFrame, colour, buildingBrightness, pieFlag, pieFlagData, modelMatrix * matrix, viewMatrix); + pie_Draw3DShape(pMountDisplayIMD, animFrame, colour, buildingBrightness, pieFlag, pieFlagData, modelMatrix * matrix, viewMatrix, -heightAboveTerrain); if (!pMountDisplayIMD->connectors.empty()) { matrix *= glm::translate(glm::vec3(pMountDisplayIMD->connectors[0].xzy())); @@ -2606,7 +2608,7 @@ static void renderStructureTurrets(STRUCTURE *psStructure, iIMDShape *strImd, PI matrix *= glm::translate(glm::vec3(0, 0, recoilValue)); iIMDShape *pWeaponDisplayIMD = weaponImd[i]->displayModel(); - pie_Draw3DShape(pWeaponDisplayIMD, 0, colour, buildingBrightness, pieFlag, pieFlagData, modelMatrix * matrix, viewMatrix); + pie_Draw3DShape(pWeaponDisplayIMD, 0, colour, buildingBrightness, pieFlag, pieFlagData, modelMatrix * matrix, viewMatrix, -heightAboveTerrain); if (psStructure->status == SS_BUILT && psStructure->visibleForLocalDisplay() > (UBYTE_MAX / 2)) { if (psStructure->pStructureType->type == REF_REPAIR_FACILITY) @@ -2628,14 +2630,14 @@ static void renderStructureTurrets(STRUCTURE *psStructure, iIMDShape *strImd, PI glm::rotate(UNDEG(rot.direction), glm::vec3(0.f, 1.f, 0.f)) * glm::rotate(UNDEG(-playerPos.r.y), glm::vec3(0.f, 1.f, 0.f)) * glm::rotate(UNDEG(-playerPos.r.x), glm::vec3(1.f, 0.f, 0.f)); - pie_Draw3DShape(pRepImd, getModularScaledGraphicsTime(pRepImd->animInterval, pRepImd->numFrames), colour, buildingBrightness, pie_ADDITIVE, 192, modelMatrix * matrix, viewMatrix); + pie_Draw3DShape(pRepImd, getModularScaledGraphicsTime(pRepImd->animInterval, pRepImd->numFrames), colour, buildingBrightness, pie_ADDITIVE, 192, modelMatrix * matrix, viewMatrix, -heightAboveTerrain); } } } else // we have a weapon so we draw a muzzle flash { iIMDShape *pFlashDisplayIMD = (flashImd[i]) ? flashImd[i]->displayModel() : nullptr; - drawMuzzleFlash(psStructure->asWeaps[i], pWeaponDisplayIMD, pFlashDisplayIMD, buildingBrightness, pieFlag, pieFlagData, modelMatrix * matrix, viewMatrix, colour); + drawMuzzleFlash(psStructure->asWeaps[i], pWeaponDisplayIMD, pFlashDisplayIMD, buildingBrightness, pieFlag, pieFlagData, modelMatrix * matrix, viewMatrix, heightAboveTerrain, colour); } } } diff --git a/src/droid.cpp b/src/droid.cpp index dcfb7fa3b1c..b25f7b926b1 100644 --- a/src/droid.cpp +++ b/src/droid.cpp @@ -393,6 +393,7 @@ DROID::DROID(uint32_t id, unsigned player) , secondaryOrderPendingCount(0) , action(DACTION_NONE) , actionPos(0, 0) + , heightAboveMap(0) { memset(aName, 0, sizeof(aName)); memset(asBits, 0, sizeof(asBits)); diff --git a/src/droiddef.h b/src/droiddef.h index bd3876351f1..3923da1d8a8 100644 --- a/src/droiddef.h +++ b/src/droiddef.h @@ -156,6 +156,7 @@ struct DROID : public BASE_OBJECT uint8_t blockedBits; ///< Bit set telling which tiles block this type of droid (TODO) /* anim data */ SDWORD iAudioID; + int32_t heightAboveMap; ///< Current calculated height above the terrain (set for VTOL-propulsion units) }; #endif // __INCLUDED_DROIDDEF_H__ diff --git a/src/move.cpp b/src/move.cpp index 19f0e3723cf..8cf639585fc 100644 --- a/src/move.cpp +++ b/src/move.cpp @@ -1775,6 +1775,7 @@ static void moveUpdateVtolModel(DROID *psDroid, SDWORD speed, uint16_t direction iMapZ = map_Height(psDroid->pos.x, psDroid->pos.y); psDroid->pos.z = MAX(iMapZ, psDroid->pos.z + gameTimeAdjustedIncrement(psDroid->sMove.iVertSpeed)); moveAdjustVtolHeight(psDroid, iMapZ); + psDroid->heightAboveMap = psDroid->pos.z - iMapZ; } } diff --git a/src/terrain.cpp b/src/terrain.cpp index 85e6ff7e265..c6a072c6970 100644 --- a/src/terrain.cpp +++ b/src/terrain.cpp @@ -1956,6 +1956,16 @@ void perFrameTerrainUpdates() cullTerrain(); } +gfx_api::texture* getTerrainLightmapTexture() +{ + return lightmap_texture; +} + +const glm::mat4& getModelUVLightmapMatrix() +{ + return lightmapValues.ModelUVLightmap; +} + void drawTerrainDepthOnly(const glm::mat4 &mvp) { drawDepthOnlyForDepthMap(mvp, lightmapValues.paramsXLight, lightmapValues.paramsYLight, false); diff --git a/src/terrain.h b/src/terrain.h index 998cc2a3051..fc182b33b7f 100644 --- a/src/terrain.h +++ b/src/terrain.h @@ -38,6 +38,14 @@ void drawTerrainDepthOnly(const glm::mat4 &mvp); void drawTerrain(const glm::mat4 &mvp, const glm::mat4& viewMatrix, const Vector3f &cameraPos, const Vector3f &sunPos, const ShadowCascadesInfo& shadowMVPMatrix); void drawWater(const glm::mat4 &ModelViewProjection, const Vector3f &cameraPos, const Vector3f &sunPos); +namespace gfx_api +{ + struct texture; // forward-declare +} + +gfx_api::texture* getTerrainLightmapTexture(); +const glm::mat4& getModelUVLightmapMatrix(); + PIELIGHT getTileColour(int x, int y); void setTileColour(int x, int y, PIELIGHT colour);