summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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.