|
@@ -39,6 +39,196 @@
|
|
|
#include "scene/scene_string_names.h"
|
|
|
#include "servers/visual_server.h"
|
|
|
|
|
|
+Mutex *CanvasItemMaterial::material_mutex = NULL;
|
|
|
+SelfList<CanvasItemMaterial>::List CanvasItemMaterial::dirty_materials;
|
|
|
+Map<CanvasItemMaterial::MaterialKey, CanvasItemMaterial::ShaderData> CanvasItemMaterial::shader_map;
|
|
|
+
|
|
|
+void CanvasItemMaterial::init_shaders() {
|
|
|
+
|
|
|
+#ifndef NO_THREADS
|
|
|
+ material_mutex = Mutex::create();
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+void CanvasItemMaterial::finish_shaders() {
|
|
|
+
|
|
|
+#ifndef NO_THREADS
|
|
|
+ memdelete(material_mutex);
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+void CanvasItemMaterial::_update_shader() {
|
|
|
+
|
|
|
+ dirty_materials.remove(&element);
|
|
|
+
|
|
|
+ MaterialKey mk = _compute_key();
|
|
|
+ if (mk.key == current_key.key)
|
|
|
+ return; //no update required in the end
|
|
|
+
|
|
|
+ if (shader_map.has(current_key)) {
|
|
|
+ shader_map[current_key].users--;
|
|
|
+ if (shader_map[current_key].users == 0) {
|
|
|
+ //deallocate shader, as it's no longer in use
|
|
|
+ VS::get_singleton()->free(shader_map[current_key].shader);
|
|
|
+ shader_map.erase(current_key);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ current_key = mk;
|
|
|
+
|
|
|
+ if (shader_map.has(mk)) {
|
|
|
+
|
|
|
+ VS::get_singleton()->material_set_shader(_get_material(), shader_map[mk].shader);
|
|
|
+ shader_map[mk].users++;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ //must create a shader!
|
|
|
+
|
|
|
+ String code = "shader_type canvas_item;\nrender_mode ";
|
|
|
+ switch (blend_mode) {
|
|
|
+ case BLEND_MODE_MIX: code += "blend_mix"; break;
|
|
|
+ case BLEND_MODE_ADD: code += "blend_add"; break;
|
|
|
+ case BLEND_MODE_SUB: code += "blend_sub"; break;
|
|
|
+ case BLEND_MODE_MUL: code += "blend_mul"; break;
|
|
|
+ case BLEND_MODE_PREMULT_ALPHA: code += "blend_premul_alpha"; break;
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (light_mode) {
|
|
|
+ case LIGHT_MODE_NORMAL: break;
|
|
|
+ case LIGHT_MODE_UNSHADED: code += "unshaded"; break;
|
|
|
+ case LIGHT_MODE_LIGHT_ONLY: code += "light_only"; break;
|
|
|
+ }
|
|
|
+ code += ";\n"; //thats it.
|
|
|
+
|
|
|
+ ShaderData shader_data;
|
|
|
+ shader_data.shader = VS::get_singleton()->shader_create();
|
|
|
+ shader_data.users = 1;
|
|
|
+
|
|
|
+ VS::get_singleton()->shader_set_code(shader_data.shader, code);
|
|
|
+
|
|
|
+ shader_map[mk] = shader_data;
|
|
|
+
|
|
|
+ VS::get_singleton()->material_set_shader(_get_material(), shader_data.shader);
|
|
|
+}
|
|
|
+
|
|
|
+void CanvasItemMaterial::flush_changes() {
|
|
|
+
|
|
|
+ if (material_mutex)
|
|
|
+ material_mutex->lock();
|
|
|
+
|
|
|
+ while (dirty_materials.first()) {
|
|
|
+
|
|
|
+ dirty_materials.first()->self()->_update_shader();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (material_mutex)
|
|
|
+ material_mutex->unlock();
|
|
|
+}
|
|
|
+
|
|
|
+void CanvasItemMaterial::_queue_shader_change() {
|
|
|
+
|
|
|
+ if (material_mutex)
|
|
|
+ material_mutex->lock();
|
|
|
+
|
|
|
+ if (!element.in_list()) {
|
|
|
+ dirty_materials.add(&element);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (material_mutex)
|
|
|
+ material_mutex->unlock();
|
|
|
+}
|
|
|
+
|
|
|
+bool CanvasItemMaterial::_is_shader_dirty() const {
|
|
|
+
|
|
|
+ bool dirty = false;
|
|
|
+
|
|
|
+ if (material_mutex)
|
|
|
+ material_mutex->lock();
|
|
|
+
|
|
|
+ dirty = element.in_list();
|
|
|
+
|
|
|
+ if (material_mutex)
|
|
|
+ material_mutex->unlock();
|
|
|
+
|
|
|
+ return dirty;
|
|
|
+}
|
|
|
+void CanvasItemMaterial::set_blend_mode(BlendMode p_blend_mode) {
|
|
|
+
|
|
|
+ blend_mode = p_blend_mode;
|
|
|
+ _queue_shader_change();
|
|
|
+}
|
|
|
+
|
|
|
+CanvasItemMaterial::BlendMode CanvasItemMaterial::get_blend_mode() const {
|
|
|
+ return blend_mode;
|
|
|
+}
|
|
|
+
|
|
|
+void CanvasItemMaterial::set_light_mode(LightMode p_light_mode) {
|
|
|
+
|
|
|
+ light_mode = p_light_mode;
|
|
|
+ _queue_shader_change();
|
|
|
+}
|
|
|
+
|
|
|
+CanvasItemMaterial::LightMode CanvasItemMaterial::get_light_mode() const {
|
|
|
+
|
|
|
+ return light_mode;
|
|
|
+}
|
|
|
+
|
|
|
+void CanvasItemMaterial::_validate_property(PropertyInfo &property) const {
|
|
|
+}
|
|
|
+
|
|
|
+void CanvasItemMaterial::_bind_methods() {
|
|
|
+
|
|
|
+ ClassDB::bind_method(D_METHOD("set_blend_mode", "blend_mode"), &CanvasItemMaterial::set_blend_mode);
|
|
|
+ ClassDB::bind_method(D_METHOD("get_blend_mode"), &CanvasItemMaterial::get_blend_mode);
|
|
|
+
|
|
|
+ ClassDB::bind_method(D_METHOD("set_light_mode", "light_mode"), &CanvasItemMaterial::set_light_mode);
|
|
|
+ ClassDB::bind_method(D_METHOD("get_light_mode"), &CanvasItemMaterial::get_light_mode);
|
|
|
+
|
|
|
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul,Premult Alpha"), "set_blend_mode", "get_blend_mode");
|
|
|
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mode", PROPERTY_HINT_ENUM, "Normal,Unshaded,Light Only"), "set_light_mode", "get_light_mode");
|
|
|
+
|
|
|
+ BIND_CONSTANT(BLEND_MODE_MIX);
|
|
|
+ BIND_CONSTANT(BLEND_MODE_ADD);
|
|
|
+ BIND_CONSTANT(BLEND_MODE_SUB);
|
|
|
+ BIND_CONSTANT(BLEND_MODE_MUL);
|
|
|
+ BIND_CONSTANT(BLEND_MODE_PREMULT_ALPHA);
|
|
|
+ BIND_CONSTANT(LIGHT_MODE_NORMAL);
|
|
|
+ BIND_CONSTANT(LIGHT_MODE_UNSHADED);
|
|
|
+ BIND_CONSTANT(LIGHT_MODE_LIGHT_ONLY);
|
|
|
+}
|
|
|
+
|
|
|
+CanvasItemMaterial::CanvasItemMaterial()
|
|
|
+ : element(this) {
|
|
|
+
|
|
|
+ blend_mode = BLEND_MODE_MIX;
|
|
|
+ light_mode = LIGHT_MODE_NORMAL;
|
|
|
+
|
|
|
+ current_key.key = 0;
|
|
|
+ current_key.invalid_key = 1;
|
|
|
+ _queue_shader_change();
|
|
|
+}
|
|
|
+
|
|
|
+CanvasItemMaterial::~CanvasItemMaterial() {
|
|
|
+
|
|
|
+ if (material_mutex)
|
|
|
+ material_mutex->lock();
|
|
|
+
|
|
|
+ if (shader_map.has(current_key)) {
|
|
|
+ shader_map[current_key].users--;
|
|
|
+ if (shader_map[current_key].users == 0) {
|
|
|
+ //deallocate shader, as it's no longer in use
|
|
|
+ VS::get_singleton()->free(shader_map[current_key].shader);
|
|
|
+ shader_map.erase(current_key);
|
|
|
+ }
|
|
|
+
|
|
|
+ VS::get_singleton()->material_set_shader(_get_material(), RID());
|
|
|
+ }
|
|
|
+
|
|
|
+ if (material_mutex)
|
|
|
+ material_mutex->unlock();
|
|
|
+}
|
|
|
+
|
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
|
|
bool CanvasItem::is_visible_in_tree() const {
|
|
@@ -665,7 +855,7 @@ bool CanvasItem::is_draw_behind_parent_enabled() const {
|
|
|
return behind;
|
|
|
}
|
|
|
|
|
|
-void CanvasItem::set_material(const Ref<ShaderMaterial> &p_material) {
|
|
|
+void CanvasItem::set_material(const Ref<Material> &p_material) {
|
|
|
|
|
|
material = p_material;
|
|
|
RID rid;
|
|
@@ -686,7 +876,7 @@ bool CanvasItem::get_use_parent_material() const {
|
|
|
return use_parent_material;
|
|
|
}
|
|
|
|
|
|
-Ref<ShaderMaterial> CanvasItem::get_material() const {
|
|
|
+Ref<Material> CanvasItem::get_material() const {
|
|
|
|
|
|
return material;
|
|
|
}
|
|
@@ -788,8 +978,8 @@ void CanvasItem::_bind_methods() {
|
|
|
ClassDB::bind_method(D_METHOD("get_world_2d"), &CanvasItem::get_world_2d);
|
|
|
//ClassDB::bind_method(D_METHOD("get_viewport"),&CanvasItem::get_viewport);
|
|
|
|
|
|
- ClassDB::bind_method(D_METHOD("set_material", "material:ShaderMaterial"), &CanvasItem::set_material);
|
|
|
- ClassDB::bind_method(D_METHOD("get_material:ShaderMaterial"), &CanvasItem::get_material);
|
|
|
+ ClassDB::bind_method(D_METHOD("set_material", "material:Material"), &CanvasItem::set_material);
|
|
|
+ ClassDB::bind_method(D_METHOD("get_material:Material"), &CanvasItem::get_material);
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("set_use_parent_material", "enable"), &CanvasItem::set_use_parent_material);
|
|
|
ClassDB::bind_method(D_METHOD("get_use_parent_material"), &CanvasItem::get_use_parent_material);
|
|
@@ -815,7 +1005,7 @@ void CanvasItem::_bind_methods() {
|
|
|
ADD_PROPERTYNO(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask");
|
|
|
|
|
|
ADD_GROUP("Material", "");
|
|
|
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial"), "set_material", "get_material");
|
|
|
+ ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,CanvasItemMaterial"), "set_material", "get_material");
|
|
|
ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "use_parent_material"), "set_use_parent_material", "get_use_parent_material");
|
|
|
//exporting these two things doesn't really make much sense i think
|
|
|
//ADD_PROPERTY( PropertyInfo(Variant::BOOL,"transform/toplevel"), "set_as_toplevel","is_set_as_toplevel") ;
|