Added proper import support for 3D and Array textures

This commit is contained in:
Juan Linietsky 2018-08-06 14:56:06 -03:00
parent 80a8636aa3
commit edde52c8de
16 changed files with 906 additions and 215 deletions

View file

@ -987,8 +987,10 @@ int Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int &
int pixsize = get_format_pixel_size(p_format);
int pixshift = get_format_pixel_rshift(p_format);
int block = get_format_block_size(p_format);
int minw, minh;
get_format_min_pixel_size(p_format, minw, minh);
//technically, you can still compress up to 1 px no matter the format, so commenting this
//int minw, minh;
//get_format_min_pixel_size(p_format, minw, minh);
int minw = 1, minh = 1;
while (true) {
@ -1304,7 +1306,7 @@ void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_forma
int size = _get_dst_image_size(p_width, p_height, p_format, mm, p_use_mipmaps ? -1 : 0);
if (size != p_data.size()) {
ERR_EXPLAIN("Expected data size of " + itos(size) + " in Image::create()");
ERR_EXPLAIN("Expected data size of " + itos(size) + " bytes in Image::create(), got instead " + itos(p_data.size()) + " bytes.");
ERR_FAIL_COND(p_data.size() != size);
}
@ -1592,10 +1594,10 @@ Error Image::save_png(const String &p_path) const {
return save_png_func(p_path, Ref<Image>((Image *)this));
}
int Image::get_image_data_size(int p_width, int p_height, Format p_format, int p_mipmaps) {
int Image::get_image_data_size(int p_width, int p_height, Format p_format, bool p_mipmaps) {
int mm;
return _get_dst_image_size(p_width, p_height, p_format, mm, p_mipmaps);
return _get_dst_image_size(p_width, p_height, p_format, mm, p_mipmaps ? -1 : 0);
}
int Image::get_image_required_mipmaps(int p_width, int p_height, Format p_format) {
@ -2376,6 +2378,17 @@ Image::DetectChannels Image::get_detected_channels() {
return DETECTED_RGBA;
}
void Image::optimize_channels() {
switch (get_detected_channels()) {
case DETECTED_L: convert(FORMAT_L8); break;
case DETECTED_LA: convert(FORMAT_LA8); break;
case DETECTED_R: convert(FORMAT_R8); break;
case DETECTED_RG: convert(FORMAT_RG8); break;
case DETECTED_RGB: convert(FORMAT_RGB8); break;
case DETECTED_RGBA: convert(FORMAT_RGBA8); break;
}
}
void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_width"), &Image::get_width);

View file

@ -116,7 +116,8 @@ public:
enum CompressSource {
COMPRESS_SOURCE_GENERIC,
COMPRESS_SOURCE_SRGB,
COMPRESS_SOURCE_NORMAL
COMPRESS_SOURCE_NORMAL,
COMPRESS_SOURCE_LAYERED,
};
//some functions provided by something else
@ -272,7 +273,7 @@ public:
static int get_format_block_size(Format p_format);
static void get_format_min_pixel_size(Format p_format, int &r_w, int &r_h);
static int get_image_data_size(int p_width, int p_height, Format p_format, int p_mipmaps = 0);
static int get_image_data_size(int p_width, int p_height, Format p_format, bool p_mipmaps = false);
static int get_image_required_mipmaps(int p_width, int p_height, Format p_format);
enum CompressMode {
@ -329,6 +330,7 @@ public:
};
DetectChannels get_detected_channels();
void optimize_channels();
Color get_pixelv(const Point2 &p_src) const;
Color get_pixel(int p_x, int p_y) const;

View file

@ -370,13 +370,17 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_
switch (p_type) {
case VS::TEXTURE_TYPE_2D: {
texture->target = GL_TEXTURE_2D;
texture->images.resize(1);
} break;
case VS::TEXTURE_TYPE_CUBEMAP: {
texture->target = GL_TEXTURE_CUBE_MAP;
texture->images.resize(6);
} break;
case VS::TEXTURE_TYPE_2D_ARRAY: {
texture->images.resize(p_depth_3d);
} break;
case VS::TEXTURE_TYPE_3D: {
texture->images.resize(p_depth_3d);
} break;
}
@ -419,7 +423,7 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p
bool compressed = false;
if (config.keep_original_textures && !(texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING)) {
texture->images[p_layer] = p_image;
texture->images.write[p_layer] = p_image;
}
Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, format, internal_format, type, compressed);

View file

@ -258,7 +258,7 @@ public:
RenderTarget *render_target;
Ref<Image> images[6];
Vector<Ref<Image> > images;
bool redraw_if_visible;

View file

@ -622,15 +622,19 @@ void RasterizerStorageGLES3::texture_allocate(RID p_texture, int p_width, int p_
switch (p_type) {
case VS::TEXTURE_TYPE_2D: {
texture->target = GL_TEXTURE_2D;
texture->images.resize(1);
} break;
case VS::TEXTURE_TYPE_CUBEMAP: {
texture->target = GL_TEXTURE_CUBE_MAP;
texture->images.resize(6);
} break;
case VS::TEXTURE_TYPE_2D_ARRAY: {
texture->target = GL_TEXTURE_2D_ARRAY;
texture->images.resize(p_depth_3d);
} break;
case VS::TEXTURE_TYPE_3D: {
texture->target = GL_TEXTURE_3D;
texture->images.resize(p_depth_3d);
} break;
}
@ -703,7 +707,7 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p
bool srgb;
if (config.keep_original_textures && !(texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING)) {
texture->images[p_layer] = p_image;
texture->images.write[p_layer] = p_image;
}
Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, format, internal_format, type, compressed, srgb);

View file

@ -277,7 +277,7 @@ public:
RenderTarget *render_target;
Ref<Image> images[6];
Vector<Ref<Image> > images;
VisualServer::TextureDetectCallback detect_3d;
void *detect_3d_ud;

View file

@ -63,6 +63,7 @@
#include "editor/import/resource_importer_bitmask.h"
#include "editor/import/resource_importer_csv_translation.h"
#include "editor/import/resource_importer_image.h"
#include "editor/import/resource_importer_layered_texture.h"
#include "editor/import/resource_importer_obj.h"
#include "editor/import/resource_importer_scene.h"
#include "editor/import/resource_importer_texture.h"
@ -4666,6 +4667,16 @@ EditorNode::EditorNode() {
import_texture.instance();
ResourceFormatImporter::get_singleton()->add_importer(import_texture);
Ref<ResourceImporterLayeredTexture> import_3d;
import_3d.instance();
import_3d->set_3d(true);
ResourceFormatImporter::get_singleton()->add_importer(import_3d);
Ref<ResourceImporterLayeredTexture> import_array;
import_array.instance();
import_array->set_3d(false);
ResourceFormatImporter::get_singleton()->add_importer(import_array);
Ref<ResourceImporterImage> import_image;
import_image.instance();
ResourceFormatImporter::get_singleton()->add_importer(import_image);

View file

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
version="1.1"
viewBox="0 0 16 16"
id="svg6"
sodipodi:docname="icon_texture_3_d.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1853"
inkscape:window-height="1016"
id="namedview8"
showgrid="false"
inkscape:zoom="29.5"
inkscape:cx="15.226978"
inkscape:cy="9.4909723"
inkscape:window-x="67"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="svg6" />
<g
id="g830"
transform="translate(0.35954582,-0.28763666)">
<path
d="M 2,1 C 1.4477153,1 1,1.4477153 1,2 v 12 c 0,0.552285 0.4477153,1 1,1 h 12 c 0.552285,0 1,-0.447715 1,-1 V 2 C 15,1.4477153 14.552285,1 14,1 Z m 1,2 h 10 v 8 H 3 Z"
id="path2"
inkscape:connector-curvature="0"
style="fill:#e0e0e0;fill-opacity:0.99607999"
sodipodi:nodetypes="sssssssssccccc" />
</g>
<g
aria-label="3D"
transform="scale(0.9167105,1.0908569)"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.12847996px;line-height:1.25;font-family:Ubuntu;-inkscape-font-specification:'Ubuntu Bold';letter-spacing:0px;word-spacing:0px;fill:#e0e0e0;fill-opacity:0.99607843;stroke:none;stroke-width:0.20321201"
id="text834">
<path
d="m 5.8175194,8.9717502 q -0.2194689,0 -0.4633233,-0.032514 Q 5.1103417,8.9148508 4.8827442,8.86608 4.6551468,8.8173091 4.4681918,8.7604097 4.2812367,8.7035104 4.1755665,8.6547395 L 4.4112924,7.646808 q 0.2113405,0.089413 0.5364797,0.1950835 0.3332677,0.097542 0.8209765,0.097542 0.5608651,0 0.8209764,-0.2113404 0.2601114,-0.2113405 0.2601114,-0.5689936 0,-0.219469 -0.097542,-0.3657816 Q 6.6628814,6.6388764 6.5003118,6.5494632 6.3377422,6.4519214 6.1101447,6.4194075 5.8906758,6.3787651 5.6386929,6.3787651 H 5.167241 V 5.4033475 h 0.5364797 q 0.1788266,0 0.3413962,-0.032514 0.1706981,-0.032514 0.3007537,-0.1056703 0.1300557,-0.081285 0.203212,-0.2113404 0.081285,-0.1381842 0.081285,-0.3413962 0,-0.1544411 -0.065028,-0.2682398 Q 6.5003118,4.3303881 6.3946415,4.2572318 6.2970998,4.1840755 6.1589156,4.1515616 6.0288599,4.1109192 5.8906758,4.1109192 q -0.3495247,0 -0.6502784,0.1056702 Q 4.9477721,4.3222597 4.7039177,4.4767008 L 4.2731082,3.5906965 Q 4.4031639,3.5094117 4.573862,3.4199984 4.7526886,3.3305851 4.964029,3.2574288 5.1753695,3.1842725 5.4110954,3.1355016 q 0.2438544,-0.048771 0.5120943,-0.048771 0.4958373,0 0.8534904,0.1219272 0.3657816,0.1137987 0.6015075,0.3332677 0.2357259,0.2113405 0.3495246,0.5039657 0.1137987,0.2844968 0.1137987,0.625893 0,0.3332677 -0.186955,0.6502784 -0.186955,0.3088822 -0.5039657,0.4714518 0.4389379,0.1788266 0.6746638,0.5364797 0.2438544,0.3495246 0.2438544,0.8453619 0,0.3901671 -0.1300557,0.7234347 Q 7.808997,8.22393 7.5326287,8.4677844 7.2562604,8.7035104 6.825451,8.8416945 6.40277,8.9717502 5.8175194,8.9717502 Z"
style="fill:#e0e0e0;fill-opacity:0.99607843;stroke-width:0.20321201"
id="path836" />
<path
d="m 10.502445,7.817506 q 0.08941,0.00813 0.203212,0.016257 0.121927,0 0.284497,0 0.951032,0 1.406227,-0.4795803 0.463323,-0.4795803 0.463323,-1.3249422 0,-0.8860044 -0.438938,-1.3411992 -0.438938,-0.4551949 -1.38997,-0.4551949 -0.130055,0 -0.26824,0.00813 -0.138184,0 -0.260111,0.016257 z M 14.16839,6.0292405 q 0,0.7315631 -0.227598,1.2761713 -0.227597,0.5446082 -0.650278,0.9022613 -0.414553,0.3576531 -1.01606,0.5364797 -0.601508,0.1788265 -1.349328,0.1788265 -0.341396,0 -0.796591,-0.032514 Q 9.6733402,8.86608 9.2344022,8.7766667 v -5.486724 q 0.438938,-0.081285 0.9103898,-0.1056702 0.47958,-0.032514 0.820976,-0.032514 0.723435,0 1.308686,0.1625696 0.593379,0.1625696 1.01606,0.5120943 0.422681,0.3495246 0.650278,0.8941328 0.227598,0.5446081 0.227598,1.3086853 z"
style="fill:#e0e0e0;fill-opacity:0.99607843;stroke-width:0.20321201"
id="path838" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.8 KiB

View file

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
version="1.1"
viewBox="0 0 16 16"
id="svg6"
sodipodi:docname="icon_texture_array.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1526"
inkscape:window-height="766"
id="namedview8"
showgrid="false"
inkscape:zoom="29.5"
inkscape:cx="8.3117238"
inkscape:cy="9.4909723"
inkscape:window-x="67"
inkscape:window-y="27"
inkscape:window-maximized="0"
inkscape:current-layer="svg6" />
<g
id="g830"
transform="translate(0.35954582,-0.28763666)">
<path
d="M 2,1 C 1.4477153,1 1,1.4477153 1,2 v 12 c 0,0.552285 0.4477153,1 1,1 h 12 c 0.552285,0 1,-0.447715 1,-1 V 2 C 15,1.4477153 14.552285,1 14,1 Z m 1,2 h 10 v 8 H 3 Z"
id="path2"
inkscape:connector-curvature="0"
style="fill:#e0e0e0;fill-opacity:0.99607999"
sodipodi:nodetypes="sssssssssccccc" />
</g>
<g
aria-label="[]"
transform="matrix(1.6197742,0,0,0.750929,-3.7231532,1.8329569)"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.29580784px;line-height:1.25;font-family:Ubuntu;-inkscape-font-specification:'Ubuntu Bold';letter-spacing:0px;word-spacing:0px;fill:#e0e0e0;fill-opacity:0.99607843;stroke:none;stroke-width:0.2073952"
id="text834">
<path
d="M 4.7302951,2.4553483 H 6.978459 V 3.4425495 H 5.9082998 V 9.4984892 H 6.978459 V 10.48569 H 4.7302951 Z"
style="fill:#e0e0e0;fill-opacity:0.99607843;stroke-width:0.2073952"
id="path862"
inkscape:connector-curvature="0" />
<path
d="M 10.138643,10.48569 H 7.8904794 V 9.4984892 H 8.9606386 V 3.4425495 H 7.8904794 V 2.4553483 h 2.2481636 z"
style="fill:#e0e0e0;fill-opacity:0.99607843;stroke-width:0.2073952"
id="path864"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -0,0 +1,274 @@
#include "resource_importer_layered_texture.h"
#include "resource_importer_texture.h"
#include "editor/editor_file_system.h"
#include "editor/editor_node.h"
#include "io/config_file.h"
#include "io/image_loader.h"
#include "scene/resources/texture.h"
String ResourceImporterLayeredTexture::get_importer_name() const {
return is_3d ? "texture_3d" : "texture_array";
}
String ResourceImporterLayeredTexture::get_visible_name() const {
return is_3d ? "Texture3D" : "TextureArray";
}
void ResourceImporterLayeredTexture::get_recognized_extensions(List<String> *p_extensions) const {
ImageLoader::get_recognized_extensions(p_extensions);
}
String ResourceImporterLayeredTexture::get_save_extension() const {
return is_3d ? "tex3d" : "texarr";
}
String ResourceImporterLayeredTexture::get_resource_type() const {
return is_3d ? "Texture3D" : "TextureArray";
}
bool ResourceImporterLayeredTexture::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
return true;
}
int ResourceImporterLayeredTexture::get_preset_count() const {
return 3;
}
String ResourceImporterLayeredTexture::get_preset_name(int p_idx) const {
static const char *preset_names[] = {
"3D",
"2D",
"ColorCorrect"
};
return preset_names[p_idx];
}
void ResourceImporterLayeredTexture::get_import_options(List<ImportOption> *r_options, int p_preset) const {
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/mode", PROPERTY_HINT_ENUM, "Lossless,Video RAM,Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), p_preset == PRESET_3D ? 1 : 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "flags/repeat", PROPERTY_HINT_ENUM, "Disabled,Enabled,Mirrored"), 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "flags/filter"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "flags/mipmaps"), p_preset == PRESET_COLOR_CORRECT ? 0 : 1));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "flags/srgb", PROPERTY_HINT_ENUM, "Disable,Enable"), p_preset == PRESET_3D ? 1 : 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slices/horizontal", PROPERTY_HINT_RANGE, "1,256,1"), p_preset == PRESET_COLOR_CORRECT ? 16 : 8));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slices/vertical", PROPERTY_HINT_RANGE, "1,256,1"), p_preset == PRESET_COLOR_CORRECT ? 1 : 8));
}
void ResourceImporterLayeredTexture::_save_tex(const Vector<Ref<Image> > &p_images, const String &p_to_path, int p_compress_mode, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags) {
FileAccess *f = FileAccess::open(p_to_path, FileAccess::WRITE);
f->store_8('G');
f->store_8('D');
if (is_3d) {
f->store_8('3');
} else {
f->store_8('A');
}
f->store_8('T'); //godot streamable texture
f->store_32(p_images[0]->get_width());
f->store_32(p_images[0]->get_height());
f->store_32(p_images.size()); //depth
f->store_32(p_texture_flags);
if (p_compress_mode != COMPRESS_VIDEO_RAM) {
//vram needs to do a first compression to tell what the format is, for the rest its ok
f->store_32(p_images[0]->get_format());
f->store_32(p_compress_mode); // 0 - lossless (PNG), 1 - vram, 2 - uncompressed
}
if ((p_compress_mode == COMPRESS_LOSSLESS) && p_images[0]->get_format() > Image::FORMAT_RGBA8) {
p_compress_mode = COMPRESS_UNCOMPRESSED; //these can't go as lossy
}
for (int i = 0; i < p_images.size(); i++) {
switch (p_compress_mode) {
case COMPRESS_LOSSLESS: {
Ref<Image> image = p_images[i]->duplicate();
if (p_mipmaps) {
image->generate_mipmaps();
} else {
image->clear_mipmaps();
}
int mmc = image->get_mipmap_count() + 1;
f->store_32(mmc);
for (int i = 0; i < mmc; i++) {
if (i > 0) {
image->shrink_x2();
}
PoolVector<uint8_t> data = Image::lossless_packer(image);
int data_len = data.size();
f->store_32(data_len);
PoolVector<uint8_t>::Read r = data.read();
f->store_buffer(r.ptr(), data_len);
}
} break;
case COMPRESS_VIDEO_RAM: {
Ref<Image> image = p_images[i]->duplicate();
image->generate_mipmaps(false);
Image::CompressSource csource = Image::COMPRESS_SOURCE_LAYERED;
image->compress(p_vram_compression, csource, 0.7);
if (i == 0) {
//hack so we can properly tell the format
f->store_32(image->get_format());
f->store_32(p_compress_mode); // 0 - lossless (PNG), 1 - vram, 2 - uncompressed
}
PoolVector<uint8_t> data = image->get_data();
int dl = data.size();
PoolVector<uint8_t>::Read r = data.read();
f->store_buffer(r.ptr(), dl);
} break;
case COMPRESS_UNCOMPRESSED: {
Ref<Image> image = p_images[i]->duplicate();
if (p_mipmaps) {
image->generate_mipmaps();
} else {
image->clear_mipmaps();
}
PoolVector<uint8_t> data = image->get_data();
int dl = data.size();
PoolVector<uint8_t>::Read r = data.read();
f->store_buffer(r.ptr(), dl);
} break;
}
}
memdelete(f);
}
Error ResourceImporterLayeredTexture::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) {
int compress_mode = p_options["compress/mode"];
int repeat = p_options["flags/repeat"];
bool filter = p_options["flags/filter"];
bool mipmaps = p_options["flags/mipmaps"];
int srgb = p_options["flags/srgb"];
int hslices = p_options["slices/horizontal"];
int vslices = p_options["slices/vertical"];
Ref<Image> image;
image.instance();
Error err = ImageLoader::load_image(p_source_file, image, NULL, false, 1.0);
if (err != OK)
return err;
int tex_flags = 0;
if (repeat > 0)
tex_flags |= Texture::FLAG_REPEAT;
if (repeat == 2)
tex_flags |= Texture::FLAG_MIRRORED_REPEAT;
if (filter)
tex_flags |= Texture::FLAG_FILTER;
if (mipmaps || compress_mode == COMPRESS_VIDEO_RAM)
tex_flags |= Texture::FLAG_MIPMAPS;
if (srgb == 1)
tex_flags |= Texture::FLAG_CONVERT_TO_LINEAR;
Vector<Ref<Image> > slices;
int slice_w = image->get_width() / hslices;
int slice_h = image->get_height() / vslices;
//optimize
if (compress_mode == COMPRESS_VIDEO_RAM) {
//if using video ram, optimize
if (srgb) {
//remove alpha if not needed, so compression is more efficient
if (image->get_format() == Image::FORMAT_RGBA8 && !image->detect_alpha()) {
image->convert(Image::FORMAT_RGB8);
}
} else {
image->optimize_channels();
}
}
for (int i = 0; i < vslices; i++) {
for (int j = 0; j < hslices; j++) {
int x = slice_w * j;
int y = slice_h * i;
Ref<Image> slice = image->get_rect(Rect2(x, y, slice_w, slice_h));
ERR_CONTINUE(slice.is_null() || slice->empty());
if (slice->get_width() != slice_w || slice->get_height() != slice_h) {
slice->resize(slice_w, slice_h);
}
slices.push_back(slice);
}
}
String extension = get_save_extension();
if (compress_mode == COMPRESS_VIDEO_RAM) {
//must import in all formats, in order of priority (so platform choses the best supported one. IE, etc2 over etc).
//Android, GLES 2.x
bool ok_on_pc = false;
if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_s3tc")) {
_save_tex(slices, p_save_path + ".s3tc." + extension, compress_mode, Image::COMPRESS_S3TC, mipmaps, tex_flags);
r_platform_variants->push_back("s3tc");
ok_on_pc = true;
}
if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc2")) {
_save_tex(slices, p_save_path + ".etc2." + extension, compress_mode, Image::COMPRESS_ETC2, mipmaps, tex_flags);
r_platform_variants->push_back("etc2");
}
if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc")) {
_save_tex(slices, p_save_path + ".etc." + extension, compress_mode, Image::COMPRESS_ETC, mipmaps, tex_flags);
r_platform_variants->push_back("etc");
}
if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_pvrtc")) {
_save_tex(slices, p_save_path + ".pvrtc." + extension, compress_mode, Image::COMPRESS_PVRTC4, mipmaps, tex_flags);
r_platform_variants->push_back("pvrtc");
}
if (!ok_on_pc) {
EditorNode::add_io_error("Warning, no suitable PC VRAM compression enabled in Project Settings. This texture will not display correcly on PC.");
}
} else {
//import normally
_save_tex(slices, p_save_path + "." + extension, compress_mode, Image::COMPRESS_S3TC /*this is ignored */, mipmaps, tex_flags);
}
return OK;
}
ResourceImporterLayeredTexture *ResourceImporterLayeredTexture::singleton = NULL;
ResourceImporterLayeredTexture::ResourceImporterLayeredTexture() {
singleton = this;
is_3d = true;
}
ResourceImporterLayeredTexture::~ResourceImporterLayeredTexture() {
}

