Browse Source

Many separate fixes to ensure non power of 2 textures work on GLES2, closes #25897 and many others

Juan Linietsky 6 years ago
parent
commit
74d0ed2236

+ 22 - 2
drivers/gles2/rasterizer_canvas_gles2.cpp

@@ -499,6 +499,23 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
 				glDisableVertexAttribArray(VS::ARRAY_COLOR);
 				glVertexAttrib4fv(VS::ARRAY_COLOR, r->modulate.components);
 
+				bool can_tile = true;
+				if (r->texture.is_valid() && r->flags & CANVAS_RECT_TILE && !storage->config.support_npot_repeat_mipmap) {
+					// workaround for when setting tiling does not work due to hardware limitation
+
+					RasterizerStorageGLES2::Texture *texture = storage->texture_owner.getornull(r->texture);
+
+					if (texture) {
+
+						texture = texture->get_ptr();
+
+						if (next_power_of_2(texture->alloc_width) != texture->alloc_width && next_power_of_2(texture->alloc_height) != texture->alloc_height) {
+							state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_FORCE_REPEAT, true);
+							can_tile = false;
+						}
+					}
+				}
+
 				// On some widespread Nvidia cards, the normal draw method can produce some
 				// flickering in draw_rect and especially TileMap rendering (tiles randomly flicker).
 				// See GH-9913.
@@ -559,7 +576,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
 
 						bool untile = false;
 
