1 /*************************************************************************/
2 /* particles_2d_editor_plugin.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2019 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 "particles_2d_editor_plugin.h"
32 #include "canvas_item_editor_plugin.h"
33 #include "io/image_loader.h"
34 #include "scene/gui/separator.h"
35
edit(Object * p_object)36 void Particles2DEditorPlugin::edit(Object *p_object) {
37
38 if (p_object) {
39 particles = p_object->cast_to<Particles2D>();
40 } else {
41 particles = NULL;
42 }
43 }
44
handles(Object * p_object) const45 bool Particles2DEditorPlugin::handles(Object *p_object) const {
46
47 return p_object->is_type("Particles2D");
48 }
49
make_visible(bool p_visible)50 void Particles2DEditorPlugin::make_visible(bool p_visible) {
51
52 if (p_visible) {
53
54 toolbar->show();
55 } else {
56
57 toolbar->hide();
58 }
59 }
60
_file_selected(const String & p_file)61 void Particles2DEditorPlugin::_file_selected(const String &p_file) {
62
63 print_line("file: " + p_file);
64
65 int epc = epoints->get_val();
66
67 Image img;
68 Error err = ImageLoader::load_image(p_file, &img);
69 ERR_EXPLAIN(TTR("Error loading image:") + " " + p_file);
70 ERR_FAIL_COND(err != OK);
71
72 img.convert(Image::FORMAT_GRAYSCALE_ALPHA);
73 ERR_FAIL_COND(img.get_format() != Image::FORMAT_GRAYSCALE_ALPHA);
74 Size2i s = Size2(img.get_width(), img.get_height());
75 ERR_FAIL_COND(s.width == 0 || s.height == 0);
76
77 DVector<uint8_t> data = img.get_data();
78 DVector<uint8_t>::Read r = data.read();
79
80 Vector<Point2i> valid_positions;
81 valid_positions.resize(s.width * s.height);
82 int vpc = 0;
83
84 for (int i = 0; i < s.width * s.height; i++) {
85
86 uint8_t a = r[i * 2 + 1];
87 if (a > 128) {
88 valid_positions[vpc++] = Point2i(i % s.width, i / s.width);
89 }
90 }
91
92 valid_positions.resize(vpc);
93
94 ERR_EXPLAIN(TTR("No pixels with transparency > 128 in image.."));
95 ERR_FAIL_COND(valid_positions.size() == 0);
96
97 DVector<Point2> epoints;
98 epoints.resize(epc);
99 DVector<Point2>::Write w = epoints.write();
100
101 Size2 extents = Size2(img.get_width() * 0.5, img.get_height() * 0.5);
102
103 for (int i = 0; i < epc; i++) {
104
105 Point2 p = valid_positions[Math::rand() % vpc];
106 p -= s / 2;
107 w[i] = p / extents;
108 }
109
110 w = DVector<Point2>::Write();
111
112 undo_redo->create_action(TTR("Set Emission Mask"));
113 undo_redo->add_do_method(particles, "set_emission_points", epoints);
114 undo_redo->add_do_method(particles, "set_emission_half_extents", extents);
115 undo_redo->add_undo_method(particles, "set_emission_points", particles->get_emission_points());
116 undo_redo->add_undo_method(particles, "set_emission_half_extents", particles->get_emission_half_extents());
117 undo_redo->commit_action();
118 }
119
_menu_callback(int p_idx)120 void Particles2DEditorPlugin::_menu_callback(int p_idx) {
121
122 switch (p_idx) {
123 case MENU_LOAD_EMISSION_MASK: {
124
125 file->popup_centered_ratio();
126
127 } break;
128 case MENU_CLEAR_EMISSION_MASK: {
129
130 undo_redo->create_action(TTR("Clear Emission Mask"));
131 undo_redo->add_do_method(particles, "set_emission_points", DVector<Vector2>());
132 undo_redo->add_undo_method(particles, "set_emission_points", particles->get_emission_points());
133 undo_redo->commit_action();
134 } break;
135 }
136 }
137
_notification(int p_what)138 void Particles2DEditorPlugin::_notification(int p_what) {
139
140 if (p_what == NOTIFICATION_ENTER_TREE) {
141
142 menu->get_popup()->connect("item_pressed", this, "_menu_callback");
143 menu->set_icon(menu->get_popup()->get_icon("Particles2D", "EditorIcons"));
144 file->connect("file_selected", this, "_file_selected");
145 }
146 }
147
_bind_methods()148 void Particles2DEditorPlugin::_bind_methods() {
149
150 ObjectTypeDB::bind_method(_MD("_menu_callback"), &Particles2DEditorPlugin::_menu_callback);
151 ObjectTypeDB::bind_method(_MD("_file_selected"), &Particles2DEditorPlugin::_file_selected);
152 }
153
Particles2DEditorPlugin(EditorNode * p_node)154 Particles2DEditorPlugin::Particles2DEditorPlugin(EditorNode *p_node) {
155
156 particles = NULL;
157 editor = p_node;
158 undo_redo = editor->get_undo_redo();
159
160 toolbar = memnew(HBoxContainer);
161 add_control_to_container(CONTAINER_CANVAS_EDITOR_MENU, toolbar);
162 toolbar->hide();
163
164 toolbar->add_child(memnew(VSeparator));
165
166 menu = memnew(MenuButton);
167 menu->get_popup()->add_item(TTR("Load Emission Mask"), MENU_LOAD_EMISSION_MASK);
168 menu->get_popup()->add_item(TTR("Clear Emission Mask"), MENU_CLEAR_EMISSION_MASK);
169 menu->set_text("Particles");
170 toolbar->add_child(menu);
171
172 file = memnew(EditorFileDialog);
173 List<String> ext;
174 ImageLoader::get_recognized_extensions(&ext);
175 for (List<String>::Element *E = ext.front(); E; E = E->next()) {
176 file->add_filter("*." + E->get() + "; " + E->get().to_upper());
177 }
178 file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
179 toolbar->add_child(file);
180
181 epoints = memnew(SpinBox);
182 epoints->set_min(1);
183 epoints->set_max(8192);
184 epoints->set_step(1);
185 epoints->set_val(512);
186 file->get_vbox()->add_margin_child(TTR("Generated Point Count:"), epoints);
187 }
188
~Particles2DEditorPlugin()189 Particles2DEditorPlugin::~Particles2DEditorPlugin() {
190 }
191