-Ability to and unwrap lightmap coordinates on import

-Added unwrap functionality to Mesh
-Ability to display and debug mesh UVs
-Added multiline draw, so it's easier and faster to draw UVs
-Many fixes to SurfaceTool
-Fixes to Thekla Unwrap, but it's a piece of ass and it keeps crashing. Will have to go away
This commit is contained in:
Juan Linietsky 2017-12-09 14:11:26 -03:00
parent ccef401700
commit 65fb961b8b
22 changed files with 846 additions and 78 deletions

View file

@ -527,7 +527,9 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur
_draw_generic(GL_TRIANGLE_STRIP, pline->triangles.size(), pline->triangles.ptr(), NULL, pline->triangle_colors.ptr(), pline->triangle_colors.size() == 1);
#ifdef GLES_OVER_GL
glEnable(GL_LINE_SMOOTH);
if (pline->lines.size()) {
if (pline->multiline) {
//needs to be different
} else {
_draw_generic(GL_LINE_LOOP, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1);
}
glDisable(GL_LINE_SMOOTH);
@ -538,7 +540,23 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur
if (pline->antialiased)
glEnable(GL_LINE_SMOOTH);
#endif
_draw_generic(GL_LINE_STRIP, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1);
if (pline->multiline) {
int todo = pline->lines.size() / 2;
int max_per_call = data.polygon_buffer_size / (sizeof(real_t) * 4);
int offset = 0;
while (todo) {
int to_draw = MIN(max_per_call, todo);
_draw_generic(GL_LINES, to_draw * 2, &pline->lines.ptr()[offset], NULL, pline->line_colors.size() == 1 ? pline->line_colors.ptr() : &pline->line_colors.ptr()[offset], pline->line_colors.size() == 1);
todo -= to_draw;
offset += to_draw * 2;
}
} else {
_draw_generic(GL_LINES, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1);
}
#ifdef GLES_OVER_GL
if (pline->antialiased)
@ -1705,6 +1723,7 @@ void RasterizerCanvasGLES3::initialize() {
glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer);
glBufferData(GL_ARRAY_BUFFER, poly_size, NULL, GL_DYNAMIC_DRAW); //allocate max size
glBindBuffer(GL_ARRAY_BUFFER, 0);
data.polygon_buffer_size = poly_size;
//quad arrays
for (int i = 0; i < 4; i++) {

View file

@ -47,8 +47,6 @@
#include "scene/resources/ray_shape.h"
#include "scene/resources/sphere_shape.h"
uint32_t EditorSceneImporter::get_import_flags() const {
if (get_script_instance()) {
@ -60,80 +58,73 @@ uint32_t EditorSceneImporter::get_import_flags() const {
void EditorSceneImporter::get_extensions(List<String> *r_extensions) const {
if (get_script_instance()) {
Array arr= get_script_instance()->call("_get_extensions");
for(int i=0;i<arr.size();i++) {
Array arr = get_script_instance()->call("_get_extensions");
for (int i = 0; i < arr.size(); i++) {
r_extensions->push_back(arr[i]);
}
return;
}
ERR_FAIL();
}
Node *EditorSceneImporter::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) {
if (get_script_instance()) {
return get_script_instance()->call("_import_scene",p_path,p_flags,p_bake_fps);
return get_script_instance()->call("_import_scene", p_path, p_flags, p_bake_fps);
}
ERR_FAIL_V(NULL);
}
Ref<Animation> EditorSceneImporter::import_animation(const String &p_path, uint32_t p_flags,int p_bake_fps) {
Ref<Animation> EditorSceneImporter::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) {
if (get_script_instance()) {
return get_script_instance()->call("_import_animation",p_path,p_flags);
return get_script_instance()->call("_import_animation", p_path, p_flags);
}
ERR_FAIL_V(NULL);
}
//for documenters, these functions are useful when an importer calls an external conversion helper (like, fbx2gltf),
//and you want to load the resulting file
Node* EditorSceneImporter::import_scene_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps) {
return ResourceImporterScene::get_singleton()->import_scene_from_other_importer(this,p_path,p_flags,p_bake_fps);
Node *EditorSceneImporter::import_scene_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps) {
return ResourceImporterScene::get_singleton()->import_scene_from_other_importer(this, p_path, p_flags, p_bake_fps);
}
Ref<Animation> EditorSceneImporter::import_animation_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps) {
return ResourceImporterScene::get_singleton()->import_animation_from_other_importer(this,p_path,p_flags,p_bake_fps);
return ResourceImporterScene::get_singleton()->import_animation_from_other_importer(this, p_path, p_flags, p_bake_fps);
}
void EditorSceneImporter::_bind_methods() {
ClassDB::bind_method(D_METHOD("import_scene_from_other_importer","path","flags","bake_fps"),&EditorSceneImporter::import_scene_from_other_importer);
ClassDB::bind_method(D_METHOD("import_animation_from_other_importer","path","flags","bake_fps"),&EditorSceneImporter::import_animation_from_other_importer);
ClassDB::bind_method(D_METHOD("import_scene_from_other_importer", "path", "flags", "bake_fps"), &EditorSceneImporter::import_scene_from_other_importer);
ClassDB::bind_method(D_METHOD("import_animation_from_other_importer", "path", "flags", "bake_fps"), &EditorSceneImporter::import_animation_from_other_importer);
BIND_VMETHOD(MethodInfo(Variant::INT, "_get_import_flags"));
BIND_VMETHOD(MethodInfo(Variant::ARRAY, "_get_extensions"));
MethodInfo mi = MethodInfo(Variant::OBJECT, "_import_scene",PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "flags"), PropertyInfo(Variant::INT, "bake_fps"));
mi.return_val.class_name="Node";
MethodInfo mi = MethodInfo(Variant::OBJECT, "_import_scene", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "flags"), PropertyInfo(Variant::INT, "bake_fps"));
mi.return_val.class_name = "Node";
BIND_VMETHOD(mi);
mi = MethodInfo(Variant::OBJECT, "_import_animation",PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "flags"), PropertyInfo(Variant::INT, "bake_fps"));
mi.return_val.class_name="Animation";
mi = MethodInfo(Variant::OBJECT, "_import_animation", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "flags"), PropertyInfo(Variant::INT, "bake_fps"));
mi.return_val.class_name = "Animation";
BIND_VMETHOD(mi);
BIND_CONSTANT( IMPORT_SCENE );
BIND_CONSTANT( IMPORT_ANIMATION );
BIND_CONSTANT( IMPORT_ANIMATION_DETECT_LOOP );
BIND_CONSTANT( IMPORT_ANIMATION_OPTIMIZE );
BIND_CONSTANT( IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS );
BIND_CONSTANT( IMPORT_ANIMATION_KEEP_VALUE_TRACKS );
BIND_CONSTANT( IMPORT_GENERATE_TANGENT_ARRAYS );
BIND_CONSTANT( IMPORT_FAIL_ON_MISSING_DEPENDENCIES );
BIND_CONSTANT( IMPORT_MATERIALS_IN_INSTANCES );
BIND_CONSTANT( IMPORT_USE_COMPRESSION );
BIND_CONSTANT(IMPORT_SCENE);
BIND_CONSTANT(IMPORT_ANIMATION);
BIND_CONSTANT(IMPORT_ANIMATION_DETECT_LOOP);
BIND_CONSTANT(IMPORT_ANIMATION_OPTIMIZE);
BIND_CONSTANT(IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS);
BIND_CONSTANT(IMPORT_ANIMATION_KEEP_VALUE_TRACKS);
BIND_CONSTANT(IMPORT_GENERATE_TANGENT_ARRAYS);
BIND_CONSTANT(IMPORT_FAIL_ON_MISSING_DEPENDENCIES);
BIND_CONSTANT(IMPORT_MATERIALS_IN_INSTANCES);
BIND_CONSTANT(IMPORT_USE_COMPRESSION);
}
/////////////////////////////////
void EditorScenePostImport::_bind_methods() {
@ -201,6 +192,10 @@ bool ResourceImporterScene::get_option_visibility(const String &p_option, const
return false;
}
if (p_option == "meshes/lightmap_texel_size" && int(p_options["meshes/light_baking"]) < 2) {
return false;
}
return true;
}
@ -961,6 +956,36 @@ static String _make_extname(const String &p_str) {
return ext_name;
}
void ResourceImporterScene::_find_meshes(Node *p_node, Map<Ref<ArrayMesh>, Transform> &meshes) {
List<PropertyInfo> pi;
p_node->get_property_list(&pi);
MeshInstance *mi = Object::cast_to<MeshInstance>(p_node);
if (mi) {
Ref<ArrayMesh> mesh = mi->get_mesh();
if (mesh.is_valid() && !meshes.has(mesh)) {
Spatial *s = mi;
while (s->get_parent_spatial()) {
s = s->get_parent_spatial();
}
if (s == mi) {
meshes[mesh] = s->get_transform();
} else {
meshes[mesh] = s->get_transform() * mi->get_relative_transform(s);
}
}
}
for (int i = 0; i < p_node->get_child_count(); i++) {
_find_meshes(p_node->get_child(i), meshes);
}
}
void ResourceImporterScene::_make_external_resources(Node *p_node, const String &p_base_path, bool p_make_animations, bool p_keep_animations, bool p_make_materials, bool p_keep_materials, bool p_make_meshes, Map<Ref<Animation>, Ref<Animation> > &p_animations, Map<Ref<Material>, Ref<Material> > &p_materials, Map<Ref<ArrayMesh>, Ref<ArrayMesh> > &p_meshes) {
List<PropertyInfo> pi;
@ -1140,7 +1165,8 @@ void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, in
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/compress"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/ensure_tangents"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/storage", PROPERTY_HINT_ENUM, "Built-In,Files"), meshes_out ? 1 : 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/light_baking", PROPERTY_HINT_ENUM, "Disabled,Enable"), 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/light_baking", PROPERTY_HINT_ENUM, "Disabled,Enable,Gen Lightmaps"), 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "meshes/lightmap_texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.05));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "external_files/store_in_subdir"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 15));
@ -1171,17 +1197,16 @@ void ResourceImporterScene::_replace_owner(Node *p_node, Node *p_scene, Node *p_
Node *n = p_node->get_child(i);
_replace_owner(n, p_scene, p_new_owner);
}
}
Node* ResourceImporterScene::import_scene_from_other_importer(EditorSceneImporter *p_exception,const String &p_path, uint32_t p_flags, int p_bake_fps) {
Node *ResourceImporterScene::import_scene_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps) {
Ref<EditorSceneImporter> importer;
String ext = p_path.get_extension().to_lower();
for (Set<Ref<EditorSceneImporter> >::Element *E = importers.front(); E; E = E->next()) {
if (E->get().ptr()==p_exception)
if (E->get().ptr() == p_exception)
continue;
List<String> extensions;
E->get()->get_extensions(&extensions);
@ -1199,42 +1224,41 @@ Node* ResourceImporterScene::import_scene_from_other_importer(EditorSceneImporte
break;
}
ERR_FAIL_COND_V(!importer.is_valid(),NULL);
ERR_FAIL_COND_V(!importer.is_valid(), NULL);
List<String> missing;
Error err;
return importer->import_scene(p_path,p_flags,p_bake_fps,&missing,&err);
return importer->import_scene(p_path, p_flags, p_bake_fps, &missing, &err);
}
Ref<Animation> ResourceImporterScene::import_animation_from_other_importer(EditorSceneImporter *p_exception,const String &p_path, uint32_t p_flags, int p_bake_fps) {
Ref<Animation> ResourceImporterScene::import_animation_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps) {
Ref<EditorSceneImporter> importer;
String ext = p_path.get_extension().to_lower();
Ref<EditorSceneImporter> importer;
String ext = p_path.get_extension().to_lower();
for (Set<Ref<EditorSceneImporter> >::Element *E = importers.front(); E; E = E->next()) {
for (Set<Ref<EditorSceneImporter> >::Element *E = importers.front(); E; E = E->next()) {
if (E->get().ptr() == p_exception)
continue;
List<String> extensions;
E->get()->get_extensions(&extensions);
if (E->get().ptr()==p_exception)
continue;
List<String> extensions;
E->get()->get_extensions(&extensions);
for (List<String>::Element *F = extensions.front(); F; F = F->next()) {
for (List<String>::Element *F = extensions.front(); F; F = F->next()) {
if (F->get().to_lower() == ext) {
if (F->get().to_lower() == ext) {
importer = E->get();
break;
}
}
importer = E->get();
break;
}
}
if (importer.is_valid())
break;
}
if (importer.is_valid())
break;
}
ERR_FAIL_COND_V(!importer.is_valid(), NULL);
ERR_FAIL_COND_V(!importer.is_valid(),NULL);
return importer->import_animation(p_path,p_flags,p_bake_fps);
return importer->import_animation(p_path, p_flags, p_bake_fps);
}
Error ResourceImporterScene::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files) {
@ -1371,6 +1395,37 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
}
}
if (light_bake_mode == 2 /* || generate LOD */) {
Map<Ref<ArrayMesh>, Transform> meshes;
_find_meshes(scene, meshes);
if (light_bake_mode == 2) {
float texel_size = p_options["meshes/lightmap_texel_size"];
texel_size = MAX(0.001, texel_size);
EditorProgress progress("gen_lightmaps", TTR("Generating Lightmaps"), meshes.size());
int step = 0;
for (Map<Ref<ArrayMesh>, Transform>::Element *E = meshes.front(); E; E = E->next()) {
Ref<ArrayMesh> mesh = E->key();
String name = mesh->get_name();
if (name == "") { //should not happen but..
name = "Mesh " + itos(step);
}
progress.step(TTR("Generating for Mesh: ") + name + " (" + itos(step) + "/" + itos(meshes.size()) + ")", step);
Error err = mesh->lightmap_unwrap(E->get(), texel_size);
if (err != OK) {
EditorNode::add_io_error("Mesh '" + name + "' failed lightmap generation. Please fix geometry.");
}
step++;
}
}
}
if (external_animations || external_materials || external_meshes) {
Map<Ref<Animation>, Ref<Animation> > anim_map;
Map<Ref<Material>, Ref<Material> > mat_map;

View file

@ -40,13 +40,13 @@ class Material;
class EditorSceneImporter : public Reference {
GDCLASS(EditorSceneImporter, Reference);
protected:
protected:
static void _bind_methods();
Node* import_scene_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps);
Node *import_scene_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps);
Ref<Animation> import_animation_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps);
public:
enum ImportFlags {
IMPORT_SCENE = 1,
@ -62,11 +62,10 @@ public:
};
virtual uint32_t get_import_flags() const;
virtual void get_extensions(List<String> *r_extensions) const;
virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = NULL);
virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags,int p_bake_fps);
virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps);
EditorSceneImporter() {}
};
@ -136,6 +135,8 @@ public:
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
virtual int get_import_order() const { return 100; } //after everything
void _find_meshes(Node *p_node, Map<Ref<ArrayMesh>, Transform> &meshes);
void _make_external_resources(Node *p_node, const String &p_base_path, bool p_make_animations, bool p_keep_animations, bool p_make_materials, bool p_keep_materials, bool p_make_meshes, Map<Ref<Animation>, Ref<Animation> > &p_animations, Map<Ref<Material>, Ref<Material> > &p_materials, Map<Ref<ArrayMesh>, Ref<ArrayMesh> > &p_meshes);
Node *_fix_node(Node *p_node, Node *p_root, Map<Ref<ArrayMesh>, Ref<Shape> > &collision_map, LightBakeMode p_light_bake_mode);
@ -147,8 +148,8 @@ public:
virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL);
Node* import_scene_from_other_importer(EditorSceneImporter *p_exception,const String &p_path, uint32_t p_flags, int p_bake_fps);
Ref<Animation> import_animation_from_other_importer(EditorSceneImporter *p_exception,const String &p_path, uint32_t p_flags, int p_bake_fps);
Node *import_scene_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps);
Ref<Animation> import_animation_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps);
ResourceImporterScene();
};

