summaryrefslogtreecommitdiffstats
path: root/o3d/core/cross/bitmap.cc
diff options
context:
space:
mode:
authorgman@google.com <gman@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-06 04:53:24 +0000
committergman@google.com <gman@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-06 04:53:24 +0000
commit132899b905b0f1794d7e82e28f9fe77ca6a08282 (patch)
tree47af391191ac78d3b4e02533f74e3575970cebcc /o3d/core/cross/bitmap.cc
parent22e037073118aaf90549410b32d66885d39b78a9 (diff)
downloadchromium_src-132899b905b0f1794d7e82e28f9fe77ca6a08282.zip
chromium_src-132899b905b0f1794d7e82e28f9fe77ca6a08282.tar.gz
chromium_src-132899b905b0f1794d7e82e28f9fe77ca6a08282.tar.bz2
A step in exposing Bitmap to JavaScript.
The plan is to make pack.createBitmapFromRawData return an array of bitmaps. 1 bitmap if it's a standard 2d image 6 bitmaps if it's a cubemap N bitmaps if it's a volume map. The bitmaps will have a semantic so you can look at them and tell they were from a volumemap, a cubemap or a 2d image. On the way I'm attempting to clean up the code. Moving stuff out of Bitmap the did not belong there and Refactoring Bitmap so there are less If Format = stuff. Review URL: http://codereview.chromium.org/164034 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@22583 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d/core/cross/bitmap.cc')
-rw-r--r--o3d/core/cross/bitmap.cc827
1 files changed, 126 insertions, 701 deletions
diff --git a/o3d/core/cross/bitmap.cc b/o3d/core/cross/bitmap.cc
index 35dc34211..e44f5d9 100644
--- a/o3d/core/cross/bitmap.cc
+++ b/o3d/core/cross/bitmap.cc
@@ -44,6 +44,7 @@
#include "utils/cross/file_path_utils.h"
#include "base/file_path.h"
#include "base/file_util.h"
+#include "core/cross/features.h"
#include "core/cross/texture.h"
#include "import/cross/raw_data.h"
#include "import/cross/memory_buffer.h"
@@ -53,26 +54,9 @@ using file_util::OpenFile;
using file_util::CloseFile;
using file_util::GetFileSize;
-namespace {
-static const float kEpsilon = 0.0001f;
-static const float kPi = 3.14159265358979f;
-static const int kFilterSize = 3;
-
-// utility function, round float numbers into 0 to 255 integers.
-uint8 Safe8Round(float f) {
- f += 0.5f;
- if (f < 0.0f) {
- return 0;
- } else if (!(f < 255.0f)) {
- return 255;
- }
- return static_cast<uint8>(f);
-}
-} // anonymous namespace.
-
namespace o3d {
- O3D_DEFN_CLASS(Bitmap, ParamObject);
+O3D_DEFN_CLASS(Bitmap, ParamObject);
Bitmap::Bitmap(ServiceLocator* service_locator)
: ParamObject(service_locator),
@@ -83,54 +67,10 @@ Bitmap::Bitmap(ServiceLocator* service_locator)
num_mipmaps_(0),
is_cubemap_(false) {}
-// Gets the size of the buffer containing a an image, given its width, height
-// and format.
-unsigned int Bitmap::GetBufferSize(unsigned int width,
- unsigned int height,
- Texture::Format format) {
- DCHECK(CheckImageDimensions(width, height));
- unsigned int pixels = width * height;
- switch (format) {
- case Texture::XRGB8:
- case Texture::ARGB8:
- return 4 * sizeof(uint8) * pixels; // NOLINT
- case Texture::ABGR16F:
- return 4 * sizeof(uint16) * pixels; // NOLINT
- case Texture::R32F:
- return sizeof(float) * pixels; // NOLINT
- case Texture::ABGR32F:
- return 4 * sizeof(float) * pixels; // NOLINT
- case Texture::DXT1:
- case Texture::DXT3:
- case Texture::DXT5: {
- unsigned int blocks = ((width + 3) / 4) * ((height + 3) / 4);
- unsigned int bytes_per_block = format == Texture::DXT1 ? 8 : 16;
- return blocks * bytes_per_block;
- }
- case Texture::UNKNOWN_FORMAT:
- break;
- }
- // failed to find a matching format
- LOG(ERROR) << "Unrecognized Texture format type.";
- return 0;
-}
-
-// Gets the size of the buffer containing a mip-map chain, given its base
-// width, height, format and number of mip-map levels.
-unsigned int Bitmap::GetMipChainSize(unsigned int base_width,
- unsigned int base_height,
- Texture::Format format,
- unsigned int num_mipmaps) {
- DCHECK(CheckImageDimensions(base_width, base_height));
- unsigned int total_size = 0;
- unsigned int mip_width = base_width;
- unsigned int mip_height = base_height;
- for (unsigned int i = 0; i < num_mipmaps; ++i) {
- total_size += GetBufferSize(mip_width, mip_height, format);
- mip_width = std::max(1U, mip_width >> 1);
- mip_height = std::max(1U, mip_height >> 1);
- }
- return total_size;
+unsigned int Bitmap::GetMipSize(unsigned int level) const {
+ unsigned int mip_width = std::max(1U, width() >> level);
+ unsigned int mip_height = std::max(1U, height() >> level);
+ return image::ComputeMipChainSize(mip_width, mip_height, format(), 1);
}
void Bitmap::Allocate(Texture::Format format,
@@ -138,7 +78,7 @@ void Bitmap::Allocate(Texture::Format format,
unsigned int height,
unsigned int num_mipmaps,
bool cube_map) {
- DCHECK(CheckImageDimensions(width, height));
+ DCHECK(image::CheckImageDimensions(width, height));
switch (format) {
case Texture::XRGB8:
case Texture::ARGB8:
@@ -154,7 +94,7 @@ void Bitmap::Allocate(Texture::Format format,
break;
}
DCHECK(!cube_map || (width == height));
- DCHECK_LE(num_mipmaps, GetMipMapCount(width, height));
+ DCHECK_LE(num_mipmaps, image::ComputeMipMapCount(width, height));
DCHECK_GT(num_mipmaps, 0u);
format_ = format;
@@ -170,7 +110,7 @@ uint8 *Bitmap::GetMipData(unsigned int level) const {
DCHECK(!is_cubemap_);
if (!image_data_.get()) return NULL;
uint8 *data = image_data_.get();
- return data + GetMipChainSize(width_, height_, format_, level);
+ return data + GetMipChainSize(level);
}
uint8 *Bitmap::GetFaceMipData(TextureCUBE::CubeFace face,
@@ -180,9 +120,9 @@ uint8 *Bitmap::GetFaceMipData(TextureCUBE::CubeFace face,
uint8 *data = image_data_.get();
if (is_cubemap()) {
data += (face - TextureCUBE::FACE_POSITIVE_X) *
- GetMipChainSize(width_, height_, format_, num_mipmaps_);
+ GetMipChainSize(num_mipmaps_);
}
- return data + GetMipChainSize(width_, height_, format_, level);
+ return data + GetMipChainSize(level);
}
void Bitmap::SetRect(
@@ -195,8 +135,8 @@ void Bitmap::SetRect(
int src_pitch) {
DCHECK(src_data);
DCHECK(level < static_cast<int>(num_mipmaps()) && level >= 0);
- unsigned mip_width = Bitmap::GetMipDimension(level, width());
- unsigned mip_height = Bitmap::GetMipDimension(level, height());
+ unsigned mip_width = image::ComputeMipDimension(level, width());
+ unsigned mip_height = image::ComputeMipDimension(level, height());
DCHECK(dst_left + src_width <= mip_width &&
dst_top + src_height <= mip_height);
bool compressed = Texture::IsCompressedFormat(format());
@@ -206,22 +146,21 @@ void Bitmap::SetRect(
uint8* dst =
GetMipData(level) +
- Bitmap::GetMipChainSize(mip_width, dst_top, format(), 1) +
- Bitmap::GetMipChainSize(dst_left, 1, format(), 1);
+ image::ComputeMipChainSize(mip_width, dst_top, format(), 1) +
+ image::ComputeMipChainSize(dst_left, 1, format(), 1);
const uint8* src = static_cast<const uint8*>(src_data);
if (!compressed) {
- unsigned bytes_per_line = GetMipChainSize(src_width, 1, format(), 1);
- int dst_pitch = Bitmap::GetMipChainSize(mip_width, 1, format(), 1);
+ unsigned bytes_per_line = image::ComputePitch(format(), src_width);
+ int dst_pitch = image::ComputePitch(format(), mip_width);
for (unsigned yy = 0; yy < src_height; ++yy) {
memcpy(dst, src, bytes_per_line);
src += src_pitch;
dst += dst_pitch;
}
} else {
- memcpy(dst,
- src,
- Bitmap::GetMipChainSize(mip_width, mip_height, format(), 1));
+ memcpy(dst, src,
+ image::ComputeMipChainSize(mip_width, mip_height, format(), 1));
}
}
@@ -236,8 +175,8 @@ void Bitmap::SetFaceRect(
int src_pitch) {
DCHECK(src_data);
DCHECK(level < static_cast<int>(num_mipmaps()) && level >= 0);
- unsigned mip_width = Bitmap::GetMipDimension(level, width());
- unsigned mip_height = Bitmap::GetMipDimension(level, height());
+ unsigned mip_width = image::ComputeMipDimension(level, width());
+ unsigned mip_height = image::ComputeMipDimension(level, height());
DCHECK(dst_left + src_width <= mip_width &&
dst_top + src_height <= mip_height);
bool compressed = Texture::IsCompressedFormat(format());
@@ -247,13 +186,13 @@ void Bitmap::SetFaceRect(
uint8* dst =
GetFaceMipData(face, level) +
- Bitmap::GetMipChainSize(mip_width, dst_top, format(), 1) +
- Bitmap::GetMipChainSize(dst_left, 1, format(), 1);
+ image::ComputeMipChainSize(mip_width, dst_top, format(), 1) +
+ image::ComputeMipChainSize(dst_left, 1, format(), 1);
const uint8* src = static_cast<const uint8*>(src_data);
if (!compressed) {
- unsigned bytes_per_line = GetMipChainSize(src_width, 1, format(), 1);
- int dst_pitch = Bitmap::GetMipChainSize(mip_width, 1, format(), 1);
+ unsigned bytes_per_line = image::ComputePitch(format(), src_width);
+ int dst_pitch = image::ComputePitch(format(), mip_width);
for (unsigned yy = 0; yy < src_height; ++yy) {
memcpy(dst, src, bytes_per_line);
src += src_pitch;
@@ -262,65 +201,82 @@ void Bitmap::SetFaceRect(
} else {
memcpy(dst,
src,
- Bitmap::GetMipChainSize(mip_width, mip_height, format(), 1));
+ image::ComputeMipChainSize(mip_width, mip_height, format(), 1));
}
}
bool Bitmap::LoadFromStream(MemoryReadStream *stream,
const String &filename,
- ImageFileType file_type,
+ image::ImageFileType file_type,
bool generate_mipmaps) {
+ bool success = false;
// If we don't know what type to load, try to detect it based on the file
// name.
- if (file_type == UNKNOWN) {
- file_type = GetFileTypeFromFilename(filename.c_str());
+ if (file_type == image::UNKNOWN) {
+ file_type = image::GetFileTypeFromFilename(filename.c_str());
}
switch (file_type) {
- case TGA:
- if (LoadFromTGAStream(stream, filename, generate_mipmaps)) return true;
+ case image::TGA:
+ success = LoadFromTGAStream(stream, filename, generate_mipmaps);
break;
- case DDS:
- if (LoadFromDDSStream(stream, filename, generate_mipmaps)) return true;
+ case image::DDS:
+ success = LoadFromDDSStream(stream, filename, generate_mipmaps);
break;
- case PNG:
- if (LoadFromPNGStream(stream, filename, generate_mipmaps)) return true;
+ case image::PNG:
+ success = LoadFromPNGStream(stream, filename, generate_mipmaps);
break;
- case JPEG:
- if (LoadFromJPEGStream(stream, filename, generate_mipmaps)) return true;
+ case image::JPEG:
+ success = LoadFromJPEGStream(stream, filename, generate_mipmaps);
break;
- case UNKNOWN:
+ case image::UNKNOWN:
default:
break;
}
- // At this point we either could not detect the filetype, or possibly
- // the file extension was incorrect (eg. a JPEG image with a .png suffix)
- DLOG(INFO) << "Could not detect file type from filename \""
- << filename << "\". Trying all the loaders.";
- // We will try all the loaders, one by one, starting by the ones that can
- // have an early detect based on magic strings. We Seek(0) after each try
- // since each attempt changes the stream read position.
- if (LoadFromDDSStream(stream, filename, generate_mipmaps)) return true;
+ if (!success) {
+ // At this point we either could not detect the filetype, or possibly
+ // the file extension was incorrect (eg. a JPEG image with a .png suffix)
+ DLOG(INFO) << "Could not detect file type from filename \""
+ << filename << "\". Trying all the loaders.";
+ // We will try all the loaders, one by one, starting by the ones that can
+ // have an early detect based on magic strings. We Seek(0) after each try
+ // since each attempt changes the stream read position.
+ success = LoadFromDDSStream(stream, filename, generate_mipmaps);
+ if (!success) {
+ stream->Seek(0);
+ success = LoadFromPNGStream(stream, filename, generate_mipmaps);
+ }
- stream->Seek(0);
- if (LoadFromPNGStream(stream, filename, generate_mipmaps)) return true;
+ if (!success) {
+ stream->Seek(0);
+ success = LoadFromJPEGStream(stream, filename, generate_mipmaps);
+ }
- stream->Seek(0);
- if (LoadFromJPEGStream(stream, filename, generate_mipmaps)) return true;
+ if (!success) {
+ stream->Seek(0);
+ success = LoadFromTGAStream(stream, filename, generate_mipmaps);
+ }
+ }
- stream->Seek(0);
- if (LoadFromTGAStream(stream, filename, generate_mipmaps)) return true;
- DLOG(ERROR) << "Failed to load image \"" << filename
- << "\": unknown file type";
- return false;
+ if (success) {
+ Features* features = service_locator()->GetService<Features>();
+ DCHECK(features);
+ if (features->flip_textures()) {
+ FlipVertically();
+ }
+ } else {
+ DLOG(ERROR) << "Failed to load image \"" << filename
+ << "\": unknown file type";
+ }
+ return success;
}
// Given an arbitrary bitmap file, load it all into memory and then call our
// stream loader
bool Bitmap::LoadFromFile(const FilePath &filepath,
- ImageFileType file_type,
+ image::ImageFileType file_type,
bool generate_mipmaps) {
// Open the file.
bool result = false;
@@ -362,7 +318,7 @@ bool Bitmap::LoadFromFile(const FilePath &filepath,
// Given a RawData object containing image data in one of our known formats,
// decide which image format it is and call the correct loading function.
bool Bitmap::LoadFromRawData(RawData *raw_data,
- ImageFileType file_type,
+ image::ImageFileType file_type,
bool generate_mipmaps) {
String filename = raw_data->uri();
@@ -379,30 +335,30 @@ bool Bitmap::LoadFromRawData(RawData *raw_data,
return LoadFromStream(&stream, filename, file_type, generate_mipmaps);
}
-void Bitmap::DrawImage(Bitmap* src_img,
+void Bitmap::DrawImage(const Bitmap& src_img,
int src_x, int src_y,
int src_width, int src_height,
int dst_x, int dst_y,
int dst_width, int dst_height) {
- DCHECK(src_img->image_data());
+ DCHECK(src_img.image_data());
DCHECK(image_data());
// Clip source and destination rectangles to
// source and destination bitmaps.
// if src or dest rectangle is out of boundary,
// do nothing and return.
- if (!AdjustDrawImageBoundary(&src_x, &src_y,
- &src_width, &src_height,
- src_img->width_, src_img->height_,
- &dst_x, &dst_y,
- &dst_width, &dst_height,
- width_, height_))
+ if (!image::AdjustDrawImageBoundary(&src_x, &src_y,
+ &src_width, &src_height,
+ src_img.width_, src_img.height_,
+ &dst_x, &dst_y,
+ &dst_width, &dst_height,
+ 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_) {
+ if (src_img.format_ != format_) {
O3D_ERROR(service_locator()) << "DrawImage does not support "
<< "different formats.";
return;
@@ -410,378 +366,72 @@ void Bitmap::DrawImage(Bitmap* src_img,
// 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 &&
- src_img->width_ == width_ && src_img->height_ == height_ &&
- src_width == src_img->width_ && src_height == src_img->height_ &&
+ 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());
+ memcpy(image_data(), src_img.image_data(), GetTotalSize());
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) {
+ if (src_img.format_ == Texture::XRGB8 ||
+ src_img.format_ == Texture::ARGB8) {
components = 4;
} else {
O3D_ERROR(service_locator()) << "DrawImage does not support format: "
- << src_img->format_ << " unless src and "
+ << src_img.format_ << " unless src and "
<< "dest images are in the same size and "
<< "copying the entire bitmap";
return;
}
- uint8* src_img_data = src_img->image_data();
+ uint8* src_img_data = src_img.image_data();
uint8* dst_img_data = image_data();
// crop part of image from src img, scale it in
// bilinear interpolation fashion, and paste it
// on dst img.
- LanczosScale(src_img_data, src_x, src_y,
- src_width, src_height,
- src_img->width_, src_img->height_,
- dst_img_data, width_ * components,
- dst_x, dst_y,
- dst_width, dst_height,
- width_, height_, components);
-}
-
-void Bitmap::LanczosScale(const uint8* src,
- 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,
- 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);
+ image::LanczosScale(src_img_data, src_x, src_y,
+ src_width, src_height,
+ src_img.width_, src_img.height_,
+ dst_img_data, width_ * components,
+ dst_x, dst_y,
+ dst_width, dst_height,
+ width_, height_, components);
}
-void Bitmap::LanczosResize1D(const uint8* src, int src_x, int src_y,
- int width, int height,
- int src_bmp_width, int src_bmp_height,
- uint8* out, 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;
- // calculate scale factor and init the weight array for lanczos filter.
- float scale = fabs(static_cast<float>(width) / nwidth);
- float support = kFilterSize * scale;
- scoped_array<float> weight(new float[static_cast<int>(support * 2) + 4]);
- // we assume width is the dimension we are scaling, and height stays
- // the same.
- for (int i = 0; i < abs(nwidth); ++i) {
- // 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;
- // fill up weight array by lanczos filter.
- float wsum = 0.0;
- for (int ox = xmin; ox <= xmax; ++ox) {
- float wtemp;
- float dx = ox + 0.5f - center;
- // lanczos filter
- if (dx <= -kFilterSize || dx >= kFilterSize) {
- wtemp = 0.0;
- } else if (dx == 0.0) {
- wtemp = 1.0f;
- } else {
- wtemp = kFilterSize * sinf(kPi * dx) * sinf(kPi / kFilterSize * dx) /
- (kPi * kPi * dx * dx);
- }
-
- weight[ox - xmin] = wtemp;
- wsum += wtemp;
- }
- int wcount = xmax - xmin + 1;
-
- // Normalize the weights.
- if (fabs(wsum) > kEpsilon) {
- for (int k = 0; k < wcount; ++k) {
- weight[k] /= wsum;
- }
- }
- // Now that we've computed the filter weights for this x-position
- // 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;
- // lower bound of coordinate in original img.
- 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;
- // 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;
- 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);
- }
- } 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;
- 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);
- }
- }
- }
- }
-}
-
-Bitmap::ImageFileType Bitmap::GetFileTypeFromFilename(const char *filename) {
- // Convert the filename to lower case for matching.
- // NOTE: Surprisingly, "tolower" is not in the std namespace.
- String name(filename);
- std::transform(name.begin(), name.end(), name.begin(), ::tolower);
-
- // Dispatch loading functions based on filename extensions.
- String::size_type i = name.rfind(".");
- if (i == String::npos) {
- DLOG(INFO) << "Could not detect file type for image \""
- << filename << "\": no extension.";
- return UNKNOWN;
- }
-
- String extension = name.substr(i);
- if (extension == ".tga") {
- DLOG(INFO) << "Bitmap Found a TGA file : " << filename;
- return TGA;
- } else if (extension == ".dds") {
- DLOG(INFO) << "Bitmap Found a DDS file : " << filename;
- return DDS;
- } else if (extension == ".png") {
- DLOG(INFO) << "Bitmap Found a PNG file : " << filename;
- return PNG;
- } else if (extension == ".jpg" ||
- extension == ".jpeg" ||
- extension == ".jpe") {
- DLOG(INFO) << "Bitmap Found a JPEG file : " << filename;
- return JPEG;
- } else {
- return UNKNOWN;
- }
-}
-
-struct MimeTypeToFileType {
- const char *mime_type;
- Bitmap::ImageFileType file_type;
-};
-
-static const MimeTypeToFileType mime_type_map[] = {
- {"image/png", Bitmap::PNG},
- {"image/jpeg", Bitmap::JPEG},
- // No official MIME type for TGA or DDS.
-};
-
-Bitmap::ImageFileType Bitmap::GetFileTypeFromMimeType(const char *mime_type) {
- for (unsigned int i = 0; i < arraysize(mime_type_map); ++i) {
- if (!strcmp(mime_type, mime_type_map[i].mime_type))
- return mime_type_map[i].file_type;
- }
- return Bitmap::UNKNOWN;
-}
-
-void Bitmap::XYZToXYZA(uint8 *image_data, int pixel_count) {
- // We do this pixel by pixel, starting from the end to avoid overlapping
- // problems.
- for (int i = pixel_count - 1; i >= 0; --i) {
- image_data[i*4+3] = 0xff;
- image_data[i*4+2] = image_data[i*3+2];
- image_data[i*4+1] = image_data[i*3+1];
- image_data[i*4+0] = image_data[i*3+0];
+void Bitmap::GenerateMips(int source_level, int num_levels) {
+ if (source_level >= num_mipmaps() || source_level < 0) {
+ O3D_ERROR(service_locator()) << "source level out of range.";
+ return;
}
-}
-
-void Bitmap::RGBAToBGRA(uint8 *image_data, int pixel_count) {
- for (int i = 0; i < pixel_count; ++i) {
- uint8 c = image_data[i*4+0];
- image_data[i*4+0] = image_data[i*4+2];
- image_data[i*4+2] = c;
+ if (source_level + num_levels >= num_mipmaps() || num_levels < 0) {
+ O3D_ERROR(service_locator()) << "num levels out of range.";
+ return;
}
-}
-// Compute a texel, filtered from several source texels. This function assumes
-// minification.
-// Parameters:
-// x: x-coordinate of the destination texel in the destination image
-// y: y-coordinate of the destination texel in the destination image
-// dst_width: width of the destination image
-// dst_height: height of the destination image
-// dst_data: address of the destination image data
-// src_width: width of the source image
-// src_height: height of the source image
-// src_data: address of the source image data
-// components: number of components in the image.
-static void FilterTexel(unsigned int x,
- unsigned int y,
- unsigned int dst_width,
- unsigned int dst_height,
- uint8 *dst_data,
- unsigned int src_width,
- unsigned int src_height,
- const uint8 *src_data,
- unsigned int components) {
- DCHECK(Bitmap::CheckImageDimensions(src_width, src_height));
- DCHECK(Bitmap::CheckImageDimensions(dst_width, dst_height));
- DCHECK_LE(dst_width, src_width);
- DCHECK_LE(dst_height, src_height);
- DCHECK_LE(x, dst_width);
- DCHECK_LE(y, dst_height);
- // 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:
- // [floor(x*src_w/dst_w), ceil((x+1)*src_w/dst_w)-1]
- // x
- // [floor(y*src_h/dst_h), ceil((y+1)*src_h/dst_h)-1]
- // from the previous level.
- unsigned int src_min_x = (x*src_width)/dst_width;
- unsigned int src_max_x = ((x+1)*src_width+dst_width-1)/dst_width - 1;
- unsigned int src_min_y = (y*src_height)/dst_height;
- unsigned int src_max_y = ((y+1)*src_height+dst_height-1)/dst_height - 1;
-
- // Find the contribution of source each texel, by computing the coverage of
- // the destination texel on the source texel. We do all the computations in
- // fixed point, at a src_height*src_width factor to be able to use ints,
- // but keep all the precision.
- // Accumulators need to be 64 bits though, because src_height*src_width can
- // be 24 bits for a 4kx4k base, to which we need to multiply the component
- // value which is another 8 bits (and we need to accumulate several of them).
-
- // NOTE: all of our formats use at most 4 components per pixel.
- // Instead of dynamically allocating a buffer for each pixel on the heap,
- // just allocate the worst case on the stack.
- DCHECK_LE(components, 4u);
- uint64 accum[4] = {0};
- for (unsigned int src_x = src_min_x; src_x <= src_max_x; ++src_x) {
- for (unsigned int src_y = src_min_y; src_y <= src_max_y; ++src_y) {
- // The contribution of a fully covered texel is 1/(m_x*m_y) where m_x is
- // the x-dimension minification factor (src_width/dst_width) and m_y is
- // the y-dimenstion minification factor (src_height/dst_height).
- // If the texel is partially covered (on a border), the contribution is
- // proportional to the covered area. We compute it as the product of the
- // covered x-length by the covered y-length.
-
- unsigned int x_contrib = dst_width;
- if (src_x * dst_width < x * src_width) {
- // 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) {
- // source texel is across the right border of the footprint of the
- // destination texel.
- x_contrib = (x+1) * src_width - src_x * dst_width;
- }
- DCHECK(x_contrib > 0);
- DCHECK(x_contrib <= dst_width);
- unsigned int y_contrib = dst_height;
- if (src_y * dst_height < y * src_height) {
- // 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) {
- // source texel is across the bottom border of the footprint of the
- // destination texel.
- y_contrib = (y+1) * src_height - src_y * dst_height;
- }
- DCHECK(y_contrib > 0);
- DCHECK(y_contrib <= dst_height);
- unsigned int contrib = x_contrib * y_contrib;
- for (unsigned int c = 0; c < components; ++c) {
- accum[c] +=
- contrib * src_data[(src_y * src_width + src_x) * components + c];
- }
- }
- }
- for (unsigned int c = 0; c < components; ++c) {
- uint64 value = accum[c] / (src_height * src_width);
- DCHECK_LE(value, 255u);
- dst_data[(y * dst_width + x) * components + c] =
- static_cast<uint8>(value);
- }
+ GenerateMipmaps(image::ComputeMipDimension(source_level, width()),
+ image::ComputeMipDimension(source_level, height()),
+ format(),
+ num_levels,
+ GetMipData(source_level));
}
+// NOTE: This only works for Bitmap since Bitmap knows the pitch.
bool Bitmap::GenerateMipmaps(unsigned int base_width,
unsigned int base_height,
Texture::Format format,
unsigned int num_mipmaps,
uint8 *data) {
- DCHECK(CheckImageDimensions(base_width, base_height));
- unsigned int components = 0;
- switch (format) {
- case Texture::XRGB8:
- case Texture::ARGB8:
- components = 4;
- break;
- case Texture::ABGR16F:
- case Texture::R32F:
- case Texture::ABGR32F:
- case Texture::DXT1:
- case Texture::DXT3:
- case Texture::DXT5:
- case Texture::UNKNOWN_FORMAT:
- DLOG(ERROR) << "Mip-map generation not supported for format: " << format;
- return false;
+ DCHECK(image::CheckImageDimensions(base_width, base_height));
+ unsigned int components = image::GetNumComponentsForFormat(format);
+ if (components == 0) {
+ DLOG(ERROR) << "Mip-map generation not supported for format: " << format;
+ return false;
}
- DCHECK_GE(std::max(base_width, base_height) >> (num_mipmaps-1), 1u);
+ DCHECK_GE(std::max(base_width, base_height) >> (num_mipmaps - 1), 1u);
uint8 *mip_data = data;
unsigned int mip_width = base_width;
unsigned int mip_height = base_height;
@@ -790,239 +440,14 @@ bool Bitmap::GenerateMipmaps(unsigned int base_width,
unsigned int prev_height = mip_height;
uint8 *prev_data = mip_data;
mip_data += components * mip_width * mip_height;
- DCHECK_EQ(mip_data, data + GetMipChainSize(base_width, base_height, format,
- level));
+ DCHECK_EQ(mip_data, data + image::ComputeMipChainSize(
+ base_width, base_height, format, level));
mip_width = std::max(1U, mip_width >> 1);
mip_height = std::max(1U, mip_height >> 1);
-
- if (mip_width * 2 == prev_width && mip_height * 2 == prev_height) {
- // Easy case: every texel maps to exactly 4 texels in the previous level.
- for (unsigned int y = 0; y < mip_height; ++y) {
- 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*prev_width + x*2) * components + c;
- unsigned int value = prev_data[offset]; // (2x, 2y)
- value += prev_data[offset+components]; // (2x+1, 2y)
- value += prev_data[offset+prev_width*components]; // (2x, 2y+1)
- value +=
- prev_data[offset+(prev_width+1)*components]; // (2x+1, 2y+1)
- mip_data[(y*mip_width+x) * components + c] = value/4;
- }
- }
- }
- } else {
- for (unsigned int y = 0; y < mip_height; ++y) {
- for (unsigned int x = 0; x < mip_width; ++x) {
- FilterTexel(x, y, mip_width, mip_height, mip_data, prev_width,
- prev_height, prev_data, components);
- }
- }
- }
- }
-
- return true;
-}
-
-// Scales the image using basic point filtering.
-bool Bitmap::ScaleUpToPOT(unsigned int width,
- unsigned int height,
- Texture::Format format,
- const uint8 *src,
- uint8 *dst,
- int dst_pitch) {
- DCHECK(CheckImageDimensions(width, height));
- switch (format) {
- case Texture::XRGB8:
- case Texture::ARGB8:
- case Texture::ABGR16F:
- case Texture::R32F:
- case Texture::ABGR32F:
- break;
- case Texture::DXT1:
- case Texture::DXT3:
- case Texture::DXT5:
- case Texture::UNKNOWN_FORMAT:
- DCHECK(false);
- return false;
- }
- unsigned int pot_width = GetPOTSize(width);
- unsigned int pot_height = GetPOTSize(height);
- if (pot_width == width && pot_height == height && src == dst)
- return true;
- return Scale(
- width, height, format, src, pot_width, pot_height, dst, dst_pitch);
-}
-
-namespace {
-
-template <typename T>
-void PointScale(
- unsigned components,
- const uint8* src,
- unsigned src_width,
- unsigned src_height,
- uint8* dst,
- int dst_pitch,
- unsigned dst_width,
- unsigned dst_height) {
- const T* use_src = reinterpret_cast<const T*>(src);
- T* use_dst = reinterpret_cast<T*>(dst);
- int pitch = dst_pitch / sizeof(*use_src) / components;
- // Start from the end to be able to do it in place.
- for (unsigned int y = dst_height - 1; y < dst_height; --y) {
- // max value for y is dst_height - 1, which makes :
- // base_y = (2*dst_height - 1) * src_height / (2 * dst_height)
- // which is < src_height.
- unsigned int base_y = ((y * 2 + 1) * src_height) / (dst_height * 2);
- DCHECK_LT(base_y, src_height);
- for (unsigned int x = dst_width - 1; x < dst_width; --x) {
- unsigned int base_x = ((x * 2 + 1) * src_width) / (dst_width * 2);
- DCHECK_LT(base_x, src_width);
- for (unsigned int c = 0; c < components; ++c) {
- use_dst[(y * pitch + x) * components + c] =
- use_src[(base_y * src_width + base_x) * components + c];
- }
- }
- }
-}
-
-} // anonymous namespace
-
-// Scales the image using basic point filtering.
-bool Bitmap::Scale(unsigned int src_width,
- unsigned int src_height,
- Texture::Format format,
- const uint8 *src,
- unsigned int dst_width,
- unsigned int dst_height,
- uint8 *dst,
- int dst_pitch) {
- DCHECK(CheckImageDimensions(src_width, src_height));
- DCHECK(CheckImageDimensions(dst_width, dst_height));
- switch (format) {
- case Texture::XRGB8:
- case Texture::ARGB8: {
- PointScale<uint8>(4, src, src_width, src_height,
- dst, dst_pitch, dst_width, dst_height);
- break;
- }
- case Texture::ABGR16F: {
- PointScale<uint16>(4, src, src_width, src_height,
- dst, dst_pitch, dst_width, dst_height);
- break;
- }
- case Texture::R32F:
- case Texture::ABGR32F: {
- PointScale<float>(format == Texture::R32F ? 1 : 4,
- src, src_width, src_height,
- dst, dst_pitch, dst_width, dst_height);
- break;
- }
- case Texture::DXT1:
- case Texture::DXT3:
- case Texture::DXT5:
- case Texture::UNKNOWN_FORMAT:
- DCHECK(false);
- return false;
- }
- return true;
-}
-
-// Adjust boundaries when using DrawImage function in bitmap or texture.
-bool Bitmap::AdjustDrawImageBoundary(int* src_x, int* src_y,
- int* src_width, int* src_height,
- int src_bmp_width, int src_bmp_height,
- int* dest_x, int* dest_y,
- int* dest_width, int* dest_height,
- 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) ||
- (*src_y < 0 && *src_y + *src_height <= 0) ||
- (*dest_x < 0 && *dest_x + *dest_width <= 0) ||
- (*dest_y < 0 && *dest_y + *dest_height <= 0) ||
- (*src_x >= src_bmp_width &&
- *src_x + *src_width >= src_bmp_width - 1) ||
- (*src_y >= src_bmp_height &&
- *src_y + *src_height >= src_bmp_height - 1) ||
- (*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))
- return false;
-
- // if start points are negative.
- // check whether src_x is negative.
- if (!AdjustDrawImageBoundHelper(src_x, dest_x,
- src_width, dest_width, src_bmp_width))
- return false;
- // check whether dest_x is negative.
- if (!AdjustDrawImageBoundHelper(dest_x, src_x,
- dest_width, src_width, dest_bmp_width))
- return false;
- // check whether src_y is negative.
- if (!AdjustDrawImageBoundHelper(src_y, dest_y,
- src_height, dest_height, src_bmp_height))
- return false;
- // check whether dest_y is negative.
- if (!AdjustDrawImageBoundHelper(dest_y, src_y,
- dest_height, src_height, dest_bmp_height))
- return false;
-
- // check any width or height becomes negative after adjustment.
- if (*src_width == 0 || *src_height == 0 ||
- *dest_width == 0 || *dest_height == 0) {
- return false;
- }
-
- return true;
-}
-
-// utility function called in AdjustDrawImageBoundary.
-// help to adjust a specific dimension,
-// if start point or ending point is out of boundary.
-bool Bitmap::AdjustDrawImageBoundHelper(int* src_a, int* dest_a,
- int* src_length, int* dest_length,
- int src_bmp_length) {
- 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.
- if (*src_a < 0) {
- int src_length_delta = 0 - *src_a;
- *dest_a = *dest_a + (*dest_length) * src_length_delta / (*src_length);
- *dest_length = *dest_length - (*dest_length) *
- src_length_delta / (*src_length);
- *src_length = *src_length - src_length_delta;
- *src_a = 0;
- }
- // if src_a >= src_bmp_width, src_length must be negative.
- if (*src_a >= src_bmp_length) {
- int src_length_delta = *src_a - (src_bmp_length - 1);
- *dest_a = *dest_a - (*dest_length) * src_length_delta / (*src_length);
- *dest_length = *dest_length - (*dest_length) *
- src_length_delta / *src_length;
- *src_length = *src_length - src_length_delta;
- *src_a = src_bmp_length - 1;
- }
-
- 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) {
- int src_length_delta = *src_length - (src_bmp_length - *src_a);
- *dest_length = *dest_length - (*dest_length) *
- src_length_delta / (*src_length);
- *src_length = *src_length - src_length_delta;
- }
- // if src_a + src_length < -1, src_length must be negative.
- if (*src_a + *src_length < -1) {
- int src_length_delta = 0 - (*src_a + *src_length);
- *dest_length = *dest_length + (*dest_length) *
- src_length_delta / (*src_length);
- *src_length = *src_length + src_length_delta;
+ image::GenerateMipmap(
+ prev_width, prev_height, format,
+ prev_data, image::ComputePitch(format, prev_width),
+ mip_data, image::ComputePitch(format, mip_width));
}
return true;
@@ -1043,7 +468,7 @@ bool Bitmap::CheckAlphaIsOne() const {
const uint8 *data = GetFaceMipData(
static_cast<TextureCUBE::CubeFace>(face),
level) + 3;
- const uint8* end = data + Bitmap::GetBufferSize(
+ const uint8* end = data + image::ComputeBufferSize(
std::max(1U, width() >> level),
std::max(1U, height() >> level),
format());
@@ -1064,7 +489,7 @@ bool Bitmap::CheckAlphaIsOne() const {
const uint8 *data = GetFaceMipData(
static_cast<TextureCUBE::CubeFace>(face),
level);
- const uint8* end = data + Bitmap::GetBufferSize(
+ const uint8* end = data + image::ComputeBufferSize(
std::max(1U, width() >> level),
std::max(1U, height() >> level),
format());
@@ -1093,7 +518,7 @@ bool Bitmap::CheckAlphaIsOne() const {
const uint8 *data = GetFaceMipData(
static_cast<TextureCUBE::CubeFace>(face),
level) + 6;
- const uint8* end = data + Bitmap::GetBufferSize(
+ const uint8* end = data + image::ComputeBufferSize(
std::max(1U, width() >> level),
std::max(1U, height() >> level),
format());
@@ -1116,7 +541,7 @@ bool Bitmap::CheckAlphaIsOne() const {
const uint8* data = GetFaceMipData(
static_cast<TextureCUBE::CubeFace>(face),
level) + 12;
- const uint8* end = data + Bitmap::GetBufferSize(
+ const uint8* end = data + image::ComputeBufferSize(
std::max(1U, width() >> level),
std::max(1U, height() >> level),
format());