-						if (r->flags & CANVAS_RECT_TILE && !(texture->flags & VS::TEXTURE_FLAG_REPEAT)) {
+						if (can_tile && r->flags & CANVAS_RECT_TILE && !(texture->flags & VS::TEXTURE_FLAG_REPEAT)) {
 							glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
 							glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
 							untile = true;
@@ -616,7 +633,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
 
 						bool untile = false;
 
-						if (r->flags & CANVAS_RECT_TILE && !(tex->flags & VS::TEXTURE_FLAG_REPEAT)) {
+						if (can_tile && r->flags & CANVAS_RECT_TILE && !(tex->flags & VS::TEXTURE_FLAG_REPEAT)) {
 							glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
 							glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
 							untile = true;
@@ -664,6 +681,9 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
 					glBindBuffer(GL_ARRAY_BUFFER, 0);
 					glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
 				}
+
+				state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_FORCE_REPEAT, false);
+
 			} break;
 
 			case Item::Command::TYPE_NINEPATCH: {

+ 74 - 18
drivers/gles2/rasterizer_storage_gles2.cpp

@@ -67,7 +67,7 @@ void RasterizerStorageGLES2::bind_quad_array() const {
 	glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
 }
 
-Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed) const {
+Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_will_need_resize) const {
 
 	r_gl_format = 0;
 	Ref<Image> image = p_image;
@@ -195,7 +195,7 @@ Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_
 		} break;
 		case Image::FORMAT_DXT1: {
 
-			if (config.s3tc_supported) {
+			if (config.s3tc_supported && !p_will_need_resize) {
 				r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT1_EXT;
 				r_gl_format = GL_RGBA;
 				r_gl_type = GL_UNSIGNED_BYTE;
@@ -207,7 +207,7 @@ Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_
 		} break;
 		case Image::FORMAT_DXT3: {
 
-			if (config.s3tc_supported) {
+			if (config.s3tc_supported && !p_will_need_resize) {
 				r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT3_EXT;
 				r_gl_format = GL_RGBA;
 				r_gl_type = GL_UNSIGNED_BYTE;
@@ -219,7 +219,7 @@ Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_
 		} break;
 		case Image::FORMAT_DXT5: {
 
-			if (config.s3tc_supported) {
+			if (config.s3tc_supported && !p_will_need_resize) {
 				r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT;
 				r_gl_format = GL_RGBA;
 				r_gl_type = GL_UNSIGNED_BYTE;
@@ -269,7 +269,7 @@ Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_
 		} break;
 		case Image::FORMAT_ETC: {
 
-			if (config.etc1_supported) {
+			if (config.etc1_supported && !p_will_need_resize) {
 				r_gl_internal_format = _EXT_ETC1_RGB8_OES;
 				r_gl_format = GL_RGBA;
 				r_gl_type = GL_UNSIGNED_BYTE;
@@ -315,17 +315,38 @@ Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_
 	if (need_decompress) {
 
 		if (!image.is_null()) {
+
 			image = image->duplicate();
+			print_line("decompressing...");
 			image->decompress();
 			ERR_FAIL_COND_V(image->is_compressed(), image);
-			image->convert(Image::FORMAT_RGBA8);
+			switch (image->get_format()) {
+				case Image::FORMAT_RGB8: {
+					r_gl_format = GL_RGB;
+					r_gl_internal_format = GL_RGB;
+					r_gl_type = GL_UNSIGNED_BYTE;
+					r_real_format = Image::FORMAT_RGB8;
+					r_compressed = false;
+				} break;
+				case Image::FORMAT_RGBA8: {
+					r_gl_format = GL_RGBA;
+					r_gl_internal_format = GL_RGBA;
+					r_gl_type = GL_UNSIGNED_BYTE;
+					r_real_format = Image::FORMAT_RGBA8;
+					r_compressed = false;
+				} break;
+				default: {
+					image->convert(Image::FORMAT_RGBA8);
+					r_gl_format = GL_RGBA;
+					r_gl_internal_format = GL_RGBA;
+					r_gl_type = GL_UNSIGNED_BYTE;
+					r_real_format = Image::FORMAT_RGBA8;
+					r_compressed = false;
+
+				} break;
+			}
 		}
 
-		r_gl_format = GL_RGBA;
-		r_gl_internal_format = GL_RGBA;
-		r_gl_type = GL_UNSIGNED_BYTE;
-		r_real_format = Image::FORMAT_RGBA8;
-
 		return image;
 	}
 
@@ -395,11 +416,31 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_
 		}
 	}
 
-	Image::Format real_format;
-	_get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, format, internal_format, type, compressed);
-
 	texture->alloc_width = texture->width;
 	texture->alloc_height = texture->height;
+	texture->resize_to_po2 = false;
+	if (!config.support_npot_repeat_mipmap) {
+		int po2_width = next_power_of_2(p_width);
+		int po2_height = next_power_of_2(p_height);
+
+		bool is_po2 = p_width == po2_width && p_height == po2_height;
+
+		if (!is_po2 && (p_flags & VS::TEXTURE_FLAG_REPEAT || p_flags & VS::TEXTURE_FLAG_MIPMAPS)) {
+
+			if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) {
+				//not supported
+				ERR_PRINTS("Streaming texture for non power of 2 or has mipmaps on this hardware: " + texture->path + "'. Mipmaps and repeat disabled.");
+				texture->flags &= ~(VS::TEXTURE_FLAG_REPEAT | VS::TEXTURE_FLAG_MIPMAPS);
+			} else {
+				texture->alloc_height = po2_height;
+				texture->alloc_width = po2_width;
+				texture->resize_to_po2 = true;
+			}
+		}
+	}
+
+	Image::Format real_format;
+	_get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, format, internal_format, type, compressed, texture->resize_to_po2);
 
 	texture->gl_format_cache = format;
 	texture->gl_type_cache = type;
@@ -414,7 +455,7 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_
 
 	if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) {
 		//prealloc if video
-		glTexImage2D(texture->target, 0, internal_format, p_width, p_height, 0, format, type, NULL);
+		glTexImage2D(texture->target, 0, internal_format, texture->alloc_width, texture->alloc_height, 0, format, type, NULL);
 	}
 
 	texture->active = true;
@@ -439,7 +480,19 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p
 	}
 
 	Image::Format real_format;
-	Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, real_format, format, internal_format, type, compressed);
+	Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, real_format, format, internal_format, type, compressed, texture->resize_to_po2);
+
+	if (texture->resize_to_po2) {
+		if (p_image->is_compressed()) {
+			ERR_PRINTS("Texture '" + texture->path + "' was required to be a power of 2 (because it uses either mipmaps or repeat), so it was decompressed. This will hurt performance and memory usage.");
+		}
+
+		if (img == p_image) {
+			img = img->duplicate();
+		}
+		img->resize_to_po2(false);
+		img->save_png("res://popo.png");
+	}
 
 	if (config.shrink_textures_x2 && (p_image->has_mipmaps() || !p_image->is_compressed()) && !(texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING)) {
 
@@ -575,7 +628,7 @@ Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, int p_layer)
 	GLenum gl_internal_format;
 	GLenum gl_type;
 	bool compressed;
-	_get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed);
+	_get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed, false);
 
 	PoolVector<uint8_t> data;
 
@@ -620,7 +673,7 @@ Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, int p_layer)
 	GLenum gl_internal_format;
 	GLenum gl_type;
 	bool compressed;
-	_get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed);
+	_get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed, texture->resize_to_po2);
 
 	PoolVector<uint8_t> data;
 
