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(), ¶ms);
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(), ¶ms);
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(), ¶ms);
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