Skip to content

File phong_multi_light.cpp

File List > gs > phong_multi_light.cpp

Go to the documentation of this file

#include "phong_multi_light.hpp"
#include "create_compatibility_shader.hpp"

#include <Magnum/GL/CubeMapTextureArray.h>
#include <Magnum/GL/Texture.h>
#include <Magnum/GL/TextureArray.h>

namespace robot_dart {
    namespace gui {
        namespace magnum {
            namespace gs {
                PhongMultiLight::PhongMultiLight(PhongMultiLight::Flags flags, Magnum::Int max_lights) : _flags(flags), _max_lights(max_lights)
                {
                    Corrade::Utility::Resource rs_shaders("RobotDARTShaders");

                    const Magnum::GL::Version version = Magnum::GL::Version::GL320;

                    Magnum::GL::Shader vert = Magnum::Shaders::Implementation::createCompatibilityShader(
                        rs_shaders, version, Magnum::GL::Shader::Type::Vertex);
                    Magnum::GL::Shader frag = Magnum::Shaders::Implementation::createCompatibilityShader(
                        rs_shaders, version, Magnum::GL::Shader::Type::Fragment);

                    std::string defines = "#define LIGHT_COUNT " + std::to_string(_max_lights) + "\n";
                    defines += "#define POSITION_ATTRIBUTE_LOCATION " + std::to_string(Position::Location) + "\n";
                    defines += "#define NORMAL_ATTRIBUTE_LOCATION " + std::to_string(Normal::Location) + "\n";
                    defines += "#define TEXTURECOORDINATES_ATTRIBUTE_LOCATION " + std::to_string(TextureCoordinates::Location) + "\n";

                    vert.addSource(flags ? "#define TEXTURED\n" : "")
                        .addSource(defines)
                        .addSource(rs_shaders.get("PhongMultiLight.vert"));
                    frag.addSource(flags & Flag::AmbientTexture ? "#define AMBIENT_TEXTURE\n" : "")
                        .addSource(flags & Flag::DiffuseTexture ? "#define DIFFUSE_TEXTURE\n" : "")
                        .addSource(flags & Flag::SpecularTexture ? "#define SPECULAR_TEXTURE\n" : "")
                        .addSource(defines)
                        .addSource(rs_shaders.get("PhongMultiLight.frag"));

                    CORRADE_INTERNAL_ASSERT_OUTPUT(Magnum::GL::Shader::compile({vert, frag}));

                    attachShaders({vert, frag});

                    if (!Magnum::GL::Context::current().isExtensionSupported<Magnum::GL::Extensions::ARB::explicit_attrib_location>(version)) {
                        bindAttributeLocation(Position::Location, "position");
                        bindAttributeLocation(Normal::Location, "normal");
                        if (flags)
                            bindAttributeLocation(TextureCoordinates::Location, "textureCoords");
                    }

                    CORRADE_INTERNAL_ASSERT_OUTPUT(link());

                    /* Get light matrices uniform */
                    _lights_matrices_uniform = uniformLocation("lightMatrices[0]");

                    if (!Magnum::GL::Context::current().isExtensionSupported<Magnum::GL::Extensions::ARB::explicit_uniform_location>(version)) {
                        _transformation_matrix_uniform = uniformLocation("transformationMatrix");
                        _projection_matrix_uniform = uniformLocation("projectionMatrix");
                        _camera_matrix_uniform = uniformLocation("cameraMatrix");
                        _normal_matrix_uniform = uniformLocation("normalMatrix");
                        _lights_uniform = uniformLocation("lights[0].position");
                        _lights_matrices_uniform = uniformLocation("lightMatrices[0]");
                        _ambient_color_uniform = uniformLocation("ambientColor");
                        _diffuse_color_uniform = uniformLocation("diffuseColor");
                        _specular_color_uniform = uniformLocation("specularColor");
                        _shininess_uniform = uniformLocation("shininess");
                        _far_plane_uniform = uniformLocation("farPlane");
                        _specular_strength_uniform = uniformLocation("specularStrength");
                        _is_shadowed_uniform = uniformLocation("isShadowed");
                        _transparent_shadows_uniform = uniformLocation("drawTransparentShadows");
                    }

                    if (!Magnum::GL::Context::current()
                             .isExtensionSupported<Magnum::GL::Extensions::ARB::shading_language_420pack>(version)) {
                        setUniform(uniformLocation("shadowTextures"), _shadow_textures_location);
                        setUniform(uniformLocation("cubeMapTextures"), _cube_map_textures_location);
                        setUniform(uniformLocation("shadowColorTextures"), _shadow_color_textures_location);
                        setUniform(uniformLocation("cubeMapColorTextures"), _cube_map_color_textures_location);
                        if (flags) {
                            if (flags & Flag::AmbientTexture)
                                setUniform(uniformLocation("ambientTexture"), AmbientTextureLayer);
                            if (flags & Flag::DiffuseTexture)
                                setUniform(uniformLocation("diffuseTexture"), DiffuseTextureLayer);
                            if (flags & Flag::SpecularTexture)
                                setUniform(uniformLocation("specularTexture"), SpecularTextureLayer);
                        }
                    }

                    /* Set defaults (normally they are set in shader code itself, but just in case) */
                    Material material;

                    /* Default to fully opaque white so we can see the textures */
                    if (flags & Flag::AmbientTexture)
                        material.set_ambient_color(Magnum::Color4{1.0f});
                    else
                        material.set_ambient_color(Magnum::Color4{0.0f, 1.0f});

                    if (flags & Flag::DiffuseTexture)
                        material.set_diffuse_color(Magnum::Color4{1.0f});

                    material.set_specular_color(Magnum::Color4{1.0f});
                    material.set_shininess(80.0f);

                    set_material(material);

                    /* Lights defaults need to be set by code */
                    /* All lights are disabled i.e., color equal to black */
                    Light light;
                    for (Magnum::Int i = 0; i < _max_lights; i++)
                        set_light(i, light);
                }

                PhongMultiLight::PhongMultiLight(Magnum::NoCreateT) noexcept : Magnum::GL::AbstractShaderProgram{Magnum::NoCreate} {}

                PhongMultiLight::Flags PhongMultiLight::flags() const { return _flags; }

                PhongMultiLight& PhongMultiLight::set_material(Material& material)
                {
                    // TO-DO: Check if we should do this or let the user define the proper
                    // material
                    if (material.has_ambient_texture() && (_flags & Flag::AmbientTexture)) {
                        (*material.ambient_texture()).bind(AmbientTextureLayer);
                        setUniform(_ambient_color_uniform, Magnum::Color4{1.0f});
                    }
                    else
                        setUniform(_ambient_color_uniform, material.ambient_color());

                    if (material.has_diffuse_texture() && (_flags & Flag::DiffuseTexture)) {
                        (*material.diffuse_texture()).bind(DiffuseTextureLayer);
                        setUniform(_diffuse_color_uniform, Magnum::Color4{1.0f});
                    }
                    else
                        setUniform(_diffuse_color_uniform, material.diffuse_color());

                    if (material.has_specular_texture() && (_flags & Flag::SpecularTexture)) {
                        (*material.specular_texture()).bind(SpecularTextureLayer);
                        setUniform(_specular_color_uniform, Magnum::Color4{1.0f});
                    }
                    else
                        setUniform(_specular_color_uniform, material.specular_color());

                    setUniform(_shininess_uniform, material.shininess());

                    return *this;
                }

                PhongMultiLight& PhongMultiLight::set_light(Magnum::Int i, const Light& light)
                {
                    CORRADE_INTERNAL_ASSERT(i >= 0 && i < _max_lights);
                    Magnum::Vector4 attenuation = light.attenuation();

                    // light position
                    setUniform(_lights_uniform + i * _light_loc_size, light.transformed_position());
                    // light material
                    setUniform(_lights_uniform + i * _light_loc_size + 1, light.material().ambient_color());
                    setUniform(_lights_uniform + i * _light_loc_size + 2, light.material().diffuse_color());
                    setUniform(_lights_uniform + i * _light_loc_size + 3, light.material().specular_color());
                    // spotlight properties
                    setUniform(_lights_uniform + i * _light_loc_size + 4, light.transformed_spot_direction());
                    setUniform(_lights_uniform + i * _light_loc_size + 5, light.spot_exponent());
                    setUniform(_lights_uniform + i * _light_loc_size + 6, light.spot_cut_off());
                    // intesity
                    setUniform(_lights_uniform + i * _light_loc_size + 7, attenuation[3]);
                    // constant attenuation term
                    setUniform(_lights_uniform + i * _light_loc_size + 8, attenuation[0]);
                    // linear attenuation term
                    setUniform(_lights_uniform + i * _light_loc_size + 9, attenuation[1]);
                    // quadratic attenuation term
                    setUniform(_lights_uniform + i * _light_loc_size + 10, attenuation[2]);
                    // world position
                    setUniform(_lights_uniform + i * _light_loc_size + 11, light.position());
                    // casts shadows?
                    setUniform(_lights_uniform + i * _light_loc_size + 12, light.casts_shadows());

                    setUniform(_lights_matrices_uniform + i, light.shadow_matrix());

                    return *this;
                }

                PhongMultiLight& PhongMultiLight::set_transformation_matrix(const Magnum::Matrix4& matrix)
                {
                    setUniform(_transformation_matrix_uniform, matrix);
                    return *this;
                }

                PhongMultiLight& PhongMultiLight::set_camera_matrix(const Magnum::Matrix4& matrix)
                {
                    setUniform(_camera_matrix_uniform, matrix);
                    return *this;
                }

                PhongMultiLight& PhongMultiLight::set_normal_matrix(const Magnum::Matrix3x3& matrix)
                {
                    setUniform(_normal_matrix_uniform, matrix);
                    return *this;
                }

                PhongMultiLight& PhongMultiLight::set_projection_matrix(const Magnum::Matrix4& matrix)
                {
                    setUniform(_projection_matrix_uniform, matrix);
                    return *this;
                }

                PhongMultiLight& PhongMultiLight::set_far_plane(Magnum::Float far_plane)
                {
                    setUniform(_far_plane_uniform, far_plane);
                    return *this;
                }

                PhongMultiLight& PhongMultiLight::set_is_shadowed(bool shadows)
                {
                    setUniform(_is_shadowed_uniform, shadows);
                    return *this;
                }

                PhongMultiLight& PhongMultiLight::set_transparent_shadows(bool shadows)
                {
                    setUniform(_transparent_shadows_uniform, shadows);
                    return *this;
                }

                PhongMultiLight& PhongMultiLight::set_specular_strength(Magnum::Float specular_strength)
                {
                    setUniform(_specular_strength_uniform, std::max(0.f, specular_strength));
                    return *this;
                }

                PhongMultiLight& PhongMultiLight::bind_shadow_texture(Magnum::GL::Texture2DArray& texture)
                {
                    texture.bind(_shadow_textures_location);
                    return *this;
                }

                PhongMultiLight& PhongMultiLight::bind_shadow_color_texture(Magnum::GL::Texture2DArray& texture)
                {
                    texture.bind(_shadow_color_textures_location);
                    return *this;
                }

                PhongMultiLight& PhongMultiLight::bind_cube_map_texture(Magnum::GL::CubeMapTextureArray& texture)
                {
                    texture.bind(_cube_map_textures_location);
                    return *this;
                }

                PhongMultiLight& PhongMultiLight::bind_cube_map_color_texture(Magnum::GL::CubeMapTextureArray& texture)
                {
                    texture.bind(_cube_map_color_textures_location);
                    return *this;
                }

                Magnum::Int PhongMultiLight::max_lights() const { return _max_lights; }
            } // namespace gs
        } // namespace magnum
    } // namespace gui
} // namespace robot_dart