@@ -4900,10 +4953,13 @@ void RasterizerStorageGLES2::initialize() {
 	config.float_texture_supported = true;
 	config.s3tc_supported = true;
 	config.etc1_supported = false;
+	config.support_npot_repeat_mipmap = true;
 #else
 	config.float_texture_supported = config.extensions.has("GL_ARB_texture_float") || config.extensions.has("GL_OES_texture_float");
 	config.s3tc_supported = config.extensions.has("GL_EXT_texture_compression_s3tc") || config.extensions.has("WEBGL_compressed_texture_s3tc");
 	config.etc1_supported = config.extensions.has("GL_OES_compressed_ETC1_RGB8_texture") || config.extensions.has("WEBGL_compressed_texture_etc1");
+	config.support_npot_repeat_mipmap = config.extensions.has("GL_OES_texture_npot");
+
 #endif
 #ifdef GLES_OVER_GL
 	config.use_rgba_2d_shadows = false;

+ 5 - 1
drivers/gles2/rasterizer_storage_gles2.h

@@ -82,6 +82,7 @@ public:
 		bool support_32_bits_indices;
 		bool support_write_depth;
 		bool support_half_float_vertices;
+		bool support_npot_repeat_mipmap;
 	} config;
 
 	struct Resources {
@@ -240,6 +241,8 @@ public:
 
 		int mipmaps;
 
+		bool resize_to_po2;
+
 		bool active;
 		GLenum tex_id;
 
@@ -275,6 +278,7 @@ public:
 				ignore_mipmaps(false),
 				compressed(false),
 				mipmaps(0),
+				resize_to_po2(false),
 				active(false),
 				tex_id(0),
 				stored_cube_sides(0),
@@ -313,7 +317,7 @@ public:
 
 	mutable RID_Owner<Texture> texture_owner;
 
-	Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed) const;
+	Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_will_need_resize) const;
 
 	virtual RID texture_create();
 	virtual void texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, VS::TextureType p_type, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT);

+ 1 - 1
drivers/gles2/shader_compiler_gles2.cpp

@@ -770,7 +770,7 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
 	/** CANVAS ITEM SHADER **/
 
 	actions[VS::SHADER_CANVAS_ITEM].renames["VERTEX"] = "outvec.xy";
-	actions[VS::SHADER_CANVAS_ITEM].renames["UV"] = "uv_interp";
+	actions[VS::SHADER_CANVAS_ITEM].renames["UV"] = "uv";
 	actions[VS::SHADER_CANVAS_ITEM].renames["POINT_SIZE"] = "gl_PointSize";
 
 	actions[VS::SHADER_CANVAS_ITEM].renames["WORLD_MATRIX"] = "modelview_matrix";

+ 11 - 5
drivers/gles2/shaders/canvas.glsl

