Import 3D Scene Improvements

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

-If re-importing from the "dependency changed" dialog, edited scene will keep the local changes.
-Imported scene will keep track of changes in the source asset
-Geometry changes in source geometry or nodes with a different transform will be updated.
-Materials will be kept if changed locally.
-New nodes added will be kept
-If nodes were reparented or renamed, they will still keep track
-Deleted notes will be restored, use the -noimp option to avoid this.
-In general, you can trust that if you do local modifications to the imported scene, they will not be erased after re-import.
-Erasing your changes is done by re-importing from the "Re-Import" menu, re-opening the "Import 3D Scene" dialog. This wil re-import fresh.

Overall, This should allow you to work on a scene and see changes made to 3D assets in real-time.

So Please test!!
This commit is contained in:
Juan Linietsky 2014-06-19 02:23:03 -03:00
parent ddc0e7fd3b
commit e086bccd63
19 changed files with 667 additions and 124 deletions

View file

@ -305,7 +305,7 @@ public:
richtext->push_color(Color(1,0.5,0.5));
richtext->add_text("leprechauns");
richtext->pop();
#if 0
richtext->add_text(" and ");
richtext->push_color(Color(0,1.0,0.5));
richtext->add_text("faeries.\n");
@ -329,7 +329,7 @@ public:
richtext->pop();
richtext->add_text("of the rich text label for huge text (not like this text will really be huge but, you know).\nAs long as it is so long that it will work nicely for a test/demo, then it's welcomed in my book...\nChanging subject, the day is cloudy today and I'm wondering if I'll get che chance to travel somewhere nice. Sometimes, watching the clouds from satellite images may give a nice insight about how pressure zones in our planet work, althogh it also makes it pretty obvious to see why most weather forecasts get it wrong so often.\nClouds are so difficult to predict!\nBut it's pretty cool how our civilization has adapted to having water falling from the sky each time it rains...");
//richtext->add_text("Hello!\nGorgeous..");
#endif
//richtext->push_meta("http://www.scrollingcapabilities.xz");
///richtext->add_text("Hello!\n");

View file

@ -49,6 +49,12 @@
#define _GL_R16F_EXT 0x822D
#define _GL_R32F_EXT 0x822E
#define _GL_RED_EXT 0x1903
#define _GL_RG_EXT 0x8227
#define _GL_R8_EXT 0x8229
#define _GL_RG8_EXT 0x822B
#define _DEPTH_COMPONENT24_OES 0x81A6
#ifdef GLEW_ENABLED
@ -7874,6 +7880,7 @@ void RasterizerGLES2::_update_framebuffer() {
glDeleteFramebuffers(1,&framebuffer.luminance[i].fbo);
}
for(int i=0;i<3;i++) {
glDeleteTextures(1,&framebuffer.blur[i].color);
@ -7925,12 +7932,15 @@ void RasterizerGLES2::_update_framebuffer() {
#endif
//color
GLuint format_rgba = use_fp16_fb?_GL_RGBA16F_EXT:GL_RGBA;
// GLuint format_rgba = use_fp16_fb?_GL_RGBA16F_EXT:GL_RGBA;
GLuint format_rgba = GL_RGBA;
GLuint format_rgb = use_fp16_fb?_GL_RGB16F_EXT:GL_RGB;
GLuint format_type = use_fp16_fb?_GL_HALF_FLOAT_OES:GL_UNSIGNED_BYTE;
GLuint format_luminance = use_fp16_fb?_GL_R32F_EXT:GL_RGBA;
GLuint format_luminance_type = use_fp16_fb?GL_FLOAT:GL_UNSIGNED_BYTE;
GLuint format_luminance_components = use_fp16_fb?GL_RED:GL_RGBA;
GLuint format_luminance = use_fp16_fb?_GL_RED_EXT:GL_RGBA;
GLuint format_luminance_type = use_fp16_fb?(full_float_fb_supported?GL_FLOAT:_GL_HALF_FLOAT_OES):GL_UNSIGNED_BYTE;
GLuint format_luminance_components = use_fp16_fb?_GL_RED_EXT:GL_RGBA;
glGenTextures(1, &framebuffer.color);
glBindTexture(GL_TEXTURE_2D, framebuffer.color);
@ -8085,10 +8095,12 @@ void RasterizerGLES2::_update_framebuffer() {
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
base_size/=3;
DEBUG_TEST_ERROR("Shadow Buffer Init");
ERR_CONTINUE( status != GL_FRAMEBUFFER_COMPLETE );
base_size/=3;
framebuffer.luminance.push_back(lb);
}
@ -8239,6 +8251,7 @@ void RasterizerGLES2::init() {
// use_attribute_instancing=true;
use_texture_instancing=false;
use_attribute_instancing=true;
full_float_fb_supported=true;
#ifdef OSX_ENABLED
use_rgba_shadowmaps=true;
use_fp16_fb=false;
@ -8291,9 +8304,11 @@ void RasterizerGLES2::init() {
}
if (use_fp16_fb) {
use_fp16_fb=extensions.has("GL_OES_texture_half_float") && extensions.has("GL_EXT_color_buffer_half_float");
use_fp16_fb=extensions.has("GL_OES_texture_half_float") && extensions.has("GL_EXT_color_buffer_half_float") && extensions.has("GL_EXT_texture_rg");
}
full_float_fb_supported=extensions.has("GL_EXT_color_buffer_float");
//etc_supported=false;
use_hw_skeleton_xform=false;

View file

@ -79,6 +79,7 @@ class RasterizerGLES2 : public Rasterizer {
bool npo2_textures_available;
bool read_depth_supported;
bool use_framebuffers;
bool full_float_fb_supported;
bool use_shadow_mapping;
bool use_fp16_fb;
ShadowFilterTechnique shadow_filter;
@ -90,6 +91,7 @@ class RasterizerGLES2 : public Rasterizer {
bool use_texture_instancing;
bool use_attribute_instancing;
bool use_rgba_shadowmaps;
bool use_half_float;

View file

@ -440,7 +440,7 @@ void main() {
highp float vd_lum = dot(texture2D( source_vd_lum, vec2(0.0) ), _multcv );
lum_accum = clamp( vd_lum + (lum_accum-vd_lum)*hdr_time_delta*hdr_exp_adj_speed,min_luminance*(1.0/LUM_RANGE),max_luminance*(1.0/LUM_RANGE));
#else
highp float vd_lum=texture2D( source_vd_lum, vec2(0.0) );
highp float vd_lum=texture2D( source_vd_lum, vec2(0.0) ).r;
lum_accum = clamp( vd_lum + (lum_accum-vd_lum)*hdr_time_delta*hdr_exp_adj_speed,min_luminance,max_luminance);
#endif

View file

@ -6,6 +6,7 @@
void register_android_global_defaults() {
GLOBAL_DEF("rasterizer.Android/use_fragment_lighting",false);
GLOBAL_DEF("rasterizer.Android/fp16_framebuffer",false);
GLOBAL_DEF("display.Android/driver","GLES2");
// GLOBAL_DEF("rasterizer.Android/trilinear_mipmap_filter",false);

View file

@ -494,6 +494,17 @@ Ref<World> Spatial::get_world() const {
}
#ifdef TOOLS_ENABLED
void Spatial::set_import_transform(const Transform& p_transform) {
data.import_transform=p_transform;
}
Transform Spatial::get_import_transform() const {
return data.import_transform;
}
#endif
void Spatial::_bind_methods() {
@ -517,6 +528,9 @@ void Spatial::_bind_methods() {
#ifdef TOOLS_ENABLED
ObjectTypeDB::bind_method(_MD("_update_gizmo"), &Spatial::_update_gizmo);
ObjectTypeDB::bind_method(_MD("_set_import_transform"), &Spatial::set_import_transform);
ObjectTypeDB::bind_method(_MD("_get_import_transform"), &Spatial::get_import_transform);
ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"_import_transform",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_import_transform"),_SCS("_get_import_transform"));
#endif
ObjectTypeDB::bind_method(_MD("update_gizmo"), &Spatial::update_gizmo);

View file

@ -95,6 +95,7 @@ class Spatial : public Node {
Ref<SpatialGizmo> gizmo;
bool gizmo_disabled;
bool gizmo_dirty;
Transform import_transform;
#endif
} data;
@ -158,6 +159,11 @@ public:
Transform get_relative_transform(const Node *p_parent) const;
#ifdef TOOLS_ENABLED
void set_import_transform(const Transform& p_transform) ;
Transform get_import_transform() const;
#endif
Spatial();
~Spatial();

View file

@ -1561,8 +1561,9 @@ RichTextLabel::RichTextLabel() {
scroll_active=true;
scroll_w=0;
vscroll = memnew( VScrollBar );
vscroll = memnew( VScrollBar );
add_child(vscroll);
vscroll->set_drag_slave(String(".."));
vscroll->set_step(1);
vscroll->set_anchor_and_margin( MARGIN_TOP, ANCHOR_BEGIN, 0);
vscroll->set_anchor_and_margin( MARGIN_BOTTOM, ANCHOR_END, 0);

View file

@ -29,7 +29,7 @@
#include "scroll_bar.h"
#include "os/keyboard.h"
#include "print_string.h"
#include "os/os.h"
bool ScrollBar::focus_by_default=false;
@ -293,6 +293,117 @@ void ScrollBar::_notification(int p_what) {
}
if (p_what==NOTIFICATION_ENTER_SCENE) {
if (has_node(drag_slave_path)) {
Node *n = get_node(drag_slave_path);
drag_slave=n->cast_to<Control>();
}
if (drag_slave) {
drag_slave->connect("input_event",this,"_drag_slave_input");
drag_slave->connect("exit_scene",this,"_drag_slave_exit",varray(),CONNECT_ONESHOT);
}
}
if (p_what==NOTIFICATION_EXIT_SCENE) {
if (drag_slave) {
drag_slave->disconnect("input_event",this,"_drag_slave_input");
drag_slave->disconnect("exit_scene",this,"_drag_slave_exit");
}
drag_slave=NULL;
}
if (p_what==NOTIFICATION_FIXED_PROCESS) {
if (drag_slave_touching) {
if (drag_slave_touching_deaccel) {
Vector2 pos = Vector2(orientation==HORIZONTAL?get_val():0,orientation==VERTICAL?get_val():0);
pos+=drag_slave_speed*get_fixed_process_delta_time();
bool turnoff=false;
if (orientation==HORIZONTAL) {
if (pos.x<0) {
pos.x=0;
turnoff=true;
}
if (pos.x > (get_max()-get_page())) {
pos.x=get_max()-get_page();
turnoff=true;
}
set_val(pos.x);
float sgn_x = drag_slave_speed.x<0? -1 : 1;
float val_x = Math::abs(drag_slave_speed.x);
val_x-=1000*get_fixed_process_delta_time();
if (val_x<0) {
turnoff=true;
}
drag_slave_speed.x=sgn_x*val_x;
} else {
if (pos.y<0) {
pos.y=0;
turnoff=true;
}
if (pos.y > (get_max()-get_page())) {
pos.y=get_max()-get_page();
turnoff=true;
}
set_val(pos.y);
float sgn_y = drag_slave_speed.y<0? -1 : 1;
float val_y = Math::abs(drag_slave_speed.y);
val_y-=1000*get_fixed_process_delta_time();
if (val_y<0) {
turnoff=true;
}
drag_slave_speed.y=sgn_y*val_y;
}
if (turnoff) {
set_fixed_process(false);
drag_slave_touching=false;
drag_slave_touching_deaccel=false;
}
} else {
if (time_since_motion==0 || time_since_motion>0.1) {
Vector2 diff = drag_slave_accum - last_drag_slave_accum;
last_drag_slave_accum=drag_slave_accum;
drag_slave_speed=diff/get_fixed_process_delta_time();
}
time_since_motion+=get_fixed_process_delta_time();
}
}
}
if (p_what==NOTIFICATION_MOUSE_EXIT) {
hilite=HILITE_NONE;
@ -434,34 +545,119 @@ float ScrollBar::get_custom_step() const {
void ScrollBar::_drag_slave_exit() {
if (drag_slave) {
drag_slave->disconnect("input_event",this,"_drag_slave_input");
}
drag_slave=NULL;
}
void ScrollBar::_drag_slave_input(const InputEvent& p_input) {
switch(p_input.type) {
case InputEvent::MOUSE_BUTTON: {
const InputEventMouseButton &mb=p_input.mouse_button;
if (mb.button_index!=1)
break;
if (mb.pressed) {
if (drag_slave_touching) {
set_fixed_process(false);
drag_slave_touching_deaccel=false;
drag_slave_touching=false;
drag_slave_speed=Vector2();
drag_slave_accum=Vector2();
last_drag_slave_accum=Vector2();
drag_slave_from=Vector2();
}
if (true) {
drag_slave_speed=Vector2();
drag_slave_accum=Vector2();
last_drag_slave_accum=Vector2();
//drag_slave_from=Vector2(h_scroll->get_val(),v_scroll->get_val());
drag_slave_from= Vector2(orientation==HORIZONTAL?get_val():0,orientation==VERTICAL?get_val():0);
drag_slave_touching=OS::get_singleton()->has_touchscreen_ui_hint();
drag_slave_touching_deaccel=false;
time_since_motion=0;
if (drag_slave_touching) {
set_fixed_process(true);
time_since_motion=0;
}
}
} else {
if (drag_slave_touching) {
if (drag_slave_speed==Vector2()) {
drag_slave_touching_deaccel=false;
drag_slave_touching=false;
set_fixed_process(false);
} else {
drag_slave_touching_deaccel=true;
}
}
}
} break;
case InputEvent::MOUSE_MOTION: {
const InputEventMouseMotion &mm=p_input.mouse_motion;
if (drag_slave_touching && ! drag_slave_touching_deaccel) {
Vector2 motion = Vector2(mm.relative_x,mm.relative_y);
drag_slave_accum-=motion;
Vector2 diff = drag_slave_from+drag_slave_accum;
if (orientation==HORIZONTAL)
set_val(diff.x);
//else
// drag_slave_accum.x=0;
if (orientation==VERTICAL)
set_val(diff.y);
//else
// drag_slave_accum.y=0;
time_since_motion=0;
}
} break;
}
}
void ScrollBar::set_drag_slave(const NodePath& p_path) {
if (drag_slave) {
drag_slave->disconnect("input_event",this,"_drag_slave_input");
drag_slave->disconnect("exit_scene",this,"_drag_slave_exit");
if (is_inside_scene()) {
if (drag_slave) {
drag_slave->disconnect("input_event",this,"_drag_slave_input");
drag_slave->disconnect("exit_scene",this,"_drag_slave_exit");
}
}
drag_slave=NULL;
drag_slave_path=p_path;
if (has_node(p_path)) {
Node *n = get_node(p_path);
drag_slave=n->cast_to<Control>();
}
if (drag_slave) {
drag_slave->connect("input_event",this,"_drag_slave_input");
drag_slave->connect("exit_scene",this,"_drag_slave_exit",varray(),CONNECT_ONESHOT);
}
if (is_inside_scene()) {
if (has_node(p_path)) {
Node *n = get_node(p_path);
drag_slave=n->cast_to<Control>();
}
if (drag_slave) {
drag_slave->connect("input_event",this,"_drag_slave_input");
drag_slave->connect("exit_scene",this,"_drag_slave_exit",varray(),CONNECT_ONESHOT);
}
}
}
NodePath ScrollBar::get_drag_slave() const{
@ -629,7 +825,11 @@ ScrollBar::ScrollBar(Orientation p_orientation)
drag_slave=NULL;
drag.active=false;
drag_slave_speed=Vector2();
drag_slave_touching=false;
drag_slave_touching_deaccel=false;
if (focus_by_default)
set_focus_mode( FOCUS_ALL );

View file

@ -74,6 +74,16 @@ class ScrollBar : public Range {
Node* drag_slave;
NodePath drag_slave_path;
Vector2 drag_slave_speed;
Vector2 drag_slave_accum;
Vector2 drag_slave_from;
Vector2 last_drag_slave_accum;
float last_drag_slave_time;
float time_since_motion;
bool drag_slave_touching;
bool drag_slave_touching_deaccel;
bool click_handled;
void _drag_slave_exit();
void _drag_slave_input(const InputEvent& p_input);

View file

@ -235,7 +235,7 @@ void ScrollContainer::_notification(int p_what) {
}
if (pos.y<0) {
pos.x=0;
pos.y=0;
turnoff_v=true;
}
if (pos.y > (v_scroll->get_max()-v_scroll->get_page())) {

View file

@ -1698,6 +1698,20 @@ Array Node::_get_children() const {
return arr;
}
#ifdef TOOLS_ENABLED
void Node::set_import_path(const NodePath& p_import_path) {
data.import_path=p_import_path;
}
NodePath Node::get_import_path() const {
return data.import_path;
}
#endif
void Node::_bind_methods() {
@ -1760,6 +1774,12 @@ void Node::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_viewport"),&Node::get_viewport);
ObjectTypeDB::bind_method(_MD("queue_free"),&Node::queue_delete);
#ifdef TOOLS_ENABLED
ObjectTypeDB::bind_method(_MD("_set_import_path","import_path"),&Node::set_import_path);
ObjectTypeDB::bind_method(_MD("_get_import_path"),&Node::get_import_path);
ADD_PROPERTY( PropertyInfo(Variant::NODE_PATH,"_import_path",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_import_path"),_SCS("_get_import_path"));
#endif
BIND_CONSTANT( NOTIFICATION_ENTER_SCENE );
BIND_CONSTANT( NOTIFICATION_EXIT_SCENE );

View file

@ -82,6 +82,9 @@ private:
StringName name;
SceneMainLoop *scene;
bool inside_scene;
#ifdef TOOLS_ENABLED
NodePath import_path; //path used when imported, used by scene editors to keep tracking
#endif
Viewport *viewport;
@ -269,11 +272,18 @@ public:
void queue_delete();
//shitty hacks for speed
static void set_human_readable_collision_renaming(bool p_enabled);
static void init_node_hrcr();
void force_parent_owned() { data.parent_owned=true; } //hack to avoid duplicate nodes
#ifdef TOOLS_ENABLED
void set_import_path(const NodePath& p_import_path); //path used when imported, used by scene editors to keep tracking
NodePath get_import_path() const;
#endif
_FORCE_INLINE_ Viewport *get_viewport() const { return data.viewport; }
/* CANVAS */

View file

@ -3046,6 +3046,33 @@ void EditorNode::_load_error_notify(void* p_ud,const String& p_text) {
}
bool EditorNode::_find_scene_in_use(Node* p_node,const String& p_path) const {
if (p_node->get_filename()==p_path) {
return true;
}
for(int i=0;i<p_node->get_child_count();i++) {
if (_find_scene_in_use(p_node->get_child(i),p_path)) {
return true;
}
}
return false;
}
bool EditorNode::is_scene_in_use(const String& p_path) {
Node *es = get_edited_scene();
if (es)
return _find_scene_in_use(es,p_path);
return false;
}
void EditorNode::register_editor_types() {
ObjectTypeDB::register_type<EditorPlugin>();
@ -3212,6 +3239,7 @@ Error EditorNode::export_platform(const String& p_platform, const String& p_path
}
EditorNode::EditorNode() {
EditorHelp::generate_doc(); //before any editor classes are crated

View file

@ -398,6 +398,9 @@ class EditorNode : public Node {
static Vector<EditorNodeInitCallback> _init_callbacks;
bool _find_scene_in_use(Node* p_node,const String& p_path) const;
protected:
void _notification(int p_what);
static void _bind_methods();
@ -485,6 +488,10 @@ public:
static void progress_task_step_bg(const String& p_task,int p_step=-1);
static void progress_end_task_bg(const String& p_task);
void save_scene(String p_file) { _save_scene(p_file); }
bool is_scene_in_use(const String& p_path);
void scan_import_changes();
EditorNode();
~EditorNode();

View file

@ -42,6 +42,9 @@ void EditorReImportDialog::popup_reimport() {
List<String> ril;
EditorFileSystem::get_singleton()->get_changed_sources(&ril);
scene_must_save=false;
TreeItem *root = tree->create_item();
for(List<String>::Element *E=ril.front();E;E=E->next()) {
@ -52,11 +55,34 @@ void EditorReImportDialog::popup_reimport() {
item->set_tooltip(0,E->get());
item->set_checked(0,true);
item->set_editable(0,true);
items.push_back(item);
String name = E->get();
if (EditorFileSystem::get_singleton()->get_file_type(name)=="PackedScene" && EditorNode::get_singleton()->is_scene_in_use(name)) {
scene_must_save=true;
}
}
if (scene_must_save) {
if (EditorNode::get_singleton()->get_edited_scene() && EditorNode::get_singleton()->get_edited_scene()->get_filename()=="") {
error->set_text("Current scene must be saved to re-import.");
error->popup_centered(Size2(250,100));
get_ok()->set_text("Re-Import");
get_ok()->set_disabled(true);
return;
}
get_ok()->set_disabled(false);
get_ok()->set_text("Save & Re-Import");
} else {
get_ok()->set_text("Re-Import");
get_ok()->set_disabled(false);
}
popup_centered(Size2(600,400));
@ -70,7 +96,17 @@ void EditorReImportDialog::ok_pressed() {
error->popup_centered(Size2(250,100));
return;
}
EditorProgress ep("reimport","Re-Importing",items.size());
String reload_fname;
if (scene_must_save && EditorNode::get_singleton()->get_edited_scene()) {
reload_fname = EditorNode::get_singleton()->get_edited_scene()->get_filename();
EditorNode::get_singleton()->save_scene(reload_fname);
EditorNode::get_singleton()->clear_scene();
}
for(int i=0;i<items.size();i++) {
String it = items[i]->get_metadata(0);
@ -87,6 +123,9 @@ void EditorReImportDialog::ok_pressed() {
}
}
if (reload_fname!="") {
EditorNode::get_singleton()->load_scene(reload_fname);
}
EditorFileSystem::get_singleton()->scan_sources();
}
@ -100,5 +139,6 @@ EditorReImportDialog::EditorReImportDialog() {
set_title("Re-Import Changed Resources");
error = memnew( AcceptDialog);
add_child(error);
scene_must_save=false;
}

View file

@ -39,6 +39,7 @@ class EditorReImportDialog : public ConfirmationDialog {
Tree *tree;
Vector<TreeItem*> items;
AcceptDialog *error;
bool scene_must_save;
void ok_pressed();
public:

View file

@ -36,6 +36,8 @@
#include "io/resource_saver.h"
#include "scene/3d/mesh_instance.h"
#include "scene/3d/room_instance.h"
#include "scene/3d/body_shape.h"
#include "scene/3d/physics_body.h"
#include "scene/3d/portal.h"
#include "os/os.h"
@ -104,7 +106,9 @@ class EditorSceneImportDialog : public ConfirmationDialog {
struct FlagInfo {
int value;
const char *category;
const char *text;
bool defval;
};
static const FlagInfo scene_flag_names[];
@ -626,22 +630,24 @@ void EditorSceneImportDialog::_bind_methods() {
const EditorSceneImportDialog::FlagInfo EditorSceneImportDialog::scene_flag_names[]={
{EditorSceneImportPlugin::SCENE_FLAG_CREATE_COLLISIONS,"Create Collisions (-col},-colonly)"},
{EditorSceneImportPlugin::SCENE_FLAG_CREATE_PORTALS,"Create Portals (-portal)"},
{EditorSceneImportPlugin::SCENE_FLAG_CREATE_ROOMS,"Create Rooms (-room)"},
{EditorSceneImportPlugin::SCENE_FLAG_SIMPLIFY_ROOMS,"Simplify Rooms"},
{EditorSceneImportPlugin::SCENE_FLAG_CREATE_BILLBOARDS,"Create Billboards (-bb)"},
{EditorSceneImportPlugin::SCENE_FLAG_CREATE_IMPOSTORS,"Create Impostors (-imp:dist)"},
{EditorSceneImportPlugin::SCENE_FLAG_CREATE_LODS,"Create LODs (-lod:dist)"},
{EditorSceneImportPlugin::SCENE_FLAG_CREATE_CARS,"Create Cars (-car)"},
{EditorSceneImportPlugin::SCENE_FLAG_CREATE_WHEELS,"Create Car Wheels (-wheel)"},
{EditorSceneImportPlugin::SCENE_FLAG_DETECT_ALPHA,"Set Alpha in Materials (-alpha)"},
{EditorSceneImportPlugin::SCENE_FLAG_DETECT_VCOLOR,"Set Vert. Color in Materials (-vcol)"},
{EditorSceneImportPlugin::SCENE_FLAG_REMOVE_NOIMP,"Remove Nodes (-noimp)"},
{EditorSceneImportPlugin::SCENE_FLAG_IMPORT_ANIMATIONS,"Import Animations"},
{EditorSceneImportPlugin::SCENE_FLAG_COMPRESS_GEOMETRY,"Compress Geometry"},
{EditorSceneImportPlugin::SCENE_FLAG_GENERATE_TANGENT_ARRAYS,"Force Generation of Tangent Arrays"},
{-1,NULL}
{EditorSceneImportPlugin::SCENE_FLAG_REMOVE_NOIMP,"Actions","Remove Nodes (-noimp)",true},
{EditorSceneImportPlugin::SCENE_FLAG_IMPORT_ANIMATIONS,"Actions","Import Animations",true},
{EditorSceneImportPlugin::SCENE_FLAG_COMPRESS_GEOMETRY,"Actions","Compress Geometry",false},
{EditorSceneImportPlugin::SCENE_FLAG_GENERATE_TANGENT_ARRAYS,"Actions","Force Generation of Tangent Arrays",false},
{EditorSceneImportPlugin::SCENE_FLAG_DETECT_ALPHA,"Materials","Set Alpha in Materials (-alpha)",true},
{EditorSceneImportPlugin::SCENE_FLAG_DETECT_VCOLOR,"Materials","Set Vert. Color in Materials (-vcol)",true},
{EditorSceneImportPlugin::SCENE_FLAG_LINEARIZE_DIFFUSE_TEXTURES,"Actions","SRGB->Linear Of Diffuse Textures",false},
{EditorSceneImportPlugin::SCENE_FLAG_CREATE_COLLISIONS,"Create","Create Collisions (-col},-colonly)",true},
{EditorSceneImportPlugin::SCENE_FLAG_CREATE_PORTALS,"Create","Create Portals (-portal)",true},
{EditorSceneImportPlugin::SCENE_FLAG_CREATE_ROOMS,"Create","Create Rooms (-room)",true},
{EditorSceneImportPlugin::SCENE_FLAG_SIMPLIFY_ROOMS,"Create","Simplify Rooms",false},
{EditorSceneImportPlugin::SCENE_FLAG_CREATE_BILLBOARDS,"Create","Create Billboards (-bb)",true},
{EditorSceneImportPlugin::SCENE_FLAG_CREATE_IMPOSTORS,"Create","Create Impostors (-imp:dist)",true},
{EditorSceneImportPlugin::SCENE_FLAG_CREATE_LODS,"Create","Create LODs (-lod:dist)",true},
{EditorSceneImportPlugin::SCENE_FLAG_CREATE_CARS,"Create","Create Cars (-car)",true},
{EditorSceneImportPlugin::SCENE_FLAG_CREATE_WHEELS,"Create","Create Car Wheels (-wheel)",true},
{EditorSceneImportPlugin::SCENE_FLAG_CREATE_NAVMESH,"Create","Create Navigation Meshes (-navmesh)",true},
{-1,NULL,NULL,false}
};
@ -717,19 +723,25 @@ EditorSceneImportDialog::EditorSceneImportDialog(EditorNode *p_editor, EditorSce
TreeItem *root = import_options->create_item(NULL);
import_options->set_hide_root(true);
TreeItem *importopts = import_options->create_item(root);
importopts->set_text(0,"Import:");
const FlagInfo* fn=scene_flag_names;
Map<String,TreeItem*> categories;
while(fn->text) {
TreeItem *opt = import_options->create_item(importopts);
String cat = fn->category;
TreeItem *parent;
if (!categories.has(cat)) {
parent = import_options->create_item(root);
parent->set_text(0,cat);
categories[cat]=parent;
} else {
parent=categories[cat];
}
TreeItem *opt = import_options->create_item(parent);
opt->set_cell_mode(0,TreeItem::CELL_MODE_CHECK);
opt->set_checked(0,true);
opt->set_checked(0,fn->defval);
opt->set_editable(0,true);
opt->set_text(0,fn->text);
opt->set_metadata(0,fn->value);
@ -875,7 +887,7 @@ static String _fixstr(const String& p_what,const String& p_str) {
void EditorSceneImportPlugin::_find_resources(const Variant& p_var,Set<Ref<ImageTexture> >& image_map) {
void EditorSceneImportPlugin::_find_resources(const Variant& p_var, Map<Ref<ImageTexture>, bool> &image_map) {
switch(p_var.get_type()) {
@ -885,9 +897,9 @@ void EditorSceneImportPlugin::_find_resources(const Variant& p_var,Set<Ref<Image
Ref<Resource> res = p_var;
if (res.is_valid()) {
if (res->is_type("Texture")) {
if (res->is_type("Texture") && !image_map.has(res)) {
image_map.insert(res);
image_map.insert(res,false);
} else {
@ -898,7 +910,17 @@ void EditorSceneImportPlugin::_find_resources(const Variant& p_var,Set<Ref<Image
for(List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) {
if (E->get().type==Variant::OBJECT || E->get().type==Variant::ARRAY || E->get().type==Variant::DICTIONARY) {
_find_resources(res->get(E->get().name),image_map);
if (E->get().type==Variant::OBJECT && res->cast_to<FixedMaterial>() && (E->get().name=="textures/diffuse" || E->get().name=="textures/detail" || E->get().name=="textures/emission")) {
Ref<ImageTexture> tex =res->get(E->get().name);
if (tex.is_valid()) {
image_map.insert(tex,true);
}
} else {
_find_resources(res->get(E->get().name),image_map);
}
}
}
@ -938,7 +960,7 @@ void EditorSceneImportPlugin::_find_resources(const Variant& p_var,Set<Ref<Image
}
Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>,Ref<Shape> > &collision_map,uint32_t p_flags,Set<Ref<ImageTexture> >& image_map) {
Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>,Ref<Shape> > &collision_map,uint32_t p_flags,Map<Ref<ImageTexture>,bool >& image_map) {
// children first..
for(int i=0;i<p_node->get_child_count();i++) {
@ -1010,6 +1032,36 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>
}
}
if (p_flags&(SCENE_FLAG_DETECT_ALPHA|SCENE_FLAG_DETECT_VCOLOR) && p_node->cast_to<MeshInstance>()) {
MeshInstance *mi = p_node->cast_to<MeshInstance>();
Ref<Mesh> m = mi->get_mesh();
if (m.is_valid()) {
for(int i=0;i<m->get_surface_count();i++) {
Ref<FixedMaterial> mat = m->surface_get_material(i);
if (!mat.is_valid())
continue;
if (p_flags&SCENE_FLAG_DETECT_ALPHA && _teststr(mat->get_name(),"alpha")) {
mat->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA,true);
mat->set_name(_fixstr(mat->get_name(),"alpha"));
}
if (p_flags&SCENE_FLAG_DETECT_VCOLOR && _teststr(mat->get_name(),"vcol")) {
mat->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY,true);
mat->set_name(_fixstr(mat->get_name(),"vcol"));
}
}
}
}
if (p_flags&SCENE_FLAG_REMOVE_NOIMP && p_node->cast_to<AnimationPlayer>()) {
//remove animations referencing non-importable nodes
AnimationPlayer *ap = p_node->cast_to<AnimationPlayer>();
@ -1141,21 +1193,42 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>
MeshInstance *mi = p_node->cast_to<MeshInstance>();
Node * col = mi->create_trimesh_collision_node();
ERR_FAIL_COND_V(!col,NULL);
col->set_name(_fixstr(name,"colonly"));
col->cast_to<Spatial>()->set_transform(mi->get_transform());
p_node->replace_by(col);
memdelete(p_node);
p_node=col;
StaticBody *sb = col->cast_to<StaticBody>();
CollisionShape *colshape = memnew( CollisionShape);
colshape->set_shape(sb->get_shape(0));
colshape->set_name("shape");
sb->add_child(colshape);
colshape->set_owner(p_node->get_owner());
} else if (p_flags&SCENE_FLAG_CREATE_COLLISIONS &&_teststr(name,"col") && p_node->cast_to<MeshInstance>()) {
MeshInstance *mi = p_node->cast_to<MeshInstance>();
mi->set_name(_fixstr(name,"col"));
mi->create_trimesh_collision();
Node *col= mi->create_trimesh_collision_node();
ERR_FAIL_COND_V(!col,NULL);
col->set_name("col");
p_node->add_child(col);
StaticBody *sb = col->cast_to<StaticBody>();
CollisionShape *colshape = memnew( CollisionShape);
colshape->set_shape(sb->get_shape(0));
colshape->set_name("shape");
sb->add_child(colshape);
colshape->set_owner(p_node->get_owner());
} else if (p_flags&SCENE_FLAG_CREATE_ROOMS && _teststr(name,"room") && p_node->cast_to<MeshInstance>()) {
@ -1346,92 +1419,122 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>
}
return p_node;
}
void EditorSceneImportPlugin::_merge_node(Node *p_node,Node*p_root,Node *p_existing,Set<Ref<Resource> >& checked_resources) {
void EditorSceneImportPlugin::_merge_existing_node(Node *p_node,Node *p_imported_scene,Set<Ref<Resource> >& checked_resources,Set<Node*> &checked_nodes) {
NodePath path = p_root->get_path_to(p_node);
NodePath path = p_node->get_import_path();
bool valid=false;
if (!path.is_empty() && p_imported_scene->has_node(path)) {
if (p_existing->has_node(path)) {
Node *imported_node = p_imported_scene->get_node(path);
Node *existing = p_existing->get_node(path);
if (existing->get_type()==p_node->get_type()) {
if (imported_node->get_type()==p_node->get_type()) {
//same thing, check what it is
if (existing->get_type()=="MeshInstance") {
if (p_node->get_type()=="MeshInstance") {
//merge mesh instance, this is a special case!
MeshInstance *mi_existing=existing->cast_to<MeshInstance>();
MeshInstance *mi_imported=imported_node->cast_to<MeshInstance>();
MeshInstance *mi_node=p_node->cast_to<MeshInstance>();
Ref<Mesh> mesh_existing = mi_existing->get_mesh();
Ref<Mesh> mesh_imported = mi_imported->get_mesh();
Ref<Mesh> mesh_node = mi_node->get_mesh();
if (mesh_existing.is_null() || checked_resources.has(mesh_node)) {
if (mesh_node.is_null() && mesh_imported.is_valid()) {
if (mesh_node.is_valid())
mi_existing->set_mesh(mesh_node);
} else if (mesh_node.is_valid()) {
mi_node->set_mesh(mesh_imported);
//mesh will always be overwritten, so check materials from original
} else if (mesh_node.is_valid() && mesh_imported.is_valid()) {
for(int i=0;i<mesh_node->get_surface_count();i++) {
if (checked_resources.has(mesh_imported)) {
String name = mesh_node->surface_get_name(i);
mi_node->set_mesh(mesh_imported);
} else {
//mix up meshes
//import new geometry but keep materials
for(int i=0;i<mesh_imported->get_surface_count();i++) {
if (name!="") {
String name = mesh_imported->surface_get_name(i);
for(int j=0;j<mesh_existing->get_surface_count();j++) {
for(int j=0;j<mesh_node->get_surface_count();j++) {
Ref<Material> keep;
Ref<Material> mat = mesh_node->surface_get_material(j);
if (mat.is_valid() && mesh_node->surface_get_name(j)==name ) {
if (name==mesh_existing->surface_get_name(j)) {
Ref<Material> mat = mesh_existing->surface_get_material(j);
if (mat.is_valid()) {
if (mat->get_path()!="" && mat->get_path().begins_with("res://") && mat->get_path().find("::")==-1) {
keep=mat; //mat was loaded from file
} else if (mat->is_edited()) {
keep=mat; //mat was edited
}
}
mesh_imported->surface_set_material(i,mat);
break;
}
if (keep.is_valid())
mesh_node->surface_set_material(i,keep); //kept
}
}
// was imported, do nothing further
checked_resources.insert(mesh_imported);
mi_node->set_mesh(mesh_imported);
}
mi_existing->set_mesh(mesh_node); //always overwrite mesh
checked_resources.insert(mesh_node);
}
} else if (existing->get_type()=="Path") {
Path *path_existing =existing->cast_to<Path>();
} else if (p_node->get_type()=="Path") {
//for paths, overwrite path
Path *path_imported =imported_node->cast_to<Path>();
Path *path_node =p_node->cast_to<Path>();
if (path_node->get_curve().is_valid()) {
if (path_imported->get_curve().is_valid()) {
if (!path_existing->get_curve().is_valid() || !path_existing->get_curve()->is_edited()) {
path_existing->set_curve(path_node->get_curve());
}
path_node->set_curve(path_imported->get_curve());
}
} else if (p_node->get_type()=="Portal") {
//for paths, overwrite path
Portal *portal_imported =imported_node->cast_to<Portal>();
Portal *portal_node =p_node->cast_to<Portal>();
portal_node->set_shape( portal_imported->get_shape() );
} else if (p_node->get_type()=="Room") {
//for paths, overwrite path
Room *room_imported =imported_node->cast_to<Room>();
Room *room_node =p_node->cast_to<Room>();
room_node->set_room( room_imported->get_room() );
} else if (p_node->get_type()=="CollisionShape") {
//for paths, overwrite path
CollisionShape *collision_imported =imported_node->cast_to<CollisionShape>();
CollisionShape *collision_node =p_node->cast_to<CollisionShape>();
collision_node->set_shape( collision_imported->get_shape() );
}
}
valid=true;
} else {
if (p_node->cast_to<Spatial>() && imported_node->cast_to<Spatial>()) {
//apply transform if changed
Spatial *snode = p_node->cast_to<Spatial>();
Spatial *simp = imported_node->cast_to<Spatial>();
if (snode->get_import_transform() == snode->get_transform()) {
//not moved, apply new
snode->set_import_transform(simp->get_transform());
snode->set_transform(simp->get_transform());
} else if (snode->get_import_transform() == simp->get_import_transform()) {
//do nothing, nothing changed keep local changes
} else {
//changed both, imported and edited, merge
Transform local_xform = snode->get_import_transform().affine_inverse() * snode->get_transform();
snode->set_import_transform(simp->get_import_transform());
snode->set_transform(simp->get_import_transform() * local_xform);
}
}
checked_nodes.insert(imported_node);
}
#if 0
else {
if (p_node!=p_root && p_existing->has_node(p_root->get_path_to(p_node->get_parent()))) {
@ -1461,25 +1564,76 @@ void EditorSceneImportPlugin::_merge_node(Node *p_node,Node*p_root,Node *p_exist
}
}
#endif
if (valid) {
for(int i=0;i<p_node->get_child_count();i++) {
_merge_node(p_node->get_child(i),p_root,p_existing,checked_resources);
}
for(int i=0;i<p_node->get_child_count();i++) {
_merge_existing_node(p_node->get_child(i),p_imported_scene,checked_resources,checked_nodes);
}
}
void EditorSceneImportPlugin::_merge_scenes(Node *p_existing,Node *p_new) {
void EditorSceneImportPlugin::_add_new_nodes(Node *p_node,Node *p_imported,Node *p_imported_scene,Set<Node*> &checked_nodes) {
for(int i=0;i<p_imported->get_child_count();i++) {
Node *imported_node = p_imported->get_child(i);
if (imported_node->get_owner()!=p_imported_scene)
continue; //end of the road
Vector<StringName> nn;
nn.push_back(imported_node->get_name());
NodePath imported_path(nn,false);
if (!p_node->has_node(imported_path) && !checked_nodes.has(imported_node)) {
//not there, re-add it
//add it.. because not existing in existing scene
Object *o = ObjectTypeDB::instance(imported_node->get_type());
Node *n=NULL;
if (o)
n=o->cast_to<Node>();
if (n) {
List<PropertyInfo> pl;
imported_node->get_property_list(&pl);
for(List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) {
if (!(E->get().usage&PROPERTY_USAGE_STORAGE))
continue;
n->set( E->get().name, imported_node->get(E->get().name) );
}
p_node->add_child(n);
}
}
if (p_node->has_node(imported_path)) {
Node *other_node = p_node->get_node(imported_path);
_add_new_nodes(other_node,imported_node,p_imported_scene,checked_nodes);
}
}
}
void EditorSceneImportPlugin::_merge_scenes(Node *p_node,Node *p_imported) {
Set<Ref<Resource> > checked_resources;
_merge_node(p_new,p_new,p_existing,checked_resources);
Set<Node*> checked_nodes;
_merge_existing_node(p_node,p_imported,checked_resources,checked_nodes);
_add_new_nodes(p_node,p_imported,p_imported,checked_nodes);
//add existing.. ?
}
#if 0
Error EditorImport::import_scene(const String& p_path,const String& p_dest_path,const String& p_resource_path,uint32_t p_flags,ImageFormat p_image_format,ImageCompression p_image_compression,uint32_t p_image_flags,float p_quality,uint32_t animation_flags,Node **r_scene,Ref<EditorPostImport> p_post_import) {
@ -1488,6 +1642,26 @@ Error EditorImport::import_scene(const String& p_path,const String& p_dest_path,
}
#endif
void EditorSceneImportPlugin::_tag_import_paths(Node *p_scene,Node *p_node) {
if (p_scene!=p_node && p_node->get_owner()!=p_scene)
return;
NodePath path = p_scene->get_path_to(p_node);
p_node->set_import_path( path );
Spatial *snode=p_node->cast_to<Spatial>();
if (snode) {
snode->set_import_transform(snode->get_transform());
}
for(int i=0;i<p_node->get_child_count();i++) {
_tag_import_paths(p_scene,p_node->get_child(i));
}
}
Error EditorSceneImportPlugin::import1(const Ref<ResourceImportMetadata>& p_from,Node**r_node,List<String> *r_missing) {
@ -1549,6 +1723,8 @@ Error EditorSceneImportPlugin::import1(const Ref<ResourceImportMetadata>& p_from
return err;
}
_tag_import_paths(scene,scene);
*r_node=scene;
return OK;
}
@ -1566,6 +1742,7 @@ Error EditorSceneImportPlugin::import2(Node *scene, const String& p_dest_path, c
bool merge = !bool(from->get_option("reimport"));
from->set_source_md5(0,FileAccess::get_md5(src_path));
from->set_editor(get_name());
@ -1576,7 +1753,7 @@ Error EditorSceneImportPlugin::import2(Node *scene, const String& p_dest_path, c
Ref<ResourceImportMetadata> imd = memnew(ResourceImportMetadata);
Set< Ref<ImageTexture> > imagemap;
Map< Ref<ImageTexture>,bool > imagemap;
scene=_fix_node(scene,scene,collision_map,scene_flags,imagemap);
@ -1622,12 +1799,12 @@ Error EditorSceneImportPlugin::import2(Node *scene, const String& p_dest_path, c
int image_flags = from->get_option("texture_flags");
float image_quality = from->get_option("texture_quality");
for (Set< Ref<ImageTexture> >::Element *E=imagemap.front();E;E=E->next()) {
for (Map< Ref<ImageTexture>,bool >::Element *E=imagemap.front();E;E=E->next()) {
//texture could be converted to something more useful for 3D, that could load individual mipmaps and stuff
//but not yet..
Ref<ImageTexture> texture = E->get();
Ref<ImageTexture> texture = E->key();
ERR_CONTINUE(!texture.is_valid());
@ -1657,7 +1834,10 @@ Error EditorSceneImportPlugin::import2(Node *scene, const String& p_dest_path, c
Ref<ResourceImportMetadata> imd = memnew( ResourceImportMetadata );
print_line("flags: "+itos(image_flags));
imd->set_option("flags",image_flags);
uint32_t flags = image_flags;
if (E->get())
flags|=EditorTextureImportPlugin::IMAGE_FLAG_CONVERT_TO_LINEAR;
imd->set_option("flags",flags);
imd->set_option("format",image_format);
imd->set_option("quality",image_quality);
imd->set_option("atlas",false);
@ -1697,11 +1877,14 @@ Error EditorSceneImportPlugin::import2(Node *scene, const String& p_dest_path, c
if (merge) {
print_line("MERGING?????");
progress.step("Merging..",103);
FileAccess *fa = FileAccess::create(FileAccess::ACCESS_FILESYSTEM);
FileAccess *fa = FileAccess::create(FileAccess::ACCESS_RESOURCES);
print_line("OPEN IN FS: "+p_dest_path);
if (fa->file_exists(p_dest_path)) {
print_line("TRY REALLY TO MERGE?");
//try to merge
Ref<PackedScene> s = ResourceLoader::load(p_dest_path);
@ -1711,7 +1894,7 @@ Error EditorSceneImportPlugin::import2(Node *scene, const String& p_dest_path, c
if (existing) {
_merge_scenes(scene,existing);
_merge_scenes(existing,scene);
memdelete(scene);
scene=existing;

View file

@ -99,11 +99,14 @@ class EditorSceneImportPlugin : public EditorImportPlugin {
Vector<Ref<EditorSceneImporter> > importers;
void _find_resources(const Variant& p_var,Set<Ref<ImageTexture> >& image_map);
Node* _fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>,Ref<Shape> > &collision_map,uint32_t p_flags,Set<Ref<ImageTexture> >& image_map);
void _merge_node(Node *p_node,Node*p_root,Node *p_existing,Set<Ref<Resource> >& checked_resources);
void _merge_scenes(Node *p_existing,Node *p_new);
void _find_resources(const Variant& p_var,Map<Ref<ImageTexture>,bool >& image_map);
Node* _fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>,Ref<Shape> > &collision_map,uint32_t p_flags,Map<Ref<ImageTexture>,bool >& image_map);
void _merge_existing_node(Node *p_node,Node *p_imported_scene,Set<Ref<Resource> >& checked_resources,Set<Node*> &checked_nodes);
void _add_new_nodes(Node *p_node,Node *p_imported,Node *p_imported_scene,Set<Node*> &checked_nodes);
void _merge_scenes(Node *p_node, Node *p_imported);
void _tag_import_paths(Node *p_scene,Node *p_node);
public:
@ -120,11 +123,13 @@ public:
SCENE_FLAG_CREATE_WHEELS=1<<9,
SCENE_FLAG_DETECT_ALPHA=1<<15,
SCENE_FLAG_DETECT_VCOLOR=1<<16,
SCENE_FLAG_CREATE_NAVMESH=1<<17,
SCENE_FLAG_REMOVE_NOIMP=1<<24,
SCENE_FLAG_IMPORT_ANIMATIONS=1<<25,
SCENE_FLAG_COMPRESS_GEOMETRY=1<<26,
SCENE_FLAG_GENERATE_TANGENT_ARRAYS=1<<27,
SCENE_FLAG_LINEARIZE_DIFFUSE_TEXTURES=1<<28,
};