Commit bb8f0155 authored by ShyRed's avatar ShyRed Committed by Hein-Pieter van Braam-Stewart
Browse files

Add converters / generators to Sprite

Adds the following menu options to the Sprite editor: "Convert to Mesh2D", "Convert to Polygon2D", "Create CollisionPolygon2D Sibling" and "Create LightOccluder2D Sibling"

(cherry picked from commit c218c631)
parent 94f6c3a8
Loading
Loading
Loading
Loading
+254 −33
Original line number Diff line number Diff line
@@ -31,7 +31,10 @@
#include "sprite_editor_plugin.h"

#include "canvas_item_editor_plugin.h"
#include "scene/2d/collision_polygon_2d.h"
#include "scene/2d/light_occluder_2d.h"
#include "scene/2d/mesh_instance_2d.h"
#include "scene/2d/polygon_2d.h"
#include "scene/gui/box_container.h"
#include "thirdparty/misc/clipper.hpp"

@@ -116,8 +119,42 @@ void SpriteEditor::_menu_option(int p_option) {
		return;
	}

	selected_menu_item = (Menu)p_option;

	switch (p_option) {
		case MENU_OPTION_CREATE_MESH_2D: {
		case MENU_OPTION_CONVERT_TO_MESH_2D: {

			debug_uv_dialog->get_ok()->set_text(TTR("Create Mesh2D"));
			debug_uv_dialog->set_title("Mesh2D Preview");

			_update_mesh_data();
			debug_uv_dialog->popup_centered();
			debug_uv->update();

		} break;
		case MENU_OPTION_CONVERT_TO_POLYGON_2D: {

			debug_uv_dialog->get_ok()->set_text(TTR("Create Polygon2D"));
			debug_uv_dialog->set_title("Polygon2D Preview");

			_update_mesh_data();
			debug_uv_dialog->popup_centered();
			debug_uv->update();
		} break;
		case MENU_OPTION_CREATE_COLLISION_POLY_2D: {

			debug_uv_dialog->get_ok()->set_text(TTR("Create CollisionPolygon2D"));
			debug_uv_dialog->set_title("CollisionPolygon2D Preview");

			_update_mesh_data();
			debug_uv_dialog->popup_centered();
			debug_uv->update();

		} break;
		case MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D: {

			debug_uv_dialog->get_ok()->set_text(TTR("Create LightOccluder2D"));
			debug_uv_dialog->set_title("LightOccluder2D Preview");

			_update_mesh_data();
			debug_uv_dialog->popup_centered();
@@ -169,9 +206,13 @@ void SpriteEditor::_update_mesh_data() {
	computed_indices.clear();

	Size2 img_size = Vector2(image->get_width(), image->get_height());
	for (int j = 0; j < lines.size(); j++) {
		lines.write[j] = expand(lines[j], rect, epsilon);
	for (int i = 0; i < lines.size(); i++) {
		lines.write[i] = expand(lines[i], rect, epsilon);
	}

	if (selected_menu_item == MENU_OPTION_CONVERT_TO_MESH_2D) {

		for (int j = 0; j < lines.size(); j++) {
			int index_ofs = computed_vertices.size();

			for (int i = 0; i < lines[j].size(); i++) {
@@ -205,11 +246,67 @@ void SpriteEditor::_update_mesh_data() {
				}
			}
		}
	}

	outline_lines.clear();
	computed_outline_lines.clear();

	if (selected_menu_item == MENU_OPTION_CONVERT_TO_POLYGON_2D || selected_menu_item == MENU_OPTION_CREATE_COLLISION_POLY_2D || selected_menu_item == MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D) {
		outline_lines.resize(lines.size());
		computed_outline_lines.resize(lines.size());
		for (int pi = 0; pi < lines.size(); pi++) {

			Vector<Vector2> ol;
			Vector<Vector2> col;

			ol.resize(lines[pi].size());
			col.resize(lines[pi].size());

			for (int i = 0; i < lines[pi].size(); i++) {
				Vector2 vtx = lines[pi][i];

				ol.write[i] = vtx;

				vtx -= rect.position; //offset by rect position

				//flip if flipped
				if (node->is_flipped_h())
					vtx.x = rect.size.x - vtx.x - 1.0;
				if (node->is_flipped_v())
					vtx.y = rect.size.y - vtx.y - 1.0;

				if (node->is_centered())
					vtx -= rect.size / 2.0;

				col.write[i] = vtx;
			}

			outline_lines.write[pi] = ol;
			computed_outline_lines.write[pi] = col;
		}
	}

	debug_uv->update();
}

void SpriteEditor::_create_mesh_node() {
void SpriteEditor::_create_node() {
	switch (selected_menu_item) {
		case MENU_OPTION_CONVERT_TO_MESH_2D: {
			_convert_to_mesh_2d_node();
		} break;
		case MENU_OPTION_CONVERT_TO_POLYGON_2D: {
			_convert_to_polygon_2d_node();
		} break;
		case MENU_OPTION_CREATE_COLLISION_POLY_2D: {
			_create_collision_polygon_2d_node();
		} break;
		case MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D: {
			_create_light_occluder_2d_node();
		} break;
	}
}

void SpriteEditor::_convert_to_mesh_2d_node() {

	if (computed_vertices.size() < 3) {
		err_dialog->set_text(TTR("Invalid geometry, can't replace by mesh."));
@@ -233,6 +330,117 @@ void SpriteEditor::_create_mesh_node() {
	EditorNode::get_singleton()->get_scene_tree_dock()->replace_node(node, mesh_instance);
}

void SpriteEditor::_convert_to_polygon_2d_node() {
	Polygon2D *polygon_2d_instance = memnew(Polygon2D);

	int total_point_count = 0;
	for (int i = 0; i < computed_outline_lines.size(); i++)
		total_point_count += computed_outline_lines[i].size();

	PoolVector2Array polygon;
	polygon.resize(total_point_count);
	PoolVector2Array::Write polygon_write = polygon.write();

	PoolVector2Array uvs;
	uvs.resize(total_point_count);
	PoolVector2Array::Write uvs_write = uvs.write();

	int current_point_index = 0;

	Array polys;
	polys.resize(computed_outline_lines.size());

	for (int i = 0; i < computed_outline_lines.size(); i++) {

		Vector<Vector2> outline = computed_outline_lines[i];
		Vector<Vector2> uv_outline = outline_lines[i];

		if (outline.size() < 3) {
			err_dialog->set_text(TTR("Invalid geometry, can't create polygon."));
			err_dialog->popup_centered_minsize();
			return;
		}

		PoolIntArray pia;
		pia.resize(outline.size());
		PoolIntArray::Write pia_write = pia.write();

		for (int pi = 0; pi < outline.size(); pi++) {
			polygon_write[current_point_index] = outline[pi];
			uvs_write[current_point_index] = uv_outline[pi];
			pia_write[pi] = current_point_index;
			current_point_index++;
		}

		polys[i] = pia;
	}

	polygon_2d_instance->set_uv(uvs);
	polygon_2d_instance->set_polygon(polygon);
	polygon_2d_instance->set_polygons(polys);

	EditorNode::get_singleton()->get_scene_tree_dock()->replace_node(node, polygon_2d_instance);
}

void SpriteEditor::_create_collision_polygon_2d_node() {
	for (int i = 0; i < computed_outline_lines.size(); i++) {

		Vector<Vector2> outline = computed_outline_lines[i];

		if (outline.size() < 3) {
			err_dialog->set_text(TTR("Invalid geometry, can't create collision polygon."));
			err_dialog->popup_centered_minsize();
			continue;
		}

		CollisionPolygon2D *collision_polygon_2d_instance = memnew(CollisionPolygon2D);
		collision_polygon_2d_instance->set_polygon(outline);

		_add_as_sibling_or_child(node, collision_polygon_2d_instance);
	}
}

void SpriteEditor::_create_light_occluder_2d_node() {
	for (int i = 0; i < computed_outline_lines.size(); i++) {

		Vector<Vector2> outline = computed_outline_lines[i];

		if (outline.size() < 3) {
			err_dialog->set_text(TTR("Invalid geometry, can't create light occluder."));
			err_dialog->popup_centered_minsize();
			continue;
		}

		Ref<OccluderPolygon2D> polygon;
		polygon.instance();

		PoolVector2Array a;
		a.resize(outline.size());
		PoolVector2Array::Write aw = a.write();
		for (int io = 0; io < outline.size(); io++) {
			aw[io] = outline[io];
		}
		polygon->set_polygon(a);

		LightOccluder2D *light_occluder_2d_instance = memnew(LightOccluder2D);
		light_occluder_2d_instance->set_occluder_polygon(polygon);

		_add_as_sibling_or_child(node, light_occluder_2d_instance);
	}
}

void SpriteEditor::_add_as_sibling_or_child(Node2D *p_own_node, Node2D *p_new_node) {
	// Can't make sibling if own node is scene root
	if (p_own_node != this->get_tree()->get_edited_scene_root()) {
		p_own_node->get_parent()->add_child(p_new_node, true);
		p_new_node->set_transform(p_own_node->get_transform());
	} else {
		p_own_node->add_child(p_new_node, true);
	}

	p_new_node->set_owner(this->get_tree()->get_edited_scene_root());
}

#if 0
void SpriteEditor::_create_uv_lines() {

@@ -298,16 +506,26 @@ void SpriteEditor::_create_uv_lines() {
#endif
void SpriteEditor::_debug_uv_draw() {

	if (uv_lines.size() == 0)
		return;

	Ref<Texture> tex = node->get_texture();
	ERR_FAIL_COND(!tex.is_valid());
	debug_uv->set_clip_contents(true);
	debug_uv->draw_texture(tex, Point2());
	debug_uv->set_custom_minimum_size(tex->get_size());
	//debug_uv->draw_set_transform(Vector2(), 0, debug_uv->get_size());
	debug_uv->draw_multiline(uv_lines, Color(1.0, 0.8, 0.7));

	Color color = Color(1.0, 0.8, 0.7);

	if (selected_menu_item == MENU_OPTION_CONVERT_TO_MESH_2D && uv_lines.size() > 0) {
		debug_uv->draw_multiline(uv_lines, color);

	} else if ((selected_menu_item == MENU_OPTION_CONVERT_TO_POLYGON_2D || selected_menu_item == MENU_OPTION_CREATE_COLLISION_POLY_2D || selected_menu_item == MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D) && outline_lines.size() > 0) {
		for (int i = 0; i < outline_lines.size(); i++) {
			Vector<Vector2> outline = outline_lines[i];

			debug_uv->draw_polyline(outline, color);
			debug_uv->draw_line(outline[0], outline[outline.size() - 1], color);
		}
	}
}

void SpriteEditor::_bind_methods() {
@@ -315,7 +533,7 @@ void SpriteEditor::_bind_methods() {
	ClassDB::bind_method("_menu_option", &SpriteEditor::_menu_option);
	ClassDB::bind_method("_debug_uv_draw", &SpriteEditor::_debug_uv_draw);
	ClassDB::bind_method("_update_mesh_data", &SpriteEditor::_update_mesh_data);
	ClassDB::bind_method("_create_mesh_node", &SpriteEditor::_create_mesh_node);
	ClassDB::bind_method("_create_node", &SpriteEditor::_create_node);
}

SpriteEditor::SpriteEditor() {
@@ -327,7 +545,10 @@ SpriteEditor::SpriteEditor() {
	options->set_text(TTR("Sprite"));
	options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Sprite", "EditorIcons"));

	options->get_popup()->add_item(TTR("Convert to 2D Mesh"), MENU_OPTION_CREATE_MESH_2D);
	options->get_popup()->add_item(TTR("Convert to Mesh2D"), MENU_OPTION_CONVERT_TO_MESH_2D);
	options->get_popup()->add_item(TTR("Convert to Polygon2D"), MENU_OPTION_CONVERT_TO_POLYGON_2D);
	options->get_popup()->add_item(TTR("Create CollisionPolygon2D Sibling"), MENU_OPTION_CREATE_COLLISION_POLY_2D);
	options->get_popup()->add_item(TTR("Create LightOccluder2D Sibling"), MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D);

	options->get_popup()->connect("id_pressed", this, "_menu_option");

@@ -335,7 +556,7 @@ SpriteEditor::SpriteEditor() {
	add_child(err_dialog);

	debug_uv_dialog = memnew(ConfirmationDialog);
	debug_uv_dialog->get_ok()->set_text(TTR("Create 2D Mesh"));
	debug_uv_dialog->get_ok()->set_text(TTR("Create Mesh2D"));
	debug_uv_dialog->set_title("Mesh 2D Preview");
	VBoxContainer *vb = memnew(VBoxContainer);
	debug_uv_dialog->add_child(vb);
@@ -347,7 +568,7 @@ SpriteEditor::SpriteEditor() {
	debug_uv = memnew(Control);
	debug_uv->connect("draw", this, "_debug_uv_draw");
	scroll->add_child(debug_uv);
	debug_uv_dialog->connect("confirmed", this, "_create_mesh_node");
	debug_uv_dialog->connect("confirmed", this, "_create_node");

	HBoxContainer *hb = memnew(HBoxContainer);
	hb->add_child(memnew(Label(TTR("Simplification: "))));
+16 −3
Original line number Diff line number Diff line
@@ -41,9 +41,14 @@ class SpriteEditor : public Control {
	GDCLASS(SpriteEditor, Control);

	enum Menu {
		MENU_OPTION_CREATE_MESH_2D,
		MENU_OPTION_CONVERT_TO_MESH_2D,
		MENU_OPTION_CONVERT_TO_POLYGON_2D,
		MENU_OPTION_CREATE_COLLISION_POLY_2D,
		MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D
	};

	Menu selected_menu_item;

	Sprite *node;

	MenuButton *options;
@@ -55,7 +60,8 @@ class SpriteEditor : public Control {
	ConfirmationDialog *debug_uv_dialog;
	Control *debug_uv;
	Vector<Vector2> uv_lines;

	Vector<Vector<Vector2> > outline_lines;
	Vector<Vector<Vector2> > computed_outline_lines;
	Vector<Vector2> computed_vertices;
	Vector<Vector2> computed_uv;
	Vector<int> computed_indices;
@@ -71,7 +77,14 @@ class SpriteEditor : public Control {

	void _debug_uv_draw();
	void _update_mesh_data();
	void _create_mesh_node();

	void _create_node();
	void _convert_to_mesh_2d_node();
	void _convert_to_polygon_2d_node();
	void _create_collision_polygon_2d_node();
	void _create_light_occluder_2d_node();

	void _add_as_sibling_or_child(Node2D *p_own_node, Node2D *p_new_node);

protected:
	void _node_removed(Node *p_node);