Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/editor/shader/shader_globals_editor.cpp
20907 views
1
/**************************************************************************/
2
/* shader_globals_editor.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
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 "shader_globals_editor.h"
32
33
#include "core/config/project_settings.h"
34
#include "editor/editor_node.h"
35
#include "editor/editor_undo_redo_manager.h"
36
#include "editor/inspector/editor_inspector.h"
37
#include "scene/gui/label.h"
38
#include "scene/gui/line_edit.h"
39
#include "scene/gui/margin_container.h"
40
#include "servers/rendering/shader_language.h"
41
42
static const char *global_var_type_names[RS::GLOBAL_VAR_TYPE_MAX] = {
43
"bool",
44
"bvec2",
45
"bvec3",
46
"bvec4",
47
"int",
48
"ivec2",
49
"ivec3",
50
"ivec4",
51
"rect2i",
52
"uint",
53
"uvec2",
54
"uvec3",
55
"uvec4",
56
"float",
57
"vec2",
58
"vec3",
59
"vec4",
60
"color",
61
"rect2",
62
"mat2",
63
"mat3",
64
"mat4",
65
"transform_2d",
66
"transform",
67
"sampler2D",
68
"sampler2DArray",
69
"sampler3D",
70
"samplerCube",
71
"samplerExternalOES",
72
};
73
74
class ShaderGlobalsEditorInterface : public Object {
75
GDCLASS(ShaderGlobalsEditorInterface, Object)
76
77
void _set_var(const StringName &p_name, const Variant &p_value, const Variant &p_prev_value) {
78
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
79
80
undo_redo->create_action(TTR("Set Shader Global Variable"));
81
undo_redo->add_do_method(RS::get_singleton(), "global_shader_parameter_set", p_name, p_value);
82
undo_redo->add_undo_method(RS::get_singleton(), "global_shader_parameter_set", p_name, p_prev_value);
83
RS::GlobalShaderParameterType type = RS::get_singleton()->global_shader_parameter_get_type(p_name);
84
Dictionary gv;
85
gv["type"] = global_var_type_names[type];
86
if (type >= RS::GLOBAL_VAR_TYPE_SAMPLER2D) {
87
Ref<Resource> res = p_value;
88
if (res.is_valid()) {
89
gv["value"] = res->get_path();
90
} else {
91
gv["value"] = "";
92
}
93
} else {
94
gv["value"] = p_value;
95
}
96
97
String path = "shader_globals/" + String(p_name);
98
undo_redo->add_do_property(ProjectSettings::get_singleton(), path, gv);
99
undo_redo->add_undo_property(ProjectSettings::get_singleton(), path, GLOBAL_GET(path));
100
undo_redo->add_do_method(this, "_var_changed");
101
undo_redo->add_undo_method(this, "_var_changed");
102
block_update = true;
103
undo_redo->commit_action();
104
block_update = false;
105
}
106
107
void _var_changed() {
108
emit_signal(SNAME("var_changed"));
109
}
110
111
protected:
112
static void _bind_methods() {
113
ClassDB::bind_method("_var_changed", &ShaderGlobalsEditorInterface::_var_changed);
114
ADD_SIGNAL(MethodInfo("var_changed"));
115
}
116
117
bool _set(const StringName &p_name, const Variant &p_value) {
118
Variant existing = RS::get_singleton()->global_shader_parameter_get(p_name);
119
120
if (existing.get_type() == Variant::NIL) {
121
return false;
122
}
123
124
callable_mp(this, &ShaderGlobalsEditorInterface::_set_var).call_deferred(p_name, p_value, existing);
125
126
return true;
127
}
128
129
bool _get(const StringName &p_name, Variant &r_ret) const {
130
r_ret = RS::get_singleton()->global_shader_parameter_get(p_name);
131
return r_ret.get_type() != Variant::NIL;
132
}
133
void _get_property_list(List<PropertyInfo> *p_list) const {
134
Vector<StringName> variables;
135
variables = RS::get_singleton()->global_shader_parameter_get_list();
136
for (int i = 0; i < variables.size(); i++) {
137
PropertyInfo pinfo;
138
pinfo.name = variables[i];
139
140
switch (RS::get_singleton()->global_shader_parameter_get_type(variables[i])) {
141
case RS::GLOBAL_VAR_TYPE_BOOL: {
142
pinfo.type = Variant::BOOL;
143
} break;
144
case RS::GLOBAL_VAR_TYPE_BVEC2: {
145
pinfo.type = Variant::INT;
146
pinfo.hint = PROPERTY_HINT_FLAGS;
147
pinfo.hint_string = "x,y";
148
} break;
149
case RS::GLOBAL_VAR_TYPE_BVEC3: {
150
pinfo.type = Variant::INT;
151
pinfo.hint = PROPERTY_HINT_FLAGS;
152
pinfo.hint_string = "x,y,z";
153
} break;
154
case RS::GLOBAL_VAR_TYPE_BVEC4: {
155
pinfo.type = Variant::INT;
156
pinfo.hint = PROPERTY_HINT_FLAGS;
157
pinfo.hint_string = "x,y,z,w";
158
} break;
159
case RS::GLOBAL_VAR_TYPE_INT: {
160
pinfo.type = Variant::INT;
161
} break;
162
case RS::GLOBAL_VAR_TYPE_IVEC2: {
163
pinfo.type = Variant::VECTOR2I;
164
} break;
165
case RS::GLOBAL_VAR_TYPE_IVEC3: {
166
pinfo.type = Variant::VECTOR3I;
167
} break;
168
case RS::GLOBAL_VAR_TYPE_IVEC4: {
169
pinfo.type = Variant::VECTOR4I;
170
} break;
171
case RS::GLOBAL_VAR_TYPE_RECT2I: {
172
pinfo.type = Variant::RECT2I;
173
} break;
174
case RS::GLOBAL_VAR_TYPE_UINT: {
175
pinfo.type = Variant::INT;
176
} break;
177
case RS::GLOBAL_VAR_TYPE_UVEC2: {
178
pinfo.type = Variant::VECTOR2I;
179
} break;
180
case RS::GLOBAL_VAR_TYPE_UVEC3: {
181
pinfo.type = Variant::VECTOR3I;
182
} break;
183
case RS::GLOBAL_VAR_TYPE_UVEC4: {
184
pinfo.type = Variant::VECTOR4I;
185
} break;
186
case RS::GLOBAL_VAR_TYPE_FLOAT: {
187
pinfo.type = Variant::FLOAT;
188
} break;
189
case RS::GLOBAL_VAR_TYPE_VEC2: {
190
pinfo.type = Variant::VECTOR2;
191
} break;
192
case RS::GLOBAL_VAR_TYPE_VEC3: {
193
pinfo.type = Variant::VECTOR3;
194
} break;
195
case RS::GLOBAL_VAR_TYPE_VEC4: {
196
pinfo.type = Variant::VECTOR4;
197
} break;
198
case RS::GLOBAL_VAR_TYPE_RECT2: {
199
pinfo.type = Variant::RECT2;
200
} break;
201
case RS::GLOBAL_VAR_TYPE_COLOR: {
202
pinfo.type = Variant::COLOR;
203
} break;
204
case RS::GLOBAL_VAR_TYPE_MAT2: {
205
pinfo.type = Variant::PACKED_FLOAT32_ARRAY;
206
} break;
207
case RS::GLOBAL_VAR_TYPE_MAT3: {
208
pinfo.type = Variant::BASIS;
209
} break;
210
case RS::GLOBAL_VAR_TYPE_TRANSFORM_2D: {
211
pinfo.type = Variant::TRANSFORM2D;
212
} break;
213
case RS::GLOBAL_VAR_TYPE_TRANSFORM: {
214
pinfo.type = Variant::TRANSFORM3D;
215
} break;
216
case RS::GLOBAL_VAR_TYPE_MAT4: {
217
pinfo.type = Variant::PROJECTION;
218
} break;
219
case RS::GLOBAL_VAR_TYPE_SAMPLER2D: {
220
pinfo.type = Variant::OBJECT;
221
pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;
222
pinfo.hint_string = "Texture2D";
223
} break;
224
case RS::GLOBAL_VAR_TYPE_SAMPLER2DARRAY: {
225
pinfo.type = Variant::OBJECT;
226
pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;
227
pinfo.hint_string = "Texture2DArray,CompressedTexture2DArray";
228
} break;
229
case RS::GLOBAL_VAR_TYPE_SAMPLER3D: {
230
pinfo.type = Variant::OBJECT;
231
pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;
232
pinfo.hint_string = "Texture3D";
233
} break;
234
case RS::GLOBAL_VAR_TYPE_SAMPLERCUBE: {
235
pinfo.type = Variant::OBJECT;
236
pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;
237
pinfo.hint_string = "Cubemap,CompressedCubemap";
238
} break;
239
case RS::GLOBAL_VAR_TYPE_SAMPLEREXT: {
240
pinfo.type = Variant::OBJECT;
241
pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;
242
pinfo.hint_string = "ExternalTexture";
243
} break;
244
default: {
245
} break;
246
}
247
248
p_list->push_back(pinfo);
249
}
250
}
251
252
public:
253
bool block_update = false;
254
255
ShaderGlobalsEditorInterface() {
256
}
257
};
258
259
static Variant create_var(RS::GlobalShaderParameterType p_type) {
260
switch (p_type) {
261
case RS::GLOBAL_VAR_TYPE_BOOL: {
262
return false;
263
}
264
case RS::GLOBAL_VAR_TYPE_BVEC2: {
265
return 0; //bits
266
}
267
case RS::GLOBAL_VAR_TYPE_BVEC3: {
268
return 0; //bits
269
}
270
case RS::GLOBAL_VAR_TYPE_BVEC4: {
271
return 0; //bits
272
}
273
case RS::GLOBAL_VAR_TYPE_INT: {
274
return 0; //bits
275
}
276
case RS::GLOBAL_VAR_TYPE_IVEC2: {
277
return Vector2i();
278
}
279
case RS::GLOBAL_VAR_TYPE_IVEC3: {
280
return Vector3i();
281
}
282
case RS::GLOBAL_VAR_TYPE_IVEC4: {
283
return Vector4i();
284
}
285
case RS::GLOBAL_VAR_TYPE_RECT2I: {
286
return Rect2i();
287
}
288
case RS::GLOBAL_VAR_TYPE_UINT: {
289
return 0;
290
}
291
case RS::GLOBAL_VAR_TYPE_UVEC2: {
292
return Vector2i();
293
}
294
case RS::GLOBAL_VAR_TYPE_UVEC3: {
295
return Vector3i();
296
}
297
case RS::GLOBAL_VAR_TYPE_UVEC4: {
298
return Vector4i();
299
}
300
case RS::GLOBAL_VAR_TYPE_FLOAT: {
301
return 0.0;
302
}
303
case RS::GLOBAL_VAR_TYPE_VEC2: {
304
return Vector2();
305
}
306
case RS::GLOBAL_VAR_TYPE_VEC3: {
307
return Vector3();
308
}
309
case RS::GLOBAL_VAR_TYPE_VEC4: {
310
return Vector4();
311
}
312
case RS::GLOBAL_VAR_TYPE_RECT2: {
313
return Rect2();
314
}
315
case RS::GLOBAL_VAR_TYPE_COLOR: {
316
return Color();
317
}
318
case RS::GLOBAL_VAR_TYPE_MAT2: {
319
Vector<float> xform;
320
xform.resize(4);
321
xform.write[0] = 1;
322
xform.write[1] = 0;
323
xform.write[2] = 0;
324
xform.write[3] = 1;
325
return xform;
326
}
327
case RS::GLOBAL_VAR_TYPE_MAT3: {
328
return Basis();
329
}
330
case RS::GLOBAL_VAR_TYPE_TRANSFORM_2D: {
331
return Transform2D();
332
}
333
case RS::GLOBAL_VAR_TYPE_TRANSFORM: {
334
return Transform3D();
335
}
336
case RS::GLOBAL_VAR_TYPE_MAT4: {
337
return Projection();
338
}
339
case RS::GLOBAL_VAR_TYPE_SAMPLER2D: {
340
return "";
341
}
342
case RS::GLOBAL_VAR_TYPE_SAMPLER2DARRAY: {
343
return "";
344
}
345
case RS::GLOBAL_VAR_TYPE_SAMPLER3D: {
346
return "";
347
}
348
case RS::GLOBAL_VAR_TYPE_SAMPLERCUBE: {
349
return "";
350
}
351
case RS::GLOBAL_VAR_TYPE_SAMPLEREXT: {
352
return "";
353
}
354
default: {
355
return Variant();
356
}
357
}
358
}
359
360
String ShaderGlobalsEditor::_check_new_variable_name(const String &p_variable_name) {
361
if (p_variable_name.is_empty()) {
362
return TTRC("Name cannot be empty.");
363
}
364
365
if (!p_variable_name.is_valid_ascii_identifier()) {
366
return TTRC("Name must be a valid identifier.");
367
}
368
369
return "";
370
}
371
372
LineEdit *ShaderGlobalsEditor::get_name_box() const {
373
return variable_name;
374
}
375
376
void ShaderGlobalsEditor::_variable_name_text_changed(const String &p_variable_name) {
377
const String &warning = _check_new_variable_name(p_variable_name.strip_edges());
378
variable_add->set_tooltip_text(warning);
379
variable_add->set_disabled(!warning.is_empty());
380
}
381
382
void ShaderGlobalsEditor::_variable_added() {
383
String var = variable_name->get_text().strip_edges();
384
385
if (RenderingServer::get_singleton()->global_shader_parameter_get(var).get_type() != Variant::NIL) {
386
EditorNode::get_singleton()->show_warning(vformat(TTR("Global shader parameter '%s' already exists."), var));
387
return;
388
}
389
390
List<String> keywords;
391
ShaderLanguage::get_keyword_list(&keywords);
392
393
if (keywords.find(var) != nullptr || var == "script") {
394
EditorNode::get_singleton()->show_warning(vformat(TTR("Name '%s' is a reserved shader language keyword."), var));
395
return;
396
}
397
398
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
399
400
Variant value = create_var(RS::GlobalShaderParameterType(variable_type->get_selected()));
401
402
undo_redo->create_action(TTR("Add Shader Global Parameter"));
403
undo_redo->add_do_method(RS::get_singleton(), "global_shader_parameter_add", var, RS::GlobalShaderParameterType(variable_type->get_selected()), value);
404
undo_redo->add_undo_method(RS::get_singleton(), "global_shader_parameter_remove", var);
405
Dictionary gv;
406
gv["type"] = global_var_type_names[variable_type->get_selected()];
407
gv["value"] = value;
408
409
undo_redo->add_do_property(ProjectSettings::get_singleton(), "shader_globals/" + var, gv);
410
undo_redo->add_undo_property(ProjectSettings::get_singleton(), "shader_globals/" + var, Variant());
411
undo_redo->add_do_method(this, "_changed");
412
undo_redo->add_undo_method(this, "_changed");
413
undo_redo->commit_action();
414
415
variable_name->clear();
416
}
417
418
void ShaderGlobalsEditor::_variable_deleted(const String &p_variable) {
419
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
420
421
undo_redo->create_action(TTR("Add Shader Global Parameter"));
422
undo_redo->add_do_method(RS::get_singleton(), "global_shader_parameter_remove", p_variable);
423
undo_redo->add_undo_method(RS::get_singleton(), "global_shader_parameter_add", p_variable, RS::get_singleton()->global_shader_parameter_get_type(p_variable), RS::get_singleton()->global_shader_parameter_get(p_variable));
424
425
undo_redo->add_do_property(ProjectSettings::get_singleton(), "shader_globals/" + p_variable, Variant());
426
undo_redo->add_undo_property(ProjectSettings::get_singleton(), "shader_globals/" + p_variable, GLOBAL_GET("shader_globals/" + p_variable));
427
undo_redo->add_do_method(this, "_changed");
428
undo_redo->add_undo_method(this, "_changed");
429
undo_redo->commit_action();
430
}
431
432
void ShaderGlobalsEditor::_changed() {
433
emit_signal(SNAME("globals_changed"));
434
if (!interface->block_update) {
435
interface->notify_property_list_changed();
436
}
437
}
438
439
void ShaderGlobalsEditor::_bind_methods() {
440
ClassDB::bind_method("_changed", &ShaderGlobalsEditor::_changed);
441
ADD_SIGNAL(MethodInfo("globals_changed"));
442
}
443
444
void ShaderGlobalsEditor::_notification(int p_what) {
445
switch (p_what) {
446
case NOTIFICATION_VISIBILITY_CHANGED: {
447
if (is_visible_in_tree()) {
448
inspector->edit(interface);
449
}
450
} break;
451
452
case NOTIFICATION_THEME_CHANGED: {
453
variable_add->set_button_icon(get_editor_theme_icon(SNAME("Add")));
454
} break;
455
456
case NOTIFICATION_PREDELETE: {
457
inspector->edit(nullptr);
458
} break;
459
}
460
}
461
462
ShaderGlobalsEditor::ShaderGlobalsEditor() {
463
ProjectSettings::get_singleton()->add_hidden_prefix("shader_globals/");
464
465
HBoxContainer *add_menu_hb = memnew(HBoxContainer);
466
add_child(add_menu_hb);
467
468
add_menu_hb->add_child(memnew(Label(TTRC("Name:"))));
469
variable_name = memnew(LineEdit);
470
variable_name->set_h_size_flags(SIZE_EXPAND_FILL);
471
variable_name->set_clear_button_enabled(true);
472
variable_name->connect(SceneStringName(text_changed), callable_mp(this, &ShaderGlobalsEditor::_variable_name_text_changed));
473
variable_name->connect(SceneStringName(text_submitted), callable_mp(this, &ShaderGlobalsEditor::_variable_added).unbind(1));
474
475
add_menu_hb->add_child(variable_name);
476
477
add_menu_hb->add_child(memnew(Label(TTRC("Type:"))));
478
variable_type = memnew(OptionButton);
479
variable_type->set_h_size_flags(SIZE_EXPAND_FILL);
480
add_menu_hb->add_child(variable_type);
481
482
for (int i = 0; i < RS::GLOBAL_VAR_TYPE_MAX; i++) {
483
variable_type->add_item(global_var_type_names[i]);
484
}
485
486
variable_add = memnew(Button(TTRC("Add")));
487
variable_add->set_disabled(true);
488
add_menu_hb->add_child(variable_add);
489
variable_add->connect(SceneStringName(pressed), callable_mp(this, &ShaderGlobalsEditor::_variable_added));
490
491
MarginContainer *mc = memnew(MarginContainer);
492
mc->set_theme_type_variation("NoBorderHorizontalBottomWide");
493
mc->set_v_size_flags(SIZE_EXPAND_FILL);
494
add_child(mc);
495
496
inspector = memnew(EditorInspector);
497
inspector->set_use_wide_editors(true);
498
inspector->set_property_name_style(EditorPropertyNameProcessor::STYLE_RAW);
499
inspector->set_use_deletable_properties(true);
500
inspector->set_scroll_hint_mode(ScrollContainer::SCROLL_HINT_MODE_TOP_AND_LEFT);
501
mc->add_child(inspector);
502
inspector->connect("property_deleted", callable_mp(this, &ShaderGlobalsEditor::_variable_deleted), CONNECT_DEFERRED);
503
504
interface = memnew(ShaderGlobalsEditorInterface);
505
interface->connect("var_changed", callable_mp(this, &ShaderGlobalsEditor::_changed));
506
}
507
508
ShaderGlobalsEditor::~ShaderGlobalsEditor() {
509
memdelete(interface);
510
}
511
512