-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:
parent
ccef401700
commit
65fb961b8b
|
@ -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++) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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]
|
||||
|
||||
|
|
|
@ -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() {
|
||||
}
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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>());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
Loading…
Reference in New Issue