1 /*************************************************************************/
2 /*  material_editor_plugin.cpp                                           */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
10 /*                                                                       */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the       */
13 /* "Software"), to deal in the Software without restriction, including   */
14 /* without limitation the rights to use, copy, modify, merge, publish,   */
15 /* distribute, sublicense, and/or sell copies of the Software, and to    */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions:                                             */
18 /*                                                                       */
19 /* The above copyright notice and this permission notice shall be        */
20 /* included in all copies or substantial portions of the Software.       */
21 /*                                                                       */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
29 /*************************************************************************/
30 
31 #include "material_editor_plugin.h"
32 
33 #include "editor/editor_scale.h"
34 #include "scene/gui/viewport_container.h"
35 #include "scene/resources/particles_material.h"
36 
_notification(int p_what)37 void MaterialEditor::_notification(int p_what) {
38 
39 	if (p_what == NOTIFICATION_READY) {
40 
41 		//get_scene()->connect("node_removed",this,"_node_removed");
42 
43 		if (first_enter) {
44 			//it's in propertyeditor so.. could be moved around
45 
46 			light_1_switch->set_normal_texture(get_icon("MaterialPreviewLight1", "EditorIcons"));
47 			light_1_switch->set_pressed_texture(get_icon("MaterialPreviewLight1Off", "EditorIcons"));
48 			light_2_switch->set_normal_texture(get_icon("MaterialPreviewLight2", "EditorIcons"));
49 			light_2_switch->set_pressed_texture(get_icon("MaterialPreviewLight2Off", "EditorIcons"));
50 
51 			sphere_switch->set_normal_texture(get_icon("MaterialPreviewSphereOff", "EditorIcons"));
52 			sphere_switch->set_pressed_texture(get_icon("MaterialPreviewSphere", "EditorIcons"));
53 			box_switch->set_normal_texture(get_icon("MaterialPreviewCubeOff", "EditorIcons"));
54 			box_switch->set_pressed_texture(get_icon("MaterialPreviewCube", "EditorIcons"));
55 
56 			first_enter = false;
57 		}
58 	}
59 
60 	if (p_what == NOTIFICATION_DRAW) {
61 
62 		Ref<Texture> checkerboard = get_icon("Checkerboard", "EditorIcons");
63 		Size2 size = get_size();
64 
65 		draw_texture_rect(checkerboard, Rect2(Point2(), size), true);
66 	}
67 }
68 
edit(Ref<Material> p_material,const Ref<Environment> & p_env)69 void MaterialEditor::edit(Ref<Material> p_material, const Ref<Environment> &p_env) {
70 
71 	material = p_material;
72 	camera->set_environment(p_env);
73 	if (!material.is_null()) {
74 		sphere_instance->set_material_override(material);
75 		box_instance->set_material_override(material);
76 	} else {
77 
78 		hide();
79 	}
80 }
81 
_button_pressed(Node * p_button)82 void MaterialEditor::_button_pressed(Node *p_button) {
83 
84 	if (p_button == light_1_switch) {
85 		light1->set_visible(!light_1_switch->is_pressed());
86 	}
87 
88 	if (p_button == light_2_switch) {
89 		light2->set_visible(!light_2_switch->is_pressed());
90 	}
91 
92 	if (p_button == box_switch) {
93 		box_instance->show();
94 		sphere_instance->hide();
95 		box_switch->set_pressed(true);
96 		sphere_switch->set_pressed(false);
97 		EditorSettings::get_singleton()->set_project_metadata("inspector_options", "material_preview_on_sphere", false);
98 	}
99 
100 	if (p_button == sphere_switch) {
101 		box_instance->hide();
102 		sphere_instance->show();
103 		box_switch->set_pressed(false);
104 		sphere_switch->set_pressed(true);
105 		EditorSettings::get_singleton()->set_project_metadata("inspector_options", "material_preview_on_sphere", true);
106 	}
107 }
108 
_bind_methods()109 void MaterialEditor::_bind_methods() {
110 
111 	ClassDB::bind_method(D_METHOD("_button_pressed"), &MaterialEditor::_button_pressed);
112 }
113 
MaterialEditor()114 MaterialEditor::MaterialEditor() {
115 
116 	vc = memnew(ViewportContainer);
117 	vc->set_stretch(true);
118 	add_child(vc);
119 	vc->set_anchors_and_margins_preset(PRESET_WIDE);
120 	viewport = memnew(Viewport);
121 	Ref<World> world;
122 	world.instance();
123 	viewport->set_world(world); //use own world
124 	vc->add_child(viewport);
125 	viewport->set_disable_input(true);
126 	viewport->set_transparent_background(true);
127 	viewport->set_msaa(Viewport::MSAA_4X);
128 
129 	camera = memnew(Camera);
130 	camera->set_transform(Transform(Basis(), Vector3(0, 0, 3)));
131 	camera->set_perspective(45, 0.1, 10);
132 	camera->make_current();
133 	viewport->add_child(camera);
134 
135 	light1 = memnew(DirectionalLight);
136 	light1->set_transform(Transform().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0)));
137 	viewport->add_child(light1);
138 
139 	light2 = memnew(DirectionalLight);
140 	light2->set_transform(Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1)));
141 	light2->set_color(Color(0.7, 0.7, 0.7));
142 	viewport->add_child(light2);
143 
144 	sphere_instance = memnew(MeshInstance);
145 	viewport->add_child(sphere_instance);
146 
147 	box_instance = memnew(MeshInstance);
148 	viewport->add_child(box_instance);
149 
150 	Transform box_xform;
151 	box_xform.basis.rotate(Vector3(1, 0, 0), Math::deg2rad(25.0));
152 	box_xform.basis = box_xform.basis * Basis().rotated(Vector3(0, 1, 0), Math::deg2rad(-25.0));
153 	box_xform.basis.scale(Vector3(0.8, 0.8, 0.8));
154 	box_xform.origin.y = 0.2;
155 	box_instance->set_transform(box_xform);
156 
157 	sphere_mesh.instance();
158 	sphere_instance->set_mesh(sphere_mesh);
159 	box_mesh.instance();
160 	box_instance->set_mesh(box_mesh);
161 
162 	set_custom_minimum_size(Size2(1, 150) * EDSCALE);
163 
164 	HBoxContainer *hb = memnew(HBoxContainer);
165 	add_child(hb);
166 	hb->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 2);
167 
168 	VBoxContainer *vb_shape = memnew(VBoxContainer);
169 	hb->add_child(vb_shape);
170 
171 	sphere_switch = memnew(TextureButton);
172 	sphere_switch->set_toggle_mode(true);
173 	sphere_switch->set_pressed(true);
174 	vb_shape->add_child(sphere_switch);
175 	sphere_switch->connect("pressed", this, "_button_pressed", varray(sphere_switch));
176 
177 	box_switch = memnew(TextureButton);
178 	box_switch->set_toggle_mode(true);
179 	box_switch->set_pressed(false);
180 	vb_shape->add_child(box_switch);
181 	box_switch->connect("pressed", this, "_button_pressed", varray(box_switch));
182 
183 	hb->add_spacer();
184 
185 	VBoxContainer *vb_light = memnew(VBoxContainer);
186 	hb->add_child(vb_light);
187 
188 	light_1_switch = memnew(TextureButton);
189 	light_1_switch->set_toggle_mode(true);
190 	vb_light->add_child(light_1_switch);
191 	light_1_switch->connect("pressed", this, "_button_pressed", varray(light_1_switch));
192 
193 	light_2_switch = memnew(TextureButton);
194 	light_2_switch->set_toggle_mode(true);
195 	vb_light->add_child(light_2_switch);
196 	light_2_switch->connect("pressed", this, "_button_pressed", varray(light_2_switch));
197 
198 	first_enter = true;
199 
200 	if (EditorSettings::get_singleton()->get_project_metadata("inspector_options", "material_preview_on_sphere", true)) {
201 		box_instance->hide();
202 	} else {
203 		box_instance->show();
204 		sphere_instance->hide();
205 		box_switch->set_pressed(true);
206 		sphere_switch->set_pressed(false);
207 	}
208 }
209 
210 ///////////////////////
211 
can_handle(Object * p_object)212 bool EditorInspectorPluginMaterial::can_handle(Object *p_object) {
213 
214 	Material *material = Object::cast_to<Material>(p_object);
215 	if (!material)
216 		return false;
217 
218 	return material->get_shader_mode() == Shader::MODE_SPATIAL;
219 }
220 
parse_begin(Object * p_object)221 void EditorInspectorPluginMaterial::parse_begin(Object *p_object) {
222 
223 	Material *material = Object::cast_to<Material>(p_object);
224 	if (!material) {
225 		return;
226 	}
227 	Ref<Material> m(material);
228 
229 	MaterialEditor *editor = memnew(MaterialEditor);
230 	editor->edit(m, env);
231 	add_custom_control(editor);
232 }
233 
EditorInspectorPluginMaterial()234 EditorInspectorPluginMaterial::EditorInspectorPluginMaterial() {
235 	env.instance();
236 	Ref<ProceduralSky> proc_sky = memnew(ProceduralSky(true));
237 	env->set_sky(proc_sky);
238 	env->set_background(Environment::BG_COLOR_SKY);
239 }
240 
MaterialEditorPlugin(EditorNode * p_node)241 MaterialEditorPlugin::MaterialEditorPlugin(EditorNode *p_node) {
242 
243 	Ref<EditorInspectorPluginMaterial> plugin;
244 	plugin.instance();
245 	add_inspector_plugin(plugin);
246 }
247 
converts_to() const248 String SpatialMaterialConversionPlugin::converts_to() const {
249 
250 	return "ShaderMaterial";
251 }
handles(const Ref<Resource> & p_resource) const252 bool SpatialMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const {
253 
254 	Ref<SpatialMaterial> mat = p_resource;
255 	return mat.is_valid();
256 }
convert(const Ref<Resource> & p_resource) const257 Ref<Resource> SpatialMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const {
258 
259 	Ref<SpatialMaterial> mat = p_resource;
260 	ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
261 
262 	Ref<ShaderMaterial> smat;
263 	smat.instance();
264 
265 	Ref<Shader> shader;
266 	shader.instance();
267 
268 	String code = VS::get_singleton()->shader_get_code(mat->get_shader_rid());
269 
270 	shader->set_code(code);
271 
272 	smat->set_shader(shader);
273 
274 	List<PropertyInfo> params;
275 	VS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), &params);
276 
277 	for (List<PropertyInfo>::Element *E = params.front(); E; E = E->next()) {
278 
279 		// Texture parameter has to be treated specially since SpatialMaterial saved it
280 		// as RID but ShaderMaterial needs Texture itself
281 		Ref<Texture> texture = mat->get_texture_by_name(E->get().name);
282 		if (texture.is_valid()) {
283 			smat->set_shader_param(E->get().name, texture);
284 		} else {
285 			Variant value = VS::get_singleton()->material_get_param(mat->get_rid(), E->get().name);
286 			smat->set_shader_param(E->get().name, value);
287 		}
288 	}
289 
290 	smat->set_render_priority(mat->get_render_priority());
291 	return smat;
292 }
293 
converts_to() const294 String ParticlesMaterialConversionPlugin::converts_to() const {
295 
296 	return "ShaderMaterial";
297 }
handles(const Ref<Resource> & p_resource) const298 bool ParticlesMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const {
299 
300 	Ref<ParticlesMaterial> mat = p_resource;
301 	return mat.is_valid();
302 }
convert(const Ref<Resource> & p_resource) const303 Ref<Resource> ParticlesMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const {
304 
305 	Ref<ParticlesMaterial> mat = p_resource;
306 	ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
307 
308 	Ref<ShaderMaterial> smat;
309 	smat.instance();
310 
311 	Ref<Shader> shader;
312 	shader.instance();
313 
314 	String code = VS::get_singleton()->shader_get_code(mat->get_shader_rid());
315 
316 	shader->set_code(code);
317 
318 	smat->set_shader(shader);
319 
320 	List<PropertyInfo> params;
321 	VS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), &params);
322 
323 	for (List<PropertyInfo>::Element *E = params.front(); E; E = E->next()) {
324 		Variant value = VS::get_singleton()->material_get_param(mat->get_rid(), E->get().name);
325 		smat->set_shader_param(E->get().name, value);
326 	}
327 
328 	smat->set_render_priority(mat->get_render_priority());
329 	return smat;
330 }
331 
converts_to() const332 String CanvasItemMaterialConversionPlugin::converts_to() const {
333 
334 	return "ShaderMaterial";
335 }
handles(const Ref<Resource> & p_resource) const336 bool CanvasItemMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const {
337 
338 	Ref<CanvasItemMaterial> mat = p_resource;
339 	return mat.is_valid();
340 }
convert(const Ref<Resource> & p_resource) const341 Ref<Resource> CanvasItemMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const {
342 
343 	Ref<CanvasItemMaterial> mat = p_resource;
344 	ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
345 
346 	Ref<ShaderMaterial> smat;
347 	smat.instance();
348 
349 	Ref<Shader> shader;
350 	shader.instance();
351 
352 	String code = VS::get_singleton()->shader_get_code(mat->get_shader_rid());
353 
354 	shader->set_code(code);
355 
356 	smat->set_shader(shader);
357 
358 	List<PropertyInfo> params;
359 	VS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), &params);
360 
361 	for (List<PropertyInfo>::Element *E = params.front(); E; E = E->next()) {
362 		Variant value = VS::get_singleton()->material_get_param(mat->get_rid(), E->get().name);
363 		smat->set_shader_param(E->get().name, value);
364 	}
365 
366 	smat->set_render_priority(mat->get_render_priority());
367 	return smat;
368 }
369