View file

@ -195,9 +195,141 @@ void MeshInstanceEditor::_menu_option(int p_option) {
outline_dialog->popup_centered(Vector2(200, 90));
} break;
case MENU_OPTION_CREATE_UV2: {
Ref<ArrayMesh> mesh = node->get_mesh();
if (!mesh.is_valid()) {
err_dialog->set_text(TTR("Contained Mesh is not of type ArrayMesh."));
err_dialog->popup_centered_minsize();
return;
}
Error err = mesh->lightmap_unwrap(node->get_global_transform());
if (err != OK) {
err_dialog->set_text(TTR("UV Unwrap failed, mesh may not be manifold?"));
err_dialog->popup_centered_minsize();
return;
}
} break;
case MENU_OPTION_DEBUG_UV1: {
Ref<Mesh> mesh = node->get_mesh();
if (!mesh.is_valid()) {
err_dialog->set_text(TTR("No mesh to debug."));
err_dialog->popup_centered_minsize();
return;
}
_create_uv_lines(0);
} break;
case MENU_OPTION_DEBUG_UV2: {
Ref<Mesh> mesh = node->get_mesh();
if (!mesh.is_valid()) {
err_dialog->set_text(TTR("No mesh to debug."));
err_dialog->popup_centered_minsize();
return;
}
_create_uv_lines(1);
} break;
}
}
struct MeshInstanceEditorEdgeSort {
Vector2 a;
Vector2 b;
bool operator<(const MeshInstanceEditorEdgeSort &p_b) const {
if (a == p_b.a)
return b < p_b.b;
else
return a < p_b.a;
}
MeshInstanceEditorEdgeSort() {}
MeshInstanceEditorEdgeSort(const Vector2 &p_a, const Vector2 &p_b) {
if (p_a < p_b) {
a = p_a;
b = p_b;
} else {
b = p_a;
a = p_b;
}
}
};
void MeshInstanceEditor::_create_uv_lines(int p_layer) {
Ref<Mesh> mesh = node->get_mesh();
ERR_FAIL_COND(!mesh.is_valid());
Set<MeshInstanceEditorEdgeSort> edges;
uv_lines.clear();
for (int i = 0; i < mesh->get_surface_count(); i++) {
if (mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES)
continue;
Array a = mesh->surface_get_arrays(i);
PoolVector<Vector2> uv = a[p_layer == 0 ? Mesh::ARRAY_TEX_UV : Mesh::ARRAY_TEX_UV2];
if (uv.size() == 0) {
err_dialog->set_text(TTR("Model has no UV in this layer"));
err_dialog->popup_centered_minsize();
return;
}
PoolVector<Vector2>::Read r = uv.read();
PoolVector<int> indices = a[Mesh::ARRAY_INDEX];
PoolVector<int>::Read ri;
int ic;
bool use_indices;
if (indices.size()) {
ic = indices.size();
ri = indices.read();
use_indices = true;
} else {
ic = uv.size();
use_indices = false;
}
for (int j = 0; j < ic; j += 3) {
for (int k = 0; k < 3; k++) {
MeshInstanceEditorEdgeSort edge;
if (use_indices) {
edge.a = r[ri[j + k]];
edge.b = r[ri[j + ((k + 1) % 3)]];
} else {
edge.a = r[j + k];
edge.b = r[j + ((k + 1) % 3)];
}
if (edges.has(edge))
continue;
uv_lines.push_back(edge.a);
uv_lines.push_back(edge.b);
edges.insert(edge);
}
}
}
debug_uv_dialog->popup_centered_minsize();
}
void MeshInstanceEditor::_debug_uv_draw() {
if (uv_lines.size() == 0)
return;
debug_uv->set_clip_contents(true);
debug_uv->draw_rect(Rect2(Vector2(), debug_uv->get_size()), Color(0.2, 0.2, 0.0));
debug_uv->draw_set_transform(Vector2(), 0, debug_uv->get_size());
debug_uv->draw_multiline(uv_lines, Color(1.0, 0.8, 0.7));
}
void MeshInstanceEditor::_create_outline_mesh() {
Ref<Mesh> mesh = node->get_mesh();
@ -244,6 +376,7 @@ void MeshInstanceEditor::_bind_methods() {
ClassDB::bind_method("_menu_option", &MeshInstanceEditor::_menu_option);
ClassDB::bind_method("_create_outline_mesh", &MeshInstanceEditor::_create_outline_mesh);
ClassDB::bind_method("_debug_uv_draw", &MeshInstanceEditor::_debug_uv_draw);
}
MeshInstanceEditor::MeshInstanceEditor() {
@ -263,6 +396,10 @@ MeshInstanceEditor::MeshInstanceEditor() {
options->get_popup()->add_item(TTR("Create Navigation Mesh"), MENU_OPTION_CREATE_NAVMESH);
options->get_popup()->add_separator();
options->get_popup()->add_item(TTR("Create Outline Mesh.."), MENU_OPTION_CREATE_OUTLINE_MESH);
options->get_popup()->add_separator();
options->get_popup()->add_item(TTR("View UV1"), MENU_OPTION_DEBUG_UV1);
options->get_popup()->add_item(TTR("View UV2"), MENU_OPTION_DEBUG_UV2);
options->get_popup()->add_item(TTR("Unwrap UV2 for Lightmap/AO"), MENU_OPTION_CREATE_UV2);
options->get_popup()->connect("id_pressed", this, "_menu_option");
@ -286,6 +423,14 @@ MeshInstanceEditor::MeshInstanceEditor() {
err_dialog = memnew(AcceptDialog);
add_child(err_dialog);
debug_uv_dialog = memnew(AcceptDialog);
debug_uv_dialog->set_title("UV Channel Debug");
add_child(debug_uv_dialog);
debug_uv = memnew(Control);
debug_uv->set_custom_minimum_size(Size2(600, 600) * EDSCALE);
debug_uv->connect("draw", this, "_debug_uv_draw");
debug_uv_dialog->add_child(debug_uv);
}
void MeshInstanceEditorPlugin::edit(Object *p_object) {

View file

@ -47,6 +47,9 @@ class MeshInstanceEditor : public Node {
MENU_OPTION_CREATE_CONVEX_COLLISION_SHAPE,
MENU_OPTION_CREATE_NAVMESH,
MENU_OPTION_CREATE_OUTLINE_MESH,
MENU_OPTION_CREATE_UV2,
MENU_OPTION_DEBUG_UV1,
MENU_OPTION_DEBUG_UV2,
};
MeshInstance *node;
@ -58,11 +61,18 @@ class MeshInstanceEditor : public Node {
AcceptDialog *err_dialog;
AcceptDialog *debug_uv_dialog;
Control *debug_uv;
Vector<Vector2> uv_lines;
void _menu_option(int p_option);
void _create_outline_mesh();
void _create_uv_lines(int p_layer);
friend class MeshInstanceEditorPlugin;
void _debug_uv_draw();
protected:
void _node_removed(Node *p_node);
static void _bind_methods();

View file

@ -47,7 +47,8 @@ if env['builtin_thekla_atlas']:
"nvmesh/param/SingleFaceMap.cpp",
"nvmesh/param/Util.cpp",
"nvmesh/weld/VertexWeld.cpp",
"nvmesh/weld/Snap.cpp"
"nvmesh/weld/Snap.cpp",
"thekla/thekla_atlas.cpp"
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]

View file

@ -28,7 +28,88 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "register_types.h"
#include "thirdparty/thekla_atlas/thekla/thekla_atlas.h"
#include <stdio.h>
#include <stdlib.h>
extern bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, const int *p_face_materials, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y);
void register_thekla_unwrap_types() {}
bool thekla_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, const int *p_face_materials, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y) {
void unregister_thekla_unwrap_types() {}
//set up input mesh
Thekla::Atlas_Input_Mesh input_mesh;
input_mesh.face_array = new Thekla::Atlas_Input_Face[p_index_count / 3];
for (int i = 0; i < p_index_count / 3; i++) {
input_mesh.face_array[i].vertex_index[0] = p_indices[i * 3 + 0];
input_mesh.face_array[i].vertex_index[1] = p_indices[i * 3 + 1];
input_mesh.face_array[i].vertex_index[2] = p_indices[i * 3 + 2];
printf("face %i - %i, %i, %i - mat %i\n", i, input_mesh.face_array[i].vertex_index[0], input_mesh.face_array[i].vertex_index[1], input_mesh.face_array[i].vertex_index[2], p_face_materials[i]);
input_mesh.face_array[i].material_index = p_face_materials[i];
}
input_mesh.vertex_array = new Thekla::Atlas_Input_Vertex[p_vertex_count];
for (int i = 0; i < p_vertex_count; i++) {
input_mesh.vertex_array[i].first_colocal = i; //wtf
for (int j = 0; j < 3; j++) {
input_mesh.vertex_array[i].position[j] = p_vertices[i * 3 + j];
input_mesh.vertex_array[i].normal[j] = p_normals[i * 3 + j];
}
input_mesh.vertex_array[i].uv[0] = 0;
input_mesh.vertex_array[i].uv[1] = 0;
printf("vertex %i - %f, %f, %f\n", i, input_mesh.vertex_array[i].position[0], input_mesh.vertex_array[i].position[1], input_mesh.vertex_array[i].position[2]);
printf("normal %i - %f, %f, %f\n", i, input_mesh.vertex_array[i].normal[0], input_mesh.vertex_array[i].normal[1], input_mesh.vertex_array[i].normal[2]);
}
input_mesh.face_count = p_index_count / 3;
input_mesh.vertex_count = p_vertex_count;
//set up options
Thekla::Atlas_Options options;
Thekla::atlas_set_default_options(&options);
options.packer_options.witness.packing_quality = 1;
options.packer_options.witness.texel_area = 1.0 / p_texel_size;
//generate
Thekla::Atlas_Error err;
Thekla::Atlas_Output_Mesh *output = atlas_generate(&input_mesh, &options, &err);
delete[] input_mesh.face_array;
delete[] input_mesh.vertex_array;
if (err != Thekla::Atlas_Error_Success) {
printf("error with atlas\n");
} else {
*r_vertex = (int *)malloc(sizeof(int) * output->vertex_count);
*r_uv = (float *)malloc(sizeof(float) * output->vertex_count * 3);
*r_index = (int *)malloc(sizeof(int) * output->index_count);
// printf("w: %i, h: %i\n", output->atlas_width, output->atlas_height);
for (int i = 0; i < output->vertex_count; i++) {
(*r_vertex)[i] = output->vertex_array[i].xref;
(*r_uv)[i * 2 + 0] = output->vertex_array[i].uv[0] / output->atlas_width;
(*r_uv)[i * 2 + 1] = output->vertex_array[i].uv[1] / output->atlas_height;
// printf("uv: %f,%f\n", (*r_uv)[i * 2 + 0], (*r_uv)[i * 2 + 1]);
}
*r_vertex_count = output->vertex_count;
for (int i = 0; i < output->index_count; i++) {
(*r_index)[i] = output->index_array[i];
}
*r_index_count = output->index_count;
*r_size_hint_x = output->atlas_height;
*r_size_hint_y = output->atlas_width;
}
if (output) {
atlas_free(output);
}
return err == Thekla::Atlas_Error_Success;
}
void register_thekla_unwrap_types() {
array_mesh_lightmap_unwrap_callback = thekla_mesh_lightmap_unwrap_callback;
}
void unregister_thekla_unwrap_types() {
}

View file

@ -623,6 +623,29 @@ void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vect
VisualServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, p_colors, p_width, p_antialiased);
}
void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_color, float p_width, bool p_antialiased) {
if (!drawing) {
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL();
}
Vector<Color> colors;
colors.push_back(p_color);
VisualServer::get_singleton()->canvas_item_add_multiline(canvas_item, p_points, colors, p_width, p_antialiased);
}
void CanvasItem::draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width, bool p_antialiased) {
if (!drawing) {
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL();
}
VisualServer::get_singleton()->canvas_item_add_multiline(canvas_item, p_points, p_colors, p_width, p_antialiased);
}
void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled) {
if (!drawing) {
@ -979,6 +1002,8 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width", "antialiased"), &CanvasItem::draw_line, DEFVAL(1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_polyline", "points", "color", "width", "antialiased"), &CanvasItem::draw_polyline, DEFVAL(1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_polyline_colors", "points", "colors", "width", "antialiased"), &CanvasItem::draw_polyline_colors, DEFVAL(1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_multiline", "points", "color", "width", "antialiased"), &CanvasItem::draw_multiline, DEFVAL(1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_multiline_colors", "points", "colors", "width", "antialiased"), &CanvasItem::draw_multiline_colors, DEFVAL(1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color", "filled"), &CanvasItem::draw_rect, DEFVAL(true));
ClassDB::bind_method(D_METHOD("draw_circle", "position", "radius", "color"), &CanvasItem::draw_circle);
ClassDB::bind_method(D_METHOD("draw_texture", "texture", "position", "modulate", "normal_map"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(Variant()));

View file

@ -268,6 +268,8 @@ public:
void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false);
void draw_polyline(const Vector<Point2> &p_points, const Color &p_color, float p_width = 1.0, bool p_antialiased = false);
void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false);
void draw_multiline(const Vector<Point2> &p_points, const Color &p_color, float p_width = 1.0, bool p_antialiased = false);
void draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false);
void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true);
void draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color);
void draw_texture(const Ref<Texture> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1), const Ref<Texture> &p_normal_map = Ref<Texture>());