View file

@ -0,0 +1,57 @@
#ifndef RESOURCE_IMPORTER_LAYERED_TEXTURE_H
#define RESOURCE_IMPORTER_LAYERED_TEXTURE_H
#include "image.h"
#include "io/resource_import.h"
class StreamTexture;
class ResourceImporterLayeredTexture : public ResourceImporter {
GDCLASS(ResourceImporterLayeredTexture, ResourceImporter)
bool is_3d;
protected:
static void _texture_reimport_srgb(const Ref<StreamTexture> &p_tex);
static void _texture_reimport_3d(const Ref<StreamTexture> &p_tex);
static void _texture_reimport_normal(const Ref<StreamTexture> &p_tex);
static ResourceImporterLayeredTexture *singleton;
public:
static ResourceImporterLayeredTexture *get_singleton() { return singleton; }
virtual String get_importer_name() const;
virtual String get_visible_name() const;
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual String get_save_extension() const;
virtual String get_resource_type() const;
enum Preset {
PRESET_3D,
PRESET_2D,
PRESET_COLOR_CORRECT,
};
enum CompressMode {
COMPRESS_LOSSLESS,
COMPRESS_VIDEO_RAM,
COMPRESS_UNCOMPRESSED
};
virtual int get_preset_count() const;
virtual String get_preset_name(int p_idx) const;
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_tex(const Vector<Ref<Image> > &p_images, const String &p_to_path, int p_compress_mode, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags);
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);
void update_imports();
void set_3d(bool p_3d) { is_3d = p_3d; }
ResourceImporterLayeredTexture();
~ResourceImporterLayeredTexture();
};
#endif // RESOURCE_IMPORTER_LAYERED_TEXTURE_H