@@ -107,6 +107,7 @@ vec2 select(vec2 a, vec2 b, bvec2 c) {
 void main() {
 
 	vec4 color = color_attrib;
+	vec2 uv;
 
 #ifdef USE_INSTANCING
 	mat4 extra_matrix_instance = extra_matrix * transpose(mat4(instance_xform0, instance_xform1, instance_xform2, vec4(0.0, 0.0, 0.0, 1.0)));
@@ -121,9 +122,9 @@ void main() {
 #ifdef USE_TEXTURE_RECT
 
 	if (dst_rect.z < 0.0) { // Transpose is encoded as negative dst_rect.z
-		uv_interp = src_rect.xy + abs(src_rect.zw) * vertex.yx;
+		uv = src_rect.xy + abs(src_rect.zw) * vertex.yx;
 	} else {
-		uv_interp = src_rect.xy + abs(src_rect.zw) * vertex;
+		uv = src_rect.xy + abs(src_rect.zw) * vertex;
 	}
 
 	vec4 outvec = vec4(0.0, 0.0, 0.0, 1.0);
@@ -140,7 +141,7 @@ void main() {
 #else
 	vec4 outvec = vec4(vertex.xy, 0.0, 1.0);
 
-	uv_interp = uv_attrib;
+	uv = uv_attrib;
 #endif
 
 	{
@@ -189,6 +190,7 @@ VERTEX_SHADER_CODE
 
 #endif
 
+	uv_interp = uv;
 	gl_Position = projection_matrix * outvec;
 
 #ifdef USE_LIGHTING
@@ -345,10 +347,14 @@ void main() {
 
 	vec4 color = color_interp;
 	vec2 uv = uv_interp;
+#ifdef USE_FORCE_REPEAT
+	//needs to use this to workaround GLES2/WebGL1 forcing tiling that textures that dont support it
+	uv = mod(uv,vec2(1.0,1.0));
+#endif
 
 #if !defined(COLOR_USED)
 	//default behavior, texture by color
-	color *= texture2D(color_texture, uv_interp);
+	color *= texture2D(color_texture, uv);
 #endif
 
 #ifdef SCREEN_UV_USED
@@ -365,7 +371,7 @@ void main() {
 #endif
 
 	if (use_default_normal) {
-		normal.xy = texture2D(normal_texture, uv_interp).xy * 2.0 - 1.0;
+		normal.xy = texture2D(normal_texture, uv).xy * 2.0 - 1.0;
 		normal.z = sqrt(1.0 - dot(normal.xy, normal.xy));
 		normal_used = true;
 	} else {

+ 24 - 8
editor/import/resource_importer_texture.cpp

@@ -219,7 +219,7 @@ void ResourceImporterTexture::get_import_options(List<ImportOption> *r_options,
 	r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "svg/scale", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 1.0));
 }
 
-void ResourceImporterTexture::_save_stex(const Ref<Image> &p_image, const String &p_to_path, int p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags, bool p_streamable, bool p_detect_3d, bool p_detect_srgb, bool p_force_rgbe, bool p_detect_normal, bool p_force_normal) {
+void ResourceImporterTexture::_save_stex(const Ref<Image> &p_image, const String &p_to_path, int p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags, bool p_streamable, bool p_detect_3d, bool p_detect_srgb, bool p_force_rgbe, bool p_detect_normal, bool p_force_normal, bool p_force_po2_for_compressed) {
 
 	FileAccess *f = FileAccess::open(p_to_path, FileAccess::WRITE);
 	f->store_8('G');
@@ -227,8 +227,21 @@ void ResourceImporterTexture::_save_stex(const Ref<Image> &p_image, const String
 	f->store_8('S');
 	f->store_8('T'); //godot streamable texture
 
-	f->store_32(p_image->get_width());
-	f->store_32(p_image->get_height());
+	bool resize_to_po2 = false;
+
+	if (p_compress_mode == COMPRESS_VIDEO_RAM && p_force_po2_for_compressed && (p_mipmaps || p_texture_flags & Texture::FLAG_REPEAT)) {
+		resize_to_po2 = true;
+		f->store_16(next_power_of_2(p_image->get_width()));
+		f->store_16(p_image->get_width());
+		f->store_16(next_power_of_2(p_image->get_height()));
+		f->store_16(p_image->get_height());
+		f->store_16(0);
+	} else {
+		f->store_16(p_image->get_width());
+		f->store_16(0);
+		f->store_16(p_image->get_height());
+		f->store_16(0);
+	}
 	f->store_32(p_texture_flags);
 
 	uint32_t format = 0;
@@ -310,6 +323,9 @@ void ResourceImporterTexture::_save_stex(const Ref<Image> &p_image, const String
 		case COMPRESS_VIDEO_RAM: {
 
 			Ref<Image> image = p_image->duplicate();
+			if (resize_to_po2) {
+				image->resize_to_po2();
+			}
 			if (p_mipmaps) {
 				image->generate_mipmaps(p_force_normal);
 			}
@@ -478,25 +494,25 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
 		}
 
 		if (can_bptc || can_s3tc) {
-			_save_stex(image, p_save_path + ".s3tc.stex", compress_mode, lossy, can_bptc ? Image::COMPRESS_BPTC : Image::COMPRESS_S3TC, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal);
+			_save_stex(image, p_save_path + ".s3tc.stex", compress_mode, lossy, can_bptc ? Image::COMPRESS_BPTC : Image::COMPRESS_S3TC, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal, false);
 			r_platform_variants->push_back("s3tc");
 			ok_on_pc = true;
 		}
 
 		if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc2")) {
 
-			_save_stex(image, p_save_path + ".etc2.stex", compress_mode, lossy, Image::COMPRESS_ETC2, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal);
+			_save_stex(image, p_save_path + ".etc2.stex", compress_mode, lossy, Image::COMPRESS_ETC2, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal, false);
 			r_platform_variants->push_back("etc2");
 		}
 
 		if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc")) {
-			_save_stex(image, p_save_path + ".etc.stex", compress_mode, lossy, Image::COMPRESS_ETC, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal);
+			_save_stex(image, p_save_path + ".etc.stex", compress_mode, lossy, Image::COMPRESS_ETC, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal, true);
 			r_platform_variants->push_back("etc");
 		}
 
 		if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_pvrtc")) {
 
-			_save_stex(image, p_save_path + ".pvrtc.stex", compress_mode, lossy, Image::COMPRESS_PVRTC4, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal);
+			_save_stex(image, p_save_path + ".pvrtc.stex", compress_mode, lossy, Image::COMPRESS_PVRTC4, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal, true);
 			r_platform_variants->push_back("pvrtc");
 		}
 
@@ -505,7 +521,7 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
 		}
 	} else {
 		//import normally
-		_save_stex(image, p_save_path + ".stex", compress_mode, lossy, Image::COMPRESS_S3TC /*this is ignored */, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal);
+		_save_stex(image, p_save_path + ".stex", compress_mode, lossy, Image::COMPRESS_S3TC /*this is ignored */, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal, false);
 	}
 
 	return OK;

+ 1 - 1
editor/import/resource_importer_texture.h

@@ -83,7 +83,7 @@ public:
 	virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const;
 	virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
 
-	void _save_stex(const Ref<Image> &p_image, const String &p_to_path, int p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags, bool p_streamable, bool p_detect_3d, bool p_detect_srgb, bool p_force_rgbe, bool p_detect_normal, bool p_force_normal);
+	void _save_stex(const Ref<Image> &p_image, const String &p_to_path, int p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags, bool p_streamable, bool p_detect_3d, bool p_detect_srgb, bool p_force_rgbe, bool p_detect_normal, bool p_force_normal, bool p_force_po2_for_compressed);
 
 	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);
 

+ 19 - 7
scene/resources/texture.cpp

@@ -481,7 +481,7 @@ Image::Format StreamTexture::get_format() const {
 	return format;
 }
 
-Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &flags, Ref<Image> &image, int p_size_limit) {
+Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &tw_custom, int &th_custom, int &flags, Ref<Image> &image, int p_size_limit) {
 
 	alpha_cache.unref();
 
@@ -497,8 +497,11 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &fla
 		ERR_FAIL_COND_V(header[0] != 'G' || header[1] != 'D' || header[2] != 'S' || header[3] != 'T', ERR_FILE_CORRUPT);
 	}
 
-	tw = f->get_32();
-	th = f->get_32();
+	tw = f->get_16();
+	tw_custom = f->get_16();
+	th = f->get_16();
+	th_custom = f->get_16();
+
 	flags = f->get_32(); //texture flags!
 	uint32_t df = f->get_32(); //data format
 
@@ -705,18 +708,26 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &fla
 
 Error StreamTexture::load(const String &p_path) {
 
-	int lw, lh, lflags;
+	int lw, lh, lwc, lhc, lflags;
 	Ref<Image> image;
 	image.instance();
-	Error err = _load_data(p_path, lw, lh, lflags, image);
+	Error err = _load_data(p_path, lw, lh, lwc, lhc, lflags, image);
 	if (err)
 		return err;
 
+	if (get_path() == String()) {
+		//temporarily set path if no path set for resource, helps find errors
+		VisualServer::get_singleton()->texture_set_path(texture, p_path);
+	}
 	VS::get_singleton()->texture_allocate(texture, image->get_width(), image->get_height(), 0, image->get_format(), VS::TEXTURE_TYPE_2D, lflags);
 	VS::get_singleton()->texture_set_data(texture, image);
+	if (lwc || lhc) {
+		VS::get_singleton()->texture_set_size_override(texture, lwc, lhc, 0);
+	} else {
+	}
 
-	w = lw;
-	h = lh;
+	w = lwc ? lwc : lw;
+	h = lhc ? lhc : lh;
 	flags = lflags;
 	path_to_file = p_path;
 	format = image->get_format();
@@ -784,6 +795,7 @@ bool StreamTexture::is_pixel_opaque(int p_x, int p_y) const {
 				decom->decompress();
 				img = decom;
 			}
+
 			alpha_cache.instance();
 			alpha_cache->create_from_image_alpha(img);
 		}

+ 1 - 1
scene/resources/texture.h

@@ -187,7 +187,7 @@ public:
 	};
 
 private:
-	Error _load_data(const String &p_path, int &tw, int &th, int &flags, Ref<Image> &image, int p_size_limit = 0);
+	Error _load_data(const String &p_path, int &tw, int &th, int &tw_custom, int &th_custom, int &flags, Ref<Image> &image, int p_size_limit = 0);
 	String path_to_file;
 	RID texture;
 	Image::Format format;