summaryrefslogtreecommitdiffstats
path: root/o3d
diff options
context:
space:
mode:
authorkbr@google.com <kbr@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-20 06:05:23 +0000
committerkbr@google.com <kbr@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-20 06:05:23 +0000
commite08b2652afb31bad466bc69d1f1aa3b80298361f (patch)
tree305527e71cd5d41394aab78e3607c9e8c31e7451 /o3d
parentb2d346da57198822ddf59563a7c100eb6f6bc5a2 (diff)
downloadchromium_src-e08b2652afb31bad466bc69d1f1aa3b80298361f.zip
chromium_src-e08b2652afb31bad466bc69d1f1aa3b80298361f.tar.gz
chromium_src-e08b2652afb31bad466bc69d1f1aa3b80298361f.tar.bz2
Added --convert-dds-to-png command line option to the COLLADA converter,
which causes all DDS textures to be outputted as PNGs. This required changes to the serialization code to reconstitute cube map textures from six separate images. Some bugs in the plugin were uncovered with this change which have been worked around for the time being. Pulled in libtxc_dxtn library for decompressing DXTn textures. Tested by converting teapot with --convert-dds-to-png and running helloworld.html and render-mode.html. BUG=none TEST=none Review URL: http://codereview.chromium.org/1677002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@45014 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d')
-rw-r--r--o3d/DEPS5
-rw-r--r--o3d/build/common.gypi1
-rw-r--r--o3d/converter/converter.gyp2
-rw-r--r--o3d/converter/cross/converter.cc1
-rw-r--r--o3d/converter/cross/converter.h7
-rw-r--r--o3d/converter/cross/converter_main.cc6
-rw-r--r--o3d/core/cross/bitmap.h2
-rw-r--r--o3d/core/cross/bitmap_png.cc18
-rw-r--r--o3d/import/cross/collada.cc144
-rw-r--r--o3d/import/cross/collada.h7
-rw-r--r--o3d/samples/o3djs/serialization.js24
-rw-r--r--o3d/samples/o3djs/texture.js60
-rw-r--r--o3d/utils/cross/file_path_utils.cc8
-rw-r--r--o3d/utils/cross/file_path_utils.h1
14 files changed, 279 insertions, 7 deletions
diff --git a/o3d/DEPS b/o3d/DEPS
index ac361bc..6900cdd 100644
--- a/o3d/DEPS
+++ b/o3d/DEPS
@@ -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,