godot/scene/main/shader_globals_override.cpp
Juan Linietsky 0e1c66d9fc Implement global and per instance shader uniforms.
Adds two keywords to shader language for uniforms:
-'global'
-'instance'

This allows them to reference values outside the material.
2020-04-17 12:35:41 -03:00

258 lines
6.8 KiB
C++

#include "shader_globals_override.h"
#include "core/core_string_names.h"
#include "scene/main/window.h"
#include "scene/scene_string_names.h"
StringName *ShaderGlobalsOverride::_remap(const StringName &p_name) const {
StringName *r = param_remaps.getptr(p_name);
if (!r) {
//not cached, do caching
String p = p_name;
if (p.begins_with("params/")) {
String q = p.replace_first("params/", "");
param_remaps[p] = q;
r = param_remaps.getptr(q);
}
}
return r;
}
bool ShaderGlobalsOverride::_set(const StringName &p_name, const Variant &p_value) {
StringName *r = _remap(p_name);
if (r) {
Override *o = overrides.getptr(*r);
if (!o) {
Override ov;
ov.in_use = false;
overrides[*r] = ov;
o = overrides.getptr(*r);
}
if (o) {
o->override = p_value;
if (active) {
RS::get_singleton()->global_variable_set_override(*r, p_value);
}
o->in_use = p_value.get_type() != Variant::NIL;
return true;
}
}
return false;
}
bool ShaderGlobalsOverride::_get(const StringName &p_name, Variant &r_ret) const {
StringName *r = _remap(p_name);
if (r) {
const Override *o = overrides.getptr(*r);
if (o) {
r_ret = o->override;
return true;
}
}
return false;
}
void ShaderGlobalsOverride::_get_property_list(List<PropertyInfo> *p_list) const {
Vector<StringName> variables;
variables = RS::get_singleton()->global_variable_get_list();
for (int i = 0; i < variables.size(); i++) {
PropertyInfo pinfo;
pinfo.name = "params/" + variables[i];
pinfo.usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE;
switch (RS::get_singleton()->global_variable_get_type(variables[i])) {
case RS::GLOBAL_VAR_TYPE_BOOL: {
pinfo.type = Variant::BOOL;
} break;
case RS::GLOBAL_VAR_TYPE_BVEC2: {
pinfo.type = Variant::INT;
pinfo.hint = PROPERTY_HINT_FLAGS;
pinfo.hint_string = "x,y";
} break;
case RS::GLOBAL_VAR_TYPE_BVEC3: {
pinfo.type = Variant::INT;
pinfo.hint = PROPERTY_HINT_FLAGS;
pinfo.hint_string = "x,y,z";
} break;
case RS::GLOBAL_VAR_TYPE_BVEC4: {
pinfo.type = Variant::INT;
pinfo.hint = PROPERTY_HINT_FLAGS;
pinfo.hint_string = "x,y,z,w";
} break;
case RS::GLOBAL_VAR_TYPE_INT: {
pinfo.type = Variant::INT;
} break;
case RS::GLOBAL_VAR_TYPE_IVEC2: {
pinfo.type = Variant::VECTOR2I;
} break;
case RS::GLOBAL_VAR_TYPE_IVEC3: {
pinfo.type = Variant::VECTOR3I;
} break;
case RS::GLOBAL_VAR_TYPE_IVEC4: {
pinfo.type = Variant::PACKED_INT32_ARRAY;
} break;
case RS::GLOBAL_VAR_TYPE_RECT2I: {
pinfo.type = Variant::RECT2I;
} break;
case RS::GLOBAL_VAR_TYPE_UINT: {
pinfo.type = Variant::INT;
} break;
case RS::GLOBAL_VAR_TYPE_UVEC2: {
pinfo.type = Variant::VECTOR2I;
} break;
case RS::GLOBAL_VAR_TYPE_UVEC3: {
pinfo.type = Variant::VECTOR3I;
} break;
case RS::GLOBAL_VAR_TYPE_UVEC4: {
pinfo.type = Variant::PACKED_INT32_ARRAY;
} break;
case RS::GLOBAL_VAR_TYPE_FLOAT: {
pinfo.type = Variant::FLOAT;
} break;
case RS::GLOBAL_VAR_TYPE_VEC2: {
pinfo.type = Variant::VECTOR2;
} break;
case RS::GLOBAL_VAR_TYPE_VEC3: {
pinfo.type = Variant::VECTOR3;
} break;
case RS::GLOBAL_VAR_TYPE_VEC4: {
pinfo.type = Variant::PLANE;
} break;
case RS::GLOBAL_VAR_TYPE_RECT2: {
pinfo.type = Variant::RECT2;
} break;
case RS::GLOBAL_VAR_TYPE_COLOR: {
pinfo.type = Variant::COLOR;
} break;
case RS::GLOBAL_VAR_TYPE_MAT2: {
pinfo.type = Variant::PACKED_INT32_ARRAY;
} break;
case RS::GLOBAL_VAR_TYPE_MAT3: {
pinfo.type = Variant::BASIS;
} break;
case RS::GLOBAL_VAR_TYPE_TRANSFORM_2D: {
pinfo.type = Variant::TRANSFORM2D;
} break;
case RS::GLOBAL_VAR_TYPE_TRANSFORM: {
pinfo.type = Variant::TRANSFORM;
} break;
case RS::GLOBAL_VAR_TYPE_MAT4: {
pinfo.type = Variant::PACKED_INT32_ARRAY;
} break;
case RS::GLOBAL_VAR_TYPE_SAMPLER2D: {
pinfo.type = Variant::OBJECT;
pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;
pinfo.hint_string = "Texture2D";
} break;
case RS::GLOBAL_VAR_TYPE_SAMPLER2DARRAY: {
pinfo.type = Variant::OBJECT;
pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;
pinfo.hint_string = "Texture2DArray";
} break;
case RS::GLOBAL_VAR_TYPE_SAMPLER3D: {
pinfo.type = Variant::OBJECT;
pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;
pinfo.hint_string = "Texture3D";
} break;
case RS::GLOBAL_VAR_TYPE_SAMPLERCUBE: {
pinfo.type = Variant::OBJECT;
pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;
pinfo.hint_string = "Cubemap";
} break;
default: {
} break;
}
if (!overrides.has(variables[i])) {
Override o;
o.in_use = false;
Callable::CallError ce;
o.override = Variant::construct(pinfo.type, NULL, 0, ce);
overrides[variables[i]] = o;
}
Override *o = overrides.getptr(variables[i]);
if (o->in_use && o->override.get_type() != Variant::NIL) {
pinfo.usage |= PROPERTY_USAGE_CHECKED;
pinfo.usage |= PROPERTY_USAGE_STORAGE;
}
p_list->push_back(pinfo);
}
}
void ShaderGlobalsOverride::_activate() {
List<Node *> nodes;
get_tree()->get_nodes_in_group(SceneStringNames::get_singleton()->shader_overrides_group_active, &nodes);
if (nodes.size() == 0) {
//good we are the only override, enable all
active = true;
add_to_group(SceneStringNames::get_singleton()->shader_overrides_group_active);
const StringName *K = nullptr;
while ((K = overrides.next(K))) {
Override *o = overrides.getptr(*K);
if (o->in_use && o->override.get_type() != Variant::NIL) {
RS::get_singleton()->global_variable_set_override(*K, o->override);
}
}
update_configuration_warning(); //may have activated
}
}
void ShaderGlobalsOverride::_notification(int p_what) {
if (p_what == Node3D::NOTIFICATION_ENTER_TREE) {
add_to_group(SceneStringNames::get_singleton()->shader_overrides_group);
_activate();
} else if (p_what == Node3D::NOTIFICATION_EXIT_TREE) {
if (active) {
//remove overrides
const StringName *K = nullptr;
while ((K = overrides.next(K))) {
Override *o = overrides.getptr(*K);
if (o->in_use) {
RS::get_singleton()->global_variable_set_override(*K, Variant());
}
}
}
remove_from_group(SceneStringNames::get_singleton()->shader_overrides_group_active);
remove_from_group(SceneStringNames::get_singleton()->shader_overrides_group);
get_tree()->call_group(SceneStringNames::get_singleton()->shader_overrides_group, "_activate"); //another may want to activate when this is removed
active = false;
}
}
String ShaderGlobalsOverride::get_configuration_warning() const {
if (!active) {
return TTR("ShaderGlobalsOverride is not active because another node of the same type is in the scene.");
}
return String();
}
void ShaderGlobalsOverride::_bind_methods() {
ClassDB::bind_method(D_METHOD("_activate"), &ShaderGlobalsOverride::_activate);
}
ShaderGlobalsOverride::ShaderGlobalsOverride() {
active = false;
}