diff options
Diffstat (limited to 'o3d/import/cross/collada.cc')
-rw-r--r-- | o3d/import/cross/collada.cc | 144 |
1 files changed, 143 insertions, 1 deletions
diff --git a/o3d/import/cross/collada.cc b/o3d/import/cross/collada.cc index 2076921d..cfc64b3 100644 --- a/o3d/import/cross/collada.cc +++ b/o3d/import/cross/collada.cc @@ -56,7 +56,9 @@ #include "import/cross/collada_conditioner.h" #include "import/cross/collada_zip_archive.h" #include "import/cross/destination_buffer.h" +#include "import/cross/file_output_stream_processor.h" #include "utils/cross/file_path_utils.h" +#include "third_party/libtxc_dxtn/files/txc_dxtn.h" #define COLLADA_NAMESPACE "collada" #define COLLADA_NAMESPACE_SEPARATOR "." @@ -1698,7 +1700,147 @@ Texture* Collada::BuildTextureFromImage(FCDImage* image) { tex->set_name(WideToUTF8(name.c_str())); } - if (options_.keep_original_data) { + bool inserted_original_data = false; + bool is_dds = uri.MatchesExtension(UTF8ToFilePathStringType(".dds")); + + if (is_dds && + options_.convert_dds_to_png && + options_.keep_original_data) { + // The Texture stubs used by the converter don't have a working + // PlatformSpecificLock, so we need to reload the images using + // the Bitmap class. We also need to do the DXTn decompression + // on the CPU because D3D wouldn't provide access to the + // decompressed data anyway. + + // These need to match the order of TextureCUBE::CubeFace. + static const char* cube_suffixes[6] = { + "_posx", "_negx", "_posy", "_negy", "_posz", "_negz" + }; + static const char* cube_prefixes[6] = { + "posx_", "negx_", "posy_", "negy_", "posz_", "negz_" + }; + + BitmapRefArray bitmaps; + bool is_cube_map = false; + if (Bitmap::LoadFromFile(service_locator_, file_path, + image::UNKNOWN, &bitmaps)) { + is_cube_map = bitmaps.size() == 6; + for (unsigned int i = 0; i < bitmaps.size(); i++) { + bool is_compressed = + (tex->format() == Texture::DXT1 || + tex->format() == Texture::DXT3 || + tex->format() == Texture::DXT5); + Bitmap::Ref src_bitmap = bitmaps[i]; + int pitch = src_bitmap->GetMipPitch(0); + if (is_compressed) { + // TODO(kbr): there is a bug somewhere in + // Bitmap::GetMipPitch for compressed textures where its + // result is off by a factor of two, at least for DXT1 + // textures. Don't have time to debug it right now. + pitch /= 2; + } + uint8* data = src_bitmap->GetMipData(0); + int width = src_bitmap->width(); + int height = src_bitmap->height(); + int row_width = width * 4; + int decompressed_size = width * height * 4; + scoped_array<uint8> decompressed_data(new uint8[decompressed_size]); + memset(decompressed_data.get(), 0, decompressed_size); + if (is_compressed) { + for (int src_y = 0; src_y < height; src_y++) { + int dest_y = src_y; + if (is_cube_map) { + dest_y = height - src_y - 1; + } + for (int x = 0; x < width; x++) { + uint8* ptr = + &decompressed_data.get()[row_width * dest_y + 4 * x]; + switch (src_bitmap->format()) { + case Texture::DXT1: { + fetch_2d_texel_rgba_dxt1(pitch, data, x, src_y, ptr); + break; + } + case Texture::DXT3: { + fetch_2d_texel_rgba_dxt3(pitch, data, x, src_y, ptr); + break; + } + case Texture::DXT5: { + fetch_2d_texel_rgba_dxt5(pitch, data, x, src_y, ptr); + break; + } + default: + DLOG(ERROR) << "Unsupported DDS compressed texture format " + << src_bitmap->format(); + break; + } + // Need to swap the red and blue channels. + std::swap(ptr[0], ptr[2]); + } + } + } else if (src_bitmap->format() == Texture::XRGB8 || + src_bitmap->format() == Texture::ARGB8) { + for (int src_y = 0; src_y < height; src_y++) { + int dest_y = src_y; + if (is_cube_map) { + dest_y = height - src_y - 1; + } + memcpy(decompressed_data.get() + row_width * dest_y, + data + pitch * src_y, + row_width); + } + } else { + DLOG(ERROR) << "Unsupported DDS uncompressed texture format " + << src_bitmap->format(); + return NULL; + } + Bitmap::Ref bitmap(new Bitmap(service_locator_)); + bitmap->Allocate(Texture::ARGB8, + width, + height, + 1, + Bitmap::IMAGE); + bitmap->SetRect(0, 0, 0, width, height, + decompressed_data.get(), + row_width); + std::vector<uint8> png_data; + if (!bitmap->WriteToPNGStream(&png_data)) { + DLOG(ERROR) << "Error writing PNG file for cube map"; + } + FilePath png_uri = uri; + if (is_cube_map) { + png_uri = png_uri.InsertBeforeExtensionASCII(cube_suffixes[i]); + } + png_uri = png_uri.ReplaceExtension(UTF8ToFilePathStringType(".png")); + std::string contents; + contents.append(reinterpret_cast<char*>(&png_data.front()), + png_data.size()); + original_data_map_.AddData(png_uri, contents, service_locator_); + inserted_original_data = true; + + // We need to rewrite the o3d.uri param in the Texture as + // well. For cube map textures, we insert six params named + // "o3d.negx_uri", etc. and remove the "o3d.uri" param. + ParamString* uri_param = NULL; + if (is_cube_map) { + String name(O3D_STRING_CONSTANT("")); + name = name.append(cube_prefixes[i]).append("uri"); + uri_param = tex->CreateParam<ParamString>(name); + } else { + uri_param = tex->GetParam<ParamString>(O3D_STRING_CONSTANT("uri")); + } + DCHECK(uri_param != NULL); + uri_param->set_value(FilePathToUTF8(png_uri)); + } + } + if (is_cube_map) { + ParamString* uri_param = + tex->GetParam<ParamString>(O3D_STRING_CONSTANT("uri")); + DCHECK(uri_param != NULL); + tex->RemoveParam(uri_param); + } + } + + if (options_.keep_original_data && !inserted_original_data) { // Cache the original data by URI so we can recover it later. std::string contents; file_util::ReadFileToString(file_path, &contents); |