View file

@ -98,6 +98,33 @@ static void _compress_etc(Image *p_img, float p_lossy_quality, bool force_etc1_f
Image::Format img_format = p_img->get_format();
Image::DetectChannels detected_channels = p_img->get_detected_channels();
if (p_source == Image::COMPRESS_SOURCE_LAYERED) {
//keep what comes in
switch (p_img->get_format()) {
case Image::FORMAT_L8: {
detected_channels = Image::DETECTED_L;
} break;
case Image::FORMAT_LA8: {
detected_channels = Image::DETECTED_LA;
} break;
case Image::FORMAT_R8: {
detected_channels = Image::DETECTED_R;
} break;
case Image::FORMAT_RG8: {
detected_channels = Image::DETECTED_RG;
} break;
case Image::FORMAT_RGB8: {
detected_channels = Image::DETECTED_RGB;
} break;
case Image::FORMAT_RGBA8:
case Image::FORMAT_RGBA4444:
case Image::FORMAT_RGBA5551: {
detected_channels = Image::DETECTED_RGBA;
} break;
default: {}
}
}
if (p_source == Image::COMPRESS_SOURCE_SRGB && (detected_channels == Image::DETECTED_R || detected_channels == Image::DETECTED_RG)) {
//R and RG do not support SRGB
detected_channels = Image::DETECTED_RGB;
@ -147,7 +174,7 @@ static void _compress_etc(Image *p_img, float p_lossy_quality, bool force_etc1_f
PoolVector<uint8_t>::Read r = img->get_data().read();
int target_size = Image::get_image_data_size(imgw, imgh, etc_format, p_img->has_mipmaps() ? -1 : 0);
int target_size = Image::get_image_data_size(imgw, imgh, etc_format, p_img->has_mipmaps());
int mmc = 1 + (p_img->has_mipmaps() ? Image::get_image_required_mipmaps(imgw, imgh, etc_format) : 0);
PoolVector<uint8_t> dst_data;

View file

@ -46,7 +46,7 @@ void image_decompress_squish(Image *p_image) {
Image::Format target_format = Image::FORMAT_RGBA8;
PoolVector<uint8_t> data;
int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps() ? -1 : 0);
int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps());
int mm_count = p_image->get_mipmap_count();
data.resize(target_size);
@ -96,6 +96,33 @@ void image_compress_squish(Image *p_image, Image::CompressSource p_source) {
Image::DetectChannels dc = p_image->get_detected_channels();
if (p_source == Image::COMPRESS_SOURCE_LAYERED) {
//keep what comes in
switch (p_image->get_format()) {
case Image::FORMAT_L8: {
dc = Image::DETECTED_L;
} break;
case Image::FORMAT_LA8: {
dc = Image::DETECTED_LA;
} break;
case Image::FORMAT_R8: {
dc = Image::DETECTED_R;
} break;
case Image::FORMAT_RG8: {
dc = Image::DETECTED_RG;
} break;
case Image::FORMAT_RGB8: {
dc = Image::DETECTED_RGB;
} break;
case Image::FORMAT_RGBA8:
case Image::FORMAT_RGBA4444:
case Image::FORMAT_RGBA5551: {
dc = Image::DETECTED_RGBA;
} break;
default: {}
}
}
p_image->convert(Image::FORMAT_RGBA8); //still uses RGBA to convert
if (p_source == Image::COMPRESS_SOURCE_SRGB && (dc == Image::DETECTED_R || dc == Image::DETECTED_RG)) {
@ -148,7 +175,7 @@ void image_compress_squish(Image *p_image, Image::CompressSource p_source) {
}
PoolVector<uint8_t> data;
int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps() ? -1 : 0);
int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps());
int mm_count = p_image->has_mipmaps() ? Image::get_image_required_mipmaps(w, h, target_format) : 0;
data.resize(target_size);
int shift = Image::get_format_pixel_rshift(target_format);

View file

@ -217,6 +217,7 @@ static ResourceFormatLoaderText *resource_loader_text = NULL;
static ResourceFormatLoaderDynamicFont *resource_loader_dynamic_font = NULL;
static ResourceFormatLoaderStreamTexture *resource_loader_stream_texture = NULL;
static ResourceFormatLoaderTextureLayered *resource_loader_texture_layered = NULL;
static ResourceFormatLoaderBMFont *resource_loader_bmfont = NULL;
@ -237,6 +238,9 @@ void register_scene_types() {
resource_loader_stream_texture = memnew(ResourceFormatLoaderStreamTexture);
ResourceLoader::add_resource_format_loader(resource_loader_stream_texture);
resource_loader_texture_layered = memnew(ResourceFormatLoaderTextureLayered);
ResourceLoader::add_resource_format_loader(resource_loader_texture_layered);
resource_loader_theme = memnew(ResourceFormatLoaderTheme);
ResourceLoader::add_resource_format_loader(resource_loader_theme);
@ -615,7 +619,9 @@ void register_scene_types() {
ClassDB::register_class<ProxyTexture>();
ClassDB::register_class<AnimatedTexture>();
ClassDB::register_class<CubeMap>();
ClassDB::register_virtual_class<TextureLayered>();
ClassDB::register_class<Texture3D>();
ClassDB::register_class<TextureArray>();
ClassDB::register_class<Animation>();
ClassDB::register_virtual_class<Font>();
ClassDB::register_class<BitmapFont>();
@ -729,6 +735,7 @@ void unregister_scene_types() {
memdelete(resource_loader_dynamic_font);
memdelete(resource_loader_stream_texture);
memdelete(resource_loader_texture_layered);
memdelete(resource_loader_theme);
DynamicFont::finish_dynamic_fonts();

View file

@ -151,13 +151,6 @@ bool ImageTexture::_get(const StringName &p_name, Variant &r_ret) const {
void ImageTexture::_get_property_list(List<PropertyInfo> *p_list) const {
PropertyHint img_hint = PROPERTY_HINT_NONE;
if (storage == STORAGE_COMPRESS_LOSSY) {
img_hint = PROPERTY_HINT_IMAGE_COMPRESS_LOSSY;
} else if (storage == STORAGE_COMPRESS_LOSSLESS) {
img_hint = PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS;
}
p_list->push_back(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Mipmaps,Repeat,Filter,Anisotropic,sRGB,Mirrored Repeat"));
p_list->push_back(PropertyInfo(Variant::OBJECT, "image", PROPERTY_HINT_RESOURCE_TYPE, "Image"));
p_list->push_back(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, ""));
@ -592,7 +585,7 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &fla
int sh = th;
int mipmaps = Image::get_image_required_mipmaps(tw, th, format);
int total_size = Image::get_image_data_size(tw, th, format, mipmaps);
int total_size = Image::get_image_data_size(tw, th, format, true);
int idx = 0;
int ofs = 0;
@ -1155,7 +1148,6 @@ void LargeTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile
Size2 scale = p_rect.size / size;
RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
for (int i = 0; i < pieces.size(); i++) {
// TODO
@ -1170,7 +1162,6 @@ void LargeTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, cons
Size2 scale = p_rect.size / p_src_rect.size;
RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
for (int i = 0; i < pieces.size(); i++) {
// TODO
@ -1322,13 +1313,6 @@ bool CubeMap::_get(const StringName &p_name, Variant &r_ret) const {
void CubeMap::_get_property_list(List<PropertyInfo> *p_list) const {
PropertyHint img_hint = PROPERTY_HINT_NONE;
if (storage == STORAGE_COMPRESS_LOSSY) {
img_hint = PROPERTY_HINT_IMAGE_COMPRESS_LOSSY;
} else if (storage == STORAGE_COMPRESS_LOSSLESS) {
img_hint = PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS;
}
p_list->push_back(PropertyInfo(Variant::OBJECT, "side/left", PROPERTY_HINT_RESOURCE_TYPE, "Image"));
p_list->push_back(PropertyInfo(Variant::OBJECT, "side/right", PROPERTY_HINT_RESOURCE_TYPE, "Image"));
p_list->push_back(PropertyInfo(Variant::OBJECT, "side/bottom", PROPERTY_HINT_RESOURCE_TYPE, "Image"));
@ -1876,112 +1860,9 @@ AnimatedTexture::AnimatedTexture() {
AnimatedTexture::~AnimatedTexture() {
VS::get_singleton()->free(proxy);
}
///////////////////////////////
bool Texture3D::get_split_single_image_enabled() const {
return split_single_image_enabled;
}
void Texture3D::set_split_single_image_enabled(bool p_split_enabled) {
split_single_image_enabled = p_split_enabled;
_change_notify();
}
uint32_t Texture3D::get_split_single_image_h_split() const {
return split_single_image_h_split;
}
void Texture3D::set_split_single_image_h_split(uint32_t p_h_split) {
split_single_image_h_split = p_h_split;
if (split_single_image_image.is_valid())
create_from_image(split_single_image_image, split_single_image_h_split, split_single_image_v_split, split_single_image_num_layers, flags);
}
uint32_t Texture3D::get_split_single_image_v_split() const {
return split_single_image_v_split;
}
void Texture3D::set_split_single_image_v_split(uint32_t p_v_split) {
split_single_image_v_split = p_v_split;
if (split_single_image_image.is_valid())
create_from_image(split_single_image_image, split_single_image_h_split, split_single_image_v_split, split_single_image_num_layers, flags);
}
uint32_t Texture3D::get_split_single_image_num_layers() const {
return split_single_image_num_layers;
}
void Texture3D::set_split_single_image_num_layers(uint32_t p_num_layers) {
split_single_image_num_layers = p_num_layers;
if (split_single_image_image.is_valid())
create_from_image(split_single_image_image, split_single_image_h_split, split_single_image_v_split, split_single_image_num_layers, flags);
}
Ref<Image> Texture3D::get_split_single_image_image() const {
return split_single_image_image;
}
void Texture3D::set_split_single_image_image(const Ref<Image> &p_image) {
split_single_image_image = p_image;
create_from_image(split_single_image_image, split_single_image_h_split, split_single_image_v_split, split_single_image_num_layers, flags);
}
void Texture3D::_validate_property(PropertyInfo &property) const {
if (property.name.begins_with("split_single_image_") && property.name != "split_single_image_enabled" && !split_single_image_enabled) {
property.usage = 0;
}
}
void Texture3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_flags", "flags"), &Texture3D::set_flags);
ClassDB::bind_method(D_METHOD("get_flags"), &Texture3D::get_flags);
ClassDB::bind_method(D_METHOD("get_format"), &Texture3D::get_format);
ClassDB::bind_method(D_METHOD("get_width"), &Texture3D::get_width);
ClassDB::bind_method(D_METHOD("get_height"), &Texture3D::get_height);
ClassDB::bind_method(D_METHOD("get_depth"), &Texture3D::get_depth);
ClassDB::bind_method(D_METHOD("set_split_single_image_enabled", "split_enabled"), &Texture3D::set_split_single_image_enabled);
ClassDB::bind_method(D_METHOD("get_split_single_image_enabled"), &Texture3D::get_split_single_image_enabled);
ClassDB::bind_method(D_METHOD("set_split_single_image_h_split", "h_split"), &Texture3D::set_split_single_image_h_split);
ClassDB::bind_method(D_METHOD("get_split_single_image_h_split"), &Texture3D::get_split_single_image_h_split);
ClassDB::bind_method(D_METHOD("set_split_single_image_v_split", "v_split"), &Texture3D::set_split_single_image_v_split);
ClassDB::bind_method(D_METHOD("get_split_single_image_v_split"), &Texture3D::get_split_single_image_v_split);
ClassDB::bind_method(D_METHOD("set_split_single_image_num_layers", "num_layers"), &Texture3D::set_split_single_image_num_layers);
ClassDB::bind_method(D_METHOD("get_split_single_image_num_layers"), &Texture3D::get_split_single_image_num_layers);
ClassDB::bind_method(D_METHOD("set_split_single_image_image", "image"), &Texture3D::set_split_single_image_image);
ClassDB::bind_method(D_METHOD("get_split_single_image_image"), &Texture3D::get_split_single_image_image);
ClassDB::bind_method(D_METHOD("create", "width", "height", "depth", "format", "flags"), &Texture3D::create, DEFVAL(FLAGS_DEFAULT));
ClassDB::bind_method(D_METHOD("create_from_image", "image", "h_split", "v_split", "num_layer", "flags"), &Texture3D::create_from_image, DEFVAL(FLAGS_DEFAULT));
ClassDB::bind_method(D_METHOD("set_data_partial", "image", "x_offset", "y_offset", "layer", "mipmap"), &Texture3D::set_data_partial, DEFVAL(0));
ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Mipmaps,Repeat,Filter"), "set_flags", "get_flags");
BIND_ENUM_CONSTANT(FLAG_MIPMAPS);
BIND_ENUM_CONSTANT(FLAG_REPEAT);
BIND_ENUM_CONSTANT(FLAG_FILTER);
BIND_ENUM_CONSTANT(FLAGS_DEFAULT);
ADD_GROUP("Split single image", "split_single_image_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "split_single_image_enabled"), "set_split_single_image_enabled", "get_split_single_image_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "split_single_image_h_split", PROPERTY_HINT_RANGE, "0,1000"), "set_split_single_image_h_split", "get_split_single_image_h_split");
ADD_PROPERTY(PropertyInfo(Variant::INT, "split_single_image_v_split", PROPERTY_HINT_RANGE, "0,1000"), "set_split_single_image_v_split", "get_split_single_image_v_split");
ADD_PROPERTY(PropertyInfo(Variant::INT, "split_single_image_num_layers"), "set_split_single_image_num_layers", "get_split_single_image_num_layers");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "split_single_image_image", PROPERTY_HINT_RESOURCE_TYPE, "Image"), "set_split_single_image_image", "get_split_single_image_image");
}
void Texture3D::set_flags(uint32_t p_flags) {
void TextureLayered::set_flags(uint32_t p_flags) {
flags = p_flags;
if (texture.is_valid()) {
@ -1989,28 +1870,71 @@ void Texture3D::set_flags(uint32_t p_flags) {
}
}
uint32_t Texture3D::get_flags() const {
uint32_t TextureLayered::get_flags() const {
return flags;
}
Image::Format Texture3D::get_format() const {
Image::Format TextureLayered::get_format() const {
return format;
}
uint32_t Texture3D::get_width() const {
uint32_t TextureLayered::get_width() const {
return width;
}
uint32_t Texture3D::get_height() const {
uint32_t TextureLayered::get_height() const {
return height;
}
uint32_t Texture3D::get_depth() const {
uint32_t TextureLayered::get_depth() const {
return depth;
}
void Texture3D::create(uint32_t p_width, uint32_t p_height, uint32_t p_depth, Image::Format p_format, uint32_t p_flags) {
VS::get_singleton()->texture_allocate(texture, p_width, p_height, p_depth, p_format, VS::TEXTURE_TYPE_3D, p_flags);
void TextureLayered::_set_data(const Dictionary &p_data) {
ERR_FAIL_COND(!p_data.has("width"));
ERR_FAIL_COND(!p_data.has("height"));
ERR_FAIL_COND(!p_data.has("depth"));
ERR_FAIL_COND(!p_data.has("format"));
ERR_FAIL_COND(!p_data.has("flags"));
ERR_FAIL_COND(!p_data.has("layers"));
int w = p_data["width"];
int h = p_data["height"];
int d = p_data["depth"];
Image::Format format = Image::Format(int(p_data["format"]));
int flags = p_data["flags"];
Array layers = p_data["layers"];
ERR_FAIL_COND(layers.size() != d);
create(w, h, d, format, flags);
for (int i = 0; i < layers.size(); i++) {
Ref<Image> img = layers[i];
ERR_CONTINUE(!img.is_valid());
ERR_CONTINUE(img->get_format() != format);
ERR_CONTINUE(img->get_width() != w);
ERR_CONTINUE(img->get_height() != h);
set_layer_data(img, i);
}
}
Dictionary TextureLayered::_get_data() const {
Dictionary d;
d["width"] = width;
d["height"] = height;
d["depth"] = depth;
d["flags"] = flags;
d["format"] = format;
Array layers;
for (int i = 0; i < depth; i++) {
layers.push_back(get_layer_data(i));
}
d["layers"] = layers;
return d;
}
void TextureLayered::create(uint32_t p_width, uint32_t p_height, uint32_t p_depth, Image::Format p_format, uint32_t p_flags) {
VS::get_singleton()->texture_allocate(texture, p_width, p_height, p_depth, p_format, is_3d ? VS::TEXTURE_TYPE_3D : VS::TEXTURE_TYPE_2D_ARRAY, p_flags);
width = p_width;
height = p_height;
@ -2019,40 +1943,27 @@ void Texture3D::create(uint32_t p_width, uint32_t p_height, uint32_t p_depth, Im
flags = p_flags;
}
void Texture3D::create_from_image(const Ref<Image> &p_image, uint32_t p_h_split, uint32_t p_v_split, uint32_t p_num_layer, uint32_t flags) {
ERR_FAIL_COND(p_image.is_null());
ERR_FAIL_COND((p_h_split + 1) * (p_v_split + 1) < p_num_layer);
uint32_t total_width = p_image->get_width();
uint32_t total_height = p_image->get_height();
uint32_t width = total_width / (p_h_split + 1);
uint32_t height = total_height / (p_v_split + 1);
create(width, height, p_num_layer, p_image->get_format(), flags);
for (uint32_t i = 0; i < p_num_layer; i++) {
uint32_t row = i / (p_v_split + 1);
uint32_t col = i % (p_v_split + 1);
uint32_t x_offset = col * width;
uint32_t y_offset = row * height;
VS::get_singleton()->texture_set_data_partial(texture, p_image, x_offset, y_offset, width, height, 0, 0, 0, i);
}
}
void Texture3D::set_data_partial(const Ref<Image> &p_image, int p_x_ofs, int p_y_ofs, int p_layer, int p_mipmap) {
void TextureLayered::set_layer_data(const Ref<Image> &p_image, int p_layer) {
ERR_FAIL_COND(!texture.is_valid());
VS::get_singleton()->texture_set_data_partial(texture, p_image, 0, 0, p_image->get_width(), p_image->get_height(), p_x_ofs, p_y_ofs, p_mipmap, p_layer);
VS::get_singleton()->texture_set_data(texture, p_image, p_layer);
}
RID Texture3D::get_rid() const {
Ref<Image> TextureLayered::get_layer_data(int p_layer) const {
ERR_FAIL_COND_V(!texture.is_valid(), Ref<Image>());
return VS::get_singleton()->texture_get_data(texture, p_layer);
}
void TextureLayered::set_data_partial(const Ref<Image> &p_image, int p_x_ofs, int p_y_ofs, int p_z, int p_mipmap) {
ERR_FAIL_COND(!texture.is_valid());
VS::get_singleton()->texture_set_data_partial(texture, p_image, 0, 0, p_image->get_width(), p_image->get_height(), p_x_ofs, p_y_ofs, p_mipmap, p_z);
}
RID TextureLayered::get_rid() const {
return texture;
}
void Texture3D::set_path(const String &p_path, bool p_take_over) {
void TextureLayered::set_path(const String &p_path, bool p_take_over) {
if (texture.is_valid()) {
VS::get_singleton()->texture_set_path(texture, p_path);
}
@ -2060,7 +1971,35 @@ void Texture3D::set_path(const String &p_path, bool p_take_over) {
Resource::set_path(p_path, p_take_over);
}
Texture3D::Texture3D() {
void TextureLayered::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_flags", "flags"), &TextureLayered::set_flags);
ClassDB::bind_method(D_METHOD("get_flags"), &TextureLayered::get_flags);
ClassDB::bind_method(D_METHOD("get_format"), &TextureLayered::get_format);
ClassDB::bind_method(D_METHOD("get_width"), &TextureLayered::get_width);
ClassDB::bind_method(D_METHOD("get_height"), &TextureLayered::get_height);
ClassDB::bind_method(D_METHOD("get_depth"), &TextureLayered::get_depth);
ClassDB::bind_method(D_METHOD("create", "width", "height", "depth", "format", "flags"), &TextureLayered::create, DEFVAL(FLAGS_DEFAULT));
ClassDB::bind_method(D_METHOD("set_layer_data", "image", "layer"), &TextureLayered::set_layer_data);
ClassDB::bind_method(D_METHOD("get_layer_data", "layer"), &TextureLayered::set_layer_data);
ClassDB::bind_method(D_METHOD("set_data_partial", "image", "x_offset", "y_offset", "layer", "mipmap"), &TextureLayered::set_data_partial, DEFVAL(0));
ClassDB::bind_method(D_METHOD("_set_data", "data"), &TextureLayered::_set_data);
ClassDB::bind_method(D_METHOD("_get_data"), &TextureLayered::_get_data);
ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Mipmaps,Repeat,Filter"), "set_flags", "get_flags");
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_data", "_get_data");
BIND_ENUM_CONSTANT(FLAG_MIPMAPS);
BIND_ENUM_CONSTANT(FLAG_REPEAT);
BIND_ENUM_CONSTANT(FLAG_FILTER);
BIND_ENUM_CONSTANT(FLAGS_DEFAULT);
}
TextureLayered::TextureLayered(bool p_3d) {
is_3d = p_3d;
format = Image::FORMAT_MAX;
flags = FLAGS_DEFAULT;
@ -2068,17 +2007,180 @@ Texture3D::Texture3D() {
height = 0;
depth = 0;
split_single_image_enabled = false;
split_single_image_h_split = 0;
split_single_image_v_split = 0;
split_single_image_num_layers = 0;
split_single_image_image = Ref<Image>();
texture = VS::get_singleton()->texture_create();
}
Texture3D::~Texture3D() {
TextureLayered::~TextureLayered() {
if (texture.is_valid()) {
VS::get_singleton()->free(texture);
}
}
RES ResourceFormatLoaderTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error) {
if (r_error) {
*r_error = ERR_CANT_OPEN;
}
Ref<TextureLayered> lt;
Ref<Texture3D> tex3d;
Ref<TextureArray> texarr;
if (p_path.ends_with("tex3d")) {
tex3d.instance();
lt = tex3d;
} else if (p_path.ends_with("texarr")) {
texarr.instance();
lt = texarr;
} else {
ERR_EXPLAIN("Unrecognized layered texture extension");
ERR_FAIL_V(RES());
}
FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
ERR_FAIL_COND_V(!f, RES());
uint8_t header[5] = { 0, 0, 0, 0, 0 };
f->get_buffer(header, 4);
if (header[0] == 'G' && header[1] == 'D' && header[2] == '3' && header[3] == 'T') {
if (tex3d.is_null()) {
memdelete(f);
ERR_FAIL_COND_V(tex3d.is_null(), RES())
}
} else if (header[0] == 'G' && header[1] == 'D' && header[2] == 'A' && header[3] == 'T') {
if (texarr.is_null()) {
memdelete(f);
ERR_FAIL_COND_V(texarr.is_null(), RES())
}
} else {
ERR_EXPLAIN("Unrecognized layered texture file format: " + String((const char *)header));
ERR_FAIL_V(RES());
}
int tw = f->get_32();
int th = f->get_32();
int td = f->get_32();
int flags = f->get_32(); //texture flags!
Image::Format format = Image::Format(f->get_32());
uint32_t compression = f->get_32(); // 0 - lossless (PNG), 1 - vram, 2 - uncompressed
lt->create(tw, th, td, format, flags);
for (int layer = 0; layer < td; layer++) {
Ref<Image> image;
image.instance();
if (compression == COMPRESSION_LOSSLESS) {
//look for a PNG file inside
int mipmaps = f->get_32();
Vector<Ref<Image> > mipmap_images;
for (int i = 0; i < mipmaps; i++) {
uint32_t size = f->get_32();
PoolVector<uint8_t> pv;
pv.resize(size);
{
PoolVector<uint8_t>::Write w = pv.write();
f->get_buffer(w.ptr(), size);
}
Ref<Image> img = Image::lossless_unpacker(pv);
if (img.is_null() || img->empty() || format != img->get_format()) {
if (r_error) {
*r_error = ERR_FILE_CORRUPT;
}
memdelete(f);
ERR_FAIL_V(RES());
}
mipmap_images.push_back(img);
}
if (mipmap_images.size() == 1) {
image = mipmap_images[0];
} else {
int total_size = Image::get_image_data_size(tw, th, format, true);
PoolVector<uint8_t> img_data;
img_data.resize(total_size);
{
PoolVector<uint8_t>::Write w = img_data.write();
int ofs = 0;
for (int i = 0; i < mipmap_images.size(); i++) {
PoolVector<uint8_t> id = mipmap_images[i]->get_data();
int len = id.size();
PoolVector<uint8_t>::Read r = id.read();
copymem(&w[ofs], r.ptr(), len);
ofs += len;
}
}
image->create(tw, th, true, format, img_data);
if (image->empty()) {
if (r_error) {
*r_error = ERR_FILE_CORRUPT;
}
memdelete(f);
ERR_FAIL_V(RES());
}
}
} else {
//look for regular format
bool mipmaps = (flags & Texture::FLAG_MIPMAPS);
int total_size = Image::get_image_data_size(tw, th, format, mipmaps);
PoolVector<uint8_t> img_data;
img_data.resize(total_size);
{
PoolVector<uint8_t>::Write w = img_data.write();
int bytes = f->get_buffer(w.ptr(), total_size);
if (bytes != total_size) {
if (r_error) {
*r_error = ERR_FILE_CORRUPT;
memdelete(f);
}
ERR_FAIL_V(RES());
}
}
image->create(tw, th, mipmaps, format, img_data);
}
lt->set_layer_data(image, layer);
}
if (r_error)
*r_error = OK;
return lt;
}
void ResourceFormatLoaderTextureLayered::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("tex3d");
p_extensions->push_back("texarr");
}
bool ResourceFormatLoaderTextureLayered::handles_type(const String &p_type) const {
return p_type == "Texture3D" || p_type == "TextureArray";
}
String ResourceFormatLoaderTextureLayered::get_resource_type(const String &p_path) const {
if (p_path.get_extension().to_lower() == "tex3d")
return "Texture3D";
if (p_path.get_extension().to_lower() == "texarr")
return "TextureArray";
return "";
}

View file

@ -401,39 +401,33 @@ VARIANT_ENUM_CAST(CubeMap::Flags)
VARIANT_ENUM_CAST(CubeMap::Side)
VARIANT_ENUM_CAST(CubeMap::Storage)
class Texture3D : public Resource {
class TextureLayered : public Resource {
GDCLASS(Texture3D, Resource)
RES_BASE_EXTENSION("tex3d")
GDCLASS(TextureLayered, Resource)
public:
enum Flags {
FLAG_MIPMAPS = VisualServer::TEXTURE_FLAG_MIPMAPS,
FLAG_REPEAT = VisualServer::TEXTURE_FLAG_REPEAT,
FLAG_FILTER = VisualServer::TEXTURE_FLAG_FILTER,
FLAGS_DEFAULT = FLAG_REPEAT | FLAG_FILTER,
FLAG_CONVERT_TO_LINEAR = VisualServer::TEXTURE_FLAG_CONVERT_TO_LINEAR,
FLAGS_DEFAULT = FLAG_FILTER,
};
private:
bool is_3d;
RID texture;
Image::Format format;
uint32_t flags;
uint32_t width;
uint32_t height;
uint32_t depth;
int width;
int height;
int depth;
// for setting an image as a property
bool split_single_image_enabled;
uint32_t split_single_image_h_split;
uint32_t split_single_image_v_split;
uint32_t split_single_image_num_layers;
Ref<Image> split_single_image_image;
void _set_data(const Dictionary &p_data);
Dictionary _get_data() const;
protected:
void _validate_property(PropertyInfo &property) const;
static void _bind_methods();
public:
@ -446,30 +440,47 @@ public:
uint32_t get_depth() const;
void create(uint32_t p_width, uint32_t p_height, uint32_t p_depth, Image::Format p_format, uint32_t p_flags = FLAGS_DEFAULT);
void create_from_image(const Ref<Image> &p_image, uint32_t p_h_split, uint32_t p_v_split, uint32_t p_num_layer, uint32_t flags = FLAGS_DEFAULT);
void set_data_partial(const Ref<Image> &p_image, int p_x_ofs, int p_y_ofs, int p_layer, int p_mipmap = 0);
void set_layer_data(const Ref<Image> &p_image, int p_layer);
Ref<Image> get_layer_data(int p_layer) const;
void set_data_partial(const Ref<Image> &p_image, int p_x_ofs, int p_y_ofs, int p_z, int p_mipmap = 0);
virtual RID get_rid() const;
bool get_split_single_image_enabled() const;
void set_split_single_image_enabled(bool p_split_enabled);
uint32_t get_split_single_image_h_split() const;
void set_split_single_image_h_split(uint32_t p_h_split);
uint32_t get_split_single_image_v_split() const;
void set_split_single_image_v_split(uint32_t p_v_split);
uint32_t get_split_single_image_num_layers() const;
void set_split_single_image_num_layers(uint32_t p_num_layers);
Ref<Image> get_split_single_image_image() const;
void set_split_single_image_image(const Ref<Image> &p_image);
virtual void set_path(const String &p_path, bool p_take_over = false);
Texture3D();
~Texture3D();
TextureLayered(bool p_3d = false);
~TextureLayered();
};
VARIANT_ENUM_CAST(TextureLayered::Flags)
class Texture3D : public TextureLayered {
GDCLASS(Texture3D, TextureLayered)
public:
Texture3D() :
TextureLayered(true) {}
};
class TextureArray : public TextureLayered {
GDCLASS(TextureArray, TextureLayered)
public:
TextureArray() :
TextureLayered(false) {}
};
class ResourceFormatLoaderTextureLayered : public ResourceFormatLoader {
public:
enum Compression {
COMPRESSION_LOSSLESS,
COMPRESSION_VRAM,
COMPRESSION_UNCOMPRESSED
};
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
};
class CurveTexture : public Texture {