diff options
Diffstat (limited to 'o3d')
-rw-r--r-- | o3d/DEPS | 5 | ||||
-rw-r--r-- | o3d/build/common.gypi | 1 | ||||
-rw-r--r-- | o3d/converter/converter.gyp | 2 | ||||
-rw-r--r-- | o3d/converter/cross/converter.cc | 1 | ||||
-rw-r--r-- | o3d/converter/cross/converter.h | 7 | ||||
-rw-r--r-- | o3d/converter/cross/converter_main.cc | 6 | ||||
-rw-r--r-- | o3d/core/cross/bitmap.h | 2 | ||||
-rw-r--r-- | o3d/core/cross/bitmap_png.cc | 18 | ||||
-rw-r--r-- | o3d/import/cross/collada.cc | 144 | ||||
-rw-r--r-- | o3d/import/cross/collada.h | 7 | ||||
-rw-r--r-- | o3d/samples/o3djs/serialization.js | 24 | ||||
-rw-r--r-- | o3d/samples/o3djs/texture.js | 60 | ||||
-rw-r--r-- | o3d/utils/cross/file_path_utils.cc | 8 | ||||
-rw-r--r-- | o3d/utils/cross/file_path_utils.h | 1 |
14 files changed, 279 insertions, 7 deletions
@@ -4,7 +4,7 @@ vars = { # When updating the chromium rev, you must also update the nss and sqlite # revs to match the version pulled-in by Chromium's own DEPS in the new rev. "chromium_rev": "37758", - "o3d_code_rev": "178", + "o3d_code_rev": "180", "skia_rev": "488", "gyp_rev": "798", "gtest_rev": "359", @@ -56,6 +56,9 @@ deps = { "o3d/third_party/glu": "http://o3d.googlecode.com/svn/trunk/googleclient/third_party/glu@" + Var("o3d_code_rev"), + "o3d/third_party/libtxc_dxtn": + "http://o3d.googlecode.com/svn/trunk/googleclient/third_party/libtxc_dxtn@" + Var("o3d_code_rev"), + "o3d/third_party/vectormath": "http://o3d.googlecode.com/svn/trunk/googleclient/third_party/vectormath@" + Var("o3d_code_rev"), diff --git a/o3d/build/common.gypi b/o3d/build/common.gypi index 4c319e4..ce9301c 100644 --- a/o3d/build/common.gypi +++ b/o3d/build/common.gypi @@ -19,6 +19,7 @@ 'screenshotsdir': 'o3d_assets/tests/screenshots', 'seleniumdir': 'third_party/selenium_rc/files', 'skiadir': 'third_party/skia/include', + 'txcdir': 'third_party/libtxc_dxtn/files', 'zlibdir': 'third_party/zlib', # Hack to ensure that these variables (specifically "renderer") are diff --git a/o3d/converter/converter.gyp b/o3d/converter/converter.gyp index ffede11f..fb99ddf 100644 --- a/o3d/converter/converter.gyp +++ b/o3d/converter/converter.gyp @@ -14,6 +14,7 @@ '..', '../..', '../../<(gtestdir)', + '../<(txcdir)', ], }, 'targets': [ @@ -53,6 +54,7 @@ 'cross/stream_bank_stub.h', 'cross/texture_stub.cc', 'cross/texture_stub.h', + '../<(txcdir)/txc_fetch_dxtn.cc', ], 'conditions' : [ ['renderer == "gl"', diff --git a/o3d/converter/cross/converter.cc b/o3d/converter/cross/converter.cc index cda3143..f039f5de 100644 --- a/o3d/converter/cross/converter.cc +++ b/o3d/converter/cross/converter.cc @@ -298,6 +298,7 @@ bool Convert(const FilePath& in_filename, collada_options.base_path = options.base_path; collada_options.file_paths = options.file_paths; collada_options.up_axis = options.up_axis; + collada_options.convert_dds_to_png = options.convert_dds_to_png; Collada collada(pack.Get(), collada_options); bool result = collada.ImportFile(in_filename, root, param_float); if (!result || !error_collector.errors().empty()) { diff --git a/o3d/converter/cross/converter.h b/o3d/converter/cross/converter.h index 47dde59..7a289ee 100644 --- a/o3d/converter/cross/converter.h +++ b/o3d/converter/cross/converter.h @@ -55,7 +55,8 @@ struct Options { pretty_print(false), keep_filters(false), keep_materials(false), - archive(true) { + archive(true), + convert_dds_to_png(false) { } // A list of paths to search for assets.. @@ -90,6 +91,10 @@ struct Options { // True means make a gzipped tar file. False means write individual files. bool archive; + + // True means convert DDS files to PNGs. For cube map textures, this + // implies writing six separate PNGs. + bool convert_dds_to_png; }; // Converts the given file for use in O3D. This is done by diff --git a/o3d/converter/cross/converter_main.cc b/o3d/converter/cross/converter_main.cc index 90d7774..9af930f 100644 --- a/o3d/converter/cross/converter_main.cc +++ b/o3d/converter/cross/converter_main.cc @@ -106,7 +106,10 @@ int CrossMain(int argc, char**argv) { << "--no-archive\n" << " Don't make a gzipped tar file, just flat files. Still takes\n" << " the name of an archive file; for archive.o3dtgz, creates\n" - << " directory named archive/ and writes files inside.\n"; + << " directory named archive/ and writes files inside.\n" + << "--convert-dds-to-png\n" + << " Convert all DDS textures to PNGs. For cube map textures,\n" + << " writes six separate PNGs with suffixes _posx, _negx, etc.\n"; return EXIT_FAILURE; } @@ -115,6 +118,7 @@ int CrossMain(int argc, char**argv) { options.pretty_print = command_line->HasSwitch("pretty-print"); options.binary = !command_line->HasSwitch("no-binary"); options.archive = !command_line->HasSwitch("no-archive"); + options.convert_dds_to_png = command_line->HasSwitch("convert-dds-to-png"); if (command_line->HasSwitch("base-path")) { options.base_path = o3d::WideToFilePath( command_line->GetSwitchValue("base-path")); diff --git a/o3d/core/cross/bitmap.h b/o3d/core/cross/bitmap.h index 96e9b7b..8af80a5 100644 --- a/o3d/core/cross/bitmap.h +++ b/o3d/core/cross/bitmap.h @@ -239,6 +239,8 @@ class Bitmap : public ParamObject { // Generates Mips from the source_level for num_levels void GenerateMips(int source_level, int num_levels); + bool WriteToPNGStream(std::vector<uint8>* stream); + private: friend class IClassManager; static ObjectBase::Ref Create(ServiceLocator* service_locator); diff --git a/o3d/core/cross/bitmap_png.cc b/o3d/core/cross/bitmap_png.cc index 6b73b94..686e854 100644 --- a/o3d/core/cross/bitmap_png.cc +++ b/o3d/core/cross/bitmap_png.cc @@ -316,6 +316,24 @@ bool CreatePNGInUInt8Vector(const Bitmap& bitmap, std::vector<uint8>* buffer) { } // anonymous namespace +bool Bitmap::WriteToPNGStream(std::vector<uint8>* stream) { + if (format_ != Texture::ARGB8) { + O3D_ERROR(service_locator()) << "Can only write ARGB8 images to PNGs."; + return false; + } + if (num_mipmaps_ != 1) { + O3D_ERROR(service_locator()) << + "Can only write 2d images with no mips to PNGs."; + return false; + } + + if (!CreatePNGInUInt8Vector(*this, stream)) { + return false; + } + + return true; +} + String Bitmap::ToDataURL() { if (format_ != Texture::ARGB8) { O3D_ERROR(service_locator()) << "Can only get data URL from ARGB8 images."; 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); diff --git a/o3d/import/cross/collada.h b/o3d/import/cross/collada.h index 1bac5ee..e0c1a02 100644 --- a/o3d/import/cross/collada.h +++ b/o3d/import/cross/collada.h @@ -161,7 +161,8 @@ class Collada { keep_original_data(false), condition_document(false), up_axis(0.0f, 0.0f, 0.0f), - base_path(FilePath::kCurrentDirectory) {} + base_path(FilePath::kCurrentDirectory), + convert_dds_to_png(false) {} // Whether or not to generate mip-maps on the textures we load. bool generate_mipmaps; @@ -182,6 +183,10 @@ class Collada { // A List of paths to search for files in. std::vector<FilePath> file_paths; + + // True means convert DDS files to PNGs. For cube map textures, this + // implies writing six separate PNGs. + bool convert_dds_to_png; }; // Collada Param Names. diff --git a/o3d/samples/o3djs/serialization.js b/o3d/samples/o3djs/serialization.js index 619fce0..51e751d 100644 --- a/o3d/samples/o3djs/serialization.js +++ b/o3d/samples/o3djs/serialization.js @@ -198,7 +198,29 @@ o3djs.serialization.Deserializer = function(pack, json) { }, 'o3d.TextureCUBE': function(deserializer, json) { - if ('o3d.uri' in json.params) { + if ('o3d.negx_uri' in json.params) { + // Cube map comprised of six separate textures. + var param_names = [ + 'o3d.posx_uri', + 'o3d.negx_uri', + 'o3d.posy_uri', + 'o3d.negy_uri', + 'o3d.posz_uri', + 'o3d.negz_uri' + ]; + var rawDataArray = []; + for (var i = 0; i < param_names.length; i++) { + var uri = json.params[param_names[i]].value; + var rawData = deserializer.archiveInfo.getFileByURI(uri); + if (!rawData) { + throw 'Could not find texture ' + uri + ' in the archive'; + } + rawDataArray.push(rawData); + } + // Cube map faces should not be flipped. + return o3djs.texture.createTextureFromRawDataArray( + pack, rawDataArray, true, false); + } else if ('o3d.uri' in json.params) { var uri = json.params['o3d.uri'].value; var rawData = deserializer.archiveInfo.getFileByURI(uri); if (!rawData) { diff --git a/o3d/samples/o3djs/texture.js b/o3d/samples/o3djs/texture.js index 5041dde..8232d26 100644 --- a/o3d/samples/o3djs/texture.js +++ b/o3d/samples/o3djs/texture.js @@ -119,6 +119,64 @@ o3djs.texture.createTextureFromRawData = function( }; /** + * Creates a texture from an array of RawData objects. This is mainly useful for + * creating a cube map out of six separate textures. + * @param {!o3d.Pack} pack The pack to create the texture in. + * @param {!Array.<!o3d.RawData>} rawDataArray The array of raw data objects to + * create the texture from. If these represent the six faces of a cube map, + * they must be in the order FACE_POSITIVE_X, FACE_NEGATIVE_X, + * FACE_POSITIVE_Y, FACE_NEGATIVE_Y, FACE_POSITIVE_Z, FACE_NEGATIVE_Z + * @param {boolean} opt_generateMips Whether or not to generate mips. Note, mips + * can not be generated for DXT textures although they will be loaded if they + * exist in the RawData. + * @param {boolean} opt_flip Whether or not to flip the texture. Most DCC tools + * Like Maya, Max, etc expect the textures to be flipped. Note that only + * 2D (image) textures will be flipped. Cube textures will not be flipped. + * Default = true. + * @param {number} opt_maxWidth The maximum width of the texture. If the RawData + * is larger than this size it will be scaled down to this size. Note that + * DXT format textures can not be scaled. Default = 2048. + * @param {number} opt_maxHeight The maximum width of the texture. If the + * RawData is larger than this size it will be scaled down to this size. Note + * that DXT format textures can not be scaled. Default = 2048. + * @return {!o3d.Texture} The created texture. + */ +o3djs.texture.createTextureFromRawDataArray = function( + pack, + rawDataArray, + opt_generateMips, + opt_flip, + opt_maxWidth, + opt_maxHeight) { + // Make bitmaps from the raw data. + var bitmaps = []; + for (var ii = 0; ii < rawDataArray.length; ++ii) { + bitmaps = bitmaps.concat(pack.createBitmapsFromRawData(rawDataArray[ii])); + } + if (opt_flip || typeof opt_flip === 'undefined') { + for (var ii = 0; ii < bitmaps.length; ++ii) { + var bitmap = bitmaps[ii]; + if (bitmap.semantic == o3djs.base.o3d.Bitmap.IMAGE) { + bitmaps[ii].flipVertically(); + } + } + } + + // Create a texture from the bitmaps. + // TODO(kbr): use createCubeTextureFrom6Bitmaps instead; bugs in the plugin + // currently prevent this. + var texture = o3djs.texture.createTextureFromBitmaps( + pack, bitmaps, opt_generateMips); + + // Delete the bitmaps. + for (var ii = 0; ii < bitmaps.length; ++ii) { + pack.removeObject(bitmaps[ii]); + } + + return texture; +}; + +/** * Returns whether or not a given texture format can be scaled. * @param {!o3d.Texture.Format} format The format to check. * @return {boolean} True if you can scale and make mips for the given format. @@ -214,7 +272,7 @@ o3djs.texture.createTextureFromBitmaps = function( /** * Creates a TextureCUBE from 6 bitmaps. The bitmaps do not have to be the same - * size thought they do have to be the same format. + * size though they do have to be the same format. * * @param {!o3d.Pack} pack The pack to create the texture in. * @param {number} edgeLength The size of the cubemap. diff --git a/o3d/utils/cross/file_path_utils.cc b/o3d/utils/cross/file_path_utils.cc index bea30de..257ac0c 100644 --- a/o3d/utils/cross/file_path_utils.cc +++ b/o3d/utils/cross/file_path_utils.cc @@ -71,6 +71,14 @@ FilePath UTF8ToFilePath(const String& input) { #endif } +FilePath::StringType UTF8ToFilePathStringType(const String& input) { +#if defined(OS_WIN) + return UTF8ToWide(input); +#else + return input; +#endif +} + bool AbsolutePath(FilePath* absolute_path) { #if defined(OS_WIN) return file_util::AbsolutePath(absolute_path); diff --git a/o3d/utils/cross/file_path_utils.h b/o3d/utils/cross/file_path_utils.h index 7398e8b..463b47de 100644 --- a/o3d/utils/cross/file_path_utils.h +++ b/o3d/utils/cross/file_path_utils.h @@ -49,6 +49,7 @@ std::wstring FilePathToWide(const FilePath& input); FilePath WideToFilePath(const std::wstring& input); String FilePathToUTF8(const FilePath& input); FilePath UTF8ToFilePath(const String& input); +FilePath::StringType UTF8ToFilePathStringType(const String& input); // On Windows, this is just the same as file_util::AbsolutePath. // On the Posix implementation of file_util::AbsolutePath, |