View file

@ -28,10 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "mesh.h"
#include "pair.h"
#include "scene/resources/concave_polygon_shape.h"
#include "scene/resources/convex_polygon_shape.h"
#include "surface_tool.h"
void Mesh::_clear_triangle_mesh() const {
triangle_mesh.unref();
@ -413,8 +413,21 @@ Ref<Mesh> Mesh::create_outline(float p_margin) const {
return newmesh;
}
void Mesh::set_lightmap_size_hint(const Vector2 &p_size) {
lightmap_size_hint = p_size;
}
Size2 Mesh::get_lightmap_size_hint() const {
return lightmap_size_hint;
}
void Mesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_lightmap_size_hint", "size"), &Mesh::set_lightmap_size_hint);
ClassDB::bind_method(D_METHOD("get_lightmap_size_hint"), &Mesh::get_lightmap_size_hint);
ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "lightmap_size_hint"), "set_lightmap_size_hint", "get_lightmap_size_hint");
BIND_ENUM_CONSTANT(PRIMITIVE_POINTS);
BIND_ENUM_CONSTANT(PRIMITIVE_LINES);
BIND_ENUM_CONSTANT(PRIMITIVE_LINE_STRIP);
@ -1035,6 +1048,200 @@ void ArrayMesh::regen_normalmaps() {
}
}
//dirty hack
bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, const int *p_face_materials, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y) = NULL;
struct ArrayMeshLightmapSurface {
Ref<Material> material;
Vector<SurfaceTool::Vertex> vertices;
Mesh::PrimitiveType primitive;
uint32_t format;
};
Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texel_size) {
ERR_FAIL_COND_V(!array_mesh_lightmap_unwrap_callback, ERR_UNCONFIGURED);
ERR_EXPLAIN("Can't unwrap mesh with blend shapes");
ERR_FAIL_COND_V(blend_shapes.size() != 0, ERR_UNAVAILABLE);
Vector<float> vertices;
Vector<float> normals;
Vector<int> indices;
Vector<int> face_materials;
Vector<float> uv;
Vector<Pair<int, int> > uv_index;
Vector<ArrayMeshLightmapSurface> surfaces;
for (int i = 0; i < get_surface_count(); i++) {
ArrayMeshLightmapSurface s;
s.primitive = surface_get_primitive_type(i);
if (s.primitive != Mesh::PRIMITIVE_TRIANGLES) {
ERR_EXPLAIN("Only triangles are supported for lightmap unwrap");
ERR_FAIL_V(ERR_UNAVAILABLE);
}
s.format = surface_get_format(i);
if (!(s.format & ARRAY_FORMAT_NORMAL)) {
ERR_EXPLAIN("Normals are required for lightmap unwrap");
ERR_FAIL_V(ERR_UNAVAILABLE);
}
Array arrays = surface_get_arrays(i);
s.material = surface_get_material(i);
s.vertices = SurfaceTool::create_vertex_array_from_triangle_arrays(arrays);
PoolVector<Vector3> rvertices = arrays[Mesh::ARRAY_VERTEX];
int vc = rvertices.size();
PoolVector<Vector3>::Read r = rvertices.read();
PoolVector<Vector3> rnormals = arrays[Mesh::ARRAY_NORMAL];
PoolVector<Vector3>::Read rn = rnormals.read();
int vertex_ofs = vertices.size() / 3;
vertices.resize((vertex_ofs + vc) * 3);
normals.resize((vertex_ofs + vc) * 3);
uv_index.resize(vertex_ofs + vc);
for (int j = 0; j < vc; j++) {
Vector3 v = p_base_transform.xform(r[j]);
vertices[(j + vertex_ofs) * 3 + 0] = v.x;
vertices[(j + vertex_ofs) * 3 + 1] = v.y;
vertices[(j + vertex_ofs) * 3 + 2] = v.z;
normals[(j + vertex_ofs) * 3 + 0] = rn[j].x;
normals[(j + vertex_ofs) * 3 + 1] = rn[j].y;
normals[(j + vertex_ofs) * 3 + 2] = rn[j].z;
uv_index[j + vertex_ofs] = Pair<int, int>(i, j);
}
PoolVector<int> rindices = arrays[Mesh::ARRAY_INDEX];
int ic = rindices.size();
int index_ofs = indices.size();
if (ic == 0) {
indices.resize(index_ofs + vc);
face_materials.resize((index_ofs + vc) / 3);
for (int j = 0; j < vc; j++) {
indices[index_ofs + j] = vertex_ofs + j;
}
for (int j = 0; j < vc / 3; j++) {
face_materials[(index_ofs / 3) + j] = i;
}
} else {
PoolVector<int>::Read ri = rindices.read();
indices.resize(index_ofs + ic);
face_materials.resize((index_ofs + ic) / 3);
for (int j = 0; j < ic; j++) {
indices[index_ofs + j] = vertex_ofs + ri[j];
}
for (int j = 0; j < ic / 3; j++) {
face_materials[(index_ofs / 3) + j] = i;
}
}
surfaces.push_back(s);
}
//unwrap
float *gen_uvs;
int *gen_vertices;
int *gen_indices;
int gen_vertex_count;
int gen_index_count;
int size_x;
int size_y;
bool ok = array_mesh_lightmap_unwrap_callback(p_texel_size, vertices.ptr(), normals.ptr(), vertices.size() / 3, indices.ptr(), face_materials.ptr(), indices.size(), &gen_uvs, &gen_vertices, &gen_vertex_count, &gen_indices, &gen_index_count, &size_x, &size_y);
if (!ok) {
return ERR_CANT_CREATE;
}
//remove surfaces
while (get_surface_count()) {
surface_remove(0);
}
//create surfacetools for each surface..
Vector<Ref<SurfaceTool> > surfaces_tools;
for (int i = 0; i < surfaces.size(); i++) {
Ref<SurfaceTool> st;
st.instance();
st->begin(Mesh::PRIMITIVE_TRIANGLES);
st->set_material(surfaces[i].material);
surfaces_tools.push_back(st); //stay there
}
print_line("gen indices: " + itos(gen_index_count));
//go through all indices
for (int i = 0; i < gen_index_count; i += 3) {
ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 0]], uv_index.size(), ERR_BUG);
ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 1]], uv_index.size(), ERR_BUG);
ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 2]], uv_index.size(), ERR_BUG);
ERR_FAIL_COND_V(uv_index[gen_vertices[gen_indices[i + 0]]].first != uv_index[gen_vertices[gen_indices[i + 1]]].first || uv_index[gen_vertices[gen_indices[i + 0]]].first != uv_index[gen_vertices[gen_indices[i + 2]]].first, ERR_BUG);
int surface = uv_index[gen_vertices[gen_indices[i + 0]]].first;
for (int j = 0; j < 3; j++) {
int vertex_idx = gen_vertices[gen_indices[i + j]];
SurfaceTool::Vertex v = surfaces[surface].vertices[uv_index[gen_vertices[gen_indices[i + j]]].second];
if (surfaces[surface].format & ARRAY_FORMAT_COLOR) {
surfaces_tools[surface]->add_color(v.color);
}
if (surfaces[surface].format & ARRAY_FORMAT_TEX_UV) {
surfaces_tools[surface]->add_uv(v.uv);
}
if (surfaces[surface].format & ARRAY_FORMAT_NORMAL) {
surfaces_tools[surface]->add_normal(v.normal);
}
if (surfaces[surface].format & ARRAY_FORMAT_TANGENT) {
Plane t;
t.normal = v.tangent;
t.d = v.binormal.dot(v.normal.cross(v.tangent)) < 0 ? -1 : 1;
surfaces_tools[surface]->add_tangent(t);
}
if (surfaces[surface].format & ARRAY_FORMAT_BONES) {
surfaces_tools[surface]->add_bones(v.bones);
}
if (surfaces[surface].format & ARRAY_FORMAT_WEIGHTS) {
surfaces_tools[surface]->add_weights(v.weights);
}
Vector2 uv2(gen_uvs[gen_indices[i + j] * 2 + 0], gen_uvs[gen_indices[i + j] * 2 + 1]);
surfaces_tools[surface]->add_uv2(uv2);
surfaces_tools[surface]->add_vertex(v.vertex);
}
}
//free stuff
::free(gen_vertices);
::free(gen_indices);
::free(gen_uvs);
//generate surfaces
for (int i = 0; i < surfaces_tools.size(); i++) {
surfaces_tools[i]->index();
surfaces_tools[i]->commit(Ref<ArrayMesh>((ArrayMesh *)this), surfaces[i].format);
}
set_lightmap_size_hint(Size2(size_x, size_y));
return OK;
}
void ArrayMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_blend_shape", "name"), &ArrayMesh::add_blend_shape);

View file

@ -43,6 +43,8 @@ class Mesh : public Resource {
GDCLASS(Mesh, Resource);
mutable Ref<TriangleMesh> triangle_mesh; //cached
Size2 lightmap_size_hint;
protected:
void _clear_triangle_mesh() const;
@ -138,6 +140,9 @@ public:
virtual AABB get_aabb() const = 0;
void set_lightmap_size_hint(const Vector2 &p_size);
Size2 get_lightmap_size_hint() const;
Mesh();
};
@ -216,6 +221,8 @@ public:
void center_geometry();
void regen_normalmaps();
Error lightmap_unwrap(const Transform &p_base_transform = Transform(), float p_texel_size = 0.05);
virtual void reload_from_file();
ArrayMesh();

View file

@ -101,6 +101,7 @@ void SurfaceTool::add_vertex(const Vector3 &p_vertex) {
vtx.color = last_color;
vtx.normal = last_normal;
vtx.uv = last_uv;
vtx.uv2 = last_uv2;
vtx.weights = last_weights;
vtx.bones = last_bones;
vtx.tangent = last_tangent.normal;
@ -401,7 +402,7 @@ Array SurfaceTool::commit_to_arrays() {
return a;
}
Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing) {
Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing, uint32_t p_flags) {
Ref<ArrayMesh> mesh;
if (p_existing.is_valid())
@ -418,7 +419,7 @@ Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing) {
Array a = commit_to_arrays();
mesh->add_surface_from_arrays(primitive, a);
mesh->add_surface_from_arrays(primitive, a, Array(), p_flags);
if (material.is_valid())
mesh->surface_set_material(surface, material);
@ -482,6 +483,113 @@ void SurfaceTool::_create_list(const Ref<Mesh> &p_existing, int p_surface, List<
_create_list_from_arrays(arr, r_vertex, r_index, lformat);
}
Vector<SurfaceTool::Vertex> SurfaceTool::create_vertex_array_from_triangle_arrays(const Array &p_arrays) {
Vector<SurfaceTool::Vertex> ret;
PoolVector<Vector3> varr = p_arrays[VS::ARRAY_VERTEX];
PoolVector<Vector3> narr = p_arrays[VS::ARRAY_NORMAL];
PoolVector<float> tarr = p_arrays[VS::ARRAY_TANGENT];
PoolVector<Color> carr = p_arrays[VS::ARRAY_COLOR];
PoolVector<Vector2> uvarr = p_arrays[VS::ARRAY_TEX_UV];
PoolVector<Vector2> uv2arr = p_arrays[VS::ARRAY_TEX_UV2];
PoolVector<int> barr = p_arrays[VS::ARRAY_BONES];
PoolVector<float> warr = p_arrays[VS::ARRAY_WEIGHTS];
int vc = varr.size();
if (vc == 0)
return ret;
int lformat = 0;
PoolVector<Vector3>::Read rv;
if (varr.size()) {
lformat |= VS::ARRAY_FORMAT_VERTEX;
rv = varr.read();
}
PoolVector<Vector3>::Read rn;
if (narr.size()) {
lformat |= VS::ARRAY_FORMAT_NORMAL;
rn = narr.read();
}
PoolVector<float>::Read rt;
if (tarr.size()) {
lformat |= VS::ARRAY_FORMAT_TANGENT;
rt = tarr.read();
}
PoolVector<Color>::Read rc;
if (carr.size()) {
lformat |= VS::ARRAY_FORMAT_COLOR;
rc = carr.read();
}
PoolVector<Vector2>::Read ruv;
if (uvarr.size()) {
lformat |= VS::ARRAY_FORMAT_TEX_UV;
ruv = uvarr.read();
}
PoolVector<Vector2>::Read ruv2;
if (uv2arr.size()) {
lformat |= VS::ARRAY_FORMAT_TEX_UV2;
ruv2 = uv2arr.read();
}
PoolVector<int>::Read rb;
if (barr.size()) {
lformat |= VS::ARRAY_FORMAT_BONES;
rb = barr.read();
}
PoolVector<float>::Read rw;
if (warr.size()) {
lformat |= VS::ARRAY_FORMAT_WEIGHTS;
rw = warr.read();
}
for (int i = 0; i < vc; i++) {
Vertex v;
if (lformat & VS::ARRAY_FORMAT_VERTEX)
v.vertex = varr[i];
if (lformat & VS::ARRAY_FORMAT_NORMAL)
v.normal = narr[i];
if (lformat & VS::ARRAY_FORMAT_TANGENT) {
Plane p(tarr[i * 4 + 0], tarr[i * 4 + 1], tarr[i * 4 + 2], tarr[i * 4 + 3]);
v.tangent = p.normal;
v.binormal = p.normal.cross(v.tangent).normalized() * p.d;
}
if (lformat & VS::ARRAY_FORMAT_COLOR)
v.color = carr[i];
if (lformat & VS::ARRAY_FORMAT_TEX_UV)
v.uv = uvarr[i];
if (lformat & VS::ARRAY_FORMAT_TEX_UV2)
v.uv2 = uv2arr[i];
if (lformat & VS::ARRAY_FORMAT_BONES) {
Vector<int> b;
b.resize(4);
b[0] = barr[i * 4 + 0];
b[1] = barr[i * 4 + 1];
b[2] = barr[i * 4 + 2];
b[3] = barr[i * 4 + 3];
v.bones = b;
}
if (lformat & VS::ARRAY_FORMAT_WEIGHTS) {
Vector<float> w;
w.resize(4);
w[0] = warr[i * 4 + 0];
w[1] = warr[i * 4 + 1];
w[2] = warr[i * 4 + 2];
w[3] = warr[i * 4 + 3];
v.weights = w;
}
ret.push_back(v);
}
return ret;
}
void SurfaceTool::_create_list_from_arrays(Array arr, List<Vertex> *r_vertex, List<int> *r_index, int &lformat) {
PoolVector<Vector3> varr = arr[VS::ARRAY_VERTEX];
@ -882,7 +990,7 @@ void SurfaceTool::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_from", "existing", "surface"), &SurfaceTool::create_from);
ClassDB::bind_method(D_METHOD("append_from", "existing", "surface", "transform"), &SurfaceTool::append_from);
ClassDB::bind_method(D_METHOD("commit", "existing"), &SurfaceTool::commit, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("commit", "existing"), &SurfaceTool::commit, DEFVAL(Variant()), DEFVAL(Mesh::ARRAY_COMPRESS_DEFAULT));
}
SurfaceTool::SurfaceTool() {

View file

@ -127,10 +127,11 @@ public:
List<Vertex> &get_vertex_array() { return vertex_array; }
void create_from_triangle_arrays(const Array &p_arrays);
static Vector<Vertex> create_vertex_array_from_triangle_arrays(const Array &p_arrays);
Array commit_to_arrays();
void create_from(const Ref<Mesh> &p_existing, int p_surface);
void append_from(const Ref<Mesh> &p_existing, int p_surface, const Transform &p_xform);
Ref<ArrayMesh> commit(const Ref<ArrayMesh> &p_existing = Ref<ArrayMesh>());
Ref<ArrayMesh> commit(const Ref<ArrayMesh> &p_existing = Ref<ArrayMesh>(), uint32_t p_flags = Mesh::ARRAY_COMPRESS_DEFAULT);
SurfaceTool();
};

View file

@ -636,6 +636,7 @@ public:
struct CommandPolyLine : public Command {
bool antialiased;
bool multiline;
Vector<Point2> triangles;
Vector<Color> triangle_colors;
Vector<Point2> lines;
@ -643,6 +644,7 @@ public:
CommandPolyLine() {
type = TYPE_POLYLINE;
antialiased = false;
multiline = false;
}
};

View file

@ -416,6 +416,7 @@ void VisualServerCanvas::canvas_item_add_polyline(RID p_item, const Vector<Point
ERR_FAIL_COND(!pline);
pline->antialiased = p_antialiased;
pline->multiline = false;
if (p_width <= 1) {
pline->lines = p_points;
@ -486,6 +487,90 @@ void VisualServerCanvas::canvas_item_add_polyline(RID p_item, const Vector<Point
canvas_item->commands.push_back(pline);
}
void VisualServerCanvas::canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width, bool p_antialiased) {
ERR_FAIL_COND(p_points.size() < 2);
Item *canvas_item = canvas_item_owner.getornull(p_item);
ERR_FAIL_COND(!canvas_item);
Item::CommandPolyLine *pline = memnew(Item::CommandPolyLine);
ERR_FAIL_COND(!pline);
pline->antialiased = false; //todo
pline->multiline = true;
// if (p_width <= 1) {
pline->lines = p_points;
pline->line_colors = p_colors;
if (pline->line_colors.size() == 0) {
pline->line_colors.push_back(Color(1, 1, 1, 1));
} else if (pline->line_colors.size() > 1 && pline->line_colors.size() != pline->lines.size()) {
pline->line_colors.resize(1);
}
#if 0
//width not yet
} else {
//make a trianglestrip for drawing the line...
Vector2 prev_t;
pline->triangles.resize(p_points.size() * 2);
if (p_antialiased) {
pline->lines.resize(p_points.size() * 2);
}
if (p_colors.size() == 0) {
pline->triangle_colors.push_back(Color(1, 1, 1, 1));
if (p_antialiased) {
pline->line_colors.push_back(Color(1, 1, 1, 1));
}
}
if (p_colors.size() == 1) {
pline->triangle_colors = p_colors;
pline->line_colors = p_colors;
} else {
pline->triangle_colors.resize(pline->triangles.size());
pline->line_colors.resize(pline->lines.size());
}
for (int i = 0; i < p_points.size(); i++) {
Vector2 t;
if (i == p_points.size() - 1) {
t = prev_t;
} else {
t = (p_points[i + 1] - p_points[i]).normalized().tangent();
if (i == 0) {
prev_t = t;
}
}
Vector2 tangent = ((t + prev_t).normalized()) * p_width * 0.5;
if (p_antialiased) {
pline->lines[i] = p_points[i] + tangent;
pline->lines[p_points.size() * 2 - i - 1] = p_points[i] - tangent;
if (pline->line_colors.size() > 1) {
pline->line_colors[i] = p_colors[i];
pline->line_colors[p_points.size() * 2 - i - 1] = p_colors[i];
}
}
pline->triangles[i * 2 + 0] = p_points[i] + tangent;
pline->triangles[i * 2 + 1] = p_points[i] - tangent;
if (pline->triangle_colors.size() > 1) {
pline->triangle_colors[i * 2 + 0] = p_colors[i];
pline->triangle_colors[i * 2 + 1] = p_colors[i];
}
prev_t = t;
}
}
#endif
canvas_item->rect_dirty = true;
canvas_item->commands.push_back(pline);
}
void VisualServerCanvas::canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) {
Item *canvas_item = canvas_item_owner.getornull(p_item);

View file

@ -172,6 +172,7 @@ public:
void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false);
void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false);
void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false);
void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color);
void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color);
void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID());

View file

@ -551,6 +551,7 @@ public:
BIND6(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float, bool)
BIND5(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool)
BIND5(canvas_item_add_multiline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool)
BIND3(canvas_item_add_rect, RID, const Rect2 &, const Color &)
BIND4(canvas_item_add_circle, RID, const Point2 &, float, const Color &)
BIND7(canvas_item_add_texture_rect, RID, const Rect2 &, RID, bool, const Color &, bool, RID)

View file

@ -467,6 +467,7 @@ public:
FUNC6(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float, bool)
FUNC5(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool)
FUNC5(canvas_item_add_multiline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool)
FUNC3(canvas_item_add_rect, RID, const Rect2 &, const Color &)
FUNC4(canvas_item_add_circle, RID, const Point2 &, float, const Color &)
FUNC7(canvas_item_add_texture_rect, RID, const Rect2 &, RID, bool, const Color &, bool, RID)

View file

@ -815,6 +815,7 @@ public:
virtual void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false) = 0;
virtual void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false) = 0;
virtual void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false) = 0;
virtual void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) = 0;
virtual void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) = 0;
virtual void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID()) = 0;

View file

@ -38,6 +38,7 @@ using namespace nv;
/// Ctor.
Atlas::Atlas()
{
failed=false;
}
// Dtor.
@ -100,6 +101,7 @@ void Atlas::extractCharts(const HalfEdge::Mesh * mesh)
void Atlas::computeCharts(const HalfEdge::Mesh * mesh, const SegmentationSettings & settings, const Array<uint> & unchartedMaterialArray)
{
failed=false;
MeshCharts * meshCharts = new MeshCharts(mesh);
meshCharts->computeCharts(settings, unchartedMaterialArray);
addMeshCharts(meshCharts);
@ -235,6 +237,8 @@ float Atlas::packCharts(int quality, float texelsPerUnit, bool blockAlign, bool
{
AtlasPacker packer(this);
packer.packCharts(quality, texelsPerUnit, blockAlign, conservative);
if (hasFailed())
return 0;
return packer.computeAtlasUtilization();
}

View file

@ -64,9 +64,12 @@ namespace nv
// Pack charts in the smallest possible rectangle.
float packCharts(int quality, float texelArea, bool blockAlign, bool conservative);
bool setFailed() { failed = true; }
bool hasFailed() const { return failed; }
private:
bool failed;
Array<MeshCharts *> m_meshChartsArray;
};

View file

@ -152,7 +152,7 @@ AtlasPacker::~AtlasPacker()
}
// This should compute convex hull and use rotating calipers to find the best box. Currently it uses a brute force method.
static void computeBoundingBox(Chart * chart, Vector2 * majorAxis, Vector2 * minorAxis, Vector2 * minCorner, Vector2 * maxCorner)
static bool computeBoundingBox(Chart * chart, Vector2 * majorAxis, Vector2 * minorAxis, Vector2 * minCorner, Vector2 * maxCorner)
{
// Compute list of boundary points.
Array<Vector2> points(16);
@ -184,6 +184,9 @@ static void computeBoundingBox(Chart * chart, Vector2 * majorAxis, Vector2 * min
#if 1
Array<Vector2> hull;
if (points.size()==0) {
return false;
}
convexHull(points, hull, 0.00001f);
@ -373,6 +376,8 @@ static void computeBoundingBox(Chart * chart, Vector2 * majorAxis, Vector2 * min
}
}*/
#endif
return true;
}
@ -431,7 +436,10 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
// Compute bounding box of chart.
Vector2 majorAxis, minorAxis, origin, end;
computeBoundingBox(chart, &majorAxis, &minorAxis, &origin, &end);
if (!computeBoundingBox(chart, &majorAxis, &minorAxis, &origin, &end)) {
m_atlas->setFailed();
return;
}
nvCheck(isFinite(majorAxis) && isFinite(minorAxis) && isFinite(origin));