Browse Source

-fixes to navigation, so edge-merging is more flexible on conflict
-add tab support to richtextlabel
-some click fixes to audio stream resampled
-ability to import largetextures (dialog)

Juan Linietsky 10 years ago
parent
commit
ab99671bb8

+ 77 - 0
core/image.cpp

@@ -1124,6 +1124,7 @@ void Image::create( const char ** p_xpm ) {
 }
 #define DETECT_ALPHA_MAX_TRESHOLD 254
 #define DETECT_ALPHA_MIN_TRESHOLD 2
+
 #define DETECT_ALPHA( m_value )\
 { \
 	uint8_t value=m_value;\
@@ -1136,6 +1137,82 @@ void Image::create( const char ** p_xpm ) {
 	}\
 }
 
+#define DETECT_NON_ALPHA( m_value )\
+{ \
+	uint8_t value=m_value;\
+	if (value>0) {\
+		\
+		detected=true;\
+		break;\
+	}\
+}
+
+
+bool Image::is_invisible() const {
+
+	if (format==FORMAT_GRAYSCALE ||
+	    format==FORMAT_RGB ||
+	    format==FORMAT_INDEXED)
+		return false;
+
+	int len = data.size();
+
+	if (len==0)
+		return true;
+
+	if (format >= FORMAT_YUV_422 && format <= FORMAT_YUV_444)
+		return false;
+
+	int w,h;
+	_get_mipmap_offset_and_size(1,len,w,h);
+
+	DVector<uint8_t>::Read r = data.read();
+	const unsigned char *data_ptr=r.ptr();
+
+	bool detected=false;
+
+	switch(format) {
+		case FORMAT_INTENSITY: {
+
+			for(int i=0;i<len;i++) {
+				DETECT_NON_ALPHA(data_ptr[i]);
+			}
+		} break;
+		case FORMAT_GRAYSCALE_ALPHA: {
+
+
+			for(int i=0;i<(len>>1);i++) {
+				DETECT_NON_ALPHA(data_ptr[(i<<1)+1]);
+			}
+
+		} break;
+		case FORMAT_RGBA: {
+
+			for(int i=0;i<(len>>2);i++) {
+				DETECT_NON_ALPHA(data_ptr[(i<<2)+3])
+			}
+
+		} break;
+		case FORMAT_INDEXED: {
+
+			return false;
+		} break;
+		case FORMAT_INDEXED_ALPHA: {
+
+			return false;
+		} break;
+		case FORMAT_PVRTC2_ALPHA:
+		case FORMAT_PVRTC4_ALPHA:
+		case FORMAT_BC2:
+		case FORMAT_BC3: {
+			detected=true;
+		} break;
+		default: {}
+	}
+
+	return !detected;
+}
+
 Image::AlphaMode Image::detect_alpha() const {
 
 	if (format==FORMAT_GRAYSCALE ||

+ 1 - 0
core/image.h

@@ -305,6 +305,7 @@ public:
 	};
 
 	AlphaMode detect_alpha() const;
+	bool is_invisible() const;
 
 	void put_indexed_pixel(int p_x, int p_y, uint8_t p_idx,int p_mipmap=0);
 	uint8_t get_indexed_pixel(int p_x, int p_y,int p_mipmap=0) const;

+ 26 - 3
scene/2d/navigation2d.cpp

@@ -91,9 +91,13 @@ void Navigation2D::_navpoly_link(int p_id) {
 			} else {
 
 				if (C->get().B!=NULL) {
-					print_line(String()+_get_vertex(ek.a)+" -> "+_get_vertex(ek.b));
+					ConnectionPending pending;
+					pending.polygon=&p;
+					pending.edge=j;
+					p.edges[j].P=C->get().pending.push_back(pending);
+					continue;
+					//print_line(String()+_get_vertex(ek.a)+" -> "+_get_vertex(ek.b));
 				}
-				ERR_CONTINUE(C->get().B!=NULL); //wut
 
 				C->get().B=&p;
 				C->get().B_edge=j;
@@ -133,7 +137,12 @@ void Navigation2D::_navpoly_unlink(int p_id) {
 			EdgeKey ek(edges[i].point,edges[next].point);
 			Map<EdgeKey,Connection>::Element *C=connections.find(ek);
 			ERR_CONTINUE(!C);
-			if (C->get().B) {
+
+			if (edges[i].P) {
+				C->get().pending.erase(edges[i].P);
+				edges[i].P=NULL;
+
+			} else if (C->get().B) {
 				//disconnect
 
 				C->get().B->edges[C->get().B_edge].C=NULL;
@@ -149,6 +158,20 @@ void Navigation2D::_navpoly_unlink(int p_id) {
 				C->get().B=NULL;
 				C->get().B_edge=-1;
 
+				if (C->get().pending.size()) {
+					//reconnect if something is pending
+					ConnectionPending cp = C->get().pending.front()->get();
+					C->get().pending.pop_front();
+
+					C->get().B=cp.polygon;
+					C->get().B_edge=cp.edge;
+					C->get().A->edges[C->get().A_edge].C=cp.polygon;
+					C->get().A->edges[C->get().A_edge].C_edge=cp.edge;
+					cp.polygon->edges[cp.edge].C=C->get().A;
+					cp.polygon->edges[cp.edge].C_edge=C->get().A_edge;
+					cp.polygon->edges[cp.edge].P=NULL;
+				}
+
 			} else {
 				connections.erase(C);
 				//erase

+ 11 - 1
scene/2d/navigation2d.h

@@ -41,7 +41,13 @@ class Navigation2D : public Node2D {
 
 
 	struct NavMesh;
+	struct Polygon;
 
+	struct ConnectionPending {
+
+		Polygon *polygon;
+		int edge;
+	};
 
 	struct Polygon {
 
@@ -49,7 +55,8 @@ class Navigation2D : public Node2D {
 			Point point;
 			Polygon *C; //connection
 			int C_edge;
-			Edge() { C=NULL; C_edge=-1; }
+			List<ConnectionPending>::Element *P;
+			Edge() { C=NULL; C_edge=-1; P=NULL; }
 		};
 
 		Vector<Edge> edges;
@@ -72,6 +79,9 @@ class Navigation2D : public Node2D {
 		int A_edge;
 		Polygon *B;
 		int B_edge;
+
+		List<ConnectionPending> pending;
+
 		Connection() { A=NULL; B=NULL; A_edge=-1; B_edge=-1;}
 	};
 

+ 27 - 3
scene/3d/navigation.cpp

@@ -85,9 +85,14 @@ void Navigation::_navmesh_link(int p_id) {
 			} else {
 
 				if (C->get().B!=NULL) {
-					print_line(String()+_get_vertex(ek.a)+" -> "+_get_vertex(ek.b));
+					ConnectionPending pending;
+					pending.polygon=&p;
+					pending.edge=j;
+					p.edges[j].P=C->get().pending.push_back(pending);
+					continue;
+					//print_line(String()+_get_vertex(ek.a)+" -> "+_get_vertex(ek.b));
 				}
-				ERR_CONTINUE(C->get().B!=NULL); //wut
+				//ERR_CONTINUE(C->get().B!=NULL); //wut
 
 				C->get().B=&p;
 				C->get().B_edge=j;
@@ -126,8 +131,13 @@ void Navigation::_navmesh_unlink(int p_id) {
 
 			EdgeKey ek(edges[i].point,edges[next].point);
 			Map<EdgeKey,Connection>::Element *C=connections.find(ek);
+
 			ERR_CONTINUE(!C);
-			if (C->get().B) {
+
+			if (edges[i].P) {
+				C->get().pending.erase(edges[i].P);
+				edges[i].P=NULL;
+			} else if (C->get().B) {
 				//disconnect
 
 				C->get().B->edges[C->get().B_edge].C=NULL;
@@ -143,6 +153,20 @@ void Navigation::_navmesh_unlink(int p_id) {
 				C->get().B=NULL;
 				C->get().B_edge=-1;
 
+				if (C->get().pending.size()) {
+					//reconnect if something is pending
+					ConnectionPending cp = C->get().pending.front()->get();
+					C->get().pending.pop_front();
+
+					C->get().B=cp.polygon;
+					C->get().B_edge=cp.edge;
+					C->get().A->edges[C->get().A_edge].C=cp.polygon;
+					C->get().A->edges[C->get().A_edge].C_edge=cp.edge;
+					cp.polygon->edges[cp.edge].C=C->get().A;
+					cp.polygon->edges[cp.edge].C_edge=C->get().A_edge;
+					cp.polygon->edges[cp.edge].P=NULL;
+				}
+
 			} else {
 				connections.erase(C);
 				//erase

+ 12 - 1
scene/3d/navigation.h

@@ -42,6 +42,13 @@ class Navigation : public Spatial {
 
 
 	struct NavMesh;
+	struct Polygon;
+
+	struct ConnectionPending {
+
+		Polygon *polygon;
+		int edge;
+	};
 
 
 	struct Polygon {
@@ -50,7 +57,8 @@ class Navigation : public Spatial {
 			Point point;
 			Polygon *C; //connection
 			int C_edge;
-			Edge() { C=NULL; C_edge=-1; }
+			List<ConnectionPending>::Element *P;
+			Edge() { C=NULL; C_edge=-1; P=NULL; }
 		};
 
 		Vector<Edge> edges;
@@ -72,6 +80,9 @@ class Navigation : public Spatial {
 		int A_edge;
 		Polygon *B;
 		int B_edge;
+
+		List<ConnectionPending> pending;
+
 		Connection() { A=NULL; B=NULL; A_edge=-1; B_edge=-1;}
 	};
 

+ 52 - 6
scene/gui/rich_text_label.cpp

@@ -58,7 +58,7 @@ RichTextLabel::Item *RichTextLabel::_get_next_item(Item* p_item) {
 
 }
 
-void RichTextLabel::_process_line(int &y, int p_width, int p_line, ProcessMode p_mode,const Ref<Font> &p_base_font,const Color &p_base_color,const Point2i& p_click_pos,Item **r_click_item,int *r_click_char,bool *r_outside) {
+void RichTextLabel::_process_line(int &y, int p_width, int p_line, ProcessMode p_mode,const Ref<Font> &p_base_font,const Color &p_base_color,const Point2i& p_click_pos,Item **r_click_item,int *r_click_char,bool *r_outside,int p_char_count) {
 
 	RID ci;
 	if (r_outside)
@@ -80,6 +80,7 @@ void RichTextLabel::_process_line(int &y, int p_width, int p_line, ProcessMode p
 	int line=0;
 	int spaces=0;
 
+
 	if (p_mode!=PROCESS_CACHE) {
 
 		ERR_FAIL_INDEX(line,l.offset_caches.size());
@@ -89,6 +90,7 @@ void RichTextLabel::_process_line(int &y, int p_width, int p_line, ProcessMode p
 	if (p_mode==PROCESS_CACHE) {
 		l.offset_caches.clear();
 		l.height_caches.clear();
+		l.char_count=0;
 	}
 
 	int wofs=margin;
@@ -216,6 +218,8 @@ if (m_height > line_height) {\
 						underline=true;
 					}
 
+				} else if (p_mode==PROCESS_CACHE) {
+					l.char_count+=text->text.length();
 				}
 
 				rchar=0;
@@ -326,18 +330,23 @@ if (m_height > line_height) {\
 									}
 								}
 
-								int cw;
+								int cw=0;
+
+								bool visible = visible_characters<0 || p_char_count<visible_characters;
 
 								if (selected) {
 
 									cw = font->get_char_size(c[i],c[i+1]).x;
 									draw_rect(Rect2(pofs,y,cw,lh),selection_bg);
-									font->draw_char(ci,Point2(pofs,y+lh-(fh-ascent)),c[i],c[i+1],selection_fg);
+									if (visible)
+										font->draw_char(ci,Point2(pofs,y+lh-(fh-ascent)),c[i],c[i+1],selection_fg);
 
 								} else {
-									cw=font->draw_char(ci,Point2(pofs,y+lh-(fh-ascent)),c[i],c[i+1],color);
+									if (visible)
+										cw=font->draw_char(ci,Point2(pofs,y+lh-(fh-ascent)),c[i],c[i+1],color);
 								}
 
+								p_char_count++;
 								if (c[i]=='\t') {
 									cw=tab_size*font->get_char_size(' ').width;
 								}
@@ -371,6 +380,8 @@ if (m_height > line_height) {\
 				lh=0;
 				if (p_mode!=PROCESS_CACHE)
 					lh = line<l.height_caches.size()?l.height_caches[line]:1;
+				else
+					l.char_count+=1; //images count as chars too
 
 				ItemImage *img = static_cast<ItemImage*>(it);
 
@@ -383,9 +394,12 @@ if (m_height > line_height) {\
 
 				ENSURE_WIDTH( img->image->get_width() );
 
-				if (p_mode==PROCESS_DRAW) {
+				bool visible = visible_characters<0 || p_char_count<visible_characters;
+
+				if (p_mode==PROCESS_DRAW && visible) {
 					img->image->draw(ci,Point2(wofs,y+lh-font->get_descent()-img->image->get_height()));
 				}
+				p_char_count++;
 
 				ADVANCE( img->image->get_width() );
 				CHECK_HEIGHT( (img->image->get_height()+font->get_descent()) );
@@ -556,11 +570,13 @@ void RichTextLabel::_notification(int p_what) {
 			//todo, change to binary search
 
 			int from_line = 0;
+			int total_chars = 0;
 			while (from_line<lines.size()) {
 
 				if (lines[from_line].height_accum_cache>=ofs)
 					break;
 				from_line++;
+				total_chars+=lines[from_line].char_count;
 			}
 
 			if (from_line>=lines.size())
@@ -572,7 +588,8 @@ void RichTextLabel::_notification(int p_what) {
 
 			while (y<size.height && from_line<lines.size()) {
 
-				_process_line(y,size.width-scroll_w,from_line,PROCESS_DRAW,base_font,base_color);
+				_process_line(y,size.width-scroll_w,from_line,PROCESS_DRAW,base_font,base_color,Point2i(),NULL,NULL,NULL,total_chars);
+				total_chars+=lines[from_line].char_count;
 				from_line++;
 			}
 		}
@@ -1688,11 +1705,17 @@ void RichTextLabel::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("set_bbcode","text"),&RichTextLabel::set_bbcode);
 	ObjectTypeDB::bind_method(_MD("get_bbcode"),&RichTextLabel::get_bbcode);
 
+	ObjectTypeDB::bind_method(_MD("set_visible_characters","amount"),&RichTextLabel::set_visible_characters);
+	ObjectTypeDB::bind_method(_MD("get_visible_characters"),&RichTextLabel::get_visible_characters);
+
+	ObjectTypeDB::bind_method(_MD("get_total_character_count"),&RichTextLabel::get_total_character_count);
+
 	ObjectTypeDB::bind_method(_MD("set_use_bbcode","enable"),&RichTextLabel::set_use_bbcode);
 	ObjectTypeDB::bind_method(_MD("is_using_bbcode"),&RichTextLabel::is_using_bbcode);
 
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL,"bbcode/enabled"),_SCS("set_use_bbcode"),_SCS("is_using_bbcode"));
 	ADD_PROPERTY(PropertyInfo(Variant::STRING,"bbcode/bbcode",PROPERTY_HINT_MULTILINE_TEXT),_SCS("set_bbcode"),_SCS("get_bbcode"));
+	ADD_PROPERTY(PropertyInfo(Variant::INT,"visible_characters",PROPERTY_HINT_RANGE,"-1,128000,1"),_SCS("set_visible_characters"),_SCS("get_visible_characters"));
 
 	ADD_SIGNAL( MethodInfo("meta_clicked",PropertyInfo(Variant::NIL,"meta")));
 
@@ -1719,6 +1742,27 @@ void RichTextLabel::_bind_methods() {
 
 }
 
+
+void RichTextLabel::set_visible_characters(int p_visible) {
+
+	visible_characters=p_visible;
+	update();
+}
+
+int RichTextLabel::get_visible_characters() const {
+
+	return visible_characters;
+}
+int RichTextLabel::get_total_character_count() const {
+
+	int tc=0;
+	for(int i=0;i<lines.size();i++)
+		tc+=lines[i].char_count;
+
+	return tc;
+}
+
+
 RichTextLabel::RichTextLabel() {
 
 
@@ -1756,6 +1800,8 @@ RichTextLabel::RichTextLabel() {
 	selection.active=false;
 	selection.enabled=false;
 
+	visible_characters=-1;
+
 }
 
 RichTextLabel::~RichTextLabel() {

+ 10 - 3
scene/gui/rich_text_label.h

@@ -171,8 +171,9 @@ private:
 		Vector<int> space_caches;
 		int height_cache;
 		int height_accum_cache;
+		int char_count;
 
-		Line() { from=NULL; }
+		Line() { from=NULL; char_count=0; }
 	};
 
 
@@ -223,10 +224,10 @@ private:
 	Selection selection;
 
 
+	int visible_characters;
 
 
-
-	void _process_line(int &y, int p_width, int p_line, ProcessMode p_mode,const Ref<Font> &p_base_font,const Color &p_base_color,const Point2i& p_click_pos=Point2i(),Item **r_click_item=NULL,int *r_click_char=NULL,bool *r_outside=NULL);
+	void _process_line(int &y, int p_width, int p_line, ProcessMode p_mode,const Ref<Font> &p_base_font,const Color &p_base_color,const Point2i& p_click_pos=Point2i(),Item **r_click_item=NULL,int *r_click_char=NULL,bool *r_outside=NULL,int p_char_count=0);
 	void _find_click(const Point2i& p_click,Item **r_click_item=NULL,int *r_click_char=NULL,bool *r_outside=NULL);
 
 
@@ -246,6 +247,8 @@ private:
 	bool use_bbcode;
 	String bbcode;
 
+
+
 protected:
 	void _notification(int p_what);
 
@@ -304,6 +307,10 @@ public:
 	void set_bbcode(const String& p_bbcode);
 	String get_bbcode() const;
 
+	void set_visible_characters(int p_visible);
+	int get_visible_characters() const;
+	int get_total_character_count() const;
+
 	RichTextLabel();
 	~RichTextLabel();
 };

+ 55 - 0
scene/resources/audio_stream_resampled.cpp

@@ -230,6 +230,51 @@ bool AudioStreamResampled::mix(int32_t *p_dest, int p_frames) {
 			case 4: read=_resample<4>(p_dest,todo,increment); break;
 			case 6: read=_resample<6>(p_dest,todo,increment); break;
 		}
+#if 1
+		//end of stream, fadeout
+		int remaining = p_frames-todo;
+		if (remaining && todo>0) {
+
+			//print_line("fadeout");
+			for(int c=0;c<channels;c++) {
+
+				for(int i=0;i<todo;i++) {
+
+					int32_t samp = p_dest[i*channels+c]>>8;
+					uint32_t mul = (todo-i) * 256 /todo;
+					//print_line("mul: "+itos(i)+" "+itos(mul));
+					p_dest[i*channels+c]=samp*mul;
+				}
+
+			}
+
+		}
+
+#else
+		int remaining = p_frames-todo;
+		if (remaining && todo>0) {
+
+
+			for(int c=0;c<channels;c++) {
+
+				int32_t from = p_dest[(todo-1)*channels+c]>>8;
+
+				for(int i=0;i<remaining;i++) {
+
+					uint32_t mul = (remaining-i) * 256 /remaining;
+					p_dest[(todo+i)*channels+c]=from*mul;
+				}
+
+			}
+
+		}
+#endif
+
+		//zero out what remains there to avoid glitches
+		for(int i=todo*channels;i<int(p_frames)*channels;i++) {
+
+			p_dest[i]=0;
+		}
 
 		if (read>rb_todo)
 			read=rb_todo;
@@ -316,6 +361,16 @@ AudioStreamResampled::AudioStreamResampled() {
 	rb=NULL;
 	offset=0;
 	read_buf=NULL;
+	rb_read_pos=0;
+	rb_write_pos=0;
+
+	rb_bits=0;
+	rb_len=0;
+	rb_mask=0;
+	read_buff_len=0;
+	channels=0;
+	mix_rate=0;
+
 }
 
 AudioStreamResampled::~AudioStreamResampled() {

+ 2 - 1
tools/editor/editor_node.cpp

@@ -4229,8 +4229,9 @@ EditorNode::EditorNode() {
 
 
 	editor_import_export->add_import_plugin( Ref<EditorTextureImportPlugin>( memnew(EditorTextureImportPlugin(this,EditorTextureImportPlugin::MODE_TEXTURE_2D) )));
-	editor_import_export->add_import_plugin( Ref<EditorTextureImportPlugin>( memnew(EditorTextureImportPlugin(this,EditorTextureImportPlugin::MODE_TEXTURE_3D) )));
 	editor_import_export->add_import_plugin( Ref<EditorTextureImportPlugin>( memnew(EditorTextureImportPlugin(this,EditorTextureImportPlugin::MODE_ATLAS) )));
+	editor_import_export->add_import_plugin( Ref<EditorTextureImportPlugin>( memnew(EditorTextureImportPlugin(this,EditorTextureImportPlugin::MODE_LARGE) )));
+	editor_import_export->add_import_plugin( Ref<EditorTextureImportPlugin>( memnew(EditorTextureImportPlugin(this,EditorTextureImportPlugin::MODE_TEXTURE_3D) )));
 	Ref<EditorSceneImportPlugin> _scene_import =  memnew(EditorSceneImportPlugin(this) );
 	Ref<EditorSceneImporterCollada> _collada_import = memnew( EditorSceneImporterCollada);
 	_scene_import->add_importer(_collada_import);

+ 333 - 34
tools/editor/io_plugins/editor_texture_import_plugin.cpp

@@ -144,6 +144,8 @@ void EditorImportTextureOptions::_changed() {
 
 void EditorImportTextureOptions::_bind_methods() {
 
+	print_line("bind toptions");
+
 	ObjectTypeDB::bind_method("_changed",&EditorImportTextureOptions::_changed);
 	ObjectTypeDB::bind_method("_changedp",&EditorImportTextureOptions::_changedp);
 
@@ -219,7 +221,6 @@ EditorImportTextureOptions::EditorImportTextureOptions() {
 		fname++;
 	}
 
-
 	add_margin_child("Texture Options",flags,true);
 
 	notice_for_2d = memnew( Label );
@@ -253,11 +254,14 @@ class EditorTextureImportDialog : public ConfirmationDialog  {
 	OptionButton *texture_action;
 	ConfirmationDialog *error_dialog;
 	CheckButton *crop_source;
+	SpinBox *size;
 	bool atlas;
+	bool large;
 
 	EditorTextureImportPlugin *plugin;
 
 	void _choose_files(const Vector<String>& p_path);
+	void _choose_file(const String& p_path);
 	void _choose_save_dir(const String& p_path);
 	void _browse();
 	void _browse_target();
@@ -272,7 +276,7 @@ public:
 
 	Error import(const String& p_from, const String& p_to, const String& p_preset);
 	void popup_import(const String &p_from=String());
-	EditorTextureImportDialog(EditorTextureImportPlugin *p_plugin=NULL,bool p_2d=false,bool p_atlas=false);
+	EditorTextureImportDialog(EditorTextureImportPlugin *p_plugin=NULL,bool p_2d=false,bool p_atlas=false,bool p_large=false);
 };
 
 
@@ -301,6 +305,15 @@ void EditorTextureImportDialog::_choose_files(const Vector<String>& p_path) {
 	import_path->set_text(files);
 
 }
+
+
+
+void EditorTextureImportDialog::_choose_file(const String& p_path) {
+
+
+	import_path->set_text(p_path);
+
+}
 void EditorTextureImportDialog::_choose_save_dir(const String& p_path) {
 
 	save_path->set_text(p_path);
@@ -336,7 +349,7 @@ void EditorTextureImportDialog::_import() {
 	}
 
 
-	if (!atlas && !DirAccess::exists(save_path->get_text())) {
+	if (!atlas && !large && !DirAccess::exists(save_path->get_text())) {
 		error_dialog->set_text("Target path must exist.");
 		error_dialog->popup_centered_minsize();
 		return;
@@ -362,6 +375,8 @@ void EditorTextureImportDialog::_import() {
 		imd->set_option("flags",texture_options->get_flags());
 		imd->set_option("quality",texture_options->get_quality());
 		imd->set_option("atlas",true);
+		imd->set_option("atlas_size",int(size->get_val()));
+		imd->set_option("large",false);
 		imd->set_option("crop",crop_source->is_pressed());
 
 		Error err = plugin->import(dst_file,imd);
@@ -372,7 +387,38 @@ void EditorTextureImportDialog::_import() {
 			return;
 
 		}
+	} else if (large) { //atlas
+
+		if (files.size()!=1) {
+
+			error_dialog->set_text("Only one file is required for large texture");
+			error_dialog->popup_centered(Size2(200,100));
+			return;
+
+		}
+		String dst_file = dst_path;
+		//dst_file=dst_file.basename()+".tex";
+		Ref<ResourceImportMetadata> imd = memnew( ResourceImportMetadata );
+		//imd->set_editor();
+		for(int i=0;i<files.size();i++) {
+			imd->add_source(EditorImportPlugin::validate_source_path(files[i]));
+		}
+		imd->set_option("format",texture_options->get_format());
+		imd->set_option("flags",texture_options->get_flags());
+		imd->set_option("quality",texture_options->get_quality());
+		imd->set_option("atlas",false);
+		imd->set_option("large",true);
+		imd->set_option("large_cell_size",int(size->get_val()));
+		imd->set_option("crop",crop_source->is_pressed());
 
+		Error err = plugin->import(dst_file,imd);
+		if (err) {
+
+			error_dialog->set_text("Error importing: "+dst_file.get_file());
+			error_dialog->popup_centered(Size2(200,100));
+			return;
+
+		}
 	} else {
 
 
@@ -387,6 +433,8 @@ void EditorTextureImportDialog::_import() {
 			imd->set_option("flags",texture_options->get_flags());
 			imd->set_option("quality",texture_options->get_quality());
 			imd->set_option("atlas",false);
+			imd->set_option("large",false);
+
 			Error err = plugin->import(dst_file,imd);
 			if (err) {
 
@@ -408,7 +456,7 @@ void EditorTextureImportDialog::_browse() {
 
 void EditorTextureImportDialog::_browse_target() {
 
-	if (atlas) {
+	if (atlas || large) {
 		save_file_select->popup_centered_ratio();
 	} else {
 		save_select->popup_centered_ratio();
@@ -424,7 +472,7 @@ void EditorTextureImportDialog::popup_import(const String& p_from) {
 		Ref<ResourceImportMetadata> rimd = ResourceLoader::load_import_metadata(p_from);
 		ERR_FAIL_COND(!rimd.is_valid());
 
-		if (plugin->get_mode()==EditorTextureImportPlugin::MODE_ATLAS)
+		if (plugin->get_mode()==EditorTextureImportPlugin::MODE_ATLAS || plugin->get_mode()==EditorTextureImportPlugin::MODE_LARGE)
 			save_path->set_text(p_from);
 		else
 			save_path->set_text(p_from.get_base_dir());
@@ -474,6 +522,7 @@ void EditorTextureImportDialog::_bind_methods() {
 
 
 	ObjectTypeDB::bind_method("_choose_files",&EditorTextureImportDialog::_choose_files);
+	ObjectTypeDB::bind_method("_choose_file",&EditorTextureImportDialog::_choose_file);
 	ObjectTypeDB::bind_method("_choose_save_dir",&EditorTextureImportDialog::_choose_save_dir);
 	ObjectTypeDB::bind_method("_import",&EditorTextureImportDialog::_import);
 	ObjectTypeDB::bind_method("_browse",&EditorTextureImportDialog::_browse);
@@ -481,21 +530,25 @@ void EditorTextureImportDialog::_bind_methods() {
 //	ADD_SIGNAL( MethodInfo("imported",PropertyInfo(Variant::OBJECT,"scene")) );
 }
 
-EditorTextureImportDialog::EditorTextureImportDialog(EditorTextureImportPlugin* p_plugin, bool p_2d, bool p_atlas) {
+EditorTextureImportDialog::EditorTextureImportDialog(EditorTextureImportPlugin* p_plugin, bool p_2d, bool p_atlas,bool p_large) {
 
 
 	atlas=p_atlas;
+	large=p_large;
 	plugin=p_plugin;
 	set_title("Import Textures");
 
-	texture_options = memnew( EditorImportTextureOptions );;
-	VBoxContainer *vbc = texture_options;
+
+	VBoxContainer *vbc = memnew(VBoxContainer);
 	add_child(vbc);
 	set_child_rect(vbc);
 
 
 	VBoxContainer *source_vb=memnew(VBoxContainer);
-	vbc->add_margin_child("Source Texture(s):",source_vb);
+	if (large)
+		vbc->add_margin_child("Source Texture:",source_vb);
+	else
+		vbc->add_margin_child("Source Texture(s):",source_vb);
 
 	HBoxContainer *hbc = memnew( HBoxContainer );
 	source_vb->add_child(hbc);
@@ -510,6 +563,7 @@ EditorTextureImportDialog::EditorTextureImportDialog(EditorTextureImportPlugin*
 	if (!p_atlas)
 		crop_source->hide();
 
+
 	Button * import_choose = memnew( Button );
 	import_choose->set_text(" .. ");
 	hbc->add_child(import_choose);
@@ -519,6 +573,19 @@ EditorTextureImportDialog::EditorTextureImportDialog(EditorTextureImportPlugin*
 	hbc = memnew( HBoxContainer );
 	vbc->add_margin_child("Target Path:",hbc);
 
+	size = memnew( SpinBox );
+	size->set_min(128);
+	size->set_max(16384);
+
+	if (p_atlas) {
+		size->set_val(2048);
+		vbc->add_margin_child("Max Texture size:",size);
+	} else {
+		size->set_val(256);
+		vbc->add_margin_child("Cell Size:",size);
+	}
+
+
 	save_path = memnew( LineEdit );
 	save_path->set_h_size_flags(SIZE_EXPAND_FILL);
 	hbc->add_child(save_path);
@@ -532,15 +599,22 @@ EditorTextureImportDialog::EditorTextureImportDialog(EditorTextureImportPlugin*
 	file_select = memnew(FileDialog);
 	file_select->set_access(FileDialog::ACCESS_FILESYSTEM);
 	add_child(file_select);
-	file_select->set_mode(FileDialog::MODE_OPEN_FILES);
+	if (!large)
+		file_select->set_mode(FileDialog::MODE_OPEN_FILES);
+	else
+		file_select->set_mode(FileDialog::MODE_OPEN_FILE);
 	file_select->connect("files_selected", this,"_choose_files");
+	file_select->connect("file_selected", this,"_choose_file");
 
 	save_file_select = memnew(FileDialog);
 	save_file_select->set_access(FileDialog::ACCESS_RESOURCES);
 	add_child(save_file_select);
 	save_file_select->set_mode(FileDialog::MODE_SAVE_FILE);
 	save_file_select->clear_filters();
-	save_file_select->add_filter("*.tex;Base Atlas Texture");
+	if (large)
+		save_file_select->add_filter("*.ltex;Large Texture");
+	else
+		save_file_select->add_filter("*.tex;Base Atlas Texture");
 	save_file_select->connect("file_selected", this,"_choose_save_dir");
 
 	save_select = memnew(	EditorDirDialog );
@@ -553,8 +627,8 @@ EditorTextureImportDialog::EditorTextureImportDialog(EditorTextureImportPlugin*
 	get_ok()->set_text("Import");
 
 	//move stuff up
-	for(int i=0;i<4;i++)
-		vbc->move_child( vbc->get_child( vbc->get_child_count() -1), 0);
+	//for(int i=0;i<4;i++)
+	//	vbc->move_child( vbc->get_child( vbc->get_child_count() -1), 0);
 
 	error_dialog = memnew ( ConfirmationDialog );
 	add_child(error_dialog);
@@ -563,13 +637,24 @@ EditorTextureImportDialog::EditorTextureImportDialog(EditorTextureImportPlugin*
 
 	set_hide_on_ok(false);
 
+	texture_options = memnew( EditorImportTextureOptions );;
+	vbc->add_child(texture_options);
+	texture_options->set_v_size_flags(SIZE_EXPAND_FILL);
+
 	if (atlas) {
 
 		texture_options->set_flags(EditorTextureImportPlugin::IMAGE_FLAG_FIX_BORDER_ALPHA|EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS|EditorTextureImportPlugin::IMAGE_FLAG_FILTER);
 		texture_options->set_quality(0.7);
 		texture_options->set_format(EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_DISK_LOSSY);
-		texture_options->show_2d_notice();
+		//texture_options->show_2d_notice();
 		set_title("Import Textures for Atlas (2D)");
+	} else if (large) {
+
+		texture_options->set_flags(EditorTextureImportPlugin::IMAGE_FLAG_FIX_BORDER_ALPHA|EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS|EditorTextureImportPlugin::IMAGE_FLAG_FILTER);
+		texture_options->set_quality(0.7);
+		texture_options->set_format(EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_DISK_LOSSLESS);
+		texture_options->show_2d_notice();
+		set_title("Import Large Textures (2D)");
 
 	} else if (p_2d) {
 
@@ -615,12 +700,17 @@ String EditorTextureImportPlugin::get_name() const {
 
 			return "texture_atlas";
 		} break;
+		case MODE_LARGE: {
+
+			return "texture_large";
+		} break;
 
 	}
 
 	return "";
 
 }
+
 String EditorTextureImportPlugin::get_visible_name() const {
 
 	switch(mode) {
@@ -635,7 +725,11 @@ String EditorTextureImportPlugin::get_visible_name() const {
 		} break;
 		case MODE_ATLAS: {
 
-			return "Atlas Texture";
+			return "2D Atlas Texture";
+		} break;
+		case MODE_LARGE: {
+
+			return "2D Large Texture";
 		} break;
 
 	}
@@ -733,6 +827,135 @@ Error EditorTextureImportPlugin::import(const String& p_path, const Ref<Resource
 	return import2(p_path,p_from,EditorExportPlatform::IMAGE_COMPRESSION_BC,false);
 }
 
+
+Error EditorTextureImportPlugin::_process_texture_data(Ref<ImageTexture> &texture,int format, float quality,int flags,EditorExportPlatform::ImageCompression p_compr,int tex_flags,int shrink)  {
+
+
+	if (format==IMAGE_FORMAT_COMPRESS_DISK_LOSSLESS || format==IMAGE_FORMAT_COMPRESS_DISK_LOSSY) {
+
+		Image image=texture->get_data();
+		ERR_FAIL_COND_V(image.empty(),ERR_INVALID_DATA);
+
+		bool has_alpha=image.detect_alpha();
+		if (!has_alpha && image.get_format()==Image::FORMAT_RGBA) {
+
+			image.convert(Image::FORMAT_RGB);
+
+		}
+
+		if (image.get_format()==Image::FORMAT_RGBA && flags&IMAGE_FLAG_FIX_BORDER_ALPHA) {
+
+			image.fix_alpha_edges();
+		}
+
+		if (image.get_format()==Image::FORMAT_RGBA && flags&IMAGE_FLAG_PREMULT_ALPHA) {
+
+			image.premultiply_alpha();
+		}
+
+		if (flags&IMAGE_FLAG_CONVERT_NORMAL_TO_XY) {
+			image.normalmap_to_xy();
+		}
+
+		//if ((image.get_format()==Image::FORMAT_RGB || image.get_format()==Image::FORMAT_RGBA) && flags&IMAGE_FLAG_CONVERT_TO_LINEAR) {
+
+		//	image.srgb_to_linear();
+		//}
+
+		if (shrink>1) {
+
+			int orig_w=image.get_width();
+			int orig_h=image.get_height();
+			image.resize(orig_w/shrink,orig_h/shrink);
+			texture->create_from_image(image,tex_flags);
+			texture->set_size_override(Size2(orig_w,orig_h));
+
+
+		} else {
+
+			texture->create_from_image(image,tex_flags);
+		}
+
+
+		if (format==IMAGE_FORMAT_COMPRESS_DISK_LOSSLESS) {
+			texture->set_storage(ImageTexture::STORAGE_COMPRESS_LOSSLESS);
+		} else {
+			texture->set_storage(ImageTexture::STORAGE_COMPRESS_LOSSY);
+		}
+
+
+
+		texture->set_lossy_storage_quality(quality);
+
+
+	} else {
+
+
+		Image image=texture->get_data();
+		ERR_FAIL_COND_V(image.empty(),ERR_INVALID_DATA);
+
+
+		bool has_alpha=image.detect_alpha();
+		if (!has_alpha && image.get_format()==Image::FORMAT_RGBA) {
+
+			image.convert(Image::FORMAT_RGB);
+
+		}
+
+		if (image.get_format()==Image::FORMAT_RGBA && flags&IMAGE_FLAG_FIX_BORDER_ALPHA) {
+
+			image.fix_alpha_edges();
+		}
+
+		if (image.get_format()==Image::FORMAT_RGBA && flags&IMAGE_FLAG_PREMULT_ALPHA) {
+
+			image.premultiply_alpha();
+		}
+
+		if (flags&IMAGE_FLAG_CONVERT_NORMAL_TO_XY) {
+			image.normalmap_to_xy();
+		}
+
+		//if ((image.get_format()==Image::FORMAT_RGB || image.get_format()==Image::FORMAT_RGBA) && flags&IMAGE_FLAG_CONVERT_TO_LINEAR) {
+//
+		//	print_line("CONVERT BECAUSE: "+itos(flags));
+		//	image.srgb_to_linear();
+		//}
+
+		int orig_w=image.get_width();
+		int orig_h=image.get_height();
+
+		if (shrink>1) {
+			image.resize(orig_w/shrink,orig_h/shrink);
+			texture->create_from_image(image,tex_flags);
+			texture->set_size_override(Size2(orig_w,orig_h));
+		}
+
+		if (!(flags&IMAGE_FLAG_NO_MIPMAPS)) {
+			image.generate_mipmaps();
+
+		}
+
+		if (format!=IMAGE_FORMAT_UNCOMPRESSED) {
+
+			compress_image(p_compr,image,flags&IMAGE_FLAG_COMPRESS_EXTRA);
+		}
+
+
+		texture->create_from_image(image,tex_flags);
+
+
+		if (shrink>1 || (format!=IMAGE_FORMAT_UNCOMPRESSED && (image.get_width()!=orig_w || image.get_height()!=orig_h))) {
+			texture->set_size_override(Size2(orig_w,orig_h));
+		}
+
+		//uint32_t save_flags=ResourceSaver::FLAG_COMPRESS;
+	}
+
+	return OK;
+}
+
+
 Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<ResourceImportMetadata>& p_from,EditorExportPlatform::ImageCompression p_compr, bool p_external){
 
 
@@ -744,8 +967,11 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
 	Ref<ImageTexture> texture;
 	Vector<Ref<AtlasTexture> > atlases;
 	bool atlas = from->get_option("atlas");
+	bool large = from->get_option("large");
 
 	int flags=from->get_option("flags");
+	int format=from->get_option("format");
+	float quality=from->get_option("quality");
 
 	uint32_t tex_flags=0;
 
@@ -765,7 +991,80 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
 	if (from->has_option("shrink"))
 		shrink=from->get_option("shrink");
 
-	if (atlas) {
+	if (large) {
+		ERR_FAIL_COND_V(from->get_source_count()!=1,ERR_INVALID_PARAMETER);
+
+		String src_path = EditorImportPlugin::expand_source_path(from->get_source_path(0));
+
+
+		int cell_size=from->get_option("large_cell_size");
+		ERR_FAIL_COND_V(cell_size<128 || cell_size>16384,ERR_CANT_OPEN);
+
+		EditorProgress pg("ltex","Import Large Texture",3);
+
+		pg.step("Load Source Image",0);
+		Image img;
+		Error err = ImageLoader::load_image(src_path,&img);
+		if (err) {
+			return err;
+		}
+
+		pg.step("Slicing",1);
+
+		Map<Vector2,Image> pieces;
+		for(int i=0;i<img.get_width();i+=cell_size) {
+			int w = MIN(img.get_width()-i,cell_size);
+			for(int j=0;j<img.get_height();j+=cell_size) {
+				int h = MIN(img.get_height()-j,cell_size);
+
+				Image piece(w,h,0,img.get_format());
+				piece.blit_rect(img,Rect2(i,j,w,h),Point2(0,0));
+				if (!piece.is_invisible()) {
+					pieces[Vector2(i,j)]=piece;
+					//print_line("ADDING PIECE AT "+Vector2(i,j));
+				}
+			}
+		}
+
+		Ref<LargeTexture> existing;
+		if (ResourceCache::has(p_path)) {
+			existing = ResourceCache::get(p_path);
+		}
+
+		if (existing.is_valid()) {
+			existing->clear();
+		} else {
+			existing = Ref<LargeTexture>(memnew( LargeTexture ));
+		}
+
+		existing->set_size(Size2(img.get_width(),img.get_height()));
+		pg.step("Inserting",2);
+
+		for (Map<Vector2,Image>::Element *E=pieces.front();E;E=E->next()) {
+
+			Ref<ImageTexture> imgtex = Ref<ImageTexture>( memnew( ImageTexture ) );
+			imgtex->create_from_image(E->get(),tex_flags);
+			_process_texture_data(imgtex,format,quality,flags,p_compr,tex_flags,shrink);
+			existing->add_piece(E->key(),imgtex);
+		}
+
+		if (!p_external) {
+			from->set_editor(get_name());
+			existing->set_path(p_path);
+			existing->set_import_metadata(from);
+		}
+		pg.step("Saving",3);
+
+		err = ResourceSaver::save(p_path,existing);
+		if (err!=OK) {
+			EditorNode::add_io_error("Couldn't save large texture: "+p_path);
+			return err;
+		}
+
+		return OK;
+
+
+	} else if (atlas) {
 
 		//prepare atlas!
 		Vector< Image > sources;
@@ -897,8 +1196,6 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
 	}
 
 
-	int format=from->get_option("format");
-	float quality=from->get_option("quality");
 
 	if (!p_external) {
 		from->set_editor(get_name());
@@ -932,7 +1229,11 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
 		}
 	}
 
+	bool compress=false;
+#if 1
 
+	_process_texture_data(texture,format,quality,flags,p_compr,tex_flags,shrink);
+#else
 	if (format==IMAGE_FORMAT_COMPRESS_DISK_LOSSLESS || format==IMAGE_FORMAT_COMPRESS_DISK_LOSSY) {
 
 		Image image=texture->get_data();
@@ -989,13 +1290,6 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
 
 		texture->set_lossy_storage_quality(quality);
 
-		Error err = ResourceSaver::save(p_path,texture);
-
-		if (err!=OK) {
-			EditorNode::add_io_error("Couldn't save converted texture: "+p_path);
-			return err;
-		}
-
 
 	} else {
 
@@ -1058,15 +1352,20 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
 			texture->set_size_override(Size2(orig_w,orig_h));
 		}
 
-		uint32_t save_flags=ResourceSaver::FLAG_COMPRESS;
+		compress=true;
 
-		Error err = ResourceSaver::save(p_path,texture,save_flags);
-		if (err!=OK) {
-			EditorNode::add_io_error("Couldn't save converted texture: "+p_path);
-			return err;
-		}
 
 	}
+#endif
+	uint32_t save_flags=0;
+	if (compress)
+		save_flags=ResourceSaver::FLAG_COMPRESS;
+
+	Error err = ResourceSaver::save(p_path,texture,save_flags);
+	if (err!=OK) {
+		EditorNode::add_io_error("Couldn't save converted texture: "+p_path);
+		return err;
+	}
 
 	return OK;
 }
@@ -1255,14 +1554,14 @@ Vector<uint8_t> EditorTextureImportPlugin::custom_export(const String& p_path, c
 }
 
 
-EditorTextureImportPlugin *EditorTextureImportPlugin::singleton[3]={NULL,NULL,NULL};
+EditorTextureImportPlugin *EditorTextureImportPlugin::singleton[EditorTextureImportPlugin::MODE_MAX]={NULL,NULL,NULL,NULL};
 
 EditorTextureImportPlugin::EditorTextureImportPlugin(EditorNode *p_editor, Mode p_mode) {
 
 	singleton[p_mode]=this;
 	editor=p_editor;
-	mode=p_mode;
-	dialog = memnew( EditorTextureImportDialog(this,p_mode==MODE_TEXTURE_2D || p_mode==MODE_ATLAS,p_mode==MODE_ATLAS) );
+	mode=p_mode;	
+	dialog = memnew( EditorTextureImportDialog(this,p_mode==MODE_TEXTURE_2D || p_mode==MODE_ATLAS || p_mode==MODE_LARGE,p_mode==MODE_ATLAS,p_mode==MODE_LARGE) );
 	editor->get_gui_base()->add_child(dialog);
 
 }

+ 5 - 3
tools/editor/io_plugins/editor_texture_import_plugin.h

@@ -56,7 +56,9 @@ public:
 	enum Mode {
 		MODE_TEXTURE_2D,
 		MODE_TEXTURE_3D,
-		MODE_ATLAS
+		MODE_ATLAS,
+		MODE_LARGE,
+		MODE_MAX
 	};
 
 
@@ -65,10 +67,10 @@ private:
 	Mode mode;
 	EditorNode *editor;
 	EditorTextureImportDialog *dialog;
-	static EditorTextureImportPlugin *singleton[3];
+	static EditorTextureImportPlugin *singleton[MODE_MAX];
 	//used by other importers such as mesh
 
-
+	Error _process_texture_data(Ref<ImageTexture> &texture, int format, float quality, int flags,EditorExportPlatform::ImageCompression p_compr,int tex_flags,int shrink);
 	void compress_image(EditorExportPlatform::ImageCompression p_mode,Image& image,bool p_smaller);
 public: