diff --git a/Model3d.cpp b/Model3d.cpp index 29530bd1..7c6bab1a 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -285,7 +285,8 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic std::replace(material.begin(), material.end(), '\\', '/'); if (material == "none") { // rysowanie podanym kolorem - m_material = null_handle; + Name_Material("colored"); + m_material = GfxRenderer.Fetch_Material(m_materialname); iFlags |= 0x10; // rysowane w cyklu nieprzezroczystych } else if (material.find("replacableskin") != material.npos) @@ -338,6 +339,7 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic if (m_material != null_handle) { opengl_material &mat = GfxRenderer.Material(m_material); + // if material have opacity set, replace submodel opacity with it if (!std::isnan(mat.opacity)) { @@ -347,6 +349,10 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic else iFlags |= 0x10; // opaque } + + // and same thing with selfillum + if (!std::isnan(mat.selfillum)) + fLight = mat.selfillum; } // visibility range @@ -1690,6 +1696,15 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, std::vector *t, else iFlags |= 0x10; // opaque } + + if (m_material != null_handle) + { + opengl_material &mat = GfxRenderer.Material(m_material); + + // replace submodel selfillum with material one + if (!std::isnan(mat.selfillum)) + fLight = mat.selfillum; + } } else { ErrorLog( "Bad model: reference to nonexistent texture index in sub-model" + ( pName.empty() ? "" : " \"" + pName + "\"" ), logtype::model ); @@ -1697,7 +1712,12 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, std::vector *t, } } else - m_material = iTexture; + { + if (iTexture == 0) + m_material = GfxRenderer.Fetch_Material("colored"); + else + m_material = iTexture; + } b_aAnim = b_Anim; // skopiowanie animacji do drugiego cyklu diff --git a/Texture.cpp b/Texture.cpp index 97c2c718..03252a1b 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -578,7 +578,7 @@ opengl_texture::bind(size_t unit) { return false; } - if (m_units[unit] == id) + if (units[unit] == id) return true; if (GLEW_ARB_direct_state_access) @@ -595,7 +595,7 @@ opengl_texture::bind(size_t unit) { glBindTexture(target, id); } - m_units[unit] = id; + units[unit] = id; return true; } @@ -620,13 +620,13 @@ void opengl_texture::unbind(size_t unit) void opengl_texture::reset_unit_cache() { - for( auto &unit : m_units ) { + for( auto &unit : units ) { unit = 0; } m_activeunit = -1; } -std::array opengl_texture::m_units = { 0 }; +std::array opengl_texture::units = { 0 }; GLint opengl_texture::m_activeunit = -1; std::unordered_map opengl_texture::precompressed_formats = @@ -1006,7 +1006,7 @@ texture_manager::create(std::string Filename, bool const Loadnow , GLint fh) { void texture_manager::bind( std::size_t const Unit, texture_handle const Texture ) { - m_textures[ Texture ].second = m_garbagecollector.timestamp(); + mark_as_used(Texture); if (Texture != null_handle) texture(Texture).bind(Unit); @@ -1014,6 +1014,13 @@ texture_manager::bind( std::size_t const Unit, texture_handle const Texture ) { opengl_texture::unbind(Unit); } +opengl_texture &texture_manager::mark_as_used(const texture_handle Texture) +{ + auto &pair = m_textures[ Texture ]; + pair.second = m_garbagecollector.timestamp(); + return *pair.first; +} + void texture_manager::delete_textures() { for( auto const &texture : m_textures ) { diff --git a/Texture.h b/Texture.h index b28fa1d5..b7575d00 100644 --- a/Texture.h +++ b/Texture.h @@ -57,6 +57,7 @@ struct opengl_texture { GLint components_hint; // components that material wants GLenum target = GL_TEXTURE_2D; + static std::array units; private: // methods @@ -91,7 +92,6 @@ private: static std::unordered_map drivercompressed_formats; static std::unordered_map> mapping; - static std::array m_units; static GLint m_activeunit; }; @@ -109,6 +109,7 @@ public: // binds specified texture to specified texture unit void bind( std::size_t const Unit, texture_handle const Texture ); + opengl_texture& mark_as_used(texture_handle const Texture); // provides direct access to specified texture object opengl_texture & texture( texture_handle const Texture ) const { return *(m_textures[ Texture ].first); } diff --git a/gl/shader.cpp b/gl/shader.cpp index 490bba31..fbc674f4 100644 --- a/gl/shader.cpp +++ b/gl/shader.cpp @@ -104,11 +104,7 @@ void gl::shader::parse_texture_entries(std::string &str) if (arg == 0) token_ss >> name; else if (arg == 1) - { token_ss >> conf.id; - if (conf.id >= gl::MAX_TEXTURES) - log_error("invalid texture binding: " + std::to_string(conf.id)); - } else if (arg == 2) { std::string comp; @@ -122,7 +118,14 @@ void gl::shader::parse_texture_entries(std::string &str) } if (arg == 3) - texture_conf.emplace(std::make_pair(name, conf)); + { + if (name.empty()) + log_error("empty name"); + else if (conf.id >= gl::MAX_TEXTURES) + log_error("invalid texture binding: " + std::to_string(conf.id)); + else + texture_conf.emplace(std::make_pair(name, conf)); + } else log_error("invalid argument count to #texture"); @@ -155,11 +158,7 @@ void gl::shader::parse_param_entries(std::string &str) if (arg == 0) token_ss >> name; else if (arg == 1) - { token_ss >> conf.location; - if (conf.location >= gl::MAX_PARAMS) - log_error("invalid param binding: " + std::to_string(conf.location)); - } else if (arg == 2) token_ss >> conf.offset; else if (arg == 3) @@ -176,7 +175,18 @@ void gl::shader::parse_param_entries(std::string &str) } if (arg == 5) - param_conf.emplace(std::make_pair(name, conf)); + { + if (name.empty()) + log_error("empty name"); + else if (conf.location >= gl::MAX_PARAMS) + log_error("invalid param binding: " + std::to_string(conf.location)); + else if (conf.offset > 3) + log_error("invalid offset: " + std::to_string(conf.offset)); + else if (conf.offset + conf.size > 4) + log_error("invalid size: " + std::to_string(conf.size)); + else + param_conf.emplace(std::make_pair(name, conf)); + } else log_error("invalid argument count to #param"); diff --git a/gl/ubo.h b/gl/ubo.h index 63cd17c7..de72f27e 100644 --- a/gl/ubo.h +++ b/gl/ubo.h @@ -31,7 +31,7 @@ namespace gl #pragma pack(push, 1) - const size_t MAX_TEXTURES = 4; + const size_t MAX_TEXTURES = 8; struct scene_ubs { @@ -91,7 +91,7 @@ namespace gl static_assert(sizeof(light_element_ubs) == 64, "bad size of ubs"); - const size_t MAX_LIGHTS = 4; + const size_t MAX_LIGHTS = 8; struct light_ubs { diff --git a/material.cpp b/material.cpp index 23a67728..9fbe4d29 100644 --- a/material.cpp +++ b/material.cpp @@ -15,6 +15,12 @@ http://mozilla.org/MPL/2.0/. #include "utilities.h" #include "Logs.h" +opengl_material::opengl_material() +{ + for (size_t i = 0; i < params.size(); i++) + params[i] = glm::vec4(std::numeric_limits::quiet_NaN()); +} + bool opengl_material::deserialize( cParser &Input, bool const Loadnow ) { parse_info = std::make_unique(); @@ -34,12 +40,6 @@ void opengl_material::log_error(const std::string &str) void opengl_material::finalize(bool Loadnow) { - if (!shader) - { - log_error("shader not specified, assuming \"default\""); - shader = GfxRenderer.Fetch_Shader("default"); - } - if (parse_info) { for (auto it : parse_info->tex_mapping) @@ -59,7 +59,7 @@ void opengl_material::finalize(bool Loadnow) { key.erase(0, 1); key.pop_back(); - if (shader->texture_conf.find(key) != shader->texture_conf.end()) + if (shader && shader->texture_conf.find(key) != shader->texture_conf.end()) textures[shader->texture_conf[key].id] = GfxRenderer.Fetch_Texture(value, Loadnow); else log_error("unknown texture binding: " + key); @@ -68,6 +68,25 @@ void opengl_material::finalize(bool Loadnow) log_error("unrecognized texture binding: " + key); } + if (!shader) + { + if (textures[0] == null_handle) + { + log_error("shader not specified, assuming \"default_0\""); + shader = GfxRenderer.Fetch_Shader("default_0"); + } + else if (textures[1] == null_handle) + { + log_error("shader not specified, assuming \"default_1\""); + shader = GfxRenderer.Fetch_Shader("default_1"); + } + else if (textures[2] == null_handle) + { + log_error("shader not specified, assuming \"default_2\""); + shader = GfxRenderer.Fetch_Shader("default_2"); + } + } + for (auto it : parse_info->param_mapping) { std::string key = it.first; @@ -319,6 +338,10 @@ material_manager::create( std::string const &Filename, bool const Loadnow ) { // if there's also no texture, give up return null_handle; } + + // material would attach default shader anyway, but it would spit to error log + material.shader = GfxRenderer.Fetch_Shader("default_1"); + // use texture path and name to tell the newly created materials apart filename = GfxRenderer.Texture( material.textures[0] ).name; erase_extension( filename ); diff --git a/material.h b/material.h index de54fcaa..76261bcb 100644 --- a/material.h +++ b/material.h @@ -20,7 +20,7 @@ typedef int material_handle; // for modern opengl this translates to set of attributes for shaders struct opengl_material { std::array textures = { null_handle }; - std::array params = { glm::vec4(std::numeric_limits::quiet_NaN()) }; + std::array params; std::vector params_state; std::shared_ptr shader; @@ -30,7 +30,7 @@ struct opengl_material { std::string name; // constructors - opengl_material() = default; + opengl_material(); // methods bool diff --git a/renderer.cpp b/renderer.cpp index dfda65e2..6fc636d9 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -1101,15 +1101,17 @@ void opengl_renderer::Bind_Material(material_handle const Material, TSubModel *s { gl::shader::param_entry entry = material.params_state[i]; - glm::vec4 src; - if (entry.defaultparam == gl::shader::defaultparam_e::ambient) - src = sm->f4Ambient; - else if (entry.defaultparam == gl::shader::defaultparam_e::diffuse) - src = sm->f4Diffuse; - else if (entry.defaultparam == gl::shader::defaultparam_e::specular) - src = sm->f4Specular; - else - continue; + glm::vec4 src(1.0f); + + if (sm) + { + if (entry.defaultparam == gl::shader::defaultparam_e::ambient) + src = sm->f4Ambient; + else if (entry.defaultparam == gl::shader::defaultparam_e::diffuse) + src = sm->f4Diffuse; + else if (entry.defaultparam == gl::shader::defaultparam_e::specular) + src = sm->f4Specular; + } for (size_t j = 0; j < entry.size; j++) model_ubs.param[entry.location][entry.offset + j] = src[j]; @@ -1125,18 +1127,24 @@ void opengl_renderer::Bind_Material(material_handle const Material, TSubModel *s if (GLEW_ARB_multi_bind) { - GLuint textures[gl::MAX_TEXTURES] = { 0 }; + GLuint lastdiff = 0; size_t i; for (i = 0; i < gl::MAX_TEXTURES; i++) if (material.textures[i] != null_handle) { - opengl_texture &tex = m_textures.texture(material.textures[i]); + opengl_texture &tex = m_textures.mark_as_used(material.textures[i]); tex.create(); - textures[i] = tex.id; + if (opengl_texture::units[i] != tex.id) + { + opengl_texture::units[i] = tex.id; + lastdiff = i + 1; + } } else break; - glBindTextures(0, i, textures); + + if (lastdiff) + glBindTextures(0, lastdiff, &opengl_texture::units[0]); } else { @@ -1937,12 +1945,12 @@ void opengl_renderer::Render(TSubModel *Submodel) // textures... if (Submodel->m_material < 0) { // zmienialne skóry - Bind_Material(Submodel->ReplacableSkinId[-Submodel->m_material]); + Bind_Material(Submodel->ReplacableSkinId[-Submodel->m_material], Submodel); } else { // również 0 - Bind_Material(Submodel->m_material); + Bind_Material(Submodel->m_material, Submodel); } // ...colors... @@ -2106,7 +2114,7 @@ void opengl_renderer::Render(TSubModel *Submodel) { if (Global.fLuminance < Submodel->fLight) { - Bind_Material(Submodel->m_material); + Bind_Material(Submodel->m_material, Submodel); // main draw call model_ubs.set_modelview(OpenGLMatrices.data(GL_MODELVIEW)); @@ -2781,11 +2789,11 @@ void opengl_renderer::Render_Alpha(TSubModel *Submodel) // textures... if (Submodel->m_material < 0) { // zmienialne skóry - Bind_Material(Submodel->ReplacableSkinId[-Submodel->m_material]); + Bind_Material(Submodel->ReplacableSkinId[-Submodel->m_material], Submodel); } else { - Bind_Material(Submodel->m_material); + Bind_Material(Submodel->m_material, Submodel); } // ...luminance diff --git a/shaders/alphashadowmap.frag b/shaders/alphashadowmap.frag index 2e2c571d..a0986579 100644 --- a/shaders/alphashadowmap.frag +++ b/shaders/alphashadowmap.frag @@ -7,7 +7,5 @@ uniform sampler2D tex1; void main() { - //gl_FragColor = texture(tex, f_coord); - //gl_FragDepth = gl_FragCoord.z; gl_FragDepth = gl_FragCoord.z + (1.0 - texture(tex1, f_coord).a); } diff --git a/shaders/mat_notex.frag b/shaders/mat_colored.frag similarity index 68% rename from shaders/mat_notex.frag rename to shaders/mat_colored.frag index 4eeecbde..f07d61ee 100644 --- a/shaders/mat_notex.frag +++ b/shaders/mat_colored.frag @@ -2,6 +2,8 @@ #include +#param (color, 0, 0, 4, diffuse) + void main() { gl_FragColor = param[0]; diff --git a/shaders/mat_default.frag b/shaders/mat_default.frag index a6fff639..528e57ee 100644 --- a/shaders/mat_default.frag +++ b/shaders/mat_default.frag @@ -7,7 +7,11 @@ in vec4 f_light_pos; #include -#texture (tex1, 0, sRGB_A) +#param (color, 0, 0, 4, diffuse) +#param (diffuse, 1, 0, 1, one) +#param (specular, 1, 1, 1, specular) + +#texture (diffuse, 0, sRGB_A) uniform sampler2D tex1; uniform sampler2DShadow shadowmap; @@ -56,6 +60,7 @@ float calc_light(vec3 light_dir) float diffuse_v = max(dot(normal, light_dir), 0.0); float specular_v = pow(max(dot(normal, halfway_dir), 0.0), 15.0); + //return specular_v * param[1].y + diffuse_v * param[1].x; return specular_v + diffuse_v; } @@ -113,7 +118,7 @@ void main() if (i == 0U) part *= shadow; - result += light.color * part * envcolor; + result += light.color * part;// * envcolor; } vec3 c = apply_fog(result * tex_color.xyz); diff --git a/shaders/mat_default_0.frag b/shaders/mat_default_0.frag new file mode 100644 index 00000000..f951f70d --- /dev/null +++ b/shaders/mat_default_0.frag @@ -0,0 +1 @@ +#include diff --git a/shaders/mat_default_1.frag b/shaders/mat_default_1.frag new file mode 100644 index 00000000..8eb248b7 --- /dev/null +++ b/shaders/mat_default_1.frag @@ -0,0 +1 @@ +#include diff --git a/shaders/mat_default_2.frag b/shaders/mat_default_2.frag new file mode 100644 index 00000000..8eb248b7 --- /dev/null +++ b/shaders/mat_default_2.frag @@ -0,0 +1 @@ +#include diff --git a/shaders/mat_mirr.frag b/shaders/mat_mirr.frag deleted file mode 100644 index a88dc286..00000000 --- a/shaders/mat_mirr.frag +++ /dev/null @@ -1,123 +0,0 @@ -#version 330 - -in vec3 f_normal; -in vec2 f_coord; -in vec3 f_pos; -in vec4 f_light_pos; - -#include - -#texture (tex1, 0, sRGB_A) -uniform sampler2D tex1; - -uniform sampler2DShadow shadowmap; -uniform samplerCube envmap; - -float calc_shadow() -{ - vec3 coords = f_light_pos.xyz / f_light_pos.w; - - // do something better - float bias = 0.0001f; - - //sampler PCF - //float shadow = texture(shadowmap, vec3(coords.xy, coords.z - bias)); - - //sampler PCF + PCF - float shadow = 0.0; - vec2 texel = 1.0 / textureSize(shadowmap, 0); - for (float y = -1.5; y <= 1.5; y += 1.0) - for (float x = -1.5; x <= 1.5; x += 1.0) - shadow += texture(shadowmap, coords.xyz + vec3(vec2(x, y) * texel, -bias)); - shadow /= 16.0; - - if (coords.z > 1.0f) - shadow = 1.0f; - - return shadow; -} - -vec3 apply_fog(vec3 color) -{ - float sun_amount = 0.0; - if (lights_count >= 1U && lights[0].type == LIGHT_DIR) - sun_amount = max(dot(normalize(f_pos), normalize(-lights[0].dir)), 0.0); - vec3 fog_color_v = mix(fog_color, lights[0].color, pow(sun_amount, 30.0)); - float fog_amount_v = 1.0 - min(1.0, exp(-length(f_pos) * fog_density)); - return mix(color, fog_color_v, fog_amount_v); -} - -float calc_light(vec3 light_dir) -{ - vec3 normal = normalize(f_normal); - vec3 view_dir = normalize(vec3(0.0f, 0.0f, 0.0f) - f_pos); - vec3 halfway_dir = normalize(light_dir + view_dir); - - float diffuse_v = max(dot(normal, light_dir), 0.0); - float specular_v = pow(max(dot(normal, halfway_dir), 0.0), 15.0); - - return specular_v + diffuse_v; -} - -float calc_point_light(light_s light) -{ - vec3 light_dir = normalize(light.pos - f_pos); - float val = calc_light(light_dir); - - float distance = length(light.pos - f_pos); - float atten = 1.0f / (1.0f + light.linear * distance + light.quadratic * (distance * distance)); - - return val * atten; -} - -float calc_spot_light(light_s light) -{ - vec3 light_dir = normalize(light.pos - f_pos); - - float theta = dot(light_dir, normalize(-light.dir)); - float epsilon = light.in_cutoff - light.out_cutoff; - float intensity = clamp((theta - light.out_cutoff) / epsilon, 0.0, 1.0); - - float point = calc_point_light(light); - return point * intensity; -} - -float calc_dir_light(light_s light) -{ - vec3 light_dir = normalize(-light.dir); - return calc_light(light_dir); -} - -void main() -{ - vec4 tex_color = texture(tex1, f_coord); - - if (opacity == 0.0f && tex_color.a < 0.9f) - discard; - - float shadow = calc_shadow(); - vec3 result = ambient * 0.3 + vec3(1.0) * emission; - for (uint i = 0U; i < lights_count; i++) - { - light_s light = lights[i]; - float part = 0.0; - - if (light.type == LIGHT_SPOT) - part = calc_spot_light(light); - else if (light.type == LIGHT_POINT) - part = calc_point_light(light); - else if (light.type == LIGHT_DIR) - part = calc_dir_light(light); - - if (i == 0U) - part *= shadow; - result += light.color * part; - } - - vec3 R = reflect(f_pos, normalize(f_normal)); - vec3 r = texture(envmap, R).rgb; - r *= vec3(1.0, 0.84, 0.2); - - vec3 c = apply_fog(result * tex_color.xyz); - gl_FragColor = vec4(c * 0.05 + r * 0.95, tex_color.w); -} diff --git a/shaders/shadowmap.frag b/shaders/shadowmap.frag index 37f0753f..9fb6da4d 100644 --- a/shaders/shadowmap.frag +++ b/shaders/shadowmap.frag @@ -2,11 +2,7 @@ in vec2 f_coord; -//uniform sampler2D tex; - void main() { - //gl_FragColor = texture(tex, f_coord); gl_FragDepth = gl_FragCoord.z; - //gl_FragDepth = gl_FragCoord.z + (1.0 - texture(tex, f_coord).w); }