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