summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgman@google.com <gman@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-19 00:07:49 +0000
committergman@google.com <gman@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-19 00:07:49 +0000
commit8653167fd370f88b3bcc2be052a9aa26873dbe44 (patch)
tree602e188104e6d3992adac469f17d5c1605690f73
parentc1b7f06be387b3828d38eccbf0e88d1ec71bac3b (diff)
downloadchromium_src-8653167fd370f88b3bcc2be052a9aa26873dbe44.zip
chromium_src-8653167fd370f88b3bcc2be052a9aa26873dbe44.tar.gz
chromium_src-8653167fd370f88b3bcc2be052a9aa26873dbe44.tar.bz2
expose Bitmap to JavaScript.
Also added Texture.drawImage(canvas...) There's still the big question of whether we should flip textures by default in the o3d code. Currently I'm flipping them by default in o3djs.texture.createTextureFromRawData and I'm flipping them by default in o3djs.canvas.CanvasQuad.updateTexture. I'm torn whether or not I should be flipping them. I feel like 2d examples and examples of displaying images, like a picasa viewer, would be simpler if we didn't flip by default but the problem then is if you load some textures through a collada scene they'll be flipped the opposite of any textures you load by hand. Review URL: http://codereview.chromium.org/171060 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@23678 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--o3d/core/cross/bitmap.cc67
-rw-r--r--o3d/core/cross/bitmap.h14
-rw-r--r--o3d/core/cross/bitmap_dds.cc5
-rw-r--r--o3d/core/cross/bitmap_jpg.cc19
-rw-r--r--o3d/core/cross/bitmap_png.cc6
-rw-r--r--o3d/core/cross/bitmap_test.cc148
-rw-r--r--o3d/core/cross/bitmap_tga.cc5
-rw-r--r--o3d/core/cross/canvas.cc28
-rw-r--r--o3d/core/cross/canvas.h24
-rw-r--r--o3d/core/cross/draw_pass.h3
-rw-r--r--o3d/core/cross/image_utils.cc314
-rw-r--r--o3d/core/cross/image_utils.h72
-rw-r--r--o3d/core/cross/image_utils_test.cc263
-rw-r--r--o3d/core/cross/render_node.h1
-rw-r--r--o3d/core/cross/texture.cc230
-rw-r--r--o3d/core/cross/texture.h65
-rw-r--r--o3d/plugin/idl/param.idl2
-rw-r--r--o3d/plugin/idl/texture.idl128
-rw-r--r--o3d/samples/MANIFEST1
-rw-r--r--o3d/samples/archive-textures.html3
-rw-r--r--o3d/samples/bitmap-draw-image.html25
-rw-r--r--o3d/samples/o3djs/canvas.js5
-rw-r--r--o3d/samples/o3djs/io.js15
-rw-r--r--o3d/samples/o3djs/js_list.scons1
-rw-r--r--o3d/samples/o3djs/serialization.js11
-rw-r--r--o3d/samples/o3djs/texture.js236
-rw-r--r--o3d/samples/o3djs/util.js2
27 files changed, 1360 insertions, 333 deletions
diff --git a/o3d/core/cross/bitmap.cc b/o3d/core/cross/bitmap.cc
index 8f82dc1..f2c96a0 100644
--- a/o3d/core/cross/bitmap.cc
+++ b/o3d/core/cross/bitmap.cc
@@ -74,6 +74,13 @@ size_t Bitmap::GetMipSize(unsigned int level) const {
return image::ComputeMipChainSize(mip_width, mip_height, format(), 1);
}
+size_t Bitmap::ComputeMaxSize(
+ unsigned width, unsigned height, Texture::Format format) {
+ return image::ComputeMipChainSize(
+ width, height, format,
+ image::ComputeMipMapCount(width, height));
+}
+
void Bitmap::SetContents(Texture::Format format,
unsigned int num_mipmaps,
unsigned int width,
@@ -138,6 +145,15 @@ uint8 *Bitmap::GetMipData(unsigned int level) const {
return data + GetMipChainSize(level);
}
+uint8 *Bitmap::GetPixelData(
+ unsigned int level, unsigned int x, unsigned int y) const {
+ uint8* data = GetMipData(level);
+ if (data) {
+ data += GetMipPitch(level) * y + image::ComputePitch(format(), 1) * x;
+ }
+ return data;
+}
+
void Bitmap::SetRect(
int level,
unsigned dst_left,
@@ -157,10 +173,7 @@ void Bitmap::SetRect(
src_width == mip_width && src_height == mip_height;
DCHECK(!compressed || entire_rect);
- uint8* dst =
- GetMipData(level) +
- image::ComputePitch(format(), mip_width) * dst_top +
- image::ComputePitch(format(), dst_left);
+ uint8* dst = GetPixelData(level, dst_left, dst_top);
const uint8* src = static_cast<const uint8*>(src_data);
if (!compressed) {
@@ -322,26 +335,37 @@ bool Bitmap::LoadFromRawData(RawData *raw_data,
}
void Bitmap::DrawImage(const Bitmap& src_img,
+ int src_level,
int src_x, int src_y,
int src_width, int src_height,
+ int dst_level,
int dst_x, int dst_y,
int dst_width, int dst_height) {
DCHECK(src_img.image_data());
DCHECK(image_data());
+ if (dst_level < 0 || dst_level >= num_mipmaps()) {
+ O3D_ERROR(service_locator()) << "Destination Mip out of range";
+ }
+
+ if (src_level < 0 || src_level >= src_img.num_mipmaps()) {
+ O3D_ERROR(service_locator()) << "Source Mip out of range";
+ }
+
// Clip source and destination rectangles to
// source and destination bitmaps.
// if src or dest rectangle is out of boundary,
// do nothing and return.
if (!image::AdjustDrawImageBoundary(&src_x, &src_y,
&src_width, &src_height,
+ src_level,
src_img.width_, src_img.height_,
&dst_x, &dst_y,
&dst_width, &dst_height,
+ dst_level,
width_, height_))
return;
- unsigned int components = 0;
// check formats of source and dest images.
// format of source and dest should be the same.
if (src_img.format_ != format_) {
@@ -355,16 +379,13 @@ void Bitmap::DrawImage(const Bitmap& src_img,
src_img.width_ == width_ && src_img.height_ == height_ &&
src_width == src_img.width_ && src_height == src_img.height_ &&
dst_width == width_ && dst_height == height_) {
- memcpy(image_data(), src_img.image_data(), GetTotalSize());
+ SetRect(dst_level, 0, 0, dst_width, dst_height,
+ src_img.GetMipData(src_level), src_img.GetMipPitch(src_level));
return;
}
- // if drawImage is not copying the whole bitmap, we need to check
- // the format. currently only support XRGB8 and ARGB8
- if (src_img.format_ == Texture::XRGB8 ||
- src_img.format_ == Texture::ARGB8) {
- components = 4;
- } else {
+ unsigned int components = image::GetNumComponentsForFormat(format_);
+ if (components == 0) {
O3D_ERROR(service_locator()) << "DrawImage does not support format: "
<< src_img.format_ << " unless src and "
<< "dest images are in the same size and "
@@ -372,22 +393,30 @@ void Bitmap::DrawImage(const Bitmap& src_img,
return;
}
- uint8* src_img_data = src_img.image_data();
- uint8* dst_img_data = image_data();
+ int src_pitch = src_img.GetMipPitch(src_level);
+ if (image::AdjustForSetRect(&src_y, src_width, src_height, &src_pitch,
+ &dst_y, dst_width, &dst_height)) {
+ SetRect(dst_level, dst_x, dst_y, dst_width, dst_height,
+ src_img.GetPixelData(src_level, src_x, src_y),
+ src_pitch);
+ return;
+ }
// crop part of image from src img, scale it in
// bilinear interpolation fashion, and paste it
// on dst img.
- image::LanczosScale(src_img_data, src_x, src_y,
+ image::LanczosScale(src_img.format_,
+ src_img.GetMipData(src_level),
+ src_img.GetMipPitch(src_level),
+ src_x, src_y,
src_width, src_height,
- src_img.width_, src_img.height_,
- dst_img_data, width_ * components,
+ GetMipData(dst_level),
+ GetMipPitch(dst_level),
dst_x, dst_y,
dst_width, dst_height,
- width_, height_, components);
+ components);
}
-
void Bitmap::GenerateMips(int source_level, int num_levels) {
if (source_level >= static_cast<int>(num_mipmaps()) || source_level < 0) {
O3D_ERROR(service_locator()) << "source level out of range.";
diff --git a/o3d/core/cross/bitmap.h b/o3d/core/cross/bitmap.h
index 2188fc9c..4710cb6 100644
--- a/o3d/core/cross/bitmap.h
+++ b/o3d/core/cross/bitmap.h
@@ -149,6 +149,11 @@ class Bitmap : public ParamObject {
// level: mip level to get.
uint8 *GetMipData(unsigned int level) const;
+ // Gets the address of a particular pixel.
+ // Parameters:
+ // level: mip level to get.
+ uint8 *GetPixelData(unsigned int level, unsigned int x, unsigned int y) const;
+
// Gets the size of mip.
size_t GetMipSize(unsigned int level) const;
@@ -208,16 +213,20 @@ class Bitmap : public ParamObject {
// and dest do not match.
// Parameters:
// source_img: source bitmap which would be drawn.
+ // source_level: level to draw.
// source_x: x-coordinate of the starting pixel in the source image.
// source_x: y-coordinate of the starting pixel in the source image.
// source_width: width of the source image to draw.
// source_height: Height of the source image to draw.
+ // dest_level: level to target.
// dest_x: x-coordinate of the starting pixel in the dest image.
// dest_y: y-coordinate of the starting pixel in the dest image.
// dest_width: width of the dest image to draw.
// dest_height: height of the dest image to draw.
- void DrawImage(const Bitmap& source_img, int source_x, int source_y,
+ void DrawImage(const Bitmap& source_img, int source_level,
+ int source_x, int source_y,
int source_width, int source_height,
+ int dest_level,
int dest_x, int dest_y,
int dest_width, int dest_height);
@@ -296,6 +305,9 @@ class Bitmap : public ParamObject {
return GetMipChainSize(image::ComputeMipMapCount(width_, height_));
}
+ static size_t ComputeMaxSize(
+ unsigned width, unsigned height, Texture::Format format);
+
// pointer to the raw bitmap data
// NOTE: image_data_ is either NULL or it has space for the maximum number
// of mips for the current size bitmap, even if they are not used.
diff --git a/o3d/core/cross/bitmap_dds.cc b/o3d/core/cross/bitmap_dds.cc
index 2c4f8a9..5625ed2 100644
--- a/o3d/core/cross/bitmap_dds.cc
+++ b/o3d/core/cross/bitmap_dds.cc
@@ -449,8 +449,9 @@ bool Bitmap::LoadFromDDSStream(ServiceLocator* service_locator,
}
unsigned int num_bitmaps = is_cubemap ? 6 : 1;
- size_t face_size = image::ComputeMipChainSize(
- dds_width, dds_height, format, mip_count);
+ // Bitmap requires we allocate enough memory for all mips even if we don't use
+ // them.
+ size_t face_size = Bitmap::ComputeMaxSize(dds_width, dds_height, format);
BitmapRefArray temp_bitmaps;
diff --git a/o3d/core/cross/bitmap_jpg.cc b/o3d/core/cross/bitmap_jpg.cc
index 7b84490..21bc59a5 100644
--- a/o3d/core/cross/bitmap_jpg.cc
+++ b/o3d/core/cross/bitmap_jpg.cc
@@ -200,8 +200,9 @@ bool Bitmap::LoadFromJPEGStream(ServiceLocator* service_locator,
}
unsigned int image_components = 4;
Texture::Format format = Texture::XRGB8;
- // Allocate storage for the pixels.
- size_t image_size = image::ComputeMipChainSize(width, height, format, 1);
+ // Allocate storage for the pixels. Bitmap requires we allocate enough
+ // memory for all mips even if we don't use them.
+ size_t image_size = Bitmap::ComputeMaxSize(width, height, format);
image_data.reset(new uint8[image_size]);
if (image_data.get() == NULL) {
DLOG(ERROR) << "JPEG memory allocation error \"" << filename << "\"";
@@ -249,13 +250,13 @@ bool Bitmap::LoadFromJPEGStream(ServiceLocator* service_locator,
// copy the scanline to its final destination
for (unsigned int i = 0; i < width; ++i) {
// RGB -> BGRX
- image_write_ptr[i*image_components+0] =
- buffer[0][i*cinfo.output_components+2];
- image_write_ptr[i*image_components+1] =
- buffer[0][i*cinfo.output_components+1];
- image_write_ptr[i*image_components+2] =
- buffer[0][i*cinfo.output_components+0];
- image_write_ptr[i*image_components+3] = 0xff;
+ image_write_ptr[i * image_components + 0] =
+ buffer[0][i * cinfo.output_components + 2];
+ image_write_ptr[i * image_components + 1] =
+ buffer[0][i * cinfo.output_components + 1];
+ image_write_ptr[i * image_components + 2] =
+ buffer[0][i * cinfo.output_components + 0];
+ image_write_ptr[i * image_components + 3] = 0xff;
}
}
diff --git a/o3d/core/cross/bitmap_png.cc b/o3d/core/cross/bitmap_png.cc
index 9e30011..fc2b56a 100644
--- a/o3d/core/cross/bitmap_png.cc
+++ b/o3d/core/cross/bitmap_png.cc
@@ -226,9 +226,9 @@ bool Bitmap::LoadFromPNGStream(ServiceLocator* service_locator,
// selected such a transform above).
png_read_update_info(png_ptr, info_ptr);
- // Allocate storage for the pixels.
- size_t png_image_size =
- image::ComputeMipChainSize(png_width, png_height, format, 1);
+ // Allocate storage for the pixels. Bitmap requires we allocate enough
+ // memory for all mips even if we don't use them.
+ size_t png_image_size = Bitmap::ComputeMaxSize(png_width, png_height, format);
image_data.reset(new uint8[png_image_size]);
if (image_data.get() == NULL) {
DLOG(ERROR) << "PNG image memory allocation error \"" << filename << "\"";
diff --git a/o3d/core/cross/bitmap_test.cc b/o3d/core/cross/bitmap_test.cc
index 7bebafb..b094188 100644
--- a/o3d/core/cross/bitmap_test.cc
+++ b/o3d/core/cross/bitmap_test.cc
@@ -740,20 +740,20 @@ static uint8 kpng_8x4_drawImage[128] = {
static uint8 kpng_8x4_drawImage_top_left[128] = {
// expected result of drawimage on top left corner of dest image.
- 0x30, 0x60, 0xc0, 0xff, 0x32, 0x64, 0xc8, 0xff,
- 0x34, 0x68, 0xd0, 0xff, 0x36, 0x6c, 0xd8, 0xff,
+ 0x28, 0x28, 0x28, 0xff, 0x29, 0x29, 0x29, 0xff,
+ 0x2a, 0x2a, 0x2a, 0xff, 0x36, 0x6c, 0xd8, 0xff,
0x38, 0x70, 0xe0, 0xff, 0x3a, 0x74, 0xe8, 0xff,
0x3c, 0x78, 0xf0, 0xff, 0x3e, 0x7c, 0xf8, 0xff,
- 0x2c, 0x2c, 0x2c, 0xff, 0x2d, 0x2d, 0x2d, 0xff,
- 0x2e, 0x2e, 0x2e, 0xff, 0x26, 0x4c, 0x98, 0xff,
+ 0x24, 0x24, 0x24, 0xff, 0x25, 0x25, 0x25, 0xff,
+ 0x26, 0x26, 0x26, 0xff, 0x26, 0x4c, 0x98, 0xff,
0x28, 0x50, 0xa0, 0xff, 0x2a, 0x54, 0xa8, 0xff,
0x2c, 0x58, 0xb0, 0xff, 0x2e, 0x5c, 0xb8, 0xff,
- 0x28, 0x28, 0x28, 0xff, 0x29, 0x29, 0x29, 0xff,
- 0x2a, 0x2a, 0x2a, 0xff, 0x16, 0x2c, 0x58, 0xff,
+ 0x20, 0x20, 0x20, 0xff, 0x21, 0x21, 0x21, 0xff,
+ 0x22, 0x22, 0x22, 0xff, 0x16, 0x2c, 0x58, 0xff,
0x18, 0x30, 0x60, 0xff, 0x1a, 0x34, 0x68, 0xff,
0x1c, 0x38, 0x70, 0xff, 0x1e, 0x3c, 0x78, 0xff,
- 0x24, 0x24, 0x24, 0xff, 0x25, 0x25, 0x25, 0xff,
- 0x26, 0x26, 0x26, 0xff, 0x06, 0x0c, 0x18, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x02, 0x04, 0x08, 0xff,
+ 0x04, 0x08, 0x10, 0xff, 0x06, 0x0c, 0x18, 0xff,
0x08, 0x10, 0x20, 0xff, 0x0a, 0x14, 0x28, 0xff,
0x0c, 0x18, 0x30, 0xff, 0x0e, 0x1c, 0x38, 0xff,
};
@@ -860,20 +860,20 @@ static uint8 kpng_8x4_drawImage_bottom[128] = {
static uint8 kpng_8x4_drawImage_bottom_left[128] = {
// expected result of drawimage on bottom left corner of dest image.
- 0x28, 0x28, 0x28, 0xff, 0x29, 0x29, 0x29, 0xff,
- 0x2a, 0x2a, 0x2a, 0xff, 0x36, 0x6c, 0xd8, 0xff,
+ 0x30, 0x60, 0xc0, 0xff, 0x32, 0x64, 0xc8, 0xff,
+ 0x34, 0x68, 0xd0, 0xff, 0x36, 0x6c, 0xd8, 0xff,
0x38, 0x70, 0xe0, 0xff, 0x3a, 0x74, 0xe8, 0xff,
0x3c, 0x78, 0xf0, 0xff, 0x3e, 0x7c, 0xf8, 0xff,
- 0x24, 0x24, 0x24, 0xff, 0x25, 0x25, 0x25, 0xff,
- 0x26, 0x26, 0x26, 0xff, 0x26, 0x4c, 0x98, 0xff,
+ 0x2c, 0x2c, 0x2c, 0xff, 0x2d, 0x2d, 0x2d, 0xff,
+ 0x2e, 0x2e, 0x2e, 0xff, 0x26, 0x4c, 0x98, 0xff,
0x28, 0x50, 0xa0, 0xff, 0x2a, 0x54, 0xa8, 0xff,
0x2c, 0x58, 0xb0, 0xff, 0x2e, 0x5c, 0xb8, 0xff,
- 0x20, 0x20, 0x20, 0xff, 0x21, 0x21, 0x21, 0xff,
- 0x22, 0x22, 0x22, 0xff, 0x16, 0x2c, 0x58, 0xff,
+ 0x28, 0x28, 0x28, 0xff, 0x29, 0x29, 0x29, 0xff,
+ 0x2a, 0x2a, 0x2a, 0xff, 0x16, 0x2c, 0x58, 0xff,
0x18, 0x30, 0x60, 0xff, 0x1a, 0x34, 0x68, 0xff,
0x1c, 0x38, 0x70, 0xff, 0x1e, 0x3c, 0x78, 0xff,
- 0x00, 0x00, 0x00, 0xff, 0x02, 0x04, 0x08, 0xff,
- 0x04, 0x08, 0x10, 0xff, 0x06, 0x0c, 0x18, 0xff,
+ 0x24, 0x24, 0x24, 0xff, 0x25, 0x25, 0x25, 0xff,
+ 0x26, 0x26, 0x26, 0xff, 0x06, 0x0c, 0x18, 0xff,
0x08, 0x10, 0x20, 0xff, 0x0a, 0x14, 0x28, 0xff,
0x0c, 0x18, 0x30, 0xff, 0x0e, 0x1c, 0x38, 0xff,
};
@@ -940,22 +940,22 @@ static uint8 kpng_8x4_drawImage_scale_down[128] = {
static uint8 kpng_8x4_drawImage_scale_out[128] = {
// expected result of scale src image larger than dest image.
- 0x64, 0x64, 0x64, 0xff, 0x66, 0x66, 0x66, 0xff,
- 0x68, 0x68, 0x68, 0xff, 0x6a, 0x6a, 0x6a, 0xff,
- 0x6d, 0x6d, 0x6d, 0xff, 0x6f, 0x6f, 0x6f, 0xff,
- 0x71, 0x71, 0x71, 0xff, 0x73, 0x73, 0x73, 0xff,
- 0x58, 0x58, 0x58, 0xff, 0x5a, 0x5a, 0x5a, 0xff,
- 0x5c, 0x5c, 0x5c, 0xff, 0x5e, 0x5e, 0x5e, 0xff,
- 0x61, 0x61, 0x61, 0xff, 0x63, 0x63, 0x63, 0xff,
- 0x65, 0x65, 0x65, 0xff, 0x67, 0x67, 0x67, 0xff,
- 0x3e, 0x3e, 0x3e, 0xff, 0x40, 0x40, 0x40, 0xff,
- 0x42, 0x42, 0x42, 0xff, 0x44, 0x44, 0x44, 0xff,
- 0x47, 0x47, 0x47, 0xff, 0x49, 0x49, 0x49, 0xff,
- 0x4b, 0x4b, 0x4b, 0xff, 0x4d, 0x4d, 0x4d, 0xff,
- 0x32, 0x32, 0x32, 0xff, 0x34, 0x34, 0x34, 0xff,
- 0x36, 0x36, 0x36, 0xff, 0x38, 0x38, 0x38, 0xff,
- 0x3b, 0x3b, 0x3b, 0xff, 0x3d, 0x3d, 0x3d, 0xff,
- 0x3f, 0x3f, 0x3f, 0xff, 0x41, 0x41, 0x41, 0xff,
+ 0x7c, 0x7c, 0x7c, 0xff, 0x7e, 0x7e, 0x7e, 0xff,
+ 0x80, 0x80, 0x80, 0xff, 0x82, 0x82, 0x82, 0xff,
+ 0x85, 0x85, 0x85, 0xff, 0x87, 0x87, 0x87, 0xff,
+ 0x89, 0x89, 0x89, 0xff, 0x8b, 0x8b, 0x8b, 0xff,
+ 0x70, 0x70, 0x70, 0xff, 0x72, 0x72, 0x72, 0xff,
+ 0x74, 0x74, 0x74, 0xff, 0x76, 0x76, 0x76, 0xff,
+ 0x79, 0x79, 0x79, 0xff, 0x7b, 0x7b, 0x7b, 0xff,
+ 0x7d, 0x7d, 0x7d, 0xff, 0x7f, 0x7f, 0x7f, 0xff,
+ 0x56, 0x56, 0x56, 0xff, 0x58, 0x58, 0x58, 0xff,
+ 0x5a, 0x5a, 0x5a, 0xff, 0x5c, 0x5c, 0x5c, 0xff,
+ 0x5f, 0x5f, 0x5f, 0xff, 0x61, 0x61, 0x61, 0xff,
+ 0x63, 0x63, 0x63, 0xff, 0x65, 0x65, 0x65, 0xff,
+ 0x4a, 0x4a, 0x4a, 0xff, 0x4c, 0x4c, 0x4c, 0xff,
+ 0x4e, 0x4e, 0x4e, 0xff, 0x50, 0x50, 0x50, 0xff,
+ 0x53, 0x53, 0x53, 0xff, 0x55, 0x55, 0x55, 0xff,
+ 0x57, 0x57, 0x57, 0xff, 0x59, 0x59, 0x59, 0xff,
};
static uint8 kpng_8x4_drawImage_flip[128] = {
@@ -1042,7 +1042,8 @@ TEST_F(BitmapTest, DrawImage) {
// test whether the raw image is loaded correctly or not.
EXPECT_TRUE(bitmap_dest_top_left->image_data() != NULL);
EXPECT_TRUE(TestBitmapData(*bitmap_dest_top_left, kpng_8x4_drawImage));
- bitmap_dest_top_left->DrawImage(*bitmap_4x4_src, 0, 0, 4, 4, -1, -1, 4, 4);
+ bitmap_dest_top_left->DrawImage(
+ *bitmap_4x4_src, 0, 0, 0, 4, 4, 0, -1, -1, 4, 4);
EXPECT_TRUE(TestBitmapData(*bitmap_dest_top_left,
kpng_8x4_drawImage_top_left));
@@ -1053,7 +1054,7 @@ TEST_F(BitmapTest, DrawImage) {
image::PNG, &bitmaps));
ASSERT_EQ(1u, bitmaps.size());
Bitmap::Ref bitmap_dest_top(bitmaps[0]);
- bitmap_dest_top->DrawImage(*bitmap_4x4_src, 0, 0, 4, 4, 2, -2, 4, 4);
+ bitmap_dest_top->DrawImage(*bitmap_4x4_src, 0, 0, 0, 4, 4, 0, 2, -2, 4, 4);
EXPECT_TRUE(TestBitmapData(*bitmap_dest_top, kpng_8x4_drawImage_top));
// test draw image on top right boundary.
@@ -1063,7 +1064,8 @@ TEST_F(BitmapTest, DrawImage) {
image::PNG, &bitmaps));
ASSERT_EQ(1u, bitmaps.size());
Bitmap::Ref bitmap_dest_top_right(bitmaps[0]);
- bitmap_dest_top_right->DrawImage(*bitmap_4x4_src, 0, 0, 4, 4, 5, -1, 4, 4);
+ bitmap_dest_top_right->DrawImage(
+ *bitmap_4x4_src, 0, 0, 0, 4, 4, 0, 5, -1, 4, 4);
EXPECT_TRUE(TestBitmapData(*bitmap_dest_top_right,
kpng_8x4_drawImage_top_right));
@@ -1074,7 +1076,7 @@ TEST_F(BitmapTest, DrawImage) {
image::PNG, &bitmaps));
ASSERT_EQ(1u, bitmaps.size());
Bitmap::Ref bitmap_dest_right(bitmaps[0]);
- bitmap_dest_right->DrawImage(*bitmap_4x4_src, 0, 0, 4, 4, 5, 0, 4, 4);
+ bitmap_dest_right->DrawImage(*bitmap_4x4_src, 0, 0, 0, 4, 4, 0, 5, 0, 4, 4);
EXPECT_TRUE(TestBitmapData(*bitmap_dest_right, kpng_8x4_drawImage_right));
// test draw image on bottom right boundary.
@@ -1084,7 +1086,8 @@ TEST_F(BitmapTest, DrawImage) {
image::PNG, &bitmaps));
ASSERT_EQ(1u, bitmaps.size());
Bitmap::Ref bitmap_dest_bottom_right(bitmaps[0]);
- bitmap_dest_bottom_right->DrawImage(*bitmap_4x4_src, 0, 0, 4, 4, 5, 1, 4, 4);
+ bitmap_dest_bottom_right->DrawImage(
+ *bitmap_4x4_src, 0, 0, 0, 4, 4, 0, 5, 1, 4, 4);
EXPECT_TRUE(TestBitmapData(*bitmap_dest_bottom_right,
kpng_8x4_drawImage_bottom_right));
@@ -1095,7 +1098,8 @@ TEST_F(BitmapTest, DrawImage) {
image::PNG, &bitmaps));
ASSERT_EQ(1u, bitmaps.size());
Bitmap::Ref bitmap_dest_bottom(bitmaps[0]);
- bitmap_dest_bottom->DrawImage(*bitmap_4x4_src, 0, 0, 4, 4, 2, 1, 4, 4);
+ bitmap_dest_bottom->DrawImage(
+ *bitmap_4x4_src, 0, 0, 0, 4, 4, 0, 2, 1, 4, 4);
EXPECT_TRUE(TestBitmapData(*bitmap_dest_bottom, kpng_8x4_drawImage_bottom));
// test draw image on bottom left boundary.
@@ -1105,7 +1109,8 @@ TEST_F(BitmapTest, DrawImage) {
image::PNG, &bitmaps));
ASSERT_EQ(1u, bitmaps.size());
Bitmap::Ref bitmap_dest_bottom_left(bitmaps[0]);
- bitmap_dest_bottom_left->DrawImage(*bitmap_4x4_src, 0, 0, 4, 4, -1, 1, 4, 4);
+ bitmap_dest_bottom_left->DrawImage(
+ *bitmap_4x4_src, 0, 0, 0, 4, 4, 0, -1, 1, 4, 4);
EXPECT_TRUE(TestBitmapData(*bitmap_dest_bottom_left,
kpng_8x4_drawImage_bottom_left));
@@ -1116,7 +1121,7 @@ TEST_F(BitmapTest, DrawImage) {
image::PNG, &bitmaps));
ASSERT_EQ(1u, bitmaps.size());
Bitmap::Ref bitmap_dest_left(bitmaps[0]);
- bitmap_dest_left->DrawImage(*bitmap_4x4_src, 0, 0, 4, 4, -1, 0, 4, 4);
+ bitmap_dest_left->DrawImage(*bitmap_4x4_src, 0, 0, 0, 4, 4, 0, -1, 0, 4, 4);
EXPECT_TRUE(TestBitmapData(*bitmap_dest_left, kpng_8x4_drawImage_left));
// test scale up.
@@ -1126,7 +1131,8 @@ TEST_F(BitmapTest, DrawImage) {
image::PNG, &bitmaps));
ASSERT_EQ(1u, bitmaps.size());
Bitmap::Ref bitmap_dest_scale_up(bitmaps[0]);
- bitmap_dest_scale_up->DrawImage(*bitmap_2x2_src, 0, 0, 2, 2, 0, 0, 8, 4);
+ bitmap_dest_scale_up->DrawImage(
+ *bitmap_2x2_src, 0, 0, 0, 2, 2, 0, 0, 0, 8, 4);
EXPECT_TRUE(TestBitmapData(*bitmap_dest_scale_up,
kpng_8x4_drawImage_scale_up));
@@ -1137,7 +1143,8 @@ TEST_F(BitmapTest, DrawImage) {
image::PNG, &bitmaps));
ASSERT_EQ(1u, bitmaps.size());
Bitmap::Ref bitmap_dest_scale_down(bitmaps[0]);
- bitmap_dest_scale_down->DrawImage(*bitmap_8x8_src, 0, 0, 8, 8, 0, 0, 4, 4);
+ bitmap_dest_scale_down->DrawImage(
+ *bitmap_8x8_src, 0, 0, 0, 8, 8, 0, 0, 0, 4, 4);
EXPECT_TRUE(TestBitmapData(*bitmap_dest_scale_down,
kpng_8x4_drawImage_scale_down));
@@ -1148,7 +1155,8 @@ TEST_F(BitmapTest, DrawImage) {
image::PNG, &bitmaps));
ASSERT_EQ(1u, bitmaps.size());
Bitmap::Ref bitmap_dest_scale_out(bitmaps[0]);
- bitmap_dest_scale_out->DrawImage(*bitmap_8x8_src, 0, 0, 8, 8, -2, -4, 12, 12);
+ bitmap_dest_scale_out->DrawImage(
+ *bitmap_8x8_src, 0, 0, 0, 8, 8, 0, -2, -4, 12, 12);
EXPECT_TRUE(TestBitmapData(*bitmap_dest_scale_out,
kpng_8x4_drawImage_scale_out));
@@ -1159,7 +1167,7 @@ TEST_F(BitmapTest, DrawImage) {
image::PNG, &bitmaps));
ASSERT_EQ(1u, bitmaps.size());
Bitmap::Ref bitmap_dest_flip(bitmaps[0]);
- bitmap_dest_flip->DrawImage(*bitmap_4x4_src, 0, 0, 4, 4, 5, 3, -4, -4);
+ bitmap_dest_flip->DrawImage(*bitmap_4x4_src, 0, 0, 0, 4, 4, 0, 5, 3, -4, -4);
EXPECT_TRUE(TestBitmapData(*bitmap_dest_flip, kpng_8x4_drawImage_flip));
// test draw image on argb8 format.
@@ -1181,8 +1189,58 @@ TEST_F(BitmapTest, DrawImage) {
image::PNG, &bitmaps));
ASSERT_EQ(1u, bitmaps.size());
Bitmap::Ref bitmap_src_argb8(bitmaps[0]);
- bitmap_dest_argb8->DrawImage(*bitmap_src_argb8, 0, 0, 4, 4, 0, 0, 4, 4);
+ bitmap_dest_argb8->DrawImage(*bitmap_src_argb8, 0, 0, 0, 4, 4, 0, 0, 0, 4, 4);
EXPECT_TRUE(TestBitmapData(*bitmap_dest_argb8, kpng_8x4_drawImage_argb8));
}
+TEST_F(BitmapTest, SetRect) {
+ Bitmap::Ref bitmap(new Bitmap(g_service_locator));
+ const int kWidth = 8;
+ const int kHeight = 8;
+ const int kLevels = 2;
+ const int kDestMip = 1;
+ const unsigned kDestX = 1u;
+ const unsigned kDestY = 1u;
+ bitmap->Allocate(o3d::Texture::R32F, kWidth, kHeight, kLevels, Bitmap::IMAGE);
+ const float* pixels =
+ reinterpret_cast<const float*>(bitmap->GetMipData(kDestMip));
+ static const float kExpected1[] = {
+ 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f,
+ };
+ EXPECT_EQ(0, memcmp(pixels, kExpected1, sizeof(kExpected1)));
+ const int kSrcWidth = 2;
+ const int kSrcHeight = 2;
+ static const float kSourcePixels[] = {
+ 0.123f, 0.456f,
+ 0.789f, 123.0f,
+ };
+ const int kSourcePitch = sizeof(kSourcePixels[0]) * kSrcWidth;
+ // normal copy
+ bitmap->SetRect(kDestMip, kDestX, kDestY,
+ kSrcWidth, kSrcHeight, kSourcePixels, kSourcePitch);
+ static const float kExpected2[] = {
+ 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.123f, 0.456f, 0.0f,
+ 0.0f, 0.789f, 123.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f,
+ };
+ EXPECT_EQ(0, memcmp(pixels, kExpected2, sizeof(kExpected2)));
+ // flipped copy
+ bitmap->SetRect(
+ kDestMip, kDestX, kDestY,
+ kSrcWidth, kSrcHeight,
+ reinterpret_cast<const uint8*>(kSourcePixels) + kSourcePitch,
+ -kSourcePitch);
+ static const float kExpected3[] = {
+ 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.789f, 123.0f, 0.0f,
+ 0.0f, 0.123f, 0.456f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f,
+ };
+ EXPECT_EQ(0, memcmp(pixels, kExpected3, sizeof(kExpected3)));
+}
+
} // namespace
diff --git a/o3d/core/cross/bitmap_tga.cc b/o3d/core/cross/bitmap_tga.cc
index e31736a..883f7a3 100644
--- a/o3d/core/cross/bitmap_tga.cc
+++ b/o3d/core/cross/bitmap_tga.cc
@@ -111,8 +111,9 @@ bool Bitmap::LoadFromTGAStream(ServiceLocator* service_locator,
unsigned int pixel_count = tga_width * tga_height;
// Allocate storage for the pixels.
Texture::Format format = components == 3 ? Texture::XRGB8 : Texture::ARGB8;
- size_t image_size =
- image::ComputeMipChainSize(tga_width, tga_height, format, 1);
+ // Allocate storage for the pixels. Bitmap requires we allocate enough
+ // memory for all mips even if we don't use them.
+ size_t image_size = Bitmap::ComputeMaxSize(tga_width, tga_height, format);
scoped_array<uint8> image_data(new uint8[image_size]);
if (image_data.get() == NULL) {
DLOG(ERROR) << "Targa file memory allocation error \"" << filename << "\"";
diff --git a/o3d/core/cross/canvas.cc b/o3d/core/cross/canvas.cc
index 7dccb2d..a0dea81 100644
--- a/o3d/core/cross/canvas.cc
+++ b/o3d/core/cross/canvas.cc
@@ -38,6 +38,7 @@
#include "core/cross/canvas_utils.h"
#include "core/cross/client.h"
#include "core/cross/error.h"
+#include "core/cross/features.h"
#include "third_party/skia/include/core/SkPath.h"
@@ -49,6 +50,10 @@ Canvas::Canvas(ServiceLocator* service_locator)
: ParamObject(service_locator),
width_(0),
height_(0) {
+ Features* features = service_locator->GetService<Features>();
+ DCHECK(features);
+ flip_ = features->flip_textures();
+
// Initialize a 0x0 bitmap
sk_bitmap_.setConfig(SkBitmap::kARGB_8888_Config, 0, 0);
sk_canvas_.setBitmapDevice(sk_bitmap_);
@@ -67,11 +72,14 @@ bool Canvas::SetSize(int width, int height) {
return false;
}
sk_canvas_.setBitmapDevice(sk_bitmap_);
- // Translate and flip our canvas to change from o3d coordinates
- // (where the lower left is (0,0)) to skia coordinates (where the
- // upper left is (0,0))
- sk_canvas_.translate(0, SkIntToScalar(sk_bitmap_.height()));
- sk_canvas_.scale(SK_Scalar1, -SK_Scalar1);
+
+ if (flip_) {
+ // Translate and flip our canvas to change from o3d coordinates
+ // (where the lower left is (0,0)) to skia coordinates (where the
+ // upper left is (0,0))
+ sk_canvas_.translate(0, SkIntToScalar(sk_bitmap_.height()));
+ sk_canvas_.scale(SK_Scalar1, -SK_Scalar1);
+ }
return true;
}
@@ -205,12 +213,10 @@ void Canvas::DrawBitmap(Texture2D* texture2d,
}
// Now copy from the temporary bitmap to the canvas bitmap.
- // Note that we scale Y by -1 to flip the image vertically. The reason is
- // that in O3D textures the first byte is the bottom left corner whereas
- // in Skia the first byte is the top left of a bitmap.
SaveMatrix();
- Scale(1, -1);
-
+ if (flip_) {
+ Scale(1, -1);
+ }
sk_canvas_.drawBitmap(bitmap,
SkFloatToScalar(left),
SkFloatToScalar(-bottom),
@@ -231,7 +237,7 @@ void Canvas::Translate(float dx, float dy) {
}
// Copy the contents of the local bitmap to a Texture object.
-bool Canvas::CopyToTexture(Texture2D* texture_2d) {
+bool Canvas::CopyToTexture(Texture2D* texture_2d) const {
DCHECK(texture_2d);
if (texture_2d->width() != sk_bitmap_.width() ||
diff --git a/o3d/core/cross/canvas.h b/o3d/core/cross/canvas.h
index 5c9c62e..0c86be9 100644
--- a/o3d/core/cross/canvas.h
+++ b/o3d/core/cross/canvas.h
@@ -50,7 +50,7 @@ class CanvasPaint;
// The Canvas class provides an API for drawing text and 2D primitives onto
// a 2D bitmap surface whose contents can be transfered to a compatible
-// Texture2D object via the CopyToTexture() method. Each Canvas object
+// Texture2D object via the CopyToTexture() method. Each Canvas object
// maintains a stack of 2D transformation matrices which allow fine control over
// the placement of drawable elements. Both geometry and drawing coordinates
// provided to every draw call are transformed by the concatenation of
@@ -115,6 +115,7 @@ class Canvas : public ParamObject {
// Draws the contents of the specified texture onto the canvas surface.
// The bottom left corner of the bitmap will be at (x, y) and transformed by
// the current matrix.
+ // DEPRECATED
// Parameters:
// texture: Pointer to Texture2D object where the bitmap is extracted from
// left: The position of the left side of the bitmap.
@@ -153,15 +154,27 @@ class Canvas : public ParamObject {
// Copies the contents of the Canvas bitmap to a Texture2D object. The
// texture object must have the same size as the canvas and a ARGB8 or XRGB8
// format. All mip levels of the the texture will be filled.
+ // DEPRECATED
// Parameters:
// texture_2d: The texture object to copy the bitmap to.
- bool CopyToTexture(Texture2D* texture_2d);
+ bool CopyToTexture(Texture2D* texture_2d) const;
// Returns the width of the canvas bitmap.
- int width() { return width_; }
+ int width() const { return width_; }
// Returns the height of the canvas bitmap.
- int height() { return height_; }
+ int height() const { return height_; }
+
+ // Returns the actual pixels of the canvas
+ const uint8* GetPixelData(int x, int y) const {
+ return static_cast<const uint8*>(sk_bitmap_.getPixels()) +
+ y * GetPitch() + x * 4;
+ }
+
+ // Returns the pitch of the pixel data
+ int GetPitch() const {
+ return width_ * 4;
+ }
protected:
explicit Canvas(ServiceLocator* service_locator);
@@ -178,6 +191,9 @@ class Canvas : public ParamObject {
int width_;
int height_;
+ // For backward compatibility. Whether to flip the bitmap.
+ bool flip_;
+
O3D_DECL_CLASS(Canvas, ParamObject)
DISALLOW_COPY_AND_ASSIGN(Canvas);
};
diff --git a/o3d/core/cross/draw_pass.h b/o3d/core/cross/draw_pass.h
index 51e8878..60bb8e9 100644
--- a/o3d/core/cross/draw_pass.h
+++ b/o3d/core/cross/draw_pass.h
@@ -35,8 +35,9 @@
#ifndef O3D_CORE_CROSS_DRAW_PASS_H_
#define O3D_CORE_CROSS_DRAW_PASS_H_
-#include "core/cross/render_node.h"
+#include "core/cross/draw_context.h"
#include "core/cross/draw_list.h"
+#include "core/cross/render_node.h"
namespace o3d {
diff --git a/o3d/core/cross/image_utils.cc b/o3d/core/cross/image_utils.cc
index ca1eec4..4a94aad 100644
--- a/o3d/core/cross/image_utils.cc
+++ b/o3d/core/cross/image_utils.cc
@@ -96,8 +96,8 @@ size_t ComputeMipChainSize(unsigned int base_width,
bool ScaleUpToPOT(unsigned int width,
unsigned int height,
Texture::Format format,
- const uint8 *src,
- uint8 *dst,
+ const void *src,
+ void *dst,
int dst_pitch) {
DCHECK(CheckImageDimensions(width, height));
switch (format) {
@@ -164,10 +164,10 @@ uint8 Safe8Round(float f) {
template <typename T>
void PointScale(
unsigned components,
- const uint8* src,
+ const void* src,
unsigned src_width,
unsigned src_height,
- uint8* dst,
+ void* dst,
int dst_pitch,
unsigned dst_width,
unsigned dst_height) {
@@ -198,10 +198,10 @@ void PointScale(
bool Scale(unsigned int src_width,
unsigned int src_height,
Texture::Format format,
- const uint8 *src,
+ const void *src,
unsigned int dst_width,
unsigned int dst_height,
- uint8 *dst,
+ void *dst,
int dst_pitch) {
DCHECK(CheckImageDimensions(src_width, src_height));
DCHECK(CheckImageDimensions(dst_width, dst_height));
@@ -243,8 +243,9 @@ namespace {
bool AdjustDrawImageBoundHelper(int* src_a, int* dest_a,
int* src_length, int* dest_length,
int src_bmp_length) {
- if (*src_length == 0 || *dest_length == 0)
+ if (*src_length == 0 || *dest_length == 0) {
return false;
+ }
// check if start point is out of boundary.
// if src_a < 0, src_length must be positive.
@@ -266,8 +267,9 @@ bool AdjustDrawImageBoundHelper(int* src_a, int* dest_a,
*src_a = src_bmp_length - 1;
}
- if (*src_length == 0 || *dest_length == 0)
+ if (*src_length == 0 || *dest_length == 0) {
return false;
+ }
// check whether start point + related length is out of boundary.
// if src_a + src_length > src_bmp_length, src_length must be positive.
if (*src_a + *src_length > src_bmp_length) {
@@ -287,15 +289,16 @@ bool AdjustDrawImageBoundHelper(int* src_a, int* dest_a,
return true;
}
-void LanczosResize1D(const uint8* src, int src_x, int src_y,
+template <typename OriginalType,
+ float convert_to_float(OriginalType value),
+ OriginalType convert_to_original(float)>
+void LanczosResize1D(const void* src_data, int src_pitch,
+ int src_x, int src_y,
int width, int height,
- int src_bmp_width, int src_bmp_height,
- uint8* out, int dest_pitch,
+ void* dest_data, int dest_pitch,
int dest_x, int dest_y,
int nwidth,
- int dest_bmp_width, int dest_bmp_height,
- bool isWidth, int components) {
- int pitch = dest_pitch / components;
+ bool is_width, int components) {
// calculate scale factor and init the weight array for lanczos filter.
float scale = fabs(static_cast<float>(width) / nwidth);
float support = kFilterSize * scale;
@@ -306,10 +309,14 @@ void LanczosResize1D(const uint8* src, int src_x, int src_y,
// center is the corresponding coordinate of i in original img.
float center = (i + 0.5f) * scale;
// boundary of weight array in original img.
- int xmin = static_cast<int>(floor(center - support));
- if (xmin < 0) xmin = 0;
- int xmax = static_cast<int>(ceil(center + support));
- if (xmax >= abs(width)) xmax = abs(width) - 1;
+ int xmin = static_cast<int>(floorf(center - support));
+ if (xmin < 0) {
+ xmin = 0;
+ }
+ int xmax = static_cast<int>(ceilf(center + support));
+ if (xmax >= abs(width)) {
+ xmax = abs(width) - 1;
+ }
// fill up weight array by lanczos filter.
float wsum = 0.0;
@@ -341,57 +348,95 @@ void LanczosResize1D(const uint8* src, int src_x, int src_y,
// of the image, we can apply that filter to all pixels in that
// column.
// calculate coordinate in new img.
- int x = i;
- if (nwidth < 0)
- x = -1 * x;
+ int x = nwidth >= 0 ? i : -i;
// lower bound of coordinate in original img.
- if (width < 0)
+ if (width < 0) {
xmin = -1 * xmin;
+ }
for (int j = 0; j < abs(height); ++j) {
// coordinate in height, same in src and dest img.
- int base_y = j;
- if (height < 0)
- base_y = -1 * base_y;
+ int base_y = height >= 0 ? j : -j;
// TODO(yux): fix the vertical flip problem and merge this if-else
// statement coz at that time, there would be no need to check
// which measure we are scaling.
- if (isWidth) {
- const uint8* inrow = src + ((src_bmp_height - (src_y + base_y) - 1) *
- src_bmp_width + src_x + xmin) * components;
- uint8* outpix = out + ((dest_bmp_height - (dest_y + base_y) - 1) *
- pitch + dest_x + x) * components;
- int step = components;
- if (width < 0)
- step = -1 * step;
+ if (is_width) {
+ const OriginalType* inrow = PointerFromVoidPointer<const OriginalType*>(
+ src_data, (src_y + base_y) * src_pitch) +
+ (src_x + xmin) * components;
+ OriginalType* outpix = PointerFromVoidPointer<OriginalType*>(
+ dest_data, (dest_y + base_y) * dest_pitch) +
+ (dest_x + x) * components;
+ int step = width >= 0 ? components : -components;
for (int b = 0; b < components; ++b) {
float sum = 0.0;
- for (int k = 0, xk = b; k < wcount; ++k, xk += step)
- sum += weight[k] * inrow[xk];
-
- outpix[b] = Safe8Round(sum);
+ for (int k = 0, xk = b; k < wcount; ++k, xk += step) {
+ sum += weight[k] * convert_to_float(inrow[xk]);
+ }
+ outpix[b] = convert_to_original(sum);
}
} else {
- const uint8* inrow = src + (src_x + base_y + (src_bmp_height -
- (src_y + xmin) - 1) * src_bmp_width) *
- components;
- uint8* outpix = out + (dest_x + base_y + (dest_bmp_height -
- (dest_y + x) - 1) * pitch) * components;
-
- int step = src_bmp_width * components;
- if (width < 0)
- step = -1 * step;
+ const OriginalType* inrow = PointerFromVoidPointer<const OriginalType*>(
+ src_data,
+ (src_y + xmin) * src_pitch) +
+ (src_x + base_y) * components;
+ OriginalType* outpix = PointerFromVoidPointer<OriginalType*>(
+ dest_data,
+ (dest_y + x) * dest_pitch) +
+ (dest_x + base_y) * components;
+ int step = width >= 0 ? src_pitch : -src_pitch;
for (int b = 0; b < components; ++b) {
float sum = 0.0;
- for (int k = 0, xk = b; k < wcount; ++k, xk -= step)
- sum += weight[k] * inrow[xk];
-
- outpix[b] = Safe8Round(sum);
+ const OriginalType* work = inrow + b;
+ for (int k = 0; k < wcount; ++k) {
+ sum += weight[k] * convert_to_float(*work);
+ work = AddPointerOffset<const OriginalType*>(work, step);
+ }
+ outpix[b] = convert_to_original(sum);
}
}
}
}
}
+template <typename OriginalType,
+ float convert_to_float(OriginalType value),
+ OriginalType convert_to_original(float)>
+void TypedLanczosScale(const void* src, int src_pitch,
+ int src_x, int src_y,
+ int src_width, int src_height,
+ void* dest, int dest_pitch,
+ int dest_x, int dest_y,
+ int dest_width, int dest_height,
+ int components) {
+ // Scale the image horizontally to a temp buffer.
+ int temp_img_width = abs(dest_width);
+ int temp_img_height = abs(src_height);
+ int temp_width = dest_width;
+ int temp_height = src_height;
+ int temp_x = 0, temp_y = 0;
+ if (temp_width < 0)
+ temp_x = abs(temp_width) - 1;
+ if (temp_height < 0)
+ temp_y = abs(temp_height) - 1;
+
+ scoped_array<OriginalType> temp(
+ new OriginalType[temp_img_width * temp_img_height * components]);
+
+ LanczosResize1D<OriginalType, convert_to_float, convert_to_original>(
+ src, src_pitch, src_x, src_y, src_width, src_height,
+ temp.get(), temp_img_width * components * sizeof(OriginalType),
+ temp_x, temp_y, temp_width,
+ true, components);
+
+ // Scale the temp buffer vertically to get the final result.
+ LanczosResize1D<OriginalType, convert_to_float, convert_to_original>(
+ temp.get(), temp_img_width * components * sizeof(OriginalType),
+ temp_x, temp_y, temp_height, temp_width,
+ dest, dest_pitch,
+ dest_x, dest_y, dest_height,
+ false, components);
+}
+
// Compute a texel, filtered from several source texels. This function assumes
// minification.
// Parameters:
@@ -400,9 +445,11 @@ void LanczosResize1D(const uint8* src, int src_x, int src_y,
// dst_width: width of the destination image
// dst_height: height of the destination image
// dst_data: address of the destination image data
+// dst_pitch: the number of bytes per row of the destination.
// src_width: width of the source image
// src_height: height of the source image
// src_data: address of the source image data
+// src_pitch: the number of bytes per row of the source.
// components: number of components in the image.
template <typename OriginalType,
typename WorkType,
@@ -428,14 +475,6 @@ void FilterTexel(unsigned int x,
DCHECK_LE(static_cast<int>(src_width), src_pitch);
DCHECK_LE(static_cast<int>(dst_width), dst_pitch);
- const OriginalType* src = static_cast<const OriginalType*>(src_data);
- OriginalType* dst = static_cast<OriginalType*>(dst_data);
-
- DCHECK_EQ(src_pitch % (components * sizeof(*src)), 0u);
- DCHECK_EQ(dst_pitch % (components * sizeof(*dst)), 0u);
-
- src_pitch /= components;
- dst_pitch /= components;
// the texel at (x, y) represents the square of texture coordinates
// [x/dst_w, (x+1)/dst_w) x [y/dst_h, (y+1)/dst_h).
// This takes contributions from the texels:
@@ -477,7 +516,7 @@ void FilterTexel(unsigned int x,
// source texel is across the left border of the footprint of the
// destination texel.
x_contrib = (src_x + 1) * dst_width - x * src_width;
- } else if ((src_x + 1) * dst_width > (x+1) * src_width) {
+ } else if ((src_x + 1) * dst_width > (x + 1) * src_width) {
// source texel is across the right border of the footprint of the
// destination texel.
x_contrib = (x+1) * src_width - src_x * dst_width;
@@ -489,23 +528,27 @@ void FilterTexel(unsigned int x,
// source texel is across the top border of the footprint of the
// destination texel.
y_contrib = (src_y + 1) * dst_height - y * src_height;
- } else if ((src_y + 1) * dst_height > (y+1) * src_height) {
+ } else if ((src_y + 1) * dst_height > (y + 1) * src_height) {
// source texel is across the bottom border of the footprint of the
// destination texel.
- y_contrib = (y+1) * src_height - src_y * dst_height;
+ y_contrib = (y + 1) * src_height - src_y * dst_height;
}
DCHECK(y_contrib > 0);
DCHECK(y_contrib <= dst_height);
WorkType contrib = static_cast<WorkType>(x_contrib * y_contrib);
+ const OriginalType* src = PointerFromVoidPointer<const OriginalType*>(
+ src_data, src_y * src_pitch);
for (unsigned int c = 0; c < components; ++c) {
accum[c] += contrib *
- convert_to_work(src[(src_y * src_pitch + src_x) * components + c]);
+ convert_to_work(src[src_x * components + c]);
}
}
}
+ OriginalType* dst = PointerFromVoidPointer<OriginalType*>(
+ dst_data, y * dst_pitch);
for (unsigned int c = 0; c < components; ++c) {
WorkType value = accum[c] / static_cast<WorkType>(src_height * src_width);
- dst[(y * dst_pitch + x) * components + c] = convert_to_original(value);
+ dst[x * components + c] = convert_to_original(value);
}
}
@@ -526,27 +569,24 @@ void GenerateMip(unsigned int components,
unsigned int mip_width = std::max(1U, src_width >> 1);
unsigned int mip_height = std::max(1U, src_height >> 1);
- const OriginalType* src = static_cast<const OriginalType*>(src_data);
- OriginalType* dst = static_cast<OriginalType*>(dst_data);
-
if (mip_width * 2 == src_width && mip_height * 2 == src_height) {
- DCHECK_EQ(src_pitch % (components * sizeof(*src)), 0u);
- DCHECK_EQ(dst_pitch % (components * sizeof(*dst)), 0u);
- src_pitch /= components;
- dst_pitch /= components;
// Easy case: every texel maps to exactly 4 texels in the previous level.
for (unsigned int y = 0; y < mip_height; ++y) {
+ const OriginalType* src0 = PointerFromVoidPointer<const OriginalType*>(
+ src_data, y * 2 * src_pitch);
+ const OriginalType* src1 =
+ AddPointerOffset<const OriginalType*>(src0, src_pitch);
+ OriginalType* dst = PointerFromVoidPointer<OriginalType*>(
+ dst_data, y * dst_pitch);
for (unsigned int x = 0; x < mip_width; ++x) {
for (unsigned int c = 0; c < components; ++c) {
// Average the 4 texels.
- unsigned int offset = (y * 2 * src_pitch + x * 2) * components + c;
- WorkType value = convert_to_work(src[offset]); // (2x, 2y)
- value += convert_to_work(src[offset + components]); // (2x+1, 2y)
- value += convert_to_work(src[offset + src_width * components]);
- // (2x, 2y+1)
- value += convert_to_work(src[offset + (src_width + 1) * components]);
- // (2x+1, 2y+1)
- dst[(y * dst_pitch + x) * components + c] =
+ unsigned int offset = x * 2 * components + c;
+ WorkType value = convert_to_work(src0[offset]); // (2x, 2y)
+ value += convert_to_work(src0[offset + components]); // (2x+1, 2y)
+ value += convert_to_work(src1[offset]); // (2x, 2y+1)
+ value += convert_to_work(src1[offset + components]); // (2x+1, 2y+1)
+ dst[x * components + c] =
convert_from_work(value / static_cast<WorkType>(4));
}
}
@@ -581,6 +621,10 @@ uint8 UInt64ToUInt8(uint64 value) {
return static_cast<uint8>(value);
};
+float UInt8ToFloat(uint8 value) {
+ return static_cast<float>(value);
+};
+
float FloatToFloat(float value) {
return value;
}
@@ -611,12 +655,44 @@ uint16 DoubleToHalf(double value) {
} // anonymous namespace
+bool AdjustForSetRect(int* src_y,
+ int src_width,
+ int src_height,
+ int* src_pitch,
+ int* dst_y,
+ int dst_width,
+ int* dst_height) {
+ if (src_width != dst_width || abs(src_height) != abs(*dst_height) ||
+ src_width < 0) {
+ return false;
+ }
+
+ if (*dst_height < 0) {
+ *dst_y = *dst_y + *dst_height + 1;
+ *dst_height = -*dst_height;
+ if (src_height < 0) {
+ *src_y = *src_y + src_height + 1;
+ } else {
+ *src_y = *src_y + src_height - 1;
+ *src_pitch = -*src_pitch;
+ }
+ } else {
+ if (src_height < 0) {
+ *src_pitch = -*src_pitch;
+ }
+ }
+
+ return true;
+}
+
// Adjust boundaries when using DrawImage function in bitmap or texture.
bool AdjustDrawImageBoundary(int* src_x, int* src_y,
int* src_width, int* src_height,
+ int src_bmp_level,
int src_bmp_width, int src_bmp_height,
int* dest_x, int* dest_y,
int* dest_width, int* dest_height,
+ int dest_bmp_level,
int dest_bmp_width, int dest_bmp_height) {
// if src or dest rectangle is out of boundaries, do nothing.
if ((*src_x < 0 && *src_x + *src_width <= 0) ||
@@ -630,25 +706,35 @@ bool AdjustDrawImageBoundary(int* src_x, int* src_y,
(*dest_x >= dest_bmp_width &&
*dest_x + *dest_width >= dest_bmp_width - 1) ||
(*dest_y >= dest_bmp_height &&
- *dest_y + *dest_height >= dest_bmp_height - 1))
+ *dest_y + *dest_height >= dest_bmp_height - 1) ||
+ (src_bmp_level < 0) || (dest_bmp_level < 0))
return false;
+ int src_mip_width = static_cast<int>(
+ image::ComputeMipDimension(src_bmp_level, src_bmp_width));
+ int src_mip_height = static_cast<int>(
+ image::ComputeMipDimension(src_bmp_level, src_bmp_height));
+ int dest_mip_width = static_cast<int>(
+ image::ComputeMipDimension(dest_bmp_level, dest_bmp_width));
+ int dest_mip_height = static_cast<int>(
+ image::ComputeMipDimension(dest_bmp_level, dest_bmp_height));
+
// if start points are negative.
// check whether src_x is negative.
if (!AdjustDrawImageBoundHelper(src_x, dest_x,
- src_width, dest_width, src_bmp_width))
+ src_width, dest_width, src_mip_width))
return false;
// check whether dest_x is negative.
if (!AdjustDrawImageBoundHelper(dest_x, src_x,
- dest_width, src_width, dest_bmp_width))
+ dest_width, src_width, dest_mip_width))
return false;
// check whether src_y is negative.
if (!AdjustDrawImageBoundHelper(src_y, dest_y,
- src_height, dest_height, src_bmp_height))
+ src_height, dest_height, src_mip_height))
return false;
// check whether dest_y is negative.
if (!AdjustDrawImageBoundHelper(dest_y, src_y,
- dest_height, src_height, dest_bmp_height))
+ dest_height, src_height, dest_mip_height))
return false;
// check any width or height becomes negative after adjustment.
@@ -660,49 +746,46 @@ bool AdjustDrawImageBoundary(int* src_x, int* src_y,
return true;
}
-void LanczosScale(const uint8* src,
+void LanczosScale(Texture::Format format, const void* src, int src_pitch,
int src_x, int src_y,
int src_width, int src_height,
- int src_img_width, int src_img_height,
- uint8* dest, int dest_pitch,
+ void* dest, int dest_pitch,
int dest_x, int dest_y,
int dest_width, int dest_height,
- int dest_img_width, int dest_img_height,
int components) {
- // Scale the image horizontally to a temp buffer.
- int temp_img_width = abs(dest_width);
- int temp_img_height = abs(src_height);
- int temp_width = dest_width;
- int temp_height = src_height;
- int temp_x = 0, temp_y = 0;
- if (temp_width < 0)
- temp_x = abs(temp_width) - 1;
- if (temp_height < 0)
- temp_y = abs(temp_height) - 1;
-
- scoped_array<uint8> temp(new uint8[temp_img_width *
- temp_img_height * components]);
-
- LanczosResize1D(src, src_x, src_y, src_width, src_height,
- src_img_width, src_img_height,
- temp.get(), temp_img_width * components,
- temp_x, temp_y, temp_width,
- temp_img_width, temp_img_height, true, components);
-
- // Scale the temp buffer vertically to get the final result.
- LanczosResize1D(temp.get(), temp_x, temp_y, temp_height, temp_width,
- temp_img_width, temp_img_height,
- dest, dest_pitch,
- dest_x, dest_y, dest_height,
- dest_img_width, dest_img_height, false, components);
+ switch (format) {
+ case Texture::ARGB8:
+ case Texture::XRGB8:
+ TypedLanczosScale<uint8, UInt8ToFloat, Safe8Round>(
+ src, src_pitch, src_x, src_y, src_width, src_height,
+ dest, dest_pitch, dest_x, dest_y, dest_width, dest_height,
+ components);
+ break;
+ case Texture::ABGR16F:
+ TypedLanczosScale<uint16, HalfToFloat, FloatToHalf>(
+ src, src_pitch, src_x, src_y, src_width, src_height,
+ dest, dest_pitch, dest_x, dest_y, dest_width, dest_height,
+ components);
+ break;
+ case Texture::ABGR32F:
+ case Texture::R32F:
+ TypedLanczosScale<float, FloatToFloat, FloatToFloat>(
+ src, src_pitch, src_x, src_y, src_width, src_height,
+ dest, dest_pitch, dest_x, dest_y, dest_width, dest_height,
+ components);
+ break;
+ default:
+ DLOG(ERROR) << "Mip-map generation not supported for format: " << format;
+ return;
+ }
}
bool GenerateMipmap(unsigned int src_width,
unsigned int src_height,
Texture::Format format,
- const uint8 *src_data,
+ const void *src_data,
int src_pitch,
- uint8 *dst_data,
+ void *dst_data,
int dst_pitch) {
unsigned int components = GetNumComponentsForFormat(format);
if (components == 0) {
@@ -737,7 +820,6 @@ bool GenerateMipmap(unsigned int src_width,
default:
DLOG(ERROR) << "Mip-map generation not supported for format: " << format;
return false;
- break;
}
return true;
}
diff --git a/o3d/core/cross/image_utils.h b/o3d/core/cross/image_utils.h
index cb2f761..ef3e75b 100644
--- a/o3d/core/cross/image_utils.h
+++ b/o3d/core/cross/image_utils.h
@@ -122,35 +122,31 @@ size_t ComputeBufferSize(unsigned int width,
// and paste in dest image. Utility function for all DrawImage
// function in bitmap and textures. Scale operation is based on
// Lanczos resampling.
-// Note: this doesn't work for DXTC, or floating-point images.
+// Note: this doesn't work for DXTC.
//
// Parameters:
+// format: The format of the images.
// src: source image which would be copied from.
+// src_pitch: The number of bytes per row in the src image.
// src_x: x-coordinate of the starting pixel in the src image.
// src_y: y-coordinate of the starting pixel in the src image.
// src_width: width of the part in src image to be croped.
// src_height: height of the part in src image to be croped.
-// src_img_width: width of the src image.
-// src_img_height: height of the src image.
// dest: dest image which would be copied to.
+// dest_pitch: The number of bytes per row in the dest image.
// dest_x: x-coordinate of the starting pixel in the dest image.
// dest_y: y-coordinate of the starting pixel in the dest image.
// dest_width: width of the part in dest image to be pasted to.
// dest_height: height of the part in dest image to be pasted to.
-// dest_img_width: width of the dest image.
-// dest_img_height: height of the src image.
-// component: size of each pixel in terms of array element.
-// Returns:
-// true if crop and scale succeeds.
-void LanczosScale(const uint8* src,
+// components: number of components per pixel.
+void LanczosScale(Texture::Format format,
+ const void* src, int src_pitch,
int src_x, int src_y,
int src_width, int src_height,
- int src_img_width, int src_img_height,
- uint8* dest, int dest_pitch,
+ void* dest, int dest_pitch,
int dest_x, int dest_y,
int dest_width, int dest_height,
- int dest_img_width, int dest_img_height,
- int component);
+ int components);
// Detects the type of image file based on the filename.
ImageFileType GetFileTypeFromFilename(const char *filename);
@@ -167,7 +163,7 @@ void XYZToXYZA(uint8 *image_data, int pixel_count);
void RGBAToBGRA(uint8 *image_data, int pixel_count);
// Generates a mip-map for 1 level.
-// NOTE: this doesn't work for DXTC, or floating-point images.
+// NOTE: this doesn't work for DXTC images.
//
// Parameters:
// src_width: the width of the source image.
@@ -182,13 +178,13 @@ void RGBAToBGRA(uint8 *image_data, int pixel_count);
bool GenerateMipmap(unsigned int src_width,
unsigned int src_height,
Texture::Format format,
- const uint8 *src_data,
+ const void *src_data,
int src_pitch,
- uint8 *dst_data,
+ void *dst_data,
int dst_pitch);
// Scales an image up to power-of-two textures, using point filtering.
-// NOTE: this doesn't work for DXTC, or floating-point images.
+// NOTE: this doesn't work for DXTC images.
//
// Parameters:
// width: the non-power-of-two width of the original image.
@@ -202,12 +198,12 @@ bool GenerateMipmap(unsigned int src_width,
bool ScaleUpToPOT(unsigned int width,
unsigned int height,
Texture::Format format,
- const uint8 *src,
- uint8 *dst,
+ const void *src,
+ void *dst,
int dst_pitch);
// Scales an image to an arbitrary size, using point filtering.
-// NOTE: this doesn't work for DXTC, or floating-point images.
+// NOTE: this doesn't work for DXTC images.
//
// Parameters:
// src_width: the width of the original image.
@@ -223,10 +219,10 @@ bool ScaleUpToPOT(unsigned int width,
bool Scale(unsigned int src_width,
unsigned int src_height,
Texture::Format format,
- const uint8 *src,
+ const void *src,
unsigned int dst_width,
unsigned int dst_height,
- uint8 *dst,
+ void *dst,
int dst_pitch);
// adjust start points and boundaries when using DrawImage data
@@ -236,23 +232,55 @@ bool Scale(unsigned int src_width,
// src_y: y-coordinate of the starting pixel in the source image.
// src_width: width of the source image to draw.
// src_height: height of the source image to draw.
+// src_bmp_level: which mip in source.
// src_bmp_width: original width of source bitmap.
// src_bmp_height: original height of source bitmap.
// dest_x: x-coordinate of the starting pixel in the dest image.
// dest_y: y-coordinate of the starting pixel in the dest image.
// dest_width: width of the dest image to draw.
// dest_height: height of the dest image to draw.
+// dest_bmp_level: which mip in dest.
// dest_bmp_width: original width of dest bitmap.
// dest_bmp_height: original height of dest bitmap.
// Returns:
// false if src or dest rectangle is out of boundaries.
bool AdjustDrawImageBoundary(int* src_x, int* src_y,
int* src_width, int* src_height,
+ int src_level,
int src_bmp_width, int src_bmp_height,
int* dest_x, int* dest_y,
int* dest_width, int* dest_height,
+ int dest_level,
int dest_bmp_width, int dest_bmp_height);
+// Checks whether or not we can call SetRect and adjust the inputs
+// accordingly so SetRect will work.
+//
+// Assumes that both the source and destination rectangles are within the
+// bounds of their respective images.
+//
+// Parameters:
+// src_y: A pointer to an int holding the Y position of the source
+// rect. Will be adjusted if SetRect can be called.
+// src_width: The width of the source rect.
+// src_height: The height of the source rect.
+// src_pitch: A pointer to an int holding the pitch of the source. Will be
+// adjusted if SetRect can be called.
+// dst_y: A pointer to an int holding the Y position of the dest rect. Will be
+// adjusted if SetRect can be called.
+// dst_width: The width of the dest rect.
+// dst_height: A pointer to an int holding the height of the dest rect. Will
+// adjusted if SetRect can be called.
+// Returns:
+// True if SetRect can be called.
+bool AdjustForSetRect(int* src_y,
+ int src_width,
+ int src_height,
+ int* src_pitch,
+ int* dst_y,
+ int dst_width,
+ int* dst_height);
+
} // namespace image
} // namespace o3d
diff --git a/o3d/core/cross/image_utils_test.cc b/o3d/core/cross/image_utils_test.cc
index ae069e0..a2a237c 100644
--- a/o3d/core/cross/image_utils_test.cc
+++ b/o3d/core/cross/image_utils_test.cc
@@ -35,12 +35,40 @@
#include "tests/common/win/testing_common.h"
#include "base/file_path.h"
#include "utils/cross/file_path_utils.h"
+#include "core/cross/math_utilities.h"
namespace o3d {
+namespace {
+
+void ConvertToHalf(const float* src, size_t count, uint16* dst) {
+ for (; count != 0; --count) {
+ *dst++ = Vectormath::Aos::FloatToHalf(*src++);
+ }
+}
+
+} // anonymous namespace.
+
class ImageTest : public testing::Test {
};
+TEST_F(ImageTest, GetNumComponentsForFormat) {
+ EXPECT_EQ(4, image::GetNumComponentsForFormat(Texture::XRGB8));
+ EXPECT_EQ(4, image::GetNumComponentsForFormat(Texture::ARGB8));
+ EXPECT_EQ(4, image::GetNumComponentsForFormat(Texture::ABGR16F));
+ EXPECT_EQ(4, image::GetNumComponentsForFormat(Texture::ABGR32F));
+ EXPECT_EQ(1, image::GetNumComponentsForFormat(Texture::R32F));
+ EXPECT_EQ(0, image::GetNumComponentsForFormat(Texture::DXT1));
+ EXPECT_EQ(0, image::GetNumComponentsForFormat(Texture::DXT3));
+ EXPECT_EQ(0, image::GetNumComponentsForFormat(Texture::DXT5));
+}
+
+TEST_F(ImageTest, IsPOT) {
+ EXPECT_TRUE(image::IsPOT(2, 2));
+ EXPECT_FALSE(image::IsPOT(3, 2));
+ EXPECT_FALSE(image::IsPOT(2, 3));
+}
+
TEST_F(ImageTest, CheckImageDimensions) {
EXPECT_TRUE(image::CheckImageDimensions(1u, 1u));
EXPECT_TRUE(image::CheckImageDimensions(image::kMaxImageDimension,
@@ -148,7 +176,6 @@ TEST_F(ImageTest, ScaleUpToPOT) {
EXPECT_EQ(0, memcmp(data.get(), kScaleUPDataPOT, dst_size));
}
-
// NOTE: untested ffile types are:
// png grayscale textures
// dds cube maps
@@ -176,7 +203,7 @@ static const uint8 kMipmapDataPOT[] = {
// Generates mip-maps from a known power-of-two image, compare with expected
// results.
-TEST_F(ImageTest, GenerateMipmapsPOT) {
+TEST_F(ImageTest, GenerateMipmapsPOTUInt8) {
const unsigned int kWidth = 4;
const unsigned int kHeight = 4;
const Texture::Format format = Texture::ARGB8;
@@ -206,6 +233,97 @@ TEST_F(ImageTest, GenerateMipmapsPOT) {
EXPECT_EQ(0, memcmp(data.get(), kMipmapDataPOT, size));
}
+TEST_F(ImageTest, GenerateMipmapsPOTFloat) {
+ static const float original[] = { 0.0f, 2.0f, 3.0f, 5.0f, };
+ static const float expected_mip1[] = { 1.0f, 4.0f, };
+ static const float expected_mip2[] = { 2.5f, };
+
+ const unsigned int kWidth = 4;
+ const unsigned int kHeight = 1;
+ const Texture::Format kFormat = Texture::R32F;
+ unsigned int mipmaps = image::ComputeMipMapCount(kWidth, kHeight);
+ EXPECT_EQ(3u, mipmaps);
+ float mip1[2 + 1];
+ float mip2[1 + 1];
+ // Put sentinels at the ends
+ const float kSentinel = 123.12345f;
+ mip1[2] = kSentinel;
+ mip2[1] = kSentinel;
+ image::GenerateMipmap(
+ kWidth, kHeight, kFormat,
+ original, image::ComputeMipPitch(kFormat, 0, kWidth),
+ mip1,
+ image::ComputeMipPitch(kFormat, 1, kWidth));
+ image::GenerateMipmap(
+ image::ComputeMipDimension(1, kWidth),
+ image::ComputeMipDimension(1, kHeight),
+ kFormat,
+ mip1,
+ image::ComputeMipPitch(kFormat, 1, kWidth),
+ mip2,
+ image::ComputeMipPitch(kFormat, 2, kWidth));
+ // Check the result.
+ EXPECT_EQ(0, memcmp(mip1, expected_mip1, sizeof(expected_mip1)));
+ EXPECT_EQ(0, memcmp(mip2, expected_mip2, sizeof(expected_mip2)));
+ EXPECT_EQ(mip1[2], kSentinel);
+ EXPECT_EQ(mip2[1], kSentinel);
+}
+
+TEST_F(ImageTest, GenerateMipmapsPOTHalf) {
+ static const float original_f[] = {
+ 0.0f, 0.0f, 0.0f, 0.0f,
+ 2.0f, 2.0f, 2.0f, 2.0f,
+ 3.0f, 3.0f, 3.0f, 3.0f,
+ 5.0f, 5.0f, 5.0f, 5.0f,
+ };
+ static const float expected_mip1_f[] = {
+ 1.0f, 1.0f, 1.0f, 1.0f,
+ 4.0f, 4.0f, 4.0f, 4.0f,
+ };
+ static const float expected_mip2_f[] = {
+ 2.5f, 2.5f, 2.5f, 2.5f,
+ };
+
+ uint16 original[arraysize(original_f)];
+ uint16 expected_mip1[arraysize(expected_mip1_f)];
+ uint16 expected_mip2[arraysize(expected_mip2_f)];
+
+ ConvertToHalf(original_f, arraysize(original_f), original);
+ ConvertToHalf(expected_mip1_f, arraysize(expected_mip1_f), expected_mip1);
+ ConvertToHalf(expected_mip2_f, arraysize(expected_mip2_f), expected_mip2);
+
+ const unsigned int kWidth = 4;
+ const unsigned int kHeight = 1;
+ const Texture::Format kFormat = Texture::ABGR16F;
+ unsigned int mipmaps = image::ComputeMipMapCount(kWidth, kHeight);
+ EXPECT_EQ(3u, mipmaps);
+ uint16 mip1[2 * 4 + 1];
+ uint16 mip2[1 * 4 + 1];
+ // Put sentinels at the ends
+ const float kSentinel = 123.12345f;
+ uint16 sentinel = Vectormath::Aos::FloatToHalf(kSentinel);
+ mip1[2 * 4] = sentinel;
+ mip2[1 * 4] = sentinel;
+ image::GenerateMipmap(
+ kWidth, kHeight, kFormat,
+ original, image::ComputeMipPitch(kFormat, 0, kWidth),
+ mip1,
+ image::ComputeMipPitch(kFormat, 1, kWidth));
+ image::GenerateMipmap(
+ image::ComputeMipDimension(1, kWidth),
+ image::ComputeMipDimension(1, kHeight),
+ kFormat,
+ mip1,
+ image::ComputeMipPitch(kFormat, 1, kWidth),
+ mip2,
+ image::ComputeMipPitch(kFormat, 2, kWidth));
+ // Check the result.
+ EXPECT_EQ(0, memcmp(mip1, expected_mip1, sizeof(expected_mip1)));
+ EXPECT_EQ(0, memcmp(mip2, expected_mip2, sizeof(expected_mip2)));
+ EXPECT_EQ(mip1[2 * 4], sentinel);
+ EXPECT_EQ(mip2[1 * 4], sentinel);
+}
+
static const uint8 kMipmapDataNPOT[] = {
// This is a 7x7 image
0x0d, 0x16, 0x68, 0x1b, 0xe6, 0x09, 0x89, 0x55,
@@ -302,6 +420,147 @@ TEST_F(ImageTest, GetFileTypeFromMimeType) {
image::GetFileTypeFromFilename("application/x-123"));
}
+TEST_F(ImageTest, LanczosScaleFloat) {
+ static const float original[] = { 0.0f, 2.0f, 3.0f, 5.0f, };
+ static const float expected_mip1[] = { 0.84352076f, 4.1564794f, };
+ static const float expected_mip2[] = { 2.5f, };
+
+ const unsigned int kWidth = 4;
+ const unsigned int kHeight = 1;
+ const Texture::Format kFormat = Texture::R32F;
+ unsigned int mipmaps = image::ComputeMipMapCount(kWidth, kHeight);
+ EXPECT_EQ(3u, mipmaps);
+ float mip1[2 + 1];
+ float mip2[1 + 1];
+ // Put sentinels at the ends
+ const float kSentinel = 123.12345f;
+ mip1[2] = kSentinel;
+ mip2[1] = kSentinel;
+ image::LanczosScale(
+ kFormat,
+ original, image::ComputeMipPitch(kFormat, 0, kWidth),
+ 0, 0, 4, 1,
+ mip1, image::ComputeMipPitch(kFormat, 1, kWidth),
+ 0, 0, 2, 1,
+ 1);
+ image::LanczosScale(
+ kFormat,
+ mip1,
+ image::ComputeMipPitch(kFormat, 1, kWidth),
+ 0, 0, 2, 1,
+ mip2, image::ComputeMipPitch(kFormat, 2, kWidth),
+ 0, 0, 1, 1,
+ 1);
+ // Check the result.
+ EXPECT_EQ(0, memcmp(mip1, expected_mip1, sizeof(expected_mip1)));
+ EXPECT_EQ(0, memcmp(mip2, expected_mip2, sizeof(expected_mip2)));
+ EXPECT_EQ(mip1[2], kSentinel);
+ EXPECT_EQ(mip2[1], kSentinel);
+}
+
+TEST_F(ImageTest, LanczosScaleHalf) {
+ static const uint16 original[] = {
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x4000, 0x4000, 0x4000, 0x4000,
+ 0x4200, 0x4200, 0x4200, 0x4200,
+ 0x4500, 0x4500, 0x4500, 0x4500,
+ };
+ static const uint16 expected_mip1[] = {
+ 0x3abf, 0x3abf, 0x3abf, 0x3abf,
+ 0x4428, 0x4428, 0x4428, 0x4428,
+ };
+ static const uint16 expected_mip2[] = {
+ 0x40ff, 0x40ff, 0x40ff, 0x40ff,
+ };
+
+ const unsigned int kWidth = 4;
+ const unsigned int kHeight = 1;
+ const Texture::Format kFormat = Texture::ABGR16F;
+ unsigned int mipmaps = image::ComputeMipMapCount(kWidth, kHeight);
+ EXPECT_EQ(3u, mipmaps);
+ uint16 mip1[2 * 4 + 1];
+ uint16 mip2[1 * 4 + 1];
+ // Put sentinels at the ends
+ const float kSentinel = 123.12345f;
+ uint16 sentinel = Vectormath::Aos::FloatToHalf(kSentinel);
+ mip1[2 * 4] = sentinel;
+ mip2[1 * 4] = sentinel;
+ image::LanczosScale(
+ kFormat,
+ original, image::ComputeMipPitch(kFormat, 0, kWidth),
+ 0, 0, 4, 1,
+ mip1, image::ComputeMipPitch(kFormat, 1, kWidth),
+ 0, 0, 2, 1,
+ 4);
+ image::LanczosScale(
+ kFormat,
+ mip1,
+ image::ComputeMipPitch(kFormat, 1, kWidth),
+ 0, 0, 2, 1,
+ mip2, image::ComputeMipPitch(kFormat, 2, kWidth),
+ 0, 0, 1, 1,
+ 4);
+ // Check the result.
+ EXPECT_EQ(0, memcmp(mip1, expected_mip1, sizeof(expected_mip1)));
+ EXPECT_EQ(0, memcmp(mip2, expected_mip2, sizeof(expected_mip2)));
+ EXPECT_EQ(mip1[2 * 4], sentinel);
+ EXPECT_EQ(mip2[1 * 4], sentinel);
+}
+
+TEST_F(ImageTest, AdjustForSetRect) {
+ int src_y = 1;
+ int src_pitch = 2;
+ int dst_y = 3;
+ int dst_height = 10;
+ // Different widths
+ EXPECT_FALSE(image::AdjustForSetRect(&src_y, 10, 10, &src_pitch,
+ &dst_y, 11, &dst_height));
+ // Different heights
+ EXPECT_FALSE(image::AdjustForSetRect(&src_y, 10, 11, &src_pitch,
+ &dst_y, 10, &dst_height));
+ // width < 0
+ EXPECT_FALSE(image::AdjustForSetRect(&src_y, -10, 10, &src_pitch,
+ &dst_y, -10, &dst_height));
+ // SH > 0, DH > 0
+ EXPECT_TRUE(image::AdjustForSetRect(&src_y, 10, 10, &src_pitch,
+ &dst_y, 10, &dst_height));
+ EXPECT_EQ(1, src_y);
+ EXPECT_EQ(2, src_pitch);
+ EXPECT_EQ(3, dst_y);
+ EXPECT_EQ(10, dst_height);
+ // SH > 0, DH < 0
+ dst_y = 9;
+ dst_height = -10;
+ EXPECT_TRUE(image::AdjustForSetRect(&src_y, 10, 10, &src_pitch,
+ &dst_y, 10, &dst_height));
+ EXPECT_EQ(10, src_y);
+ EXPECT_EQ(-2, src_pitch);
+ EXPECT_EQ(0, dst_y);
+ EXPECT_EQ(10, dst_height);
+ // SH < 0, DH < 0
+ src_y = 10;
+ src_pitch = 2;
+ dst_y = 15;
+ dst_height = -10;
+ EXPECT_TRUE(image::AdjustForSetRect(&src_y, 10, -10, &src_pitch,
+ &dst_y, 10, &dst_height));
+ EXPECT_EQ(1, src_y);
+ EXPECT_EQ(2, src_pitch);
+ EXPECT_EQ(6, dst_y);
+ EXPECT_EQ(10, dst_height);
+ // SH < 0, DH > 0
+ src_y = 10;
+ src_pitch = 2;
+ dst_y = 3;
+ dst_height = 10;
+ EXPECT_TRUE(image::AdjustForSetRect(&src_y, 10, -10, &src_pitch,
+ &dst_y, 10, &dst_height));
+ EXPECT_EQ(10, src_y);
+ EXPECT_EQ(-2, src_pitch);
+ EXPECT_EQ(3, dst_y);
+ EXPECT_EQ(10, dst_height);
+}
+
} // namespace
diff --git a/o3d/core/cross/render_node.h b/o3d/core/cross/render_node.h
index c51bf79..bbb1004 100644
--- a/o3d/core/cross/render_node.h
+++ b/o3d/core/cross/render_node.h
@@ -37,7 +37,6 @@
#include <vector>
#include "core/cross/param_object.h"
-#include "core/cross/draw_context.h"
#include "core/cross/render_context.h"
namespace o3d {
diff --git a/o3d/core/cross/texture.cc b/o3d/core/cross/texture.cc
index 10e1289..560eb6c 100644
--- a/o3d/core/cross/texture.cc
+++ b/o3d/core/cross/texture.cc
@@ -36,6 +36,7 @@
#include <cmath>
#include "core/cross/texture.h"
#include "core/cross/bitmap.h"
+#include "core/cross/canvas.h"
#include "core/cross/renderer.h"
#include "core/cross/client_info.h"
#include "core/cross/error.h"
@@ -89,18 +90,21 @@ Texture2D::~Texture2D() {
}
void Texture2D::DrawImage(const Bitmap& src_img,
+ int src_mip,
int src_x, int src_y,
int src_width, int src_height,
+ int dst_mip,
int dst_x, int dst_y,
- int dst_width, int dst_height, int dest_mip) {
+ int dst_width, int dst_height) {
DCHECK(src_img.image_data());
- if (dest_mip < 0 || dest_mip >= levels()) {
+ if (dst_mip < 0 || dst_mip >= levels()) {
O3D_ERROR(service_locator()) << "Mip out of range";
}
- unsigned int mip_width = std::max(1, width() >> dest_mip);
- unsigned int mip_height = std::max(1, height() >> dest_mip);
+ if (src_mip < 0 || src_mip >= src_img.num_mipmaps()) {
+ O3D_ERROR(service_locator()) << "Source Mip out of range";
+ }
// Clip source and destination rectangles to
// source and destination bitmaps.
@@ -108,21 +112,25 @@ void Texture2D::DrawImage(const Bitmap& src_img,
// do nothing and return.
if (!image::AdjustDrawImageBoundary(&src_x, &src_y,
&src_width, &src_height,
+ src_mip,
src_img.width(), src_img.height(),
&dst_x, &dst_y,
&dst_width, &dst_height,
- mip_width, mip_height)) {
+ dst_mip,
+ width(), height())) {
return;
}
- unsigned int components = 0;
// check formats of source and dest images.
// format of source and dest should be the same.
if (src_img.format() != format()) {
- O3D_ERROR(service_locator()) << "DrawImage does not support "
- << "different formats.";
+ O3D_ERROR(service_locator()) << "formats must be the same.";
return;
}
+
+ unsigned int mip_width = image::ComputeMipDimension(dst_mip, width());
+ unsigned int mip_height = image::ComputeMipDimension(dst_mip, height());
+
// if src and dest are in the same size and drawImage is copying
// the entire bitmap on dest image, just perform memcpy.
if (src_x == 0 && src_y == 0 && dst_x == 0 && dst_y == 0 &&
@@ -131,15 +139,14 @@ void Texture2D::DrawImage(const Bitmap& src_img,
static_cast<unsigned int>(src_height) == src_img.height() &&
static_cast<unsigned int>(dst_width) == mip_width &&
static_cast<unsigned int>(dst_height) == mip_height) {
- SetRect(dest_mip, 0, 0, mip_width, mip_height,
- src_img.image_data(),
- src_img.GetMipPitch(0));
+ SetRect(dst_mip, 0, 0, mip_width, mip_height,
+ src_img.GetMipData(src_mip),
+ src_img.GetMipPitch(src_mip));
return;
}
- if (src_img.format() == Texture::XRGB8 ||
- src_img.format() == Texture::ARGB8) {
- components = 4;
- } else {
+
+ unsigned int components = image::GetNumComponentsForFormat(format());
+ if (components == 0) {
O3D_ERROR(service_locator()) << "DrawImage does not support format: "
<< src_img.format() << " unless src and "
<< "dest images are in the same size and "
@@ -147,21 +154,93 @@ void Texture2D::DrawImage(const Bitmap& src_img,
return;
}
- LockHelper helper(this, dest_mip);
+ int src_pitch = src_img.GetMipPitch(src_mip);
+ if (image::AdjustForSetRect(&src_y, src_width, src_height, &src_pitch,
+ &dst_y, dst_width, &dst_height)) {
+ SetRect(dst_mip, dst_x, dst_y, dst_width, dst_height,
+ src_img.GetPixelData(src_mip, src_x, src_y),
+ src_pitch);
+ return;
+ }
+
+ LockHelper helper(this, dst_mip);
uint8* mip_data = helper.GetDataAs<uint8>();
if (!mip_data) {
return;
}
- uint8* src_img_data = src_img.image_data();
+ image::LanczosScale(src_img.format(),
+ src_img.GetMipData(src_mip),
+ src_img.GetMipPitch(src_mip),
+ src_x, src_y,
+ src_width, src_height,
+ mip_data, helper.pitch(),
+ dst_x, dst_y,
+ dst_width, dst_height,
+ components);
+}
+
+void Texture2D::DrawImage(const Canvas& src_img,
+ int src_x, int src_y,
+ int src_width, int src_height,
+ int dst_mip,
+ int dst_x, int dst_y,
+ int dst_width, int dst_height) {
+ if (dst_mip < 0 || dst_mip >= levels()) {
+ O3D_ERROR(service_locator()) << "Mip out of range";
+ }
- image::LanczosScale(src_img_data, src_x, src_y,
+ // Clip source and destination rectangles to
+ // source and destination bitmaps.
+ // if src or dest rectangle is out of boundary,
+ // do nothing and return.
+ if (!image::AdjustDrawImageBoundary(&src_x, &src_y,
+ &src_width, &src_height,
+ 0,
+ src_img.width(), src_img.height(),
+ &dst_x, &dst_y,
+ &dst_width, &dst_height,
+ dst_mip,
+ width(), height())) {
+ return;
+ }
+
+ // check formats of source and dest images.
+ // format of source and dest should be the same.
+ if (format() != Texture::ARGB8 && format() != Texture::XRGB8) {
+ O3D_ERROR(service_locator()) << "format must be ARGB8 or XRGB8.";
+ return;
+ }
+
+ unsigned int mip_width = image::ComputeMipDimension(dst_mip, width());
+ unsigned int mip_height = image::ComputeMipDimension(dst_mip, height());
+ unsigned int components = image::GetNumComponentsForFormat(format());
+ DCHECK(components > 0);
+
+ int src_pitch = src_img.GetPitch();
+ if (image::AdjustForSetRect(&src_y, src_width, src_height, &src_pitch,
+ &dst_y, dst_width, &dst_height)) {
+ SetRect(dst_mip, dst_x, dst_y, dst_width, dst_height,
+ src_img.GetPixelData(src_x, src_y),
+ src_pitch);
+ return;
+ }
+
+ LockHelper helper(this, dst_mip);
+ uint8* mip_data = helper.GetDataAs<uint8>();
+ if (!mip_data) {
+ return;
+ }
+
+ image::LanczosScale(format(),
+ src_img.GetPixelData(0, 0),
+ src_img.GetPitch(),
+ src_x, src_y,
src_width, src_height,
- src_img.width(), src_img.height(),
mip_data, helper.pitch(),
dst_x, dst_y,
dst_width, dst_height,
- mip_width, mip_height, components);
+ components);
}
void Texture2D::SetFromBitmap(const Bitmap& bitmap) {
@@ -291,12 +370,12 @@ ObjectBase::Ref TextureCUBE::Create(ServiceLocator* service_locator) {
return ObjectBase::Ref();
}
-void TextureCUBE::DrawImage(const Bitmap& src_img,
+void TextureCUBE::DrawImage(const Bitmap& src_img, int src_mip,
int src_x, int src_y,
int src_width, int src_height,
+ CubeFace dest_face, int dest_mip,
int dst_x, int dst_y,
- int dst_width, int dst_height,
- CubeFace dest_face, int dest_mip) {
+ int dst_width, int dst_height) {
DCHECK(src_img.image_data());
if (dest_face >= NUMBER_OF_FACES) {
@@ -305,10 +384,12 @@ void TextureCUBE::DrawImage(const Bitmap& src_img,
}
if (dest_mip < 0 || dest_mip >= levels()) {
- O3D_ERROR(service_locator()) << "Mip out of range";
+ O3D_ERROR(service_locator()) << "Destination Mip out of range";
}
- unsigned int mip_length = std::max(1, edge_length() >> dest_mip);
+ if (src_mip < 0 || src_mip >= src_img.num_mipmaps()) {
+ O3D_ERROR(service_locator()) << "Source Mip out of range";
+ }
// Clip source and destination rectangles to
// source and destination bitmaps.
@@ -316,14 +397,15 @@ void TextureCUBE::DrawImage(const Bitmap& src_img,
// do nothing and return true.
if (!image::AdjustDrawImageBoundary(&src_x, &src_y,
&src_width, &src_height,
+ src_mip,
src_img.width(), src_img.height(),
&dst_x, &dst_y,
&dst_width, &dst_height,
- mip_length, mip_length)) {
+ dest_mip,
+ edge_length(), edge_length())) {
return;
}
- unsigned int components = 0;
// check formats of source and dest images.
// format of source and dest should be the same.
if (src_img.format() != format()) {
@@ -331,6 +413,9 @@ void TextureCUBE::DrawImage(const Bitmap& src_img,
<< "different formats.";
return;
}
+
+ unsigned int mip_length = image::ComputeMipDimension(dest_mip, edge_length());
+
// if src and dest are in the same size and drawImage is copying
// the entire bitmap on dest image, just perform memcpy.
if (src_x == 0 && src_y == 0 && dst_x == 0 && dst_y == 0 &&
@@ -341,13 +426,12 @@ void TextureCUBE::DrawImage(const Bitmap& src_img,
static_cast<unsigned int>(dst_height) == mip_length) {
SetRect(dest_face, dest_mip, 0, 0, mip_length, mip_length,
src_img.image_data(),
- src_img.GetMipPitch(0));
+ src_img.GetMipPitch(src_mip));
return;
}
- if (src_img.format() == Texture::XRGB8 ||
- src_img.format() == Texture::ARGB8) {
- components = 4;
- } else {
+
+ unsigned int components = image::GetNumComponentsForFormat(format());
+ if (components == 0) {
O3D_ERROR(service_locator()) << "DrawImage does not support format: "
<< src_img.format() << " unless src and "
<< "dest images are in the same size and "
@@ -355,21 +439,95 @@ void TextureCUBE::DrawImage(const Bitmap& src_img,
return;
}
+ int src_pitch = src_img.GetMipPitch(src_mip);
+ if (image::AdjustForSetRect(&src_y, src_width, src_height, &src_pitch,
+ &dst_y, dst_width, &dst_height)) {
+ SetRect(dest_face, dest_mip, dst_x, dst_y, dst_width, dst_height,
+ src_img.GetPixelData(src_mip, src_x, src_y),
+ src_pitch);
+ }
+
LockHelper helper(this, dest_face, dest_mip);
uint8* mip_data = helper.GetDataAs<uint8>();
if (!mip_data) {
return;
}
- uint8* src_img_data = src_img.image_data();
+ image::LanczosScale(src_img.format(), src_img.GetMipData(src_mip),
+ src_img.GetMipPitch(src_mip),
+ src_x, src_y,
+ src_width, src_height,
+ mip_data, helper.pitch(),
+ dst_x, dst_y,
+ dst_width, dst_height,
+ components);
+}
+
+void TextureCUBE::DrawImage(const Canvas& src_img,
+ int src_x, int src_y,
+ int src_width, int src_height,
+ CubeFace dest_face, int dest_mip,
+ int dst_x, int dst_y,
+ int dst_width, int dst_height) {
+ if (dest_face >= NUMBER_OF_FACES) {
+ O3D_ERROR(service_locator()) << "Invalid face specification";
+ return;
+ }
+
+ if (dest_mip < 0 || dest_mip >= levels()) {
+ O3D_ERROR(service_locator()) << "Destination Mip out of range";
+ }
+
+ // Clip source and destination rectangles to
+ // source and destination bitmaps.
+ // if src or dest rectangle is out of boundary,
+ // do nothing and return true.
+ if (!image::AdjustDrawImageBoundary(&src_x, &src_y,
+ &src_width, &src_height,
+ 0,
+ src_img.width(), src_img.height(),
+ &dst_x, &dst_y,
+ &dst_width, &dst_height,
+ dest_mip,
+ edge_length(), edge_length())) {
+ return;
+ }
+
+ // check formats of source and dest images.
+ // format of source and dest should be the same.
+ if (format() != Texture::ARGB8 && format() != Texture::XRGB8) {
+ O3D_ERROR(service_locator()) << "format must be ARGB8 or XRGB8.";
+ return;
+ }
+
+ unsigned int mip_length = image::ComputeMipDimension(dest_mip, edge_length());
+ unsigned int components = image::GetNumComponentsForFormat(format());
+ DCHECK(components > 0);
+
+ int src_pitch = src_img.GetPitch();
+ if (image::AdjustForSetRect(&src_y, src_width, src_height, &src_pitch,
+ &dst_y, dst_width, &dst_height)) {
+ SetRect(dest_face, dest_mip, dst_x, dst_y, dst_width, dst_height,
+ src_img.GetPixelData(src_x, src_y),
+ src_pitch);
+ return;
+ }
+
+ LockHelper helper(this, dest_face, dest_mip);
+ uint8* mip_data = helper.GetDataAs<uint8>();
+ if (!mip_data) {
+ return;
+ }
- image::LanczosScale(src_img_data, src_x, src_y,
+ image::LanczosScale(format(),
+ src_img.GetPixelData(0, 0),
+ src_img.GetPitch(),
+ src_x, src_y,
src_width, src_height,
- src_img.width(), src_img.height(),
mip_data, helper.pitch(),
dst_x, dst_y,
dst_width, dst_height,
- mip_length, mip_length, components);
+ components);
}
void TextureCUBE::SetFromBitmap(CubeFace face, const Bitmap& bitmap) {
diff --git a/o3d/core/cross/texture.h b/o3d/core/cross/texture.h
index c16c884..79ddae2 100644
--- a/o3d/core/cross/texture.h
+++ b/o3d/core/cross/texture.h
@@ -42,6 +42,7 @@ namespace o3d {
class Pack;
class Bitmap;
+class Canvas;
// An abstract class for 2D textures that defines the interface for getting
// the dimensions of the texture and number of mipmap levels.
@@ -130,19 +131,43 @@ class Texture2D : public Texture {
// Scales if the width and height of source and dest do not match.
// Parameters:
// source_img: source bitmap which would be drawn.
+ // source_mip: source mip to draw.
// source_x: x-coordinate of the starting pixel in the source image.
// source_y: y-coordinate of the starting pixel in the source image.
// source_width: width of the source image to draw.
// source_height: Height of the source image to draw.
+ // dest_mip: on which mip level the sourceImg would be drawn.
// dest_x: x-coordinate of the starting pixel in the dest image.
// dest_y: y-coordinate of the starting pixel in the dest image.
// dest_width: width of the dest image.
// dest_height: height of the dest image.
- // dest_mip: on which mip level the sourceImg would be drawn.
- void DrawImage(const Bitmap& source_img, int source_x, int source_y,
+ void DrawImage(const Bitmap& source_img, int src_mip,
+ int source_x, int source_y,
+ int source_width, int source_height,
+ int dest_mip,
+ int dest_x, int dest_y,
+ int dest_width, int dest_height);
+
+ // Copy pixels from source bitmap to certain mip level.
+ // Scales if the width and height of source and dest do not match.
+ // Parameters:
+ // source_img: source canvas to draw.
+ // source_x: x-coordinate of the starting pixel in the source image.
+ // source_y: y-coordinate of the starting pixel in the source image.
+ // source_width: width of the source image to draw.
+ // source_height: Height of the source image to draw.
+ // dest_mip: the dest mip to draw to.
+ // dest_x: x-coordinate of the starting pixel in the dest image.
+ // dest_y: y-coordinate of the starting pixel in the dest image.
+ // dest_width: width of the dest image.
+ // dest_height: height of the dest image.
+ void DrawImage(const Canvas& source_img,
+ int source_x, int source_y,
int source_width, int source_height,
+ int dest_mip,
int dest_x, int dest_y,
- int dest_width, int dest_height, int dest_mip);
+ int dest_width, int dest_height);
+
// Sets the contents of the texture from a Bitmap.
void SetFromBitmap(const Bitmap& bitmap);
@@ -293,21 +318,45 @@ class TextureCUBE : public Texture {
// Copy pixels from source bitmap to certain mip level.
// Scales if the width and height of source and dest do not match.
// Parameters:
- // source_img: source bitmap which would be drawn.
+ // source_img: source bitmap.
+ // source_mip: source mip to draw.
// source_x: x-coordinate of the starting pixel in the source image.
// source_y: y-coordinate of the starting pixel in the source image.
// source_width: width of the source image to draw.
// source_height: Height of the source image to draw.
+ // face: face to draw to.
+ // dest_mip: mip to draw to.
// dest_x: x-coordinate of the starting pixel in the dest image.
// dest_y: y-coordinate of the starting pixel in the dest image.
// dest_width: width of the dest image.
// dest_height: height of the dest image.
- // face: on which face the sourceImg would be drawn.
- // dest_mip: on which mip level the sourceImg would be drawn.
- void DrawImage(const Bitmap& source_img, int source_x, int source_y,
+ void DrawImage(const Bitmap& source_img, int source_mip,
+ int source_x, int source_y,
+ int source_width, int source_height,
+ CubeFace face, int dest_mip,
+ int dest_x, int dest_y, int dest_width,
+ int dest_height);
+
+ // Copy pixels from source canvas to certain mip level.
+ // Scales if the width and height of source and dest do not match.
+ // Parameters:
+ // source_img: source canvas.
+ // source_x: x-coordinate of the starting pixel in the source image.
+ // source_y: y-coordinate of the starting pixel in the source image.
+ // source_width: width of the source image to draw.
+ // source_height: Height of the source image to draw.
+ // face: face to draw to.
+ // dest_mip: mip to draw to.
+ // dest_x: x-coordinate of the starting pixel in the dest image.
+ // dest_y: y-coordinate of the starting pixel in the dest image.
+ // dest_width: width of the dest image.
+ // dest_height: height of the dest image.
+ void DrawImage(const Canvas& source_img,
+ int source_x, int source_y,
int source_width, int source_height,
+ CubeFace face, int dest_mip,
int dest_x, int dest_y, int dest_width,
- int dest_height, CubeFace face, int dest_mip);
+ int dest_height);
// Sets the contents of the texture from a Bitmap.
void SetFromBitmap(CubeFace face, const Bitmap& bitmap);
diff --git a/o3d/plugin/idl/param.idl b/o3d/plugin/idl/param.idl
index e57f8fe..49aa369 100644
--- a/o3d/plugin/idl/param.idl
+++ b/o3d/plugin/idl/param.idl
@@ -316,7 +316,7 @@ typedef Param[] ParamVector;
%[
A Param which stores a DrawList.
%]
-[nocpp, include="core/cross/param.h"] class ParamDrawList : Param {
+[nocpp, include="core/cross/draw_context.h"] class ParamDrawList : Param {
%[
The DrawList stored by the Param.
%]
diff --git a/o3d/plugin/idl/texture.idl b/o3d/plugin/idl/texture.idl
index dcaf4e7..0cd27c0 100644
--- a/o3d/plugin/idl/texture.idl
+++ b/o3d/plugin/idl/texture.idl
@@ -242,34 +242,74 @@ namespace o3d {
Copy pixels from source bitmap to certain mip level.
Scales if the width and height of source and dest do not match.
- \param source_img source bitmap which would be drawn.
+ \param source_img The source bitmap.
+ \param source_mip which mip from the source to copy from.
\param source_x x-coordinate of the starting pixel in the source image.
\param source_y y-coordinate of the starting pixel in the source image.
\param source_width width of the source image to draw.
\param source_height Height of the source image to draw.
- \param dest_x x-coordinate of the starting pixel in the dest image.
- \param dest_y y-coordinate of the starting pixel in the dest image.
+ \param dest_mip on which mip level to draw to.
+ \param dest_x x-coordinate of the starting pixel in the destination texture.
+ \param dest_y y-coordinate of the starting pixel in the destination texture.
\param dest_width width of the dest image.
\param dest_height height of the dest image.
- \param dest_mip on which mip level the sourceImg would be drawn.
%]
[userglue]
- void DrawImage(Bitmap source_img, int source_x, int source_y,
+ void DrawImage(Bitmap source_img, int source_mip,
+ int source_x, int source_y,
int source_width, int source_height,
+ int dest_mip,
int dest_x, int dest_y,
- int dest_width, int dest_height, int dest_mip);
+ int dest_width, int dest_height);
+
+ %[
+ Copy pixels from source canvas to certain mip level.
+ Scales if the width and height of source and dest do not match.
+
+ \param source_img The source canvas.
+ \param source_x x-coordinate of the starting pixel in the source image.
+ \param source_y y-coordinate of the starting pixel in the source image.
+ \param source_width width of the source image to draw.
+ \param source_height Height of the source image to draw.
+ \param dest_mip on which mip level to draw to.
+ \param dest_x x-coordinate of the starting pixel in the destination texture.
+ \param dest_y y-coordinate of the starting pixel in the destination texture.
+ \param dest_width width of the dest image.
+ \param dest_height height of the dest image.
+ %]
+ [userglue, include="core/cross/canvas.h"]
+ void DrawImage(Canvas source_img,
+ int source_x, int source_y,
+ int source_width, int source_height,
+ int dest_mip,
+ int dest_x, int dest_y,
+ int dest_width, int dest_height);
+
[verbatim=cpp_glue] %{
void userglue_method_DrawImage(
o3d::Texture2D* self,
- o3d::Bitmap* source_img, int source_x, int source_y,
+ o3d::Bitmap* source_img, int source_mip, int source_x, int source_y,
+ int source_width, int source_height,
+ int dest_mip,
+ int dest_x, int dest_y,
+ int dest_width, int dest_height) {
+ self->DrawImage(*source_img, source_mip, source_x, source_y,
+ source_width, source_height,
+ dest_mip, dest_x, dest_y,
+ dest_width, dest_height);
+ }
+ void userglue_method_DrawImage(
+ o3d::Texture2D* self,
+ o3d::Canvas* source_img, int source_x, int source_y,
int source_width, int source_height,
+ int dest_mip,
int dest_x, int dest_y,
- int dest_width, int dest_height, int dest_mip) {
+ int dest_width, int dest_height) {
self->DrawImage(*source_img, source_x, source_y,
source_width, source_height,
- dest_x, dest_y,
- dest_width, dest_height, dest_mip);
+ dest_mip, dest_x, dest_y,
+ dest_width, dest_height);
}
%}
}; // Texture2D
@@ -402,40 +442,78 @@ namespace o3d {
%}
%[
- Copy pixels from source bitmap to certain mip level.
+ Copy pixels from source bitmap to certain face and mip level.
Scales if the width and height of source and dest do not match.
- \param source_img source bitmap which would be drawn.
+ \param source_img The source bitmap.
+ \param source_mip which mip of the source to copy from.
\param source_x x-coordinate of the starting pixel in the source image.
\param source_y y-coordinate of the starting pixel in the source image.
\param source_width width of the source image to draw.
\param source_height Height of the source image to draw.
- \param dest_x x-coordinate of the starting pixel in the dest image.
- \param dest_y y-coordinate of the starting pixel in the dest image.
- \param dest_width width of the dest image.
- \param dest_height height of the dest image.
- \param face on which face the sourceImg would be drawn.
- \param dest_mip on which mip level the sourceImg would be drawn.
+ \param face on which face to draw on.
+ \param dest_mip on which mip level to draw on.
+ \param dest_x x-coordinate of the starting pixel in the destination texture.
+ \param dest_y y-coordinate of the starting pixel in the destination texture.
+ \param dest_width width of the destination image.
+ \param dest_height height of the destination image.
%]
[userglue]
- void DrawImage(Bitmap source_img, int source_x, int source_y,
+ void DrawImage(Bitmap source_img, int source_mip, int source_x, int source_y,
+ int source_width, int source_height,
+ CubeFace face, int dest_mip,
+ int dest_x, int dest_y,
+ int dest_width, int dest_height);
+
+ %[
+ Copy pixels from source canvas to certain face and mip level.
+ Scales if the width and height of source and dest do not match.
+
+ \param source_img The source canvas.
+ \param source_x x-coordinate of the starting pixel in the source image.
+ \param source_y y-coordinate of the starting pixel in the source image.
+ \param source_width width of the source image to draw.
+ \param source_height Height of the source image to draw.
+ \param face on which face to draw on.
+ \param dest_mip on which mip level to draw on.
+ \param dest_x x-coordinate of the starting pixel in the destination texture.
+ \param dest_y y-coordinate of the starting pixel in the destination texture.
+ \param dest_width width of the destination image.
+ \param dest_height height of the destination image.
+ %]
+ [userglue, include="core/cross/canvas.h"]
+ void DrawImage(Canvas source_img, int source_x, int source_y,
int source_width, int source_height,
+ CubeFace face, int dest_mip,
int dest_x, int dest_y,
- int dest_width, int dest_height,
- CubeFace face, int dest_mip);
+ int dest_width, int dest_height);
[verbatim=cpp_glue] %{
void userglue_method_DrawImage(
o3d::TextureCUBE* self,
- o3d::Bitmap* source_img, int source_x, int source_y,
+ o3d::Bitmap* source_img, int source_mip, int source_x, int source_y,
+ int source_width, int source_height,
+ o3d::TextureCUBE::CubeFace dest_face, int dest_mip,
+ int dest_x, int dest_y,
+ int dest_width, int dest_height) {
+ self->DrawImage(*source_img, source_mip, source_x, source_y,
+ source_width, source_height,
+ dest_face, dest_mip,
+ dest_x, dest_y,
+ dest_width, dest_height);
+ }
+ void userglue_method_DrawImage(
+ o3d::TextureCUBE* self,
+ o3d::Canvas* source_img, int source_x, int source_y,
int source_width, int source_height,
+ o3d::TextureCUBE::CubeFace dest_face, int dest_mip,
int dest_x, int dest_y,
- int dest_width, int dest_height,
- o3d::TextureCUBE::CubeFace dest_face, int dest_mip) {
+ int dest_width, int dest_height) {
self->DrawImage(*source_img, source_x, source_y,
source_width, source_height,
+ dest_face, dest_mip,
dest_x, dest_y,
- dest_width, dest_height, dest_face, dest_mip);
+ dest_width, dest_height);
}
%}
}; // TextureCUBE
diff --git a/o3d/samples/MANIFEST b/o3d/samples/MANIFEST
index d7b0963..b17fd66 100644
--- a/o3d/samples/MANIFEST
+++ b/o3d/samples/MANIFEST
@@ -198,6 +198,7 @@ o3djs/serialization.js
o3djs/shape.js
o3djs/simple.js
o3djs/test.js
+o3djs/texture.js
o3djs/util.js
pingpong/instructions.gif
pingpong/logo.gif
diff --git a/o3d/samples/archive-textures.html b/o3d/samples/archive-textures.html
index 2e33a3e..7b7b4ea 100644
--- a/o3d/samples/archive-textures.html
+++ b/o3d/samples/archive-textures.html
@@ -49,6 +49,7 @@ o3djs.require('o3djs.io');
o3djs.require('o3djs.rendergraph');
o3djs.require('o3djs.primitives');
o3djs.require('o3djs.effect');
+o3djs.require('o3djs.texture');
// Events
// Run the init() once the page has finished loading.
@@ -173,7 +174,7 @@ function createArchiveRequest(effect) {
g_streamingStarted = true;
// Create a texture from the RawData object that was just made available.
- var texture = g_pack.createTextureFromRawData(rawData, true);
+ var texture = o3djs.texture.createTextureFromRawData(g_pack, rawData, true);
// Free the raw data object immediately since we're done with it.
// If we don't call this the RawData will stay around so we can use it
diff --git a/o3d/samples/bitmap-draw-image.html b/o3d/samples/bitmap-draw-image.html
index 1e3bac0..e4a5208 100644
--- a/o3d/samples/bitmap-draw-image.html
+++ b/o3d/samples/bitmap-draw-image.html
@@ -177,28 +177,33 @@ function initStep2(clientElements) {
function callback(archiveInfo, exception) {
if (!exception) {
var rawdata1 = archiveInfo.getFileByURI('shaving_cream_300x300.jpg', true);
- var bitmap1 = g_pack.createBitmapFromRawData(rawdata1);
+ var bitmap1 = g_pack.createBitmapsFromRawData(rawdata1)[0];
+ bitmap1.flipVertically();
var rawdata2 = archiveInfo.getFileByURI('four_pixel.png', true);
- var bitmap2 = g_pack.createBitmapFromRawData(rawdata2);
+ var bitmap2 = g_pack.createBitmapsFromRawData(rawdata2)[0];
+ bitmap2.flipVertically();
var rawdata_hi = archiveInfo.getFileByURI('hi.jpg', true);
- var bitmap_hi = g_pack.createBitmapFromRawData(rawdata_hi);
+ var bitmapHi = g_pack.createBitmapsFromRawData(rawdata_hi)[0];
+ bitmapHi.flipVertically();
var texture = g_pack.createTexture2D(300, 300, g_o3d.Texture.XRGB8, 0,
false);
// draw image on bitmap.
// scale down on top left corner.
- texture.drawImage(bitmap1, 0, 0, 300, 300, 0, 0, 150, 150, 0);
+ texture.drawImage(bitmap1, 0, 0, 0, 300, 300, 0, 0, 0, 150, 150);
// scale up on top right corner.
- texture.drawImage(bitmap1, 0, 0, 100, 100, 150, 0, 150, 150, 0);
+ texture.drawImage(bitmap1, 0, 0, 156, 100, 100, 0, 150, 0, 150, 150);
// flip and draw part of the img on bottom left.
- texture.drawImage(bitmap1, 150, 0, 150, 150, 149, 299, -150, -150, 0);
+ texture.drawImage(
+ bitmap1, 0, 150, 100, 150, 150, 0, 149, 299, -150, -150);
// draw out of boundary.
- texture.drawImage(bitmap1, 0, 0, 300, 300, 150, 150, 300, 300, 0);
+ texture.drawImage(bitmap1, 0, 0, 135, 300, 300, 0, 150, 150, 300, 300);
// draw o3d.
- texture.drawImage(bitmap_hi, 0, 0, 100, 50, 100, 125, 100, 50, 0);
+ texture.drawImage(bitmapHi, 0, 0, 0, 100, 50, 0, 100, 125, 100, 50);
// draw image on different mip-maps.
- texture.drawImage(bitmap1, 0, 0, 300, 300, 0, 0, 150, 150, 1);
- texture.drawImage(bitmap2, 0, 0, 2, 2, 0, 0, 75, 75, 2);
+ texture.drawImage(bitmap1, 0, 0, 0, 300, 300, 1, 0, 0, 150, 150);
+ texture.drawImage(bitmap2, 0, 0, 0, 2, 2, 2, 0, 0, 75, 75);
+ texture.setRect(0, 0, 0, 1, [1, 0, 0]);
makeShape(texture, effect);
}
diff --git a/o3d/samples/o3djs/canvas.js b/o3d/samples/o3djs/canvas.js
index 3c264b7..b2f6247 100644
--- a/o3d/samples/o3djs/canvas.js
+++ b/o3d/samples/o3djs/canvas.js
@@ -355,7 +355,10 @@ o3djs.canvas.CanvasQuad = function(canvasInfo,
* been issued to the CanvasQuad's Canvas object.
*/
o3djs.canvas.CanvasQuad.prototype.updateTexture = function() {
- this.canvas.copyToTexture(this.texture);
+ var width = this.texture.width;
+ var height = this.texture.height;
+ this.texture.drawImage(this.canvas, 0, height - 1, width, -height,
+ 0, 0, 0, width, height);
};
/**
diff --git a/o3d/samples/o3djs/io.js b/o3d/samples/o3djs/io.js
index 690bd2c..f575eff 100644
--- a/o3d/samples/o3djs/io.js
+++ b/o3d/samples/o3djs/io.js
@@ -36,6 +36,9 @@
o3djs.provide('o3djs.io');
+o3djs.require('o3djs.texture');
+
+
/**
* A Module with various io functions and classes.
* @namespace
@@ -543,11 +546,10 @@ o3djs.io.loadArchiveAdvanced = function(pack,
* texture is loaded. It will be passed the texture and an exception on
* error or null on success.
* @return {!o3djs.io.LoadInfo} A LoadInfo to track progress.
- * @see o3djs.io.createLoader
+ * @see o3djs.loader.createLoader
*/
o3djs.io.loadTexture = function(pack, url, callback) {
- // TODO: change this to get use RawData and Bitmap
- var request = pack.createFileRequest('TEXTURE');
+ var request = pack.createFileRequest('RAWDATA');
var loadInfo = o3djs.io.createLoadInfo(
/** @type {!o3d.FileRequest} */ (request),
false);
@@ -557,9 +559,13 @@ o3djs.io.loadTexture = function(pack, url, callback) {
*/
request.onreadystatechange = function() {
if (request.done) {
- var texture = request.texture;
+ var rawData = /** @type {!o3d.RawData} */ request.data;
var success = request.success;
var exception = request.error;
+ var texture = null;
+ if (success) {
+ texture = o3djs.texture.createTextureFromRawData(pack, rawData, true);
+ }
loadInfo.finish();
pack.removeObject(request);
if (!success && !exception) {
@@ -572,4 +578,3 @@ o3djs.io.loadTexture = function(pack, url, callback) {
return loadInfo;
};
-
diff --git a/o3d/samples/o3djs/js_list.scons b/o3d/samples/o3djs/js_list.scons
index f590330..c5fad39 100644
--- a/o3d/samples/o3djs/js_list.scons
+++ b/o3d/samples/o3djs/js_list.scons
@@ -55,6 +55,7 @@ O3D_JS_SOURCES = [
'shape.js',
'simple.js',
'test.js',
+ 'texture.js',
'util.js',
]
diff --git a/o3d/samples/o3djs/serialization.js b/o3d/samples/o3djs/serialization.js
index bc459a3..2514bd7 100644
--- a/o3d/samples/o3djs/serialization.js
+++ b/o3d/samples/o3djs/serialization.js
@@ -39,6 +39,7 @@
o3djs.provide('o3djs.serialization');
o3djs.require('o3djs.error');
+o3djs.require('o3djs.texture');
/**
* A Module for handling events related to o3d and various browsers.
@@ -162,9 +163,7 @@ o3djs.serialization.Deserializer = function(pack, json) {
if (!rawData) {
throw 'Could not find texture ' + uri + ' in the archive';
}
- return deserializer.pack.createTextureFromRawData(
- rawData,
- true);
+ return o3djs.texture.createTextureFromRawData(pack, rawData, true);
} else {
return deserializer.pack.createTexture2D(
json.custom.width,
@@ -182,9 +181,7 @@ o3djs.serialization.Deserializer = function(pack, json) {
if (!rawData) {
throw 'Could not find texture ' + uri + ' in the archive';
}
- return deserializer.pack.createTextureFromRawData(
- rawData,
- true);
+ return o3djs.texture.createTextureFromRawData(pack, rawData, true);
} else {
return deserializer.pack.createTextureCUBE(
json.custom.edgeLength,
@@ -683,7 +680,7 @@ o3djs.serialization.deserialize = function(pack, json) {
/**
* Deserializes a single json object named 'scene.json' from a loaded
* o3djs.io.ArchiveInfo.
- * @param {!o3djs.io.archiveInfo} archiveInfo Archive to load from.
+ * @param {!o3djs.io.ArchiveInfo} archiveInfo Archive to load from.
* @param {string} sceneJsonUri The relative URI of the scene JSON file within
* the archive.
* @param {!o3d.Client} client An O3D client object.
diff --git a/o3d/samples/o3djs/texture.js b/o3d/samples/o3djs/texture.js
new file mode 100644
index 0000000..6571503
--- /dev/null
+++ b/o3d/samples/o3djs/texture.js
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/**
+ * @fileoverview This file contains functions helping to manipulate and manage
+ * textures.
+ */
+
+o3djs.provide('o3djs.texture');
+
+/**
+ * A Module for bitmaps.
+ * @namespace
+ */
+o3djs.texture = o3djs.texture || {};
+
+/**
+ * The maximum dimension of a texture.
+ * @type {number}
+ */
+o3djs.texture.MAX_TEXTURE_DIMENSION = 2048;
+
+/**
+ * Computes the maximum number of levels of mips a given width and height could
+ * use.
+ * @param {number} width Width of texture.
+ * @param {number} height Height of texture.
+ * @return {number} The maximum number of levels for the given width and height.
+ */
+o3djs.texture.computeNumLevels = function(width, height) {
+ if (width == 0 || height == 0) {
+ return 0;
+ }
+ var max = Math.max(width, height);
+ var levels = 0;
+ while (max > 0) {
+ ++levels;
+ max = max >> 1;
+ }
+ return levels;
+};
+
+/**
+ * Creates a texture from a RawData object.
+ * @param {!o3d.Pack} pack The pack to create the texture in.
+ * @param {!o3d.RawData} rawData The raw data to create the texture from.
+ * @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.createTextureFromRawData = function(
+ pack,
+ rawData,
+ opt_generateMips,
+ opt_flip,
+ opt_maxWidth,
+ opt_maxHeight) {
+ // Make a bitmaps from the raw data.
+ var bitmaps = pack.createBitmapsFromRawData(rawData);
+ 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.
+ 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.
+ */
+o3djs.texture.canMakeMipsAndScale = function(format) {
+ switch (format) {
+ case o3djs.base.o3d.Texture.XRGB8:
+ case o3djs.base.o3d.Texture.ARGB8:
+ case o3djs.base.o3d.Texture.ABGR16F:
+ case o3djs.base.o3d.Texture.R32F:
+ case o3djs.base.o3d.Texture.ABGR32F:
+ return true;
+ case o3djs.base.o3d.Texture.DXT1:
+ case o3djs.base.o3d.Texture.DXT3:
+ case o3djs.base.o3d.Texture.DXT5:
+ return false;
+ }
+ return false;
+};
+
+/**
+ * Creates a Texture from an array of bitmaps.
+ * @param {!o3d.Pack} pack The pack to create the texture in.
+ * @param {!Array.<!o3d.Bitmap>} bitmaps An array of bitmaps to create the
+ * texture from. For a 2D texture this would be 1 bitmap. For a cubemap this
+ * would be 6 bitmaps.
+ * @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.
+ * @return {!o3d.Texture} The created texture.
+ */
+o3djs.texture.createTextureFromBitmaps = function(
+ pack,
+ bitmaps,
+ opt_generateMips) {
+
+ if (bitmaps.length == 0) {
+ throw 'no bitmaps';
+ }
+
+ var srcWidth = bitmaps[0].width;
+ var srcHeight = bitmaps[0].height;
+ var format = bitmaps[0].format;
+ var mipMaps = bitmaps[0].numMipmaps;
+ var maxMips = o3djs.texture.computeNumLevels(srcWidth, srcHeight);
+ var targetMips = mipMaps;
+ var dstWidth = srcWidth;
+ var dstHeight = srcHeight;
+ if (opt_generateMips && o3djs.texture.canMakeMipsAndScale(format) &&
+ mipMaps == 1 && maxMips > 1) {
+ targetMips = maxMips;
+ }
+
+ // Check that all the bitmaps are the same size and make mips
+ for (var ii = 0; ii < bitmaps.length; ++ii) {
+ var bitmap = bitmaps[ii];
+ if (bitmap.width != srcWidth ||
+ bitmap.height != srcHeight ||
+ bitmap.format != format ||
+ bitmap.numMipmaps != mipMaps) {
+ throw 'bitmaps must all be the same width, height, mips and format';
+ }
+ if (targetMips != mipMaps) {
+ bitmap.generateMips(0, targetMips - 1);
+ }
+ }
+
+ var levels = bitmap.numMipmaps > 1 ? bitmap.numMipmaps :
+ o3djs.texture.computeNumLevels(dstWidth, dstHeight);
+ var texture;
+ if (bitmaps.length == 6 &&
+ bitmaps[0].semantic != o3djs.base.o3d.Bitmap.SLICE) {
+ if (srcWidth != srcHeight ||
+ srcWidth != dstWidth ||
+ srcHeight != dstHeight) {
+ throw 'Cubemaps must be square';
+ }
+ texture = pack.createTextureCUBE(dstWidth, format, targetMips, false);
+ for (var ii = 0; ii < 6; ++ii) {
+ texture.setFromBitmap(ii, bitmaps[ii]);
+ }
+ } else if (bitmaps.length == 1) {
+ texture = pack.createTexture2D(
+ dstWidth, dstHeight, format, targetMips, false);
+ texture.setFromBitmap(bitmaps[0]);
+ }
+
+ return texture;
+};
+
+/**
+ * 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.
+ *
+ * @param {!o3d.Pack} pack The pack to create the texture in.
+ * @param {number} edgeLength The size of the cubemap.
+ * @param {!Array.<!o3d.Bitmap>} bitmaps An array of 6 bitmaps in the order
+ * FACE_POSITIVE_X, FACE_NEGATIVE_X, FACE_POSITIVE_Y, FACE_NEGATIVE_Y,
+ * FACE_POSITIVE_Z, FACE_NEGATIVE_Z.
+ * @return {!o3d.Texture} The created texture.
+ */
+o3djs.texture.createCubeTextureFrom6Bitmaps = function(
+ pack, edgeLength, bitmaps) {
+ var numMips = o3djs.texture.computeNumLevels(edgeLength, edgeLength);
+ var texture = pack.createTextureCUBE(
+ edgeLength, bitmaps[0].format, numMips, false);
+ for (var ii = 0; ii < 6; ++ii) {
+ var bitmap = bitmaps[ii];
+ texture.drawImage(bitmap, 0, 0, 0, bitmap.width, bitmap.height,
+ ii, 0, 0, edgeLength, edgeLength);
+ }
+ texture.generateMips(0, numMips - 1);
+ return texture;
+};
+
diff --git a/o3d/samples/o3djs/util.js b/o3d/samples/o3djs/util.js
index 66722e1..6df3e93 100644
--- a/o3d/samples/o3djs/util.js
+++ b/o3d/samples/o3djs/util.js
@@ -60,7 +60,7 @@ o3djs.util.PLUGIN_NAME = 'O3D Plugin';
* utility libraries.
* @type {string}
*/
-o3djs.util.REQUIRED_VERSION = '0.1.38.0';
+o3djs.util.REQUIRED_VERSION = '0.1.40.0';
/**
* A URL at which to download the client.