summaryrefslogtreecommitdiffstats
path: root/o3d
diff options
context:
space:
mode:
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,