diff options
Diffstat (limited to 'o3d')
68 files changed, 1113 insertions, 1625 deletions
diff --git a/o3d/core/build.scons b/o3d/core/build.scons index 593b301..e155919 100644 --- a/o3d/core/build.scons +++ b/o3d/core/build.scons @@ -66,6 +66,7 @@ cross_inputs = [ 'cross/iclass_manager.cc', 'cross/ierror_status.cc', 'cross/id_manager.cc', + 'cross/image_utils.cc', 'cross/imain_thread_task_poster.cc', 'cross/material.cc', 'cross/math_utilities.cc', diff --git a/o3d/core/core.gyp b/o3d/core/core.gyp index 99d79c3..e0644a1 100644 --- a/o3d/core/core.gyp +++ b/o3d/core/core.gyp @@ -126,6 +126,7 @@ 'cross/id_manager.h', 'cross/ierror_status.cc', 'cross/ierror_status.h', + 'cross/image_utils.cc', 'cross/imain_thread_task_poster.cc', 'cross/imain_thread_task_poster.h', 'cross/install_check.h', @@ -372,6 +373,7 @@ 'cross/field_test.cc', 'cross/float_n_test.cc', 'cross/function_test.cc', + 'cross/image_utils_test.cc', 'cross/material_test.cc', 'cross/math_utilities_test.cc', 'cross/matrix4_axis_rotation_test.cc', 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()); diff --git a/o3d/core/cross/bitmap.h b/o3d/core/cross/bitmap.h index 0491aac..5bd3687 100644 --- a/o3d/core/cross/bitmap.h +++ b/o3d/core/cross/bitmap.h @@ -45,6 +45,7 @@ #include "base/cross/bits.h"
#include "core/cross/types.h"
#include "core/cross/texture.h"
+#include "core/cross/image_utils.h"
class FilePath;
@@ -67,29 +68,20 @@ class Bitmap : public ParamObject { explicit Bitmap(ServiceLocator* service_locator);
virtual ~Bitmap() {}
- // We will fail to load images that are bigger than 4kx4k to avoid security
- // risks. GPUs don't usually support bigger sizes anyway.
- // The biggest bitmap buffer size with these dimensions is:
- // 4k x 4k x 4xsizeof(float) x6 x4/3 (x6 for cube maps, x4/3 for mipmaps)
- // That makes 2GB, representable in an unsigned int, so we will avoid wraps.
- static const unsigned int kMaxImageDimension = 4096;
- enum ImageFileType {
- UNKNOWN,
- TGA,
- JPEG,
- PNG,
- DDS,
+ enum Semantic {
+ FACE_POSITIVE_X,
+ FACE_NEGATIVE_X,
+ FACE_POSITIVE_Y,
+ FACE_NEGATIVE_Y,
+ FACE_POSITIVE_Z,
+ FACE_NEGATIVE_Z,
+ NORMAL,
+ SLICE,
};
- static bool CheckImageDimensions(unsigned int width, unsigned int height) {
- return width > 0 && height > 0 &&
- width <= kMaxImageDimension && height < kMaxImageDimension;
- }
-
- // Computes one dimension of a mip.
- static unsigned GetMipDimension(int level, unsigned dimension) {
- unsigned v = dimension >> level;
- return v > 0 ? v : 1u;
+ // Returns the pitch of the bitmap for a certain level.
+ int GetMipPitch(int level) const {
+ return image::ComputeMipPitch(format(), level, width());
}
// Creates a copy of a bitmap, copying the pixels as well.
@@ -184,16 +176,10 @@ class Bitmap : public ParamObject { int src_pitch);
// Gets the total size of the bitmap data, counting all faces and mip levels.
- unsigned int GetTotalSize() {
- return (is_cubemap_ ? 6 : 1) *
- GetMipChainSize(width_, height_, format_, num_mipmaps_);
+ unsigned int GetTotalSize() const {
+ return (is_cubemap_ ? 6 : 1) * GetMipChainSize(num_mipmaps_);
}
- // Computes the number of bytes of a texture pixel buffer.
- static unsigned int GetBufferSize(unsigned int width,
- unsigned int height,
- Texture::Format format);
-
// Gets the image data for a given mip-map level.
// Parameters:
// level: mip level to get.
@@ -201,10 +187,13 @@ class Bitmap : public ParamObject { // Gets the image data for a given mip-map level and cube map face.
// Parameters:
- // face: face of cube to get.
+ // face: face of cube to get. This parameter is ignored if
+ // this bitmap is not a cube map.
// level: mip level to get.
- uint8 *GetFaceMipData(TextureCUBE::CubeFace face,
- unsigned int level) const;
+ uint8 *GetFaceMipData(TextureCUBE::CubeFace face, unsigned int level) const;
+
+ // Gets the size of mip.
+ unsigned int GetMipSize(unsigned int level) const;
uint8 *image_data() const { return image_data_.get(); }
Texture::Format format() const { return format_; }
@@ -232,7 +221,7 @@ class Bitmap : public ParamObject { // known extension, all the loaders will be tried.
// generate_mipmaps: whether or not to generate all the mip-map levels.
bool LoadFromFile(const FilePath &filepath,
- ImageFileType file_type,
+ image::ImageFileType file_type,
bool generate_mipmaps);
// Loads a bitmap from a RawData object.
@@ -244,39 +233,14 @@ class Bitmap : public ParamObject { // be tried.
// generate_mipmaps: whether or not to generate all the mip-map levels.
bool LoadFromRawData(RawData *raw_data,
- ImageFileType file_type,
+ image::ImageFileType file_type,
bool generate_mipmaps);
- // Loads a bitmap from a MemoryReadStream.
- // Parameters:
- // stream: a stream for the bitmap data in one of the known formats
- // filename: a filename (or uri) of the original bitmap data
- // (may be an empty string)
- // file_type: the format of the bitmap data. If UNKNOWN, the file type
- // will be determined from the extension of |filename|
- // and if it is not a known extension, all the loaders
- // will be tried.
- // generate_mipmaps: whether or not to generate all the mip-map levels.
- bool LoadFromStream(MemoryReadStream *stream,
- const String &filename,
- ImageFileType file_type,
- bool generate_mipmaps);
-
- bool LoadFromPNGStream(MemoryReadStream *stream,
- const String &filename,
- bool generate_mipmaps);
-
- bool LoadFromTGAStream(MemoryReadStream *stream,
- const String &filename,
- bool generate_mipmaps);
-
- bool LoadFromDDSStream(MemoryReadStream *stream,
- const String &filename,
- bool generate_mipmaps);
-
- bool LoadFromJPEGStream(MemoryReadStream *stream,
- const String &filename,
- bool generate_mipmaps);
+ // Flips a bitmap vertically in place.
+ // This is needed instead of just using DrawImage because flipping DXT formats
+ // using generic algorithms would be lossy and extremely slow to reconvert
+ // from a flippable format back to a DXT format.
+ void FlipVertically();
// Saves to a PNG file. The image must be of the ARGB8 format, be a 2D image
// with no mip-maps (only the base level).
@@ -301,159 +265,19 @@ class Bitmap : public ParamObject { // 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(Bitmap* source_img, int source_x, int source_y,
+ void DrawImage(const Bitmap& source_img, int source_x, int source_y,
int source_width, int source_height,
int dest_x, int dest_y,
int dest_width, int dest_height);
- // Crop part of an image from src, scale it to an arbitrary size
- // 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.
- //
- // Parameters:
- // src: source image which would be copied from.
- // 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_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.
- static void 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 component);
-
- // Detects the type of image file based on the filename.
- static ImageFileType GetFileTypeFromFilename(const char *filename);
- // Detects the type of image file based on the mime-type.
- static ImageFileType GetFileTypeFromMimeType(const char *mime_type);
-
- // Adds filler alpha byte (0xff) after every pixel. Assumes buffer was
- // allocated with enough storage)
- // can convert RGB -> RGBA, BGR -> BGRA, etc.
- static void XYZToXYZA(uint8 *image_data, int pixel_count);
-
- // Swaps Red and Blue components in the image.
- static void RGBAToBGRA(uint8 *image_data, int pixel_count);
-
- // Gets the number of mip-maps required for a full chain starting at
- // width x height.
- static unsigned int GetMipMapCount(unsigned int width, unsigned int height) {
- return 1 + base::bits::Log2Floor(std::max(width, height));
- }
-
- // Gets the smallest power-of-two value that is at least as high as
- // dimension. This is the POT dimension used in ScaleUpToPOT.
- static unsigned int GetPOTSize(unsigned int dimension) {
- return 1 << base::bits::Log2Ceiling(dimension);
+ // Gets the size of the buffer containing a mip-map chain, given a number of
+ // mip-map levels.
+ unsigned int GetMipChainSize(unsigned int num_mipmaps) const {
+ return image::ComputeMipChainSize(width(), height(), format(), num_mipmaps);
}
- // Gets the size of the buffer containing a mip-map chain, given its base
- // width, height, format and number of mip-map levels.
- static unsigned int GetMipChainSize(unsigned int base_width,
- unsigned int base_height,
- Texture::Format format,
- unsigned int num_mipmaps);
-
- // Generates mip-map levels for a single image, using the data from the base
- // level.
- // NOTE: this doesn't work for DXTC, or floating-point images.
- //
- // Parameters:
- // base_width: the width of the base image.
- // base_height: the height of the base image.
- // format: the format of the data.
- // num_mipmaps: the number of mipmaps to generate.
- // data: the data containing the base image, and enough space for the
- // mip-maps.
- static bool GenerateMipmaps(unsigned int base_width,
- unsigned int base_height,
- Texture::Format format,
- unsigned int num_mipmaps,
- uint8 *data);
-
- // Scales an image up to power-of-two textures, using point filtering.
- // NOTE: this doesn't work for DXTC, or floating-point images.
- //
- // Parameters:
- // width: the non-power-of-two width of the original image.
- // height: the non-power-of-two height of the original image.
- // format: the format of the data.
- // src: the data containing the source data of the original image.
- // dst: a buffer with enough space for the power-of-two version. Pixels are
- // written from the end to the beginning so dst can be the same buffer
- // as src.
- // dst_pitch: Number of bytes across 1 row of pixels.
- static bool ScaleUpToPOT(unsigned int width,
- unsigned int height,
- Texture::Format format,
- const uint8 *src,
- uint8 *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.
- //
- // Parameters:
- // src_width: the width of the original image.
- // src_height: the height of the original image.
- // format: the format of the data.
- // src: the data containing the source data of the original image.
- // dst_width: the width of the target image.
- // dst_height: the height of the target image.
- // dst: a buffer with enough space for the target version. Pixels are
- // written from the end to the beginning so dst can be the same buffer
- // as src if the transformation is an upscaling.
- // dst_pitch: Number of bytes across 1 row of pixels.
- static bool 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);
-
- // adjust start points and boundaries when using DrawImage data
- // in bitmap and textures.
- // Parameters:
- // src_x: x-coordinate of the starting pixel in the source image.
- // 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_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_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.
- static bool 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);
+ // Generates Mips from the source_level for num_levels
+ void GenerateMips(int source_level, int num_levels);
private:
friend class IClassManager;
@@ -472,56 +296,117 @@ class Bitmap : public ParamObject { // is this cube-map data
bool is_cubemap_;
- // utility function used in AdjustDrawImageBoundary.
- // It adjusts start point and related measures
- // for a specific dimension.
- // Parameter:
- // src_a: the coordinate which is negative.
- // dest_a: same coordinate in the other image.
- // src_length: length measure of source image to draw.
- // dest_length: length measure of dest image to draw.
- // src_bmp_length: length measure of src image.
- // Returns:
- // true if adjust is successful.
- static bool AdjustDrawImageBoundHelper(int* src_a, int* dest_a,
- int* src_length, int* dest_length,
- int src_bmp_length);
-
- // utility function for LanczosScale function.
- // Given an image, It can scale the image in one dimension to the new
- // length using a Lanczos3 windowsed-sinc filter. This filter has
- // fairly large support, in choosing it we favor quality over speed.
- // In parameters we assume the current dimension we are scaling is
- // width, but by changing the parameter, we can easily using this
- // function on height as well.
- // Parameter:
- // src: source image which would be copied from.
- // src_x: x-coordinate of the starting pixel in the source image.
- // src_y: y-coordinate of the starting pixel in the source image.
- // width: width of the part in src image to be croped.
- // height: height of the part in src image to be croped.
- // src_bmp_width: original width of source bitmap.
- // src_bmp_height: original height of source bitmap.
- // dest: dest image which would be copied 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_bmp_width: original width of dest bitmap.
- // dest_bmp_height: original height of dest bitmap.
- // isWidth: which dimension we are working on.
- // components: size of each pixel in terms of array element.
- static void LanczosResize1D(const uint8* src, int src_x, int src_y,
- int width, int height,
- int src_bmp_width, int src_bmp_height,
- uint8* dest, int dest_pitch,
- int dest_x, int dest_y,
- int nwidth,
- int dest_bmp_width, int dest_bmp_height,
- bool isWidth, int components);
+ // Loads a bitmap from a MemoryReadStream.
+ // Parameters:
+ // stream: a stream for the bitmap data in one of the known formats
+ // filename: a filename (or uri) of the original bitmap data
+ // (may be an empty string)
+ // file_type: the format of the bitmap data. If UNKNOWN, the file type
+ // will be determined from the extension of |filename|
+ // and if it is not a known extension, all the loaders
+ // will be tried.
+ // generate_mipmaps: whether or not to generate all the mip-map levels.
+ bool LoadFromStream(MemoryReadStream *stream,
+ const String &filename,
+ image::ImageFileType file_type,
+ bool generate_mipmaps);
+
+ bool LoadFromPNGStream(MemoryReadStream *stream,
+ const String &filename,
+ bool generate_mipmaps);
+
+ bool LoadFromTGAStream(MemoryReadStream *stream,
+ const String &filename,
+ bool generate_mipmaps);
+
+ bool LoadFromDDSStream(MemoryReadStream *stream,
+ const String &filename,
+ bool generate_mipmaps);
+
+ bool LoadFromJPEGStream(MemoryReadStream *stream,
+ const String &filename,
+ bool generate_mipmaps);
+
+ bool GenerateMipmaps(unsigned int base_width,
+ unsigned int base_height,
+ Texture::Format format,
+ unsigned int num_mipmaps,
+ uint8 *data);
O3D_DECL_CLASS(Bitmap, ParamObject);
DISALLOW_COPY_AND_ASSIGN(Bitmap);
};
+class BitmapUncompressed : public Bitmap {
+ public:
+ explicit BitmapUncompressed(ServiceLocator* service_locator);
+};
+
+template <typename T>
+class TypedBitmapUncompressed : public BitmapUncompressed {
+ public:
+ typedef T ComponentType;
+ explicit TypedBitmapUncompressed(ServiceLocator* service_locator)
+ : BitmapUncompressed(service_locator) {
+ }
+};
+
+class Bitmap8 : public TypedBitmapUncompressed<uint8> {
+ public:
+ explicit Bitmap8(ServiceLocator* service_locator);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Bitmap8);
+};
+
+class Bitmap16F : public TypedBitmapUncompressed<uint16> {
+ public:
+ explicit Bitmap16F(ServiceLocator* service_locator);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Bitmap16F);
+};
+
+class Bitmap32F : public TypedBitmapUncompressed<float> {
+ public:
+ explicit Bitmap32F(ServiceLocator* service_locator);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Bitmap32F);
+};
+
+class BitmapCompressed : public Bitmap {
+ public:
+ explicit BitmapCompressed(ServiceLocator* service_locator);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BitmapCompressed);
+};
+
+class BitmapDXT1 : public BitmapCompressed {
+ public:
+ explicit BitmapDXT1(ServiceLocator* service_locator);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BitmapDXT1);
+};
+
+class BitmapDXT3 : public BitmapCompressed {
+ public:
+ explicit BitmapDXT3(ServiceLocator* service_locator);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BitmapDXT3);
+};
+
+class BitmapDXT5 : public BitmapCompressed {
+ public:
+ explicit BitmapDXT5(ServiceLocator* service_locator);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BitmapDXT5);
+};
+
} // namespace o3d
#endif // O3D_CORE_CROSS_BITMAP_H_
diff --git a/o3d/core/cross/bitmap_dds.cc b/o3d/core/cross/bitmap_dds.cc index a4f9491..b5ad5fa 100644 --- a/o3d/core/cross/bitmap_dds.cc +++ b/o3d/core/cross/bitmap_dds.cc @@ -51,17 +51,17 @@ namespace o3d { // LoadFromDDSFile ------------------------------------------------------------- // A function that flips a DXTC block. -typedef void (* FlipBlockFunction)(unsigned char *block); +typedef void (* FlipBlockFunction)(uint8 *block); // Flips a full DXT1 block in the y direction. -static void FlipDXT1BlockFull(unsigned char *block) { +static void FlipDXT1BlockFull(uint8 *block) { // A DXT1 block layout is: // [0-1] color0. // [2-3] color1. // [4-7] color bitmap, 2 bits per pixel. // So each of the 4-7 bytes represents one line, flipping a block is just // flipping those bytes. - unsigned char tmp = block[4]; + uint8 tmp = block[4]; block[4] = block[7]; block[7] = tmp; tmp = block[5]; @@ -70,21 +70,21 @@ static void FlipDXT1BlockFull(unsigned char *block) { } // Flips the first 2 lines of a DXT1 block in the y direction. -static void FlipDXT1BlockHalf(unsigned char *block) { +static void FlipDXT1BlockHalf(uint8 *block) { // See layout above. - unsigned char tmp = block[4]; + uint8 tmp = block[4]; block[4] = block[5]; block[5] = tmp; } // Flips a full DXT3 block in the y direction. -static void FlipDXT3BlockFull(unsigned char *block) { +static void FlipDXT3BlockFull(uint8 *block) { // A DXT3 block layout is: // [0-7] alpha bitmap, 4 bits per pixel. // [8-15] a DXT1 block. // We can flip the alpha bits at the byte level (2 bytes per line). - unsigned char tmp = block[0]; + uint8 tmp = block[0]; block[0] = block[6]; block[6] = tmp; tmp = block[1]; @@ -102,9 +102,9 @@ static void FlipDXT3BlockFull(unsigned char *block) { } // Flips the first 2 lines of a DXT3 block in the y direction. -static void FlipDXT3BlockHalf(unsigned char *block) { +static void FlipDXT3BlockHalf(uint8 *block) { // See layout above. - unsigned char tmp = block[0]; + uint8 tmp = block[0]; block[0] = block[2]; block[2] = tmp; tmp = block[1]; @@ -114,7 +114,7 @@ static void FlipDXT3BlockHalf(unsigned char *block) { } // Flips a full DXT5 block in the y direction. -static void FlipDXT5BlockFull(unsigned char *block) { +static void FlipDXT5BlockFull(uint8 *block) { // A DXT5 block layout is: // [0] alpha0. // [1] alpha1. @@ -157,7 +157,7 @@ static void FlipDXT5BlockFull(unsigned char *block) { } // Flips the first 2 lines of a DXT5 block in the y direction. -static void FlipDXT5BlockHalf(unsigned char *block) { +static void FlipDXT5BlockHalf(uint8 *block) { // See layout above. unsigned int line_0_1 = block[2] + 256 * (block[3] + 256 * block[4]); unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) | @@ -173,8 +173,8 @@ static void FlipDXTCImage(unsigned int width, unsigned int height, unsigned int levels, Texture::Format format, - unsigned char *data) { - DCHECK(Bitmap::CheckImageDimensions(width, height)); + uint8 *data) { + DCHECK(image::CheckImageDimensions(width, height)); // Height must be a power-of-two. DCHECK_EQ(height & (height - 1), 0u); FlipBlockFunction full_block_function = NULL; @@ -223,10 +223,10 @@ static void FlipDXTCImage(unsigned int width, // corresponding one in the second half. // note that this is a no-op if mip_height is 4. unsigned int row_bytes = block_bytes * blocks_per_row; - scoped_array<unsigned char> temp_line(new unsigned char[row_bytes]); + scoped_array<uint8> temp_line(new uint8[row_bytes]); for (unsigned int y = 0; y < blocks_per_col / 2; ++y) { - unsigned char *line1 = data + y * row_bytes; - unsigned char *line2 = data + (blocks_per_col - y - 1) * row_bytes; + uint8 *line1 = data + y * row_bytes; + uint8 *line2 = data + (blocks_per_col - y - 1) * row_bytes; memcpy(temp_line.get(), line1, row_bytes); memcpy(line1, line2, row_bytes); memcpy(line2, temp_line.get(), row_bytes); @@ -244,20 +244,21 @@ static void FlipBGRAImage(unsigned int width, unsigned int height, unsigned int levels, Texture::Format format, - unsigned char *data) { - DCHECK(Bitmap::CheckImageDimensions(width, height)); - DCHECK(format == Texture::XRGB8 || format == Texture::ARGB8); - unsigned int pixel_bytes = 4; + uint8 *data) { + DCHECK(image::CheckImageDimensions(width, height)); + DCHECK(format != Texture::DXT1 && format != Texture::DXT3 && + format != Texture::DXT5); + unsigned int pixel_bytes = image::ComputeMipChainSize(1, 1, format, 1); unsigned int mip_width = width; unsigned int mip_height = height; // rows are at most as big as the first one. - scoped_array<unsigned char> temp_line( - new unsigned char[mip_width * pixel_bytes]); + scoped_array<uint8> temp_line( + new uint8[mip_width * pixel_bytes]); for (unsigned int i = 0; i < levels; ++i) { unsigned int row_bytes = pixel_bytes * mip_width; for (unsigned int y = 0; y < mip_height / 2; ++y) { - unsigned char *line1 = data + y * row_bytes; - unsigned char *line2 = data + (mip_height - y - 1) * row_bytes; + uint8 *line1 = data + y * row_bytes; + uint8 *line2 = data + (mip_height - y - 1) * row_bytes; memcpy(temp_line.get(), line1, row_bytes); memcpy(line1, line2, row_bytes); memcpy(line2, temp_line.get(), row_bytes); @@ -269,6 +270,19 @@ static void FlipBGRAImage(unsigned int width, } } +void Bitmap::FlipVertically() { + if (!is_cubemap()) { + if (format() == Texture::DXT1 || + format() == Texture::DXT3 || + format() == Texture::DXT5) { + FlipDXTCImage(width(), height(), num_mipmaps(), format(), image_data()); + } else { + FlipBGRAImage(width(), height(), num_mipmaps(), format(), image_data()); + } + } +} + + // Load the bitmap data as DXTC compressed data from a DDS stream into the // Bitmap object. This routine only supports compressed DDS formats DXT1, // DXT3 and DXT5. @@ -314,7 +328,7 @@ bool Bitmap::LoadFromDDSStream(MemoryReadStream *stream, dd_surface_descriptor.dwMipMapCount : 1; unsigned int dds_width = dd_surface_descriptor.dwWidth; unsigned int dds_height = dd_surface_descriptor.dwHeight; - if (!CheckImageDimensions(dds_width, dds_height)) { + if (!image::CheckImageDimensions(dds_width, dds_height)) { DLOG(ERROR) << "Failed to load " << filename << ": dimensions are too large (" << dds_width << ", " << dds_height << ")."; @@ -376,7 +390,8 @@ bool Bitmap::LoadFromDDSStream(MemoryReadStream *stream, // Check that the advertised size is correct. if (dd_surface_descriptor.dwFlags & DDSD_LINEARSIZE) { - unsigned int expected_size = GetBufferSize(dds_width, dds_height, format); + unsigned int expected_size = + image::ComputeBufferSize(dds_width, dds_height, format); if (expected_size != dd_surface_descriptor.dwLinearSize) { DLOG(ERROR) << "Advertised buffer size in \"" << filename << "\" differs from expected size."; @@ -443,17 +458,18 @@ bool Bitmap::LoadFromDDSStream(MemoryReadStream *stream, unsigned int num_faces = is_cubemap ? 6 : 1; // power-of-two dimensions. unsigned int final_mip_count = - generate_mipmaps ? GetMipMapCount(dds_width, dds_height) : mip_count; - unsigned int face_size = GetMipChainSize(dds_width, dds_height, format, - final_mip_count); + generate_mipmaps ? image::ComputeMipMapCount( + dds_width, dds_height) : mip_count; + unsigned int face_size = image::ComputeMipChainSize( + dds_width, dds_height, format, final_mip_count); unsigned int buffer_size = num_faces * face_size; // Allocate and load bitmap data. - scoped_array<unsigned char> image_data(new unsigned char[buffer_size]); + scoped_array<uint8> image_data(new uint8[buffer_size]); - unsigned int disk_face_size = GetMipChainSize(dds_width, dds_height, format, - mip_count); + unsigned int disk_face_size = + image::ComputeMipChainSize(dds_width, dds_height, format, mip_count); if (!is_dxtc) { // if reading uncompressed RGB, for example, we shouldn't read alpha channel // NOTE: here we assume that RGB data is packed - it may not be true @@ -475,25 +491,16 @@ bool Bitmap::LoadFromDDSStream(MemoryReadStream *stream, DCHECK(components_per_pixel == 3 || components_per_pixel == 4); unsigned int pixel_count = disk_face_size / components_per_pixel; for (unsigned int face = 0; face < num_faces; ++face) { - unsigned char *data = image_data.get() + face_size * face; + uint8 *data = image_data.get() + face_size * face; // convert to four components per pixel if necessary if (add_filler_alpha) { DCHECK_EQ(components_per_pixel, 3u); - XYZToXYZA(data, pixel_count); + image::XYZToXYZA(data, pixel_count); } else { DCHECK_EQ(components_per_pixel, 4u); } if (rgb_to_bgr) - RGBAToBGRA(data, pixel_count); - } - } - - if (!is_cubemap) { - // NOTE: we flip the images to respect max/maya's UV orientation. - if (is_dxtc) { - FlipDXTCImage(dds_width, dds_height, mip_count, format, image_data.get()); - } else { - FlipBGRAImage(dds_width, dds_height, mip_count, format, image_data.get()); + image::RGBAToBGRA(data, pixel_count); } } @@ -502,11 +509,10 @@ bool Bitmap::LoadFromDDSStream(MemoryReadStream *stream, // face. unsigned int base_mip_width = dds_width >> (mip_count - 1); unsigned int base_mip_height = dds_height >> (mip_count - 1); - unsigned int base_mip_offset = GetMipChainSize(dds_width, dds_height, - format, mip_count - 1); + unsigned int base_mip_offset = image::ComputeMipChainSize( + dds_width, dds_height, format, mip_count - 1); for (unsigned int face = 0; face < num_faces; ++face) { - unsigned char *data = - image_data.get() + face_size * face + base_mip_offset; + uint8 *data = image_data.get() + face_size * face + base_mip_offset; if (!GenerateMipmaps(base_mip_width, base_mip_height, format, final_mip_count - mip_count, data)) { DLOG(ERROR) << "mip-map generation failed for \"" << filename << "\""; diff --git a/o3d/core/cross/bitmap_jpg.cc b/o3d/core/cross/bitmap_jpg.cc index 565bb97..bbb31d3 100644 --- a/o3d/core/cross/bitmap_jpg.cc +++ b/o3d/core/cross/bitmap_jpg.cc @@ -151,7 +151,7 @@ bool Bitmap::LoadFromJPEGStream(MemoryReadStream *stream, // NOTE: The following smart pointer needs to be declared before the // setjmp so that it is properly destroyed if we jump back. - scoped_array<unsigned char> image_data; + scoped_array<uint8> image_data; // Establish the setjmp return context for my_error_exit to use. if (setjmp(jerr.setjmp_buffer)) { @@ -182,7 +182,7 @@ bool Bitmap::LoadFromJPEGStream(MemoryReadStream *stream, // Set the Bitmap member variables from the jpeg_decompress_struct fields. unsigned int width = cinfo.image_width; unsigned int height = cinfo.image_height; - if (!CheckImageDimensions(width, height)) { + if (!image::CheckImageDimensions(width, height)) { DLOG(ERROR) << "Failed to load " << filename << ": dimensions are too large (" << width << ", " << height << ")."; @@ -199,12 +199,12 @@ bool Bitmap::LoadFromJPEGStream(MemoryReadStream *stream, } unsigned int image_components = 4; unsigned int num_mipmaps = - generate_mipmaps ? GetMipMapCount(width, height) : 1; + generate_mipmaps ? image::ComputeMipMapCount(width, height) : 1; Texture::Format format = Texture::XRGB8; // Allocate storage for the pixels. - unsigned int image_size = GetMipChainSize(width, height, format, - num_mipmaps); - image_data.reset(new unsigned char[image_size]); + unsigned int image_size = + image::ComputeMipChainSize(width, height, format, num_mipmaps); + image_data.reset(new uint8[image_size]); if (image_data.get() == NULL) { DLOG(ERROR) << "JPEG memory allocation error \"" << filename << "\""; // Invoke the longjmp() error handler. @@ -237,6 +237,10 @@ bool Bitmap::LoadFromJPEGStream(MemoryReadStream *stream, // Use the library's state variable cinfo.output_scanline as the // loop counter, so that we don't have to keep track ourselves. while (cinfo.output_scanline < height) { + // Initialise the buffer write location. + uint8 *image_write_ptr = image_data.get() + + cinfo.output_scanline * width * image_components; + // jpeg_read_scanlines() expects an array of pointers to scanlines. // Here we ask for only one scanline to be read into "buffer". jpeg_read_scanlines(&cinfo, buffer, 1); @@ -244,11 +248,6 @@ bool Bitmap::LoadFromJPEGStream(MemoryReadStream *stream, // output_scanline is the numbe of scanlines that have been emitted. DCHECK_LE(cinfo.output_scanline, height); - // Initialise the buffer write location. - // NOTE: we load images bottom to up to respect max/maya's UV - // orientation. - unsigned char *image_write_ptr = image_data.get() - + (height - cinfo.output_scanline) * width * image_components; // copy the scanline to its final destination for (unsigned int i = 0; i < width; ++i) { // RGB -> BGRX diff --git a/o3d/core/cross/bitmap_png.cc b/o3d/core/cross/bitmap_png.cc index 38f5afe..770ced0 100644 --- a/o3d/core/cross/bitmap_png.cc +++ b/o3d/core/cross/bitmap_png.cc @@ -101,7 +101,7 @@ bool Bitmap::LoadFromPNGStream(MemoryReadStream *stream, // NOTE: The following smart pointer needs to be declared before the // setjmp so that it is properly destroyed if we jump back. - scoped_array<unsigned char> image_data; + scoped_array<uint8> image_data; png_bytepp row_pointers = NULL; // Set error handling if you are using the setjmp/longjmp method. If any @@ -139,7 +139,7 @@ bool Bitmap::LoadFromPNGStream(MemoryReadStream *stream, NULL, NULL); - if (!CheckImageDimensions(png_width, png_height)) { + if (!image::CheckImageDimensions(png_width, png_height)) { DLOG(ERROR) << "Failed to load " << filename << ": dimensions are too large (" << png_width << ", " << png_height << ")."; @@ -209,11 +209,11 @@ bool Bitmap::LoadFromPNGStream(MemoryReadStream *stream, // Allocate storage for the pixels. unsigned int num_mipmaps = - generate_mipmaps ? GetMipMapCount(png_width, png_height) : 1; + generate_mipmaps ? image::ComputeMipMapCount(png_width, png_height) : 1; // Allocate storage for the pixels. - unsigned int png_image_size = GetMipChainSize(png_width, png_height, format, - num_mipmaps); - image_data.reset(new unsigned char[png_image_size]); + unsigned int png_image_size = + image::ComputeMipChainSize(png_width, png_height, format, num_mipmaps); + image_data.reset(new uint8[png_image_size]); if (image_data.get() == NULL) { DLOG(ERROR) << "PNG image memory allocation error \"" << filename << "\""; png_error(png_ptr, "Cannot allocate memory for bitmap"); @@ -231,13 +231,10 @@ bool Bitmap::LoadFromPNGStream(MemoryReadStream *stream, // Fill the row pointer array. DCHECK_LE(png_get_rowbytes(png_ptr, info_ptr), png_width * dst_components); - // NOTE: we load images bottom to up to respect max/maya's UV - // orientation. - png_bytep row_ptr = reinterpret_cast<png_bytep>(image_data.get()) - + png_width * dst_components * (png_height - 1); + png_bytep row_ptr = reinterpret_cast<png_bytep>(image_data.get()); for (unsigned int i = 0; i < png_height; ++i) { row_pointers[i] = row_ptr; - row_ptr -= png_width * dst_components; + row_ptr += png_width * dst_components; } // Read the image, applying format transforms and de-interlacing as we go. diff --git a/o3d/core/cross/bitmap_test.cc b/o3d/core/cross/bitmap_test.cc index 36f474c..4278469 100644 --- a/o3d/core/cross/bitmap_test.cc +++ b/o3d/core/cross/bitmap_test.cc @@ -42,7 +42,7 @@ class BitmapTest : public testing::Test { }; // The first 128 bytes of tga-256x256-24bit.tga, converted to BGRX format. -static unsigned char ktga256x256_24bit_BGRX[128] = { +static uint8 ktga256x256_24bit_BGRX[128] = { 0x36, 0x87, 0xbc, 0xff, 0x36, 0x87, 0xbc, 0xff, 0x35, 0x83, 0xb5, 0xff, 0x34, 0x83, 0xb5, 0xff, 0x35, 0x83, 0xb5, 0xff, 0x35, 0x82, 0xb5, 0xff, @@ -61,7 +61,7 @@ static unsigned char ktga256x256_24bit_BGRX[128] = { 0x1d, 0x8d, 0x96, 0xff, 0x1b, 0x8f, 0x90, 0xff, }; -static unsigned char ktga256x256_32bit_BGRA[128] = { +static uint8 ktga256x256_32bit_BGRA[128] = { 0x36, 0x87, 0xbc, 0x7d, 0x36, 0x87, 0xbc, 0x7c, 0x35, 0x83, 0xb5, 0x78, 0x34, 0x83, 0xb5, 0x77, 0x35, 0x83, 0xb5, 0x77, 0x35, 0x82, 0xb5, 0x76, @@ -80,7 +80,7 @@ static unsigned char ktga256x256_32bit_BGRA[128] = { 0x1d, 0x8d, 0x96, 0x75, 0x1b, 0x8f, 0x90, 0x75, }; -static unsigned char kjpg256x256_BGRX[128] = { +static uint8 kjpg256x256_BGRX[128] = { 0x3a, 0x88, 0xbd, 0xff, 0x38, 0x86, 0xbb, 0xff, 0x36, 0x85, 0xb8, 0xff, 0x34, 0x83, 0xb6, 0xff, 0x36, 0x82, 0xb6, 0xff, 0x35, 0x82, 0xb3, 0xff, @@ -99,7 +99,7 @@ static unsigned char kjpg256x256_BGRX[128] = { 0x21, 0x8d, 0x99, 0xff, 0x1a, 0x8f, 0x8e, 0xff, }; -static unsigned char kpng256x256_24bit_BGRX[128] = { +static uint8 kpng256x256_24bit_BGRX[128] = { 0x36, 0x87, 0xbc, 0xff, 0x36, 0x87, 0xbc, 0xff, 0x35, 0x83, 0xb5, 0xff, 0x34, 0x83, 0xb5, 0xff, 0x35, 0x83, 0xb5, 0xff, 0x35, 0x82, 0xb5, 0xff, @@ -118,7 +118,7 @@ static unsigned char kpng256x256_24bit_BGRX[128] = { 0x1d, 0x8d, 0x96, 0xff, 0x1b, 0x8f, 0x90, 0xff, }; -static unsigned char kpng256x256_24bit_interlaced_BGRX[128] = { +static uint8 kpng256x256_24bit_interlaced_BGRX[128] = { 0x36, 0x87, 0xbc, 0xff, 0x36, 0x87, 0xbc, 0xff, 0x35, 0x83, 0xb5, 0xff, 0x34, 0x83, 0xb5, 0xff, 0x35, 0x83, 0xb5, 0xff, 0x35, 0x82, 0xb5, 0xff, @@ -137,7 +137,7 @@ static unsigned char kpng256x256_24bit_interlaced_BGRX[128] = { 0x1d, 0x8d, 0x96, 0xff, 0x1b, 0x8f, 0x90, 0xff, }; -static unsigned char kpng256x256_32bit_BGRA[128] = { +static uint8 kpng256x256_32bit_BGRA[128] = { 0x36, 0x87, 0xbc, 0xd4, 0x36, 0x87, 0xbc, 0xfa, 0x35, 0x83, 0xb5, 0xff, 0x34, 0x83, 0xb5, 0xfe, 0x35, 0x83, 0xb5, 0xf3, 0x35, 0x82, 0xb5, 0xcf, @@ -156,7 +156,7 @@ static unsigned char kpng256x256_32bit_BGRA[128] = { 0x1d, 0x8d, 0x96, 0xff, 0x1b, 0x8f, 0x90, 0xff, }; -static unsigned char kpng256x256_8bit_palette_BGRX[128] = { +static uint8 kpng256x256_8bit_palette_BGRX[128] = { 0x36, 0x89, 0xbb, 0xff, 0x36, 0x89, 0xbb, 0xff, 0x35, 0x81, 0xb5, 0xff, 0x32, 0x84, 0xb5, 0xff, 0x35, 0x81, 0xb5, 0xff, 0x35, 0x81, 0xb5, 0xff, @@ -175,7 +175,7 @@ static unsigned char kpng256x256_8bit_palette_BGRX[128] = { 0x1f, 0x8d, 0x91, 0xff, 0x1f, 0x8d, 0x91, 0xff, }; -static unsigned char kpng20x14_4bit_palette_BGRX[128] = { +static uint8 kpng20x14_4bit_palette_BGRX[128] = { 0xed, 0xed, 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, @@ -194,7 +194,7 @@ static unsigned char kpng20x14_4bit_palette_BGRX[128] = { 0x54, 0x54, 0x54, 0xff, 0x33, 0x33, 0x33, 0xff, }; -static unsigned char kdxt1_256x256[128] = { +static uint8 kdxt1_256x256[128] = { 0x47, 0xbc, 0x06, 0xb4, 0x5a, 0x6a, 0x6a, 0xea, 0x27, 0xb4, 0x06, 0xb4, 0x57, 0x57, 0x57, 0x5e, 0x06, 0xb4, 0x07, 0xb4, 0xaa, 0xaa, 0xaa, 0xaa, @@ -213,7 +213,7 @@ static unsigned char kdxt1_256x256[128] = { 0x06, 0xb4, 0x45, 0xa4, 0xfd, 0xaf, 0xaf, 0x0a, }; -static unsigned char kdxt1_256x256_alpha[128] = { +static uint8 kdxt1_256x256_alpha[128] = { 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0xff, 0xff, @@ -232,7 +232,7 @@ static unsigned char kdxt1_256x256_alpha[128] = { 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0xff, 0xff, }; -static unsigned char kdxt1_256x256_mipmap[128] = { +static uint8 kdxt1_256x256_mipmap[128] = { 0x47, 0xbc, 0x06, 0xb4, 0x5a, 0x6a, 0x6a, 0xea, 0x27, 0xb4, 0x06, 0xb4, 0x57, 0x57, 0x57, 0x5e, 0x06, 0xb4, 0x07, 0xb4, 0xaa, 0xaa, 0xaa, 0xaa, @@ -251,7 +251,7 @@ static unsigned char kdxt1_256x256_mipmap[128] = { 0x06, 0xb4, 0x45, 0xa4, 0xfd, 0xaf, 0xaf, 0x0a, }; -static unsigned char kdxt3_256x256_alpha[128] = { +static uint8 kdxt3_256x256_alpha[128] = { 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x47, 0xbc, 0x06, 0xb4, 0x5a, 0x6a, 0x6a, 0xea, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, @@ -270,7 +270,7 @@ static unsigned char kdxt3_256x256_alpha[128] = { 0x46, 0xac, 0x83, 0x8c, 0xf0, 0x7c, 0x7c, 0x5f, }; -static unsigned char kdxt3_256x256_mipmap[128] = { +static uint8 kdxt3_256x256_mipmap[128] = { 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x47, 0xbc, 0x06, 0xb4, 0x5a, 0x6a, 0x6a, 0xea, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, @@ -289,7 +289,7 @@ static unsigned char kdxt3_256x256_mipmap[128] = { 0x46, 0xac, 0x83, 0x8c, 0xf0, 0x7c, 0x7c, 0x5f, }; -static unsigned char kdxt5_256x256_alpha[128] = { +static uint8 kdxt5_256x256_alpha[128] = { 0x7e, 0x77, 0xda, 0x23, 0x00, 0x90, 0x0a, 0x00, 0x47, 0xbc, 0x06, 0xb4, 0x5a, 0x6a, 0x6a, 0xea, 0x78, 0x76, 0x4e, 0x02, 0x00, 0x70, 0x02, 0x00, @@ -308,7 +308,7 @@ static unsigned char kdxt5_256x256_alpha[128] = { 0x46, 0xac, 0x83, 0x8c, 0xf0, 0x7c, 0x7c, 0x5f, }; -static unsigned char kdxt5_256x256_mipmap[128] = { +static uint8 kdxt5_256x256_mipmap[128] = { 0x7e, 0x77, 0xda, 0x23, 0x00, 0x90, 0x0a, 0x00, 0x47, 0xbc, 0x06, 0xb4, 0x5a, 0x6a, 0x6a, 0xea, 0x78, 0x76, 0x4e, 0x02, 0x00, 0x70, 0x02, 0x00, @@ -328,7 +328,7 @@ static unsigned char kdxt5_256x256_mipmap[128] = { }; // Match the first 128 bytes of a loaded bitmap data againt known values. -bool TestBitmapData(const Bitmap &bitmap, unsigned char reference[128]) { +bool TestBitmapData(const Bitmap &bitmap, uint8 reference[128]) { if (!bitmap.image_data()) return false; return std::memcmp(bitmap.image_data(), reference, sizeof(reference)) == 0; } @@ -336,9 +336,9 @@ bool TestBitmapData(const Bitmap &bitmap, unsigned char reference[128]) { // Prints the first 128 bytes of a loaded bitmap data. Helper function to // generate the known data above. bool PrintBitmapData(const Bitmap &bitmap, const char *name) { - const unsigned char *data = bitmap.image_data(); + const uint8 *data = bitmap.image_data(); if (!data) return false; - printf("static unsigned char %s[128] = {\n", name); + printf("static uint8 %s[128] = {\n", name); for (int i = 0; i < 16; ++i) { printf(" "); for (int j = 0; j < 8; ++j) { @@ -359,7 +359,7 @@ TEST_F(BitmapTest, LoadTGAFile24bit) { String filename = *g_program_path + "/bitmap_test/tga-256x256-24bit.tga"; FilePath filepath = UTF8ToFilePath(filename); Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_TRUE(bitmap->LoadFromFile(filepath, Bitmap::TGA, false)); + EXPECT_TRUE(bitmap->LoadFromFile(filepath, image::TGA, false)); EXPECT_TRUE(bitmap->image_data() != NULL); EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::XRGB8, bitmap->format()); @@ -374,7 +374,7 @@ TEST_F(BitmapTest, LoadTGAFile32bit) { String filename = *g_program_path + "/bitmap_test/tga-256x256-32bit.tga"; FilePath filepath = UTF8ToFilePath(filename); Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_TRUE(bitmap->LoadFromFile(filepath, Bitmap::TGA, false)); + EXPECT_TRUE(bitmap->LoadFromFile(filepath, image::TGA, false)); EXPECT_TRUE(bitmap->image_data() != NULL); EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::ARGB8, bitmap->format()); @@ -392,7 +392,7 @@ TEST_F(BitmapTest, LoadTGAFileTooLarge) { String filename = *g_program_path + "/bitmap_test/5kx5k.tga"; FilePath filepath = UTF8ToFilePath(filename); Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_FALSE(bitmap->LoadFromFile(filepath, Bitmap::TGA, false)); + EXPECT_FALSE(bitmap->LoadFromFile(filepath, image::TGA, false)); EXPECT_TRUE(bitmap->image_data() == NULL); } @@ -401,7 +401,7 @@ TEST_F(BitmapTest, LoadJPEGFile) { String filename = *g_program_path + "/bitmap_test/jpeg-256x256.jpg"; FilePath filepath = UTF8ToFilePath(filename); Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_TRUE(bitmap->LoadFromFile(filepath, Bitmap::JPEG, false)); + EXPECT_TRUE(bitmap->LoadFromFile(filepath, image::JPEG, false)); EXPECT_TRUE(bitmap->image_data() != NULL); EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::XRGB8, bitmap->format()); @@ -416,7 +416,7 @@ TEST_F(BitmapTest, LoadJPEGFileTooLarge) { String filename = *g_program_path + "/bitmap_test/5kx5k.jpg"; FilePath filepath = UTF8ToFilePath(filename); Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_FALSE(bitmap->LoadFromFile(filepath, Bitmap::JPEG, false)); + EXPECT_FALSE(bitmap->LoadFromFile(filepath, image::JPEG, false)); EXPECT_TRUE(bitmap->image_data() == NULL); } @@ -425,7 +425,7 @@ TEST_F(BitmapTest, LoadPNGFile24bit) { String filename = *g_program_path + "/bitmap_test/png-256x256-24bit.png"; FilePath filepath = UTF8ToFilePath(filename); Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_TRUE(bitmap->LoadFromFile(filepath, Bitmap::PNG, false)); + EXPECT_TRUE(bitmap->LoadFromFile(filepath, image::PNG, false)); EXPECT_TRUE(bitmap->image_data() != NULL); EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::XRGB8, bitmap->format()); @@ -441,7 +441,7 @@ TEST_F(BitmapTest, LoadPNGFile24bitInterlaced) { "/bitmap_test/png-256x256-24bit-interlaced.png"; FilePath filepath = UTF8ToFilePath(filename); Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_TRUE(bitmap->LoadFromFile(filepath, Bitmap::PNG, false)); + EXPECT_TRUE(bitmap->LoadFromFile(filepath, image::PNG, false)); EXPECT_TRUE(bitmap->image_data() != NULL); EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::XRGB8, bitmap->format()); @@ -455,7 +455,7 @@ TEST_F(BitmapTest, LoadPNGFile32bit) { String filename = *g_program_path + "/bitmap_test/png-256x256-32bit.png"; FilePath filepath = UTF8ToFilePath(filename); Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_TRUE(bitmap->LoadFromFile(filepath, Bitmap::PNG, false)); + EXPECT_TRUE(bitmap->LoadFromFile(filepath, image::PNG, false)); EXPECT_TRUE(bitmap->image_data() != NULL); EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::ARGB8, bitmap->format()); @@ -471,7 +471,7 @@ TEST_F(BitmapTest, LoadPNGFile8bitPalette) { "/bitmap_test/png-256x256-8bit-palette.png"; FilePath filepath = UTF8ToFilePath(filename); Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_TRUE(bitmap->LoadFromFile(filepath, Bitmap::PNG, false)); + EXPECT_TRUE(bitmap->LoadFromFile(filepath, image::PNG, false)); EXPECT_TRUE(bitmap->image_data() != NULL); EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::XRGB8, bitmap->format()); @@ -487,7 +487,7 @@ TEST_F(BitmapTest, LoadPNGFile4bitPalette) { "/bitmap_test/png-20x14-4bit-palette.png"; FilePath filepath = UTF8ToFilePath(filename); Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_TRUE(bitmap->LoadFromFile(filepath, Bitmap::PNG, false)); + EXPECT_TRUE(bitmap->LoadFromFile(filepath, image::PNG, false)); EXPECT_TRUE(bitmap->image_data() != NULL); EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::XRGB8, bitmap->format()); @@ -503,7 +503,7 @@ TEST_F(BitmapTest, LoadPNGFileTooLarge) { String filename = *g_program_path + "/bitmap_test/5kx5k.png"; FilePath filepath = UTF8ToFilePath(filename); Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_FALSE(bitmap->LoadFromFile(filepath, Bitmap::PNG, false)); + EXPECT_FALSE(bitmap->LoadFromFile(filepath, image::PNG, false)); EXPECT_TRUE(bitmap->image_data() == NULL); } @@ -515,7 +515,7 @@ TEST_F(BitmapTest, LoadPNGFile8bitPaletteAlpha) { "/bitmap_test/png-256x256-8bit-palette-alpha.png"; FilePath filepath = UTF8ToFilePath(filename); Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_TRUE(bitmap->LoadFromFile(filepath, Bitmap::PNG, false)); + EXPECT_TRUE(bitmap->LoadFromFile(filepath, image::PNG, false)); EXPECT_TRUE(bitmap->image_data() != NULL); EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::ARGB8, bitmap->format()); @@ -530,7 +530,7 @@ TEST_F(BitmapTest, LoadDDSFileDXT1) { String filename = *g_program_path + "/bitmap_test/dds-dxt1-256x256.dds"; FilePath filepath = UTF8ToFilePath(filename); Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_TRUE(bitmap->LoadFromFile(filepath, Bitmap::DDS, false)); + EXPECT_TRUE(bitmap->LoadFromFile(filepath, image::DDS, false)); EXPECT_TRUE(bitmap->image_data() != NULL); EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::DXT1, bitmap->format()); @@ -546,7 +546,7 @@ TEST_F(BitmapTest, LoadDDSFileDXT1Alpha) { "/bitmap_test/dds-dxt1-256x256-alpha.dds"; FilePath filepath = UTF8ToFilePath(filename); Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_TRUE(bitmap->LoadFromFile(filepath, Bitmap::DDS, false)); + EXPECT_TRUE(bitmap->LoadFromFile(filepath, image::DDS, false)); EXPECT_TRUE(bitmap->image_data() != NULL); EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::DXT1, bitmap->format()); @@ -562,7 +562,7 @@ TEST_F(BitmapTest, LoadDDSFileDXT1Mipmap) { "/bitmap_test/dds-dxt1-256x256-mipmap.dds"; FilePath filepath = UTF8ToFilePath(filename); Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_TRUE(bitmap->LoadFromFile(filepath, Bitmap::DDS, false)); + EXPECT_TRUE(bitmap->LoadFromFile(filepath, image::DDS, false)); EXPECT_TRUE(bitmap->image_data() != NULL); EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::DXT1, bitmap->format()); @@ -581,7 +581,7 @@ TEST_F(BitmapTest, LoadDDSFileDXT3) { "/bitmap_test/dds-dxt3-256x256-alpha.dds"; FilePath filepath = UTF8ToFilePath(filename); Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_TRUE(bitmap->LoadFromFile(filepath, Bitmap::DDS, false)); + EXPECT_TRUE(bitmap->LoadFromFile(filepath, image::DDS, false)); EXPECT_TRUE(bitmap->image_data() != NULL); EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::DXT3, bitmap->format()); @@ -597,7 +597,7 @@ TEST_F(BitmapTest, LoadDDSFileDXT3Mipmap) { "/bitmap_test/dds-dxt3-256x256-mipmap.dds"; FilePath filepath = UTF8ToFilePath(filename); Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_TRUE(bitmap->LoadFromFile(filepath, Bitmap::DDS, false)); + EXPECT_TRUE(bitmap->LoadFromFile(filepath, image::DDS, false)); EXPECT_TRUE(bitmap->image_data() != NULL); EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::DXT3, bitmap->format()); @@ -616,7 +616,7 @@ TEST_F(BitmapTest, LoadDDSFileDXT5) { "/bitmap_test/dds-dxt5-256x256-alpha.dds"; FilePath filepath = UTF8ToFilePath(filename); Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_TRUE(bitmap->LoadFromFile(filepath, Bitmap::DDS, false)); + EXPECT_TRUE(bitmap->LoadFromFile(filepath, image::DDS, false)); EXPECT_TRUE(bitmap->image_data() != NULL); EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::DXT5, bitmap->format()); @@ -632,7 +632,7 @@ TEST_F(BitmapTest, LoadDDSFileDXT5Mipmap) { "/bitmap_test/dds-dxt5-256x256-mipmap.dds"; FilePath filepath = UTF8ToFilePath(filename); Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_TRUE(bitmap->LoadFromFile(filepath, Bitmap::DDS, false)); + EXPECT_TRUE(bitmap->LoadFromFile(filepath, image::DDS, false)); EXPECT_TRUE(bitmap->image_data() != NULL); EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::DXT5, bitmap->format()); @@ -653,206 +653,11 @@ TEST_F(BitmapTest, LoadDDSFileTooLarge) { String filename = *g_program_path + "/bitmap_test/5kx5k.dds"; FilePath filepath = UTF8ToFilePath(filename); Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_FALSE(bitmap->LoadFromFile(filepath, Bitmap::DDS, false)); + EXPECT_FALSE(bitmap->LoadFromFile(filepath, image::DDS, false)); EXPECT_TRUE(bitmap->image_data() == NULL); } - -// NOTE: untested ffile types are: -// png grayscale textures -// dds cube maps -// dds mipmapped cube maps -// dds 1D textures -// dds 3D textures - - -static const unsigned char kMipmapDataPOT[] = { - // This is a 4x4 image - 0x7D, 0xE4, 0x0F, 0xff, 0x71, 0x7B, 0x9C, 0xff, - 0xDD, 0xF0, 0x9D, 0xff, 0xFA, 0x08, 0x49, 0xff, - 0xEA, 0x28, 0xF6, 0xff, 0x73, 0x10, 0x64, 0xff, - 0x8B, 0x36, 0x58, 0xff, 0x7A, 0x3E, 0x21, 0xff, - 0x64, 0xCE, 0xB1, 0xff, 0x36, 0x4D, 0xC5, 0xff, - 0xF3, 0x99, 0x7E, 0xff, 0x5C, 0x56, 0x1E, 0xff, - 0x59, 0x8C, 0x41, 0xff, 0x39, 0x24, 0x1B, 0xff, - 0x5D, 0x4D, 0x96, 0xff, 0x5E, 0xF8, 0x8B, 0xff, - // Followed by its 2x2 mip level - 0x92, 0x65, 0x81, 0xff, 0xb7, 0x5b, 0x57, 0xff, - 0x4b, 0x72, 0x74, 0xff, 0x82, 0x8d, 0x6f, 0xff, - // Followed by its 1x1 mip level - 0x85, 0x6f, 0x6e, 0xff, -}; - -// Generates mip-maps from a known power-of-two image, compare with expected -// results. -TEST_F(BitmapTest, GenerateMipmapsPOT) { - const unsigned int kWidth = 4; - const unsigned int kHeight = 4; - const Texture::Format format = Texture::ARGB8; - unsigned int mipmaps = Bitmap::GetMipMapCount(kWidth, kHeight); - EXPECT_EQ(3U, mipmaps); - unsigned int size = Bitmap::GetMipChainSize(kWidth, kHeight, format, mipmaps); - ASSERT_EQ(sizeof(kMipmapDataPOT), size); - scoped_array<unsigned char> data(new unsigned char[size]); - ASSERT_TRUE(data.get() != NULL); - // Copy first level into the buffer. - unsigned int base_size = Bitmap::GetMipChainSize(kWidth, kHeight, format, 1); - memcpy(data.get(), kMipmapDataPOT, base_size); - Bitmap::GenerateMipmaps(kWidth, kHeight, format, mipmaps, data.get()); - // Check the result. - EXPECT_EQ(0, memcmp(data.get(), kMipmapDataPOT, size)); -} - -static const unsigned char kMipmapDataNPOT[] = { - // This is a 7x7 image - 0x0d, 0x16, 0x68, 0x1b, 0xe6, 0x09, 0x89, 0x55, - 0xda, 0x28, 0x56, 0x55, 0x3e, 0x00, 0x6f, 0x16, - 0x98, 0x11, 0x50, 0x72, 0xe7, 0x17, 0x24, 0xca, - 0x05, 0xe9, 0x92, 0x43, 0xd6, 0xc4, 0x57, 0xcd, - 0x34, 0x9b, 0x86, 0xcf, 0x50, 0x65, 0xc4, 0x83, - 0xaf, 0xa3, 0xaa, 0xe3, 0x7c, 0xab, 0x5f, 0x08, - 0xc1, 0x2e, 0xd1, 0xe9, 0xa8, 0x2b, 0x56, 0x64, - 0x12, 0x74, 0x92, 0x56, 0x30, 0x16, 0xa0, 0x03, - 0x5a, 0x3a, 0x88, 0xb9, 0xe8, 0xa3, 0xfd, 0xf6, - 0xa1, 0x3b, 0x7b, 0x2d, 0xfd, 0x71, 0xc0, 0x0b, - 0x22, 0x31, 0x41, 0x5a, 0x45, 0x6f, 0x6b, 0x1b, - 0x10, 0x5a, 0x16, 0x6e, 0x02, 0x89, 0x12, 0xb1, - 0x67, 0xfc, 0x43, 0x78, 0xc0, 0x55, 0x59, 0xa3, - 0xf8, 0xe2, 0x6b, 0xb7, 0xad, 0x5f, 0x3c, 0x14, - 0xe1, 0x0e, 0x84, 0x89, 0x25, 0xa7, 0xea, 0xc6, - 0x63, 0x20, 0xf9, 0x84, 0xa1, 0xcd, 0x62, 0x0f, - 0x22, 0xab, 0x59, 0xde, 0xbd, 0xfa, 0xab, 0x4d, - 0xca, 0x07, 0x85, 0xdf, 0x83, 0x23, 0x80, 0x8b, - 0x5e, 0xe4, 0x57, 0x45, 0x81, 0x34, 0x52, 0x65, - 0xf0, 0x14, 0x32, 0x33, 0xfe, 0xe4, 0x31, 0x90, - 0x15, 0x51, 0x57, 0x89, 0xed, 0xcf, 0x88, 0xc9, - 0x7b, 0xbb, 0xc6, 0x41, 0xd5, 0x93, 0x7c, 0x65, - 0x39, 0x80, 0x20, 0xa2, 0xe5, 0xca, 0x9b, 0x7e, - 0xb2, 0x1f, 0x0d, 0xdc, 0x5c, 0xab, 0x6b, 0x5b, - 0xc5, 0x57, 0xc0, 0xd2, - // Followed by its 3x3 mip level - 0x75, 0x58, 0x7b, 0x76, 0x8a, 0x54, 0x85, 0x6f, - 0x93, 0x56, 0x74, 0x7d, 0x3f, 0x58, 0x7a, 0x64, - 0x7a, 0x90, 0x75, 0x8f, 0xb4, 0x7c, 0x71, 0x6b, - 0x84, 0x84, 0x85, 0x6c, 0xb1, 0x73, 0x4f, 0x7c, - 0x97, 0x87, 0x78, 0xa2, - // Followed by its 1x1 mip level - 0x88, 0x6e, 0x75, 0x7a, -}; - -// Generates mip-maps from a known non-power-of-two image, compare with expected -// results. -TEST_F(BitmapTest, GenerateMipmapsNPOT) { - const unsigned int kWidth = 7; - const unsigned int kHeight = 7; - const Texture::Format format = Texture::ARGB8; - unsigned int mipmaps = Bitmap::GetMipMapCount(kWidth, kHeight); - EXPECT_EQ(3U, mipmaps); - unsigned int size = Bitmap::GetMipChainSize(kWidth, kHeight, format, mipmaps); - ASSERT_EQ(sizeof(kMipmapDataNPOT), size); - scoped_array<unsigned char> data(new unsigned char[size]); - ASSERT_TRUE(data.get() != NULL); - // Copy first level into the buffer. - unsigned int base_size = Bitmap::GetMipChainSize(kWidth, kHeight, format, 1); - memcpy(data.get(), kMipmapDataNPOT, base_size); - Bitmap::GenerateMipmaps(kWidth, kHeight, format, mipmaps, data.get()); - // Check the result. - EXPECT_EQ(0, memcmp(data.get(), kMipmapDataNPOT, size)); -} - -// Checks that filenames are detected as the correct type. -TEST_F(BitmapTest, GetFileTypeFromFilename) { - EXPECT_EQ(Bitmap::TGA, Bitmap::GetFileTypeFromFilename("foo.tga")); - EXPECT_EQ(Bitmap::TGA, Bitmap::GetFileTypeFromFilename("BAR.TGA")); - EXPECT_EQ(Bitmap::PNG, Bitmap::GetFileTypeFromFilename("foo.png")); - EXPECT_EQ(Bitmap::PNG, Bitmap::GetFileTypeFromFilename("BAR.PNG")); - EXPECT_EQ(Bitmap::JPEG, Bitmap::GetFileTypeFromFilename("foo.jpeg")); - EXPECT_EQ(Bitmap::JPEG, Bitmap::GetFileTypeFromFilename("BAR.JPEG")); - EXPECT_EQ(Bitmap::JPEG, Bitmap::GetFileTypeFromFilename("foo.jpg")); - EXPECT_EQ(Bitmap::JPEG, Bitmap::GetFileTypeFromFilename("BAR.JPG")); - EXPECT_EQ(Bitmap::JPEG, Bitmap::GetFileTypeFromFilename("foo.jpe")); - EXPECT_EQ(Bitmap::JPEG, Bitmap::GetFileTypeFromFilename("BAR.JPE")); - EXPECT_EQ(Bitmap::DDS, Bitmap::GetFileTypeFromFilename("foo.dds")); - EXPECT_EQ(Bitmap::DDS, Bitmap::GetFileTypeFromFilename("BAR.DDS")); - EXPECT_EQ(Bitmap::UNKNOWN, Bitmap::GetFileTypeFromFilename("foo.bar")); - EXPECT_EQ(Bitmap::UNKNOWN, Bitmap::GetFileTypeFromFilename("FOO.BAR")); -} - -// Checks that mime types are detected as the correct type. -TEST_F(BitmapTest, GetFileTypeFromMimeType) { - EXPECT_EQ(Bitmap::PNG, Bitmap::GetFileTypeFromMimeType("image/png")); - EXPECT_EQ(Bitmap::JPEG, Bitmap::GetFileTypeFromMimeType("image/jpeg")); - EXPECT_EQ(Bitmap::UNKNOWN, Bitmap::GetFileTypeFromFilename("text/plain")); - EXPECT_EQ(Bitmap::UNKNOWN, - Bitmap::GetFileTypeFromFilename("application/x-123")); -} - -static const unsigned char kScaleUPDataNPOT[] = { - // This is a 3x3 image. - 0x75, 0x58, 0x7b, 0x76, - 0x8a, 0x54, 0x85, 0x6f, - 0x93, 0x56, 0x74, 0x7d, - - 0x3f, 0x58, 0x7a, 0x64, - 0x7a, 0x90, 0x75, 0x8f, - 0xb4, 0x7c, 0x71, 0x6b, - - 0x84, 0x84, 0x85, 0x6c, - 0xb1, 0x73, 0x4f, 0x7c, - 0x97, 0x87, 0x78, 0xa2, -}; - -static const unsigned char kScaleUPDataPOT[] = { - // This is the 4x4 scaled-up version of the above. - 0x75, 0x58, 0x7b, 0x76, - 0x8a, 0x54, 0x85, 0x6f, - 0x8a, 0x54, 0x85, 0x6f, - 0x93, 0x56, 0x74, 0x7d, - - 0x3f, 0x58, 0x7a, 0x64, - 0x7a, 0x90, 0x75, 0x8f, - 0x7a, 0x90, 0x75, 0x8f, - 0xb4, 0x7c, 0x71, 0x6b, - - 0x3f, 0x58, 0x7a, 0x64, - 0x7a, 0x90, 0x75, 0x8f, - 0x7a, 0x90, 0x75, 0x8f, - 0xb4, 0x7c, 0x71, 0x6b, - - 0x84, 0x84, 0x85, 0x6c, - 0xb1, 0x73, 0x4f, 0x7c, - 0xb1, 0x73, 0x4f, 0x7c, - 0x97, 0x87, 0x78, 0xa2, -}; - -// Scales up a NPOT texture, compare with expected results. -TEST_F(BitmapTest, ScaleUpToPOT) { - const unsigned int kWidth = 3; - const unsigned int kHeight = 3; - const unsigned int kPOTWidth = Bitmap::GetPOTSize(kWidth); - ASSERT_EQ(kPOTWidth, 4U); - const unsigned int kPOTHeight = Bitmap::GetPOTSize(kHeight); - ASSERT_EQ(kPOTHeight, 4U); - const Texture::Format format = Texture::ARGB8; - unsigned int src_size = Bitmap::GetBufferSize(kWidth, kHeight, format); - ASSERT_EQ(sizeof(kScaleUPDataNPOT), src_size); - unsigned int dst_size = Bitmap::GetBufferSize(kPOTWidth, kPOTHeight, format); - ASSERT_EQ(sizeof(kScaleUPDataPOT), dst_size); - scoped_array<unsigned char> data(new unsigned char[dst_size]); - ASSERT_TRUE(data.get() != NULL); - // Check that scaling works when source and destination don't alias - Bitmap::ScaleUpToPOT(kWidth, kHeight, format, kScaleUPDataNPOT, data.get(), - 4 * 4); - EXPECT_EQ(0, memcmp(data.get(), kScaleUPDataPOT, dst_size)); - - // Check that scaling works when source and destination do alias - memset(data.get(), 0, dst_size); - memcpy(data.get(), kScaleUPDataNPOT, src_size); - Bitmap::ScaleUpToPOT(kWidth, kHeight, format, data.get(), data.get(), 4 * 4); - EXPECT_EQ(0, memcmp(data.get(), kScaleUPDataPOT, dst_size)); -} - -static unsigned char kpng_8x4_drawImage[128] = { +static uint8 kpng_8x4_drawImage[128] = { // Raw dest image used in drawimage test. 0x30, 0x60, 0xc0, 0xff, 0x32, 0x64, 0xc8, 0xff, 0x34, 0x68, 0xd0, 0xff, 0x36, 0x6c, 0xd8, 0xff, @@ -872,7 +677,7 @@ static unsigned char kpng_8x4_drawImage[128] = { 0x0c, 0x18, 0x30, 0xff, 0x0e, 0x1c, 0x38, 0xff, }; -static unsigned char kpng_8x4_drawImage_top_left[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, @@ -892,7 +697,7 @@ static unsigned char kpng_8x4_drawImage_top_left[128] = { 0x0c, 0x18, 0x30, 0xff, 0x0e, 0x1c, 0x38, 0xff, }; -static unsigned char kpng_8x4_drawImage_top[128] = { +static uint8 kpng_8x4_drawImage_top[128] = { // expected result of drawimage on top bound of dest image. 0x30, 0x60, 0xc0, 0xff, 0x32, 0x64, 0xc8, 0xff, 0x34, 0x68, 0xd0, 0xff, 0x36, 0x6c, 0xd8, 0xff, @@ -912,7 +717,7 @@ static unsigned char kpng_8x4_drawImage_top[128] = { 0x0c, 0x18, 0x30, 0xff, 0x0e, 0x1c, 0x38, 0xff, }; -static unsigned char kpng_8x4_drawImage_top_right[128] = { +static uint8 kpng_8x4_drawImage_top_right[128] = { // expected result of drawimage on top right corner of dest image. 0x30, 0x60, 0xc0, 0xff, 0x32, 0x64, 0xc8, 0xff, 0x34, 0x68, 0xd0, 0xff, 0x36, 0x6c, 0xd8, 0xff, @@ -932,7 +737,7 @@ static unsigned char kpng_8x4_drawImage_top_right[128] = { 0x24, 0x24, 0x24, 0xff, 0x25, 0x25, 0x25, 0xff, }; -static unsigned char kpng_8x4_drawImage_right[128] = { +static uint8 kpng_8x4_drawImage_right[128] = { // expected result of drawimage on right bound of dest image. 0x30, 0x60, 0xc0, 0xff, 0x32, 0x64, 0xc8, 0xff, 0x34, 0x68, 0xd0, 0xff, 0x36, 0x6c, 0xd8, 0xff, @@ -952,7 +757,7 @@ static unsigned char kpng_8x4_drawImage_right[128] = { 0x20, 0x20, 0x20, 0xff, 0x21, 0x21, 0x21, 0xff, }; -static unsigned char kpng_8x4_drawImage_bottom_right[128] = { +static uint8 kpng_8x4_drawImage_bottom_right[128] = { // expected result of drawimage on bottom right corner of dest image. 0x30, 0x60, 0xc0, 0xff, 0x32, 0x64, 0xc8, 0xff, 0x34, 0x68, 0xd0, 0xff, 0x36, 0x6c, 0xd8, 0xff, @@ -972,7 +777,7 @@ static unsigned char kpng_8x4_drawImage_bottom_right[128] = { 0x0c, 0x18, 0x30, 0xff, 0x0e, 0x1c, 0x38, 0xff, }; -static unsigned char kpng_8x4_drawImage_bottom[128] = { +static uint8 kpng_8x4_drawImage_bottom[128] = { // expected result of drawimage on bottom bound of dest image. 0x30, 0x60, 0xc0, 0xff, 0x32, 0x64, 0xc8, 0xff, 0x27, 0x27, 0x27, 0xff, 0x28, 0x28, 0x28, 0xff, @@ -992,7 +797,7 @@ static unsigned char kpng_8x4_drawImage_bottom[128] = { 0x0c, 0x18, 0x30, 0xff, 0x0e, 0x1c, 0x38, 0xff, }; -static unsigned char kpng_8x4_drawImage_bottom_left[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, @@ -1012,7 +817,7 @@ static unsigned char kpng_8x4_drawImage_bottom_left[128] = { 0x0c, 0x18, 0x30, 0xff, 0x0e, 0x1c, 0x38, 0xff, }; -static unsigned char kpng_8x4_drawImage_left[128] = { +static uint8 kpng_8x4_drawImage_left[128] = { // expected result of drawimage on left bound of dest image. 0x2c, 0x2c, 0x2c, 0xff, 0x2d, 0x2d, 0x2d, 0xff, 0x2e, 0x2e, 0x2e, 0xff, 0x36, 0x6c, 0xd8, 0xff, @@ -1032,7 +837,7 @@ static unsigned char kpng_8x4_drawImage_left[128] = { 0x0c, 0x18, 0x30, 0xff, 0x0e, 0x1c, 0x38, 0xff, }; -static unsigned char kpng_8x4_drawImage_scale_up[128] = { +static uint8 kpng_8x4_drawImage_scale_up[128] = { // expected result of scale up from 2x2 to 8x4. 0x38, 0x38, 0x38, 0xff, 0x43, 0x43, 0x43, 0xff, 0x52, 0x52, 0x52, 0xff, 0x63, 0x63, 0x63, 0xff, @@ -1052,7 +857,7 @@ static unsigned char kpng_8x4_drawImage_scale_up[128] = { 0x11, 0x11, 0x11, 0xff, 0x0e, 0x0e, 0x0e, 0xff, }; -static unsigned char kpng_8x4_drawImage_scale_down[128] = { +static uint8 kpng_8x4_drawImage_scale_down[128] = { // expected result of scale down from 8x8 to 4x4. 0xa0, 0xa0, 0xa0, 0xff, 0xa7, 0xa7, 0xa7, 0xff, 0xad, 0xad, 0xad, 0xff, 0xb3, 0xb3, 0xb3, 0xff, @@ -1072,7 +877,7 @@ static unsigned char kpng_8x4_drawImage_scale_down[128] = { 0x0c, 0x18, 0x30, 0xff, 0x0e, 0x1c, 0x38, 0xff, }; -static unsigned char kpng_8x4_drawImage_scale_out[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, @@ -1092,7 +897,7 @@ static unsigned char kpng_8x4_drawImage_scale_out[128] = { 0x3f, 0x3f, 0x3f, 0xff, 0x41, 0x41, 0x41, 0xff, }; -static unsigned char kpng_8x4_drawImage_flip[128] = { +static uint8 kpng_8x4_drawImage_flip[128] = { // expected result of flip src image. 0x30, 0x60, 0xc0, 0xff, 0x32, 0x64, 0xc8, 0xff, 0x22, 0x22, 0x22, 0xff, 0x21, 0x21, 0x21, 0xff, @@ -1112,7 +917,7 @@ static unsigned char kpng_8x4_drawImage_flip[128] = { 0x0c, 0x18, 0x30, 0xff, 0x0e, 0x1c, 0x38, 0xff, }; -static unsigned char kpng_8x4_drawImage_argb8[128] = { +static uint8 kpng_8x4_drawImage_argb8[128] = { // expected result of drawimage with rgb8 format. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0xca, 0xca, 0x3e, 0xd7, 0xd7, 0xd7, 0x9a, @@ -1144,112 +949,112 @@ TEST_F(BitmapTest, DrawImage) { "/bitmap_test/png-2x2-24bit-drawimage-src.png"; Bitmap::Ref bitmap_2x2_src(new Bitmap(g_service_locator)); EXPECT_TRUE(bitmap_2x2_src->LoadFromFile(UTF8ToFilePath(filename_2x2_src), - Bitmap::PNG, false)); + image::PNG, false)); String filename_4x4_src = *g_program_path + "/bitmap_test/png-4x4-24bit-drawimage-src.png"; Bitmap::Ref bitmap_4x4_src(new Bitmap(g_service_locator)); EXPECT_TRUE(bitmap_4x4_src->LoadFromFile(UTF8ToFilePath(filename_4x4_src), - Bitmap::PNG, false)); + image::PNG, false)); String filename_8x8_src = *g_program_path + "/bitmap_test/png-8x8-24bit-drawimage-src.png"; Bitmap::Ref bitmap_8x8_src(new Bitmap(g_service_locator)); EXPECT_TRUE(bitmap_8x8_src->LoadFromFile(UTF8ToFilePath(filename_8x8_src), - Bitmap::PNG, false)); + image::PNG, false)); // test draw image on top left boundary. Bitmap::Ref bitmap_dest_top_left(new Bitmap(g_service_locator)); EXPECT_TRUE(bitmap_dest_top_left->LoadFromFile(UTF8ToFilePath(fname_dst), - Bitmap::PNG, false)); + image::PNG, false)); // 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, 4, 4, -1, -1, 4, 4); EXPECT_TRUE(TestBitmapData(*bitmap_dest_top_left, kpng_8x4_drawImage_top_left)); // test draw image on top boundary. Bitmap::Ref bitmap_dest_top(new Bitmap(g_service_locator)); EXPECT_TRUE(bitmap_dest_top->LoadFromFile(UTF8ToFilePath(fname_dst), - Bitmap::PNG, false)); - bitmap_dest_top->DrawImage(bitmap_4x4_src, 0, 0, 4, 4, 2, -2, 4, 4); + image::PNG, false)); + bitmap_dest_top->DrawImage(*bitmap_4x4_src, 0, 0, 4, 4, 2, -2, 4, 4); EXPECT_TRUE(TestBitmapData(*bitmap_dest_top, kpng_8x4_drawImage_top)); // test draw image on top right boundary. Bitmap::Ref bitmap_dest_top_right(new Bitmap(g_service_locator)); EXPECT_TRUE(bitmap_dest_top_right->LoadFromFile(UTF8ToFilePath(fname_dst), - Bitmap::PNG, false)); - bitmap_dest_top_right->DrawImage(bitmap_4x4_src, 0, 0, 4, 4, 5, -1, 4, 4); + image::PNG, false)); + bitmap_dest_top_right->DrawImage(*bitmap_4x4_src, 0, 0, 4, 4, 5, -1, 4, 4); EXPECT_TRUE(TestBitmapData(*bitmap_dest_top_right, kpng_8x4_drawImage_top_right)); // test draw image on right boundary. Bitmap::Ref bitmap_dest_right(new Bitmap(g_service_locator)); EXPECT_TRUE(bitmap_dest_right->LoadFromFile(UTF8ToFilePath(fname_dst), - Bitmap::PNG, false)); - bitmap_dest_right->DrawImage(bitmap_4x4_src, 0, 0, 4, 4, 5, 0, 4, 4); + image::PNG, false)); + bitmap_dest_right->DrawImage(*bitmap_4x4_src, 0, 0, 4, 4, 5, 0, 4, 4); EXPECT_TRUE(TestBitmapData(*bitmap_dest_right, kpng_8x4_drawImage_right)); // test draw image on bottom right boundary. Bitmap::Ref bitmap_dest_bottom_right(new Bitmap(g_service_locator)); EXPECT_TRUE(bitmap_dest_bottom_right->LoadFromFile(UTF8ToFilePath(fname_dst), - Bitmap::PNG, false)); - bitmap_dest_bottom_right->DrawImage(bitmap_4x4_src, 0, 0, 4, 4, 5, 1, 4, 4); + image::PNG, false)); + bitmap_dest_bottom_right->DrawImage(*bitmap_4x4_src, 0, 0, 4, 4, 5, 1, 4, 4); EXPECT_TRUE(TestBitmapData(*bitmap_dest_bottom_right, kpng_8x4_drawImage_bottom_right)); // test draw image on bottom boundary. Bitmap::Ref bitmap_dest_bottom(new Bitmap(g_service_locator)); EXPECT_TRUE(bitmap_dest_bottom->LoadFromFile(UTF8ToFilePath(fname_dst), - Bitmap::PNG, false)); - bitmap_dest_bottom->DrawImage(bitmap_4x4_src, 0, 0, 4, 4, 2, 1, 4, 4); + image::PNG, false)); + bitmap_dest_bottom->DrawImage(*bitmap_4x4_src, 0, 0, 4, 4, 2, 1, 4, 4); EXPECT_TRUE(TestBitmapData(*bitmap_dest_bottom, kpng_8x4_drawImage_bottom)); // test draw image on bottom left boundary. Bitmap::Ref bitmap_dest_bottom_left(new Bitmap(g_service_locator)); EXPECT_TRUE(bitmap_dest_bottom_left->LoadFromFile(UTF8ToFilePath(fname_dst), - Bitmap::PNG, false)); - bitmap_dest_bottom_left->DrawImage(bitmap_4x4_src, 0, 0, 4, 4, -1, 1, 4, 4); + image::PNG, false)); + bitmap_dest_bottom_left->DrawImage(*bitmap_4x4_src, 0, 0, 4, 4, -1, 1, 4, 4); EXPECT_TRUE(TestBitmapData(*bitmap_dest_bottom_left, kpng_8x4_drawImage_bottom_left)); // test draw image on left boundary. Bitmap::Ref bitmap_dest_left(new Bitmap(g_service_locator)); EXPECT_TRUE(bitmap_dest_left->LoadFromFile(UTF8ToFilePath(fname_dst), - Bitmap::PNG, false)); - bitmap_dest_left->DrawImage(bitmap_4x4_src, 0, 0, 4, 4, -1, 0, 4, 4); + image::PNG, false)); + bitmap_dest_left->DrawImage(*bitmap_4x4_src, 0, 0, 4, 4, -1, 0, 4, 4); EXPECT_TRUE(TestBitmapData(*bitmap_dest_left, kpng_8x4_drawImage_left)); // test scale up. Bitmap::Ref bitmap_dest_scale_up(new Bitmap(g_service_locator)); EXPECT_TRUE(bitmap_dest_scale_up->LoadFromFile(UTF8ToFilePath(fname_dst), - Bitmap::PNG, false)); - bitmap_dest_scale_up->DrawImage(bitmap_2x2_src, 0, 0, 2, 2, 0, 0, 8, 4); + image::PNG, false)); + bitmap_dest_scale_up->DrawImage(*bitmap_2x2_src, 0, 0, 2, 2, 0, 0, 8, 4); EXPECT_TRUE(TestBitmapData(*bitmap_dest_scale_up, kpng_8x4_drawImage_scale_up)); // test scale down. Bitmap::Ref bitmap_dest_scale_down(new Bitmap(g_service_locator)); EXPECT_TRUE(bitmap_dest_scale_down->LoadFromFile(UTF8ToFilePath(fname_dst), - Bitmap::PNG, false)); - bitmap_dest_scale_down->DrawImage(bitmap_8x8_src, 0, 0, 8, 8, 0, 0, 4, 4); + image::PNG, false)); + bitmap_dest_scale_down->DrawImage(*bitmap_8x8_src, 0, 0, 8, 8, 0, 0, 4, 4); EXPECT_TRUE(TestBitmapData(*bitmap_dest_scale_down, kpng_8x4_drawImage_scale_down)); // test scale up to a large size. Bitmap::Ref bitmap_dest_scale_out(new Bitmap(g_service_locator)); EXPECT_TRUE(bitmap_dest_scale_out->LoadFromFile(UTF8ToFilePath(fname_dst), - Bitmap::PNG, false)); - bitmap_dest_scale_out->DrawImage(bitmap_8x8_src, 0, 0, 8, 8, -2, -4, 12, 12); + image::PNG, false)); + bitmap_dest_scale_out->DrawImage(*bitmap_8x8_src, 0, 0, 8, 8, -2, -4, 12, 12); EXPECT_TRUE(TestBitmapData(*bitmap_dest_scale_out, kpng_8x4_drawImage_scale_out)); // test flip an image on both x and y cooridnates. Bitmap::Ref bitmap_dest_flip(new Bitmap(g_service_locator)); EXPECT_TRUE(bitmap_dest_flip->LoadFromFile(UTF8ToFilePath(fname_dst), - Bitmap::PNG, false)); - bitmap_dest_flip->DrawImage(bitmap_4x4_src, 0, 0, 4, 4, 5, 3, -4, -4); + image::PNG, false)); + bitmap_dest_flip->DrawImage(*bitmap_4x4_src, 0, 0, 4, 4, 5, 3, -4, -4); EXPECT_TRUE(TestBitmapData(*bitmap_dest_flip, kpng_8x4_drawImage_flip)); // test draw image on argb8 format. @@ -1258,14 +1063,14 @@ TEST_F(BitmapTest, DrawImage) { "png-8x4-24bit-drawimage-argb8-dest.png"; Bitmap::Ref bitmap_dest_argb8(new Bitmap(g_service_locator)); EXPECT_TRUE(bitmap_dest_argb8->LoadFromFile(UTF8ToFilePath(fname_dst_argb8), - Bitmap::PNG, false)); + image::PNG, false)); String fname_src_argb8 = *g_program_path + "/bitmap_test/" + "png-4x4-24bit-drawimage-argb8-src.png"; Bitmap::Ref bitmap_src_argb8(new Bitmap(g_service_locator)); EXPECT_TRUE(bitmap_src_argb8->LoadFromFile(UTF8ToFilePath(fname_src_argb8), - Bitmap::PNG, false)); - bitmap_dest_argb8->DrawImage(bitmap_src_argb8, 0, 0, 4, 4, 0, 0, 4, 4); + image::PNG, false)); + bitmap_dest_argb8->DrawImage(*bitmap_src_argb8, 0, 0, 4, 4, 0, 0, 4, 4); EXPECT_TRUE(TestBitmapData(*bitmap_dest_argb8, kpng_8x4_drawImage_argb8)); } diff --git a/o3d/core/cross/bitmap_tga.cc b/o3d/core/cross/bitmap_tga.cc index 97ff4fb..c85cca9 100644 --- a/o3d/core/cross/bitmap_tga.cc +++ b/o3d/core/cross/bitmap_tga.cc @@ -55,14 +55,14 @@ bool Bitmap::LoadFromTGAStream(MemoryReadStream *stream, const String &filename, bool generate_mipmaps) { // Read the magic header. - unsigned char file_magic[12]; + uint8 file_magic[12]; if (stream->Read(file_magic, sizeof(file_magic)) != sizeof(file_magic)) { DLOG(ERROR) << "Targa file magic not loaded \"" << filename << "\""; return false; } // Match the first few bytes of the TGA header to confirm we can read this // format. Multibyte values are stored little endian. - const unsigned char kTargaMagic[12] = { + const uint8 kTargaMagic[12] = { 0, // ID Length (0 = no ID string present) 0, // Color Map Type ( 0 = no color map) 2, // Image Type (2 = Uncompressed True Color) @@ -76,12 +76,16 @@ bool Bitmap::LoadFromTGAStream(MemoryReadStream *stream, // MATCHED LATER: Pixel Depth (1 byte) // MATCHED LATER: Image Descriptor (1 byte, alpha:4bit, origin:2bit) }; + + // TODO(gman): The most common targa format is compressed! We should support + // that format or remove targa support completely. If we are keeping targa + // format we should also support grayscale, 8bit indexed and 16bit formats. if (memcmp(kTargaMagic, file_magic, sizeof(kTargaMagic)) != 0) { DLOG(ERROR) << "Targa file subtype not recognized \"" << filename << "\""; return false; } // Read the image header. - unsigned char header[6]; + uint8 header[6]; if (stream->Read(header, sizeof(header)) != sizeof(header)) { DLOG(ERROR) << "Targa file header not read \"" << filename << "\""; return false; @@ -89,7 +93,7 @@ bool Bitmap::LoadFromTGAStream(MemoryReadStream *stream, // Calculate image width and height, stored as little endian. unsigned int tga_width = header[1] * 256 + header[0]; unsigned int tga_height = header[3] * 256 + header[2]; - if (!CheckImageDimensions(tga_width, tga_height)) { + if (!image::CheckImageDimensions(tga_width, tga_height)) { DLOG(ERROR) << "Failed to load " << filename << ": dimensions are too large (" << tga_width << ", " << tga_height << ")."; @@ -106,11 +110,11 @@ bool Bitmap::LoadFromTGAStream(MemoryReadStream *stream, unsigned int pixel_count = tga_width * tga_height; // Allocate storage for the pixels. unsigned int num_mipmaps = - generate_mipmaps ? GetMipMapCount(tga_width, tga_height) : 1; + generate_mipmaps ? image::ComputeMipMapCount(tga_width, tga_height) : 1; Texture::Format format = components == 3 ? Texture::XRGB8 : Texture::ARGB8; - unsigned int image_size = GetMipChainSize(tga_width, tga_height, format, - num_mipmaps); - scoped_array<unsigned char> image_data(new unsigned char[image_size]); + unsigned int image_size = + image::ComputeMipChainSize(tga_width, tga_height, format, num_mipmaps); + scoped_array<uint8> image_data(new uint8[image_size]); if (image_data.get() == NULL) { DLOG(ERROR) << "Targa file memory allocation error \"" << filename << "\""; return false; @@ -124,7 +128,7 @@ bool Bitmap::LoadFromTGAStream(MemoryReadStream *stream, if (components == 3) { // Fixup the image by inserting an alpha value of 1 (BGR->BGRX). - XYZToXYZA(image_data.get(), pixel_count); + image::XYZToXYZA(image_data.get(), pixel_count); } if (generate_mipmaps) { @@ -141,6 +145,13 @@ bool Bitmap::LoadFromTGAStream(MemoryReadStream *stream, height_ = tga_height; format_ = format; num_mipmaps_ = num_mipmaps; + + // Targas are generally bottom first in memory so flip it. + // + // TODO(gman): In truth a targa can be any orientation. We should check + // that orientation and flip or not flip accordingly. + FlipVertically(); + return true; } diff --git a/o3d/core/cross/buffer_test.cc b/o3d/core/cross/buffer_test.cc index 469df99..7bdddac 100644 --- a/o3d/core/cross/buffer_test.cc +++ b/o3d/core/cross/buffer_test.cc @@ -36,6 +36,7 @@ #include "tests/common/win/testing_common.h" #include "core/cross/error_status.h" #include "core/cross/buffer.h" +#include "core/cross/pack.h" #include "import/cross/memory_buffer.h" #include "import/cross/memory_stream.h" #include "import/cross/raw_data.h" diff --git a/o3d/core/cross/client.h b/o3d/core/cross/client.h index 07e60e5..b7de85c 100644 --- a/o3d/core/cross/client.h +++ b/o3d/core/cross/client.h @@ -52,11 +52,8 @@ #include "core/cross/object_manager.h" #include "core/cross/semantic_manager.h" #include "core/cross/transformation_context.h" -#include "core/cross/pack.h" -#include "core/cross/bitmap.h" +#include "core/cross/render_node.h" #include "core/cross/callback.h" -#include "core/cross/cursor.h" -#include "core/cross/draw_list.h" #include "core/cross/event.h" #include "core/cross/event_callback.h" #include "core/cross/event_manager.h" @@ -65,11 +62,13 @@ #include "core/cross/tick_event.h" #include "core/cross/timer.h" #include "core/cross/timingtable.h" +#include "core/cross/transform.h" namespace o3d { class MessageQueue; class Profiler; class State; +class Pack; // The Client class is the main point of entry to O3D. It defines methods // for creating and deleting packs and internal use only methods for creating diff --git a/o3d/core/cross/client_test.cc b/o3d/core/cross/client_test.cc index ac6e853..49c5d85 100644 --- a/o3d/core/cross/client_test.cc +++ b/o3d/core/cross/client_test.cc @@ -34,6 +34,8 @@ #include "core/cross/client.h" #include "tests/common/win/testing_common.h" +#include "core/cross/pack.h" +#include "core/cross/buffer.h" namespace o3d { diff --git a/o3d/core/cross/command_buffer/texture_cb.cc b/o3d/core/cross/command_buffer/texture_cb.cc index e9d5e52..88c529b 100644 --- a/o3d/core/cross/command_buffer/texture_cb.cc +++ b/o3d/core/cross/command_buffer/texture_cb.cc @@ -112,14 +112,14 @@ void UpdateResourceFromBitmap(RendererCB *renderer, unsigned int mip_height = std::max(1U, bitmap.height() >> level); unsigned char *mip_data = bitmap.GetFaceMipData(face, level); unsigned int mip_size = - Bitmap::GetBufferSize(mip_width, mip_height, bitmap.format()); + image::ComputeBufferSize(mip_width, mip_height, bitmap.format()); if (resize_to_pot) { unsigned int pot_width = - std::max(1U, Bitmap::GetPOTSize(bitmap.width()) >> level); + std::max(1U, image::ComputePOTSize(bitmap.width()) >> level); unsigned int pot_height = - std::max(1U, Bitmap::GetPOTSize(bitmap.height()) >> level); - unsigned int pot_size = Bitmap::GetBufferSize(pot_width, pot_height, - bitmap.format()); + std::max(1U, image::ComputePOTSize(bitmap.height()) >> level); + unsigned int pot_size = image::ComputeBufferSize(pot_width, pot_height, + bitmap.format()); unsigned char *buffer = allocator->AllocTyped<unsigned char>(pot_size); // This should succeed for practical purposes: we don't store persistent // data in the transfer buffer, and the maximum texture size 2048x2048 @@ -129,9 +129,9 @@ void UpdateResourceFromBitmap(RendererCB *renderer, // by bits that fit into an arbitrarily small buffer, but that is complex // for the NPOT->POT case. DCHECK(buffer); - Bitmap::Scale(mip_width, mip_height, bitmap.format(), mip_data, - pot_width, pot_height, buffer, - Bitmap::GetMipChainSize(pot_width, 1, bitmap.format(), 1)); + image::Scale(mip_width, mip_height, bitmap.format(), mip_data, + pot_width, pot_height, buffer, + image::ComputePitch(bitmap.format(), pot_width)); mip_width = pot_width; mip_height = pot_height; mip_size = pot_size; @@ -143,7 +143,7 @@ void UpdateResourceFromBitmap(RendererCB *renderer, mip_data = buffer; } - unsigned int pitch = Bitmap::GetBufferSize(mip_width, 1, bitmap.format()); + unsigned int pitch = image::ComputeBufferSize(mip_width, 1, bitmap.format()); CommandBufferEntry args[10]; args[0].value_uint32 = texture_id; @@ -180,11 +180,11 @@ void CopyBackResourceToBitmap(RendererCB *renderer, unsigned int mip_width = std::max(1U, bitmap.width() >> level); unsigned int mip_height = std::max(1U, bitmap.height() >> level); unsigned int mip_size = - Bitmap::GetBufferSize(mip_width, mip_height, bitmap.format()); + image::ComputeBufferSize(mip_width, mip_height, bitmap.format()); unsigned char *buffer = allocator->AllocTyped<unsigned char>(mip_size); DCHECK(buffer); - unsigned int pitch = Bitmap::GetBufferSize(mip_width, 1, bitmap.format()); + unsigned int pitch = image::ComputeBufferSize(mip_width, 1, bitmap.format()); CommandBufferEntry args[10]; args[0].value_uint32 = texture_id; @@ -276,8 +276,8 @@ Texture2DCB* Texture2DCB::Create(ServiceLocator* service_locator, unsigned int mip_width = bitmap->width(); unsigned int mip_height = bitmap->height(); if (resize_to_pot) { - mip_width = Bitmap::GetPOTSize(mip_width); - mip_height = Bitmap::GetPOTSize(mip_height); + mip_width = image::ComputePOTSize(mip_width); + mip_height = image::ComputePOTSize(mip_height); } ResourceID texture_id = renderer->texture_ids().AllocateID(); @@ -345,10 +345,10 @@ bool Texture2DCB::Lock(int level, void** data, int* pitch) { backing_bitmap_->Allocate(format(), width(), height(), levels(), false); } *data = backing_bitmap_->GetMipData(level); - unsigned int mip_width = Bitmap::GetMipDimension(level, width()); - unsigned int mip_height = Bitmap::GetMipDimension(level, height()); + unsigned int mip_width = image::ComputeMipDimension(level, width()); + unsigned int mip_height = image::ComputeMipDimension(level, height()); if (!IsCompressed()) { - *pitch = Bitmap::GetMipChainSize(mip_width, 1,format(), 1); + *pitch = image::ComputePitch(format(), mip_width); } else { unsigned blocks_across = (mip_width + 3) / 4; unsigned bytes_per_block = format() == Texture::DXT1 ? 8 : 16; @@ -471,8 +471,8 @@ TextureCUBECB* TextureCUBECB::Create(ServiceLocator* service_locator, unsigned int mip_width = bitmap->width(); unsigned int mip_height = bitmap->height(); if (resize_to_pot) { - mip_width = Bitmap::GetPOTSize(mip_width); - mip_height = Bitmap::GetPOTSize(mip_height); + mip_width = image::ComputePOTSize(mip_width); + mip_height = image::ComputePOTSize(mip_height); } ResourceID texture_id = renderer->texture_ids().AllocateID(); @@ -547,9 +547,9 @@ bool TextureCUBECB::Lock(CubeFace face, int level, void** data, int* pitch) { levels(), true); } *data = backing_bitmap_->GetFaceMipData(face, level); - unsigned int mip_width = Bitmap::GetMipDimension(level, edge_length()); + unsigned int mip_width = image::ComputeMipDimension(level, edge_length()); if (!IsCompressed()) { - *pitch = Bitmap::GetMipChainSize(mip_width, 1,format(), 1); + *pitch = image::ComputePitch(format(), mip_width); } else { unsigned blocks_across = (mip_width + 3) / 4; unsigned bytes_per_block = format() == Texture::DXT1 ? 8 : 16; diff --git a/o3d/core/cross/counter.h b/o3d/core/cross/counter.h index 117adbe..9faea11 100644 --- a/o3d/core/cross/counter.h +++ b/o3d/core/cross/counter.h @@ -39,6 +39,7 @@ #include <vector> #include "core/cross/callback.h" #include "core/cross/param_object.h" +#include "core/cross/pack.h" namespace o3d { diff --git a/o3d/core/cross/curve_test.cc b/o3d/core/cross/curve_test.cc index d1de1f2..ab8c47a 100644 --- a/o3d/core/cross/curve_test.cc +++ b/o3d/core/cross/curve_test.cc @@ -33,9 +33,12 @@ // This file implements unit tests for class Curve. #include <algorithm> -#include "core/cross/client.h" #include "tests/common/win/testing_common.h" #include "core/cross/curve.h" +#include "core/cross/pack.h" +#include "core/cross/service_dependency.h" +#include "core/cross/error_status.h" +#include "core/cross/object_manager.h" #include "import/cross/memory_buffer.h" #include "import/cross/memory_stream.h" #include "serializer/cross/serializer_binary.h" diff --git a/o3d/core/cross/draw_element_test.cc b/o3d/core/cross/draw_element_test.cc index aafd612..535bce6 100644 --- a/o3d/core/cross/draw_element_test.cc +++ b/o3d/core/cross/draw_element_test.cc @@ -32,9 +32,11 @@ // This file implements unit tests for class DrawElement. -#include "core/cross/client.h" #include "tests/common/win/testing_common.h" #include "core/cross/draw_element.h" +#include "core/cross/object_manager.h" +#include "core/cross/pack.h" +#include "core/cross/service_dependency.h" namespace o3d { diff --git a/o3d/core/cross/draw_list_test.cc b/o3d/core/cross/draw_list_test.cc index bff7f84..36ab6e3 100644 --- a/o3d/core/cross/draw_list_test.cc +++ b/o3d/core/cross/draw_list_test.cc @@ -32,9 +32,13 @@ // This file implements unit tests for class DrawList. -#include "core/cross/client.h" #include "tests/common/win/testing_common.h" #include "core/cross/draw_list.h" +#include "core/cross/draw_list_manager.h" +#include "core/cross/object_manager.h" +#include "core/cross/pack.h" +#include "core/cross/service_dependency.h" +#include "core/cross/transformation_context.h" namespace o3d { diff --git a/o3d/core/cross/effect_test.cc b/o3d/core/cross/effect_test.cc index b1361fb..2b1ca6c 100644 --- a/o3d/core/cross/effect_test.cc +++ b/o3d/core/cross/effect_test.cc @@ -30,13 +30,17 @@ */ +#include "tests/common/win/testing_common.h" #include "core/cross/client.h" #include "core/cross/effect.h" +#include "core/cross/image_utils.h" +#include "core/cross/pack.h" +#include "core/cross/param_array.h" #include "core/cross/primitive.h" +#include "core/cross/sampler.h" #include "core/cross/standard_param.h" -#include "core/cross/param_array.h" #include "core/cross/stream.h" -#include "tests/common/win/testing_common.h" +#include "core/cross/texture_base.h" namespace o3d { @@ -305,7 +309,7 @@ TEST_F(EffectTest, CreateAndDestroyEffect) { String filepath = *g_program_path + "/unittest_data/rock01.tga"; Texture *texture = pack->CreateTextureFromFile(filepath, filepath, - Bitmap::TGA, + image::TGA, true); EXPECT_TRUE(texture != NULL); diff --git a/o3d/core/cross/element_test.cc b/o3d/core/cross/element_test.cc index 954dd8b..fc66b15 100644 --- a/o3d/core/cross/element_test.cc +++ b/o3d/core/cross/element_test.cc @@ -33,9 +33,11 @@ // This file implements unit tests for class Element. #include <algorithm> -#include "core/cross/client.h" #include "tests/common/win/testing_common.h" #include "core/cross/element.h" +#include "core/cross/object_manager.h" +#include "core/cross/pack.h" +#include "core/cross/service_dependency.h" #include "core/cross/primitive.h" namespace o3d { diff --git a/o3d/core/cross/features.cc b/o3d/core/cross/features.cc index 75349cc..6a5d967 100644 --- a/o3d/core/cross/features.cc +++ b/o3d/core/cross/features.cc @@ -49,6 +49,7 @@ Features::Features(ServiceLocator* service_locator) large_geometry_(true), windowless_(false), not_anti_aliased_(false), + flip_textures_(true), init_status_(Renderer::SUCCESS) { // NOTE: For backward compatibility floating_point_textures and // large_geometry default to true. o3djs.util.makeClients before 0.1.35.0 @@ -58,36 +59,59 @@ Features::Features(ServiceLocator* service_locator) // which sets those to false to start. } -void Features::Init(const String& requested_features) { - large_geometry_ = false; - floating_point_textures_ = false; - - std::vector<std::string> features; - SplitString(requested_features, ',', &features); +void Features::ParseFeatures(const std::vector<std::string>& features, + bool version_pass) { for (size_t jj = 0; jj < features.size(); ++jj) { const std::string& feature_string = features[jj]; std::vector<std::string> arguments; SplitString(feature_string, '=', &arguments); const std::string feature(arguments.front()); arguments.erase(arguments.begin()); - if (feature.compare("FloatingPointTextures") == 0) { - floating_point_textures_ = true; - } else if (feature.compare("LargeGeometry") == 0) { - large_geometry_ = true; - } else if (feature.compare("Windowless") == 0) { - windowless_ = true; - } else if (feature.compare("NotAntiAliased") == 0) { - not_anti_aliased_ = true; - } else if (feature.compare("MaxCapabilities") == 0) { - large_geometry_ = true; - floating_point_textures_ = true; - } else if (feature.compare("InitStatus") == 0 && - !arguments.empty()) { - int value; - StringToInt(arguments[0], &value); - init_status_ = static_cast<Renderer::InitStatus>(value); + if (version_pass) { + if (feature.compare("APIVersion") == 0 && !arguments.empty()) { + int version[4] = { 0, }; + std::vector<std::string> parts; + SplitString(arguments[0], '.', &parts); + size_t num_parts = std::min(parts.size(), arraysize(version)); + for (size_t ii = 0; ii < num_parts; ++ii) { + StringToInt(parts[ii], &version[ii]); + } + if (version[0] >= 0 && version[1] >= 1 && version[2] >= 40) { + flip_textures_ = false; + } + } + } else { + if (feature.compare("FloatingPointTextures") == 0) { + floating_point_textures_ = true; + } else if (feature.compare("LargeGeometry") == 0) { + large_geometry_ = true; + } else if (feature.compare("Windowless") == 0) { + windowless_ = true; + } else if (feature.compare("NotAntiAliased") == 0) { + not_anti_aliased_ = true; + } else if (feature.compare("FlipTextures") == 0) { + flip_textures_ = true; + } else if (feature.compare("MaxCapabilities") == 0) { + large_geometry_ = true; + floating_point_textures_ = true; + } else if (feature.compare("InitStatus") == 0 && + !arguments.empty()) { + int value; + StringToInt(arguments[0], &value); + init_status_ = static_cast<Renderer::InitStatus>(value); + } } } } +void Features::Init(const String& requested_features) { + large_geometry_ = false; + floating_point_textures_ = false; + + std::vector<std::string> features; + SplitString(requested_features, ',', &features); + ParseFeatures(features, true); + ParseFeatures(features, false); +} + } // namespace o3d diff --git a/o3d/core/cross/features.h b/o3d/core/cross/features.h index 003c807..efd3266 100644 --- a/o3d/core/cross/features.h +++ b/o3d/core/cross/features.h @@ -35,6 +35,8 @@ #ifndef O3D_CORE_CROSS_FEATURES_H_ #define O3D_CORE_CROSS_FEATURES_H_ +#include <string> +#include <vector> #include "core/cross/types.h" #include "core/cross/service_locator.h" #include "core/cross/service_implementation.h" @@ -68,7 +70,11 @@ class Features { } bool not_anti_aliased() const { - return not_anti_aliased_; + return not_anti_aliased_; + } + + bool flip_textures() const { + return flip_textures_; } // This can be used to force the renderer to fail for testing. @@ -77,12 +83,21 @@ class Features { } private: + // Parses the features strings. + // Parameters: + // features: vector of feature strings. + // version_pass: True = only check for APIVersion, false = check everything + // but APIVersion. + void ParseFeatures(const std::vector<std::string>& features, + bool version_pass); + ServiceImplementation<Features> service_; bool floating_point_textures_; bool large_geometry_; bool windowless_; bool not_anti_aliased_; + bool flip_textures_; Renderer::InitStatus init_status_; DISALLOW_COPY_AND_ASSIGN(Features); diff --git a/o3d/core/cross/features_test.cc b/o3d/core/cross/features_test.cc index bd2e339..e844e5f 100644 --- a/o3d/core/cross/features_test.cc +++ b/o3d/core/cross/features_test.cc @@ -71,10 +71,15 @@ TEST_F(FeaturesTest, Basic) { // Features::Init is not called. o3djs,util.makeClients after and // including 0.1.35.0 do set o3d_features and therefore Init is called // which sets those to false to start. + // + // NOTE: pre 0.1.40.0 flip_textures defaults to true. After it defaults to + // false. + EXPECT_TRUE(features->floating_point_textures()); EXPECT_TRUE(features->large_geometry()); EXPECT_FALSE(features->windowless()); EXPECT_FALSE(features->not_anti_aliased()); + EXPECT_TRUE(features->flip_textures()); EXPECT_EQ(features->init_status(), Renderer::SUCCESS); delete features; @@ -90,6 +95,39 @@ TEST_F(FeaturesTest, Empty) { EXPECT_FALSE(features->large_geometry()); EXPECT_FALSE(features->windowless()); EXPECT_FALSE(features->not_anti_aliased()); + EXPECT_TRUE(features->flip_textures()); + EXPECT_EQ(features->init_status(), Renderer::SUCCESS); + + delete features; +} + +TEST_F(FeaturesTest, APIVersion0_1_38_0) { + Features* features = new Features(service_locator()); + + features->Init("APIVersion=0.1.38.0"); + + // Check that the features start off as false. + EXPECT_FALSE(features->floating_point_textures()); + EXPECT_FALSE(features->large_geometry()); + EXPECT_FALSE(features->windowless()); + EXPECT_FALSE(features->not_anti_aliased()); + EXPECT_TRUE(features->flip_textures()); + EXPECT_EQ(features->init_status(), Renderer::SUCCESS); + + delete features; +} + +TEST_F(FeaturesTest, APIVersion0_1_40_0) { + Features* features = new Features(service_locator()); + + features->Init("APIVersion=0.1.40.0"); + + // Check that the features start off as false. + EXPECT_FALSE(features->floating_point_textures()); + EXPECT_FALSE(features->large_geometry()); + EXPECT_FALSE(features->windowless()); + EXPECT_FALSE(features->not_anti_aliased()); + EXPECT_FALSE(features->flip_textures()); EXPECT_EQ(features->init_status(), Renderer::SUCCESS); delete features; @@ -104,6 +142,7 @@ TEST_F(FeaturesTest, FloatingPointTextures) { EXPECT_FALSE(features->large_geometry()); EXPECT_FALSE(features->windowless()); EXPECT_FALSE(features->not_anti_aliased()); + EXPECT_TRUE(features->flip_textures()); EXPECT_EQ(features->init_status(), Renderer::SUCCESS); delete features; @@ -118,6 +157,7 @@ TEST_F(FeaturesTest, LargeGeometry) { EXPECT_TRUE(features->large_geometry()); EXPECT_FALSE(features->windowless()); EXPECT_FALSE(features->not_anti_aliased()); + EXPECT_TRUE(features->flip_textures()); EXPECT_EQ(features->init_status(), Renderer::SUCCESS); delete features; @@ -132,6 +172,7 @@ TEST_F(FeaturesTest, Windowless) { EXPECT_FALSE(features->large_geometry()); EXPECT_TRUE(features->windowless()); EXPECT_FALSE(features->not_anti_aliased()); + EXPECT_TRUE(features->flip_textures()); EXPECT_EQ(features->init_status(), Renderer::SUCCESS); delete features; @@ -146,6 +187,22 @@ TEST_F(FeaturesTest, NotAntiAliased) { EXPECT_FALSE(features->large_geometry()); EXPECT_FALSE(features->windowless()); EXPECT_TRUE(features->not_anti_aliased()); + EXPECT_TRUE(features->flip_textures()); + EXPECT_EQ(features->init_status(), Renderer::SUCCESS); + + delete features; +} + +TEST_F(FeaturesTest, FlipTextures) { + Features* features = new Features(service_locator()); + + features->Init("FlipTextures,APIVersion=0.1.40.0"); + + EXPECT_FALSE(features->floating_point_textures()); + EXPECT_FALSE(features->large_geometry()); + EXPECT_FALSE(features->windowless()); + EXPECT_FALSE(features->not_anti_aliased()); + EXPECT_TRUE(features->flip_textures()); EXPECT_EQ(features->init_status(), Renderer::SUCCESS); delete features; @@ -166,6 +223,7 @@ TEST_F(FeaturesTest, InitStatus) { EXPECT_FALSE(features->large_geometry()); EXPECT_FALSE(features->windowless()); EXPECT_FALSE(features->not_anti_aliased()); + EXPECT_TRUE(features->flip_textures()); EXPECT_EQ(features->init_status(), statuses[ii]); delete features; @@ -181,6 +239,7 @@ TEST_F(FeaturesTest, BadInput) { EXPECT_FALSE(features->large_geometry()); EXPECT_FALSE(features->windowless()); EXPECT_FALSE(features->not_anti_aliased()); + EXPECT_TRUE(features->flip_textures()); EXPECT_EQ(features->init_status(), Renderer::SUCCESS); delete features; @@ -195,6 +254,7 @@ TEST_F(FeaturesTest, MultipleFeatures) { EXPECT_FALSE(features->large_geometry()); EXPECT_TRUE(features->windowless()); EXPECT_FALSE(features->not_anti_aliased()); + EXPECT_TRUE(features->flip_textures()); EXPECT_EQ(features->init_status(), Renderer::SUCCESS); delete features; @@ -209,6 +269,7 @@ TEST_F(FeaturesTest, MaxCapabilities) { EXPECT_TRUE(features->large_geometry()); EXPECT_FALSE(features->windowless()); EXPECT_FALSE(features->not_anti_aliased()); + EXPECT_TRUE(features->flip_textures()); EXPECT_EQ(features->init_status(), Renderer::SUCCESS); delete features; diff --git a/o3d/core/cross/field_test.cc b/o3d/core/cross/field_test.cc index 0f8afce..6b37426 100644 --- a/o3d/core/cross/field_test.cc +++ b/o3d/core/cross/field_test.cc @@ -32,10 +32,13 @@ // Tests Field, FloatField, UInt32Field, UByteNField. -#include "core/cross/client.h" #include "tests/common/win/testing_common.h" #include "core/cross/error_status.h" #include "core/cross/field.h" +#include "core/cross/buffer.h" +#include "core/cross/object_manager.h" +#include "core/cross/pack.h" +#include "core/cross/service_dependency.h" namespace o3d { diff --git a/o3d/core/cross/function_test.cc b/o3d/core/cross/function_test.cc index c53e36f..5407324 100644 --- a/o3d/core/cross/function_test.cc +++ b/o3d/core/cross/function_test.cc @@ -32,9 +32,11 @@ // This file implements unit tests for class Function and FunctionEval. -#include "core/cross/client.h" #include "tests/common/win/testing_common.h" +#include "core/cross/error_status.h" #include "core/cross/function.h" +#include "core/cross/object_manager.h" +#include "core/cross/pack.h" namespace o3d { diff --git a/o3d/core/cross/gl/renderer_gl.cc b/o3d/core/cross/gl/renderer_gl.cc index b7197b5..6741453 100644 --- a/o3d/core/cross/gl/renderer_gl.cc +++ b/o3d/core/cross/gl/renderer_gl.cc @@ -1567,7 +1567,7 @@ bool RendererGL::SaveScreen(const String& file_name) { MakeCurrentLazy(); Bitmap::Ref bitmap = Bitmap::Ref(new Bitmap(service_locator())); bitmap->Allocate(Texture::ARGB8, width(), height(), 1, false); - + // Note: glReadPixels captures the alpha component of the frame buffer as well // as the color components, the browser usually ignores the alpha channel when // drawing to the screen, so unless the alpha is 1, the png image generated diff --git a/o3d/core/cross/gl/texture_gl.cc b/o3d/core/cross/gl/texture_gl.cc index 05acd38..559271e 100644 --- a/o3d/core/cross/gl/texture_gl.cc +++ b/o3d/core/cross/gl/texture_gl.cc @@ -157,20 +157,20 @@ static bool UpdateGLImageFromBitmap(GLenum target, unsigned int mip_height = std::max(1U, bitmap.height() >> level); const unsigned char *mip_data = bitmap.GetFaceMipData(face, level); unsigned int mip_size = - Bitmap::GetBufferSize(mip_width, mip_height, bitmap.format()); + image::ComputeBufferSize(mip_width, mip_height, bitmap.format()); scoped_array<unsigned char> temp_data; if (resize_to_pot) { DCHECK(!Texture::IsCompressedFormat(bitmap.format())); unsigned int pot_width = - std::max(1U, Bitmap::GetPOTSize(bitmap.width()) >> level); + std::max(1U, image::ComputePOTSize(bitmap.width()) >> level); unsigned int pot_height = - std::max(1U, Bitmap::GetPOTSize(bitmap.height()) >> level); - unsigned int pot_size = Bitmap::GetBufferSize(pot_width, pot_height, - bitmap.format()); + std::max(1U, image::ComputePOTSize(bitmap.height()) >> level); + unsigned int pot_size = image::ComputeBufferSize(pot_width, pot_height, + bitmap.format()); temp_data.reset(new unsigned char[pot_size]); - Bitmap::Scale(mip_width, mip_height, bitmap.format(), mip_data, - pot_width, pot_height, temp_data.get(), - Bitmap::GetMipChainSize(pot_width, 1, bitmap.format(), 1)); + image::Scale(mip_width, mip_height, bitmap.format(), mip_data, + pot_width, pot_height, temp_data.get(), + image::ComputePitch(bitmap.format(), pot_width)); mip_width = pot_width; mip_height = pot_height; mip_size = pot_size; @@ -202,8 +202,8 @@ static bool CreateGLImagesAndUpload(GLenum target, unsigned int mip_width = bitmap.width(); unsigned int mip_height = bitmap.height(); if (resize_to_pot) { - mip_width = Bitmap::GetPOTSize(mip_width); - mip_height = Bitmap::GetPOTSize(mip_height); + mip_width = image::ComputePOTSize(mip_width); + mip_height = image::ComputePOTSize(mip_height); } // glCompressedTexImage2D does't accept NULL as a parameter, so we need // to pass in some data. If we can pass in the original pixel data, we'll @@ -213,8 +213,8 @@ static bool CreateGLImagesAndUpload(GLenum target, if (!format && (!bitmap.image_data() || resize_to_pot)) { // Allocate a buffer big enough for the first level which is the biggest // one. - unsigned int size = Bitmap::GetBufferSize(mip_width, mip_height, - bitmap.format()); + unsigned int size = image::ComputeBufferSize(mip_width, mip_height, + bitmap.format()); temp_data.reset(new unsigned char[size]); memset(temp_data.get(), 0, size); } @@ -231,8 +231,8 @@ static bool CreateGLImagesAndUpload(GLenum target, return false; } } else { - unsigned int mip_size = Bitmap::GetBufferSize(mip_width, mip_height, - bitmap.format()); + unsigned int mip_size = image::ComputeBufferSize(mip_width, mip_height, + bitmap.format()); DCHECK(data || temp_data.get()); glCompressedTexImage2DARB(target, i, internal_format, mip_width, mip_height, 0, mip_size, @@ -398,8 +398,8 @@ void Texture2DGL::SetRect(int level, return; } - 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()); if (dst_left + src_width > mip_width || dst_top + src_height > mip_height) { @@ -435,8 +435,7 @@ void Texture2DGL::SetRect(int level, GLenum gl_format = GLFormatFromO3DFormat(format(), &gl_internal_format, &gl_data_type); if (gl_format) { - if ((unsigned)src_pitch == Bitmap::GetMipChainSize(src_width, 1, - format(), 1)) { + if (src_pitch == image::ComputePitch(format(), src_width)) { glTexSubImage2D(GL_TEXTURE_2D, level, dst_left, dst_top, src_width, src_height, @@ -459,7 +458,7 @@ void Texture2DGL::SetRect(int level, glCompressedTexSubImage2D( GL_TEXTURE_2D, level, 0, 0, src_width, src_height, gl_internal_format, - Bitmap::GetMipChainSize(src_width, src_height, format(), 1), + image::ComputeMipChainSize(src_width, src_height, format(), 1), src_data); } } @@ -489,10 +488,9 @@ bool Texture2DGL::Lock(int level, void** data, int* pitch) { backing_bitmap_->Allocate(format(), width(), height(), levels(), false); } *data = backing_bitmap_->GetMipData(level); - unsigned int mip_width = Bitmap::GetMipDimension(level, width()); - + unsigned int mip_width = image::ComputeMipDimension(level, width()); if (!IsCompressed()) { - *pitch = Bitmap::GetMipChainSize(mip_width, 1,format(), 1); + *pitch = image::ComputePitch(format(), mip_width); } else { unsigned blocks_across = (mip_width + 3) / 4; unsigned bytes_per_block = format() == Texture::DXT1 ? 8 : 16; @@ -778,7 +776,7 @@ void TextureCUBEGL::SetRect(TextureCUBE::CubeFace face, return; } - unsigned mip_width = Bitmap::GetMipDimension(level, edge_length()); + unsigned mip_width = image::ComputeMipDimension(level, edge_length()); unsigned mip_height = mip_width; if (dst_left + src_width > mip_width || @@ -817,8 +815,7 @@ void TextureCUBEGL::SetRect(TextureCUBE::CubeFace face, &gl_data_type); int gl_face = kCubemapFaceList[face]; if (gl_format) { - if (static_cast<unsigned>(src_pitch) == - Bitmap::GetMipChainSize(src_width, 1, format(), 1)) { + if (src_pitch == image::ComputePitch(format(), src_width)) { glTexSubImage2D(gl_face, level, dst_left, dst_top, src_width, src_height, @@ -841,7 +838,7 @@ void TextureCUBEGL::SetRect(TextureCUBE::CubeFace face, glCompressedTexSubImage2D( GL_TEXTURE_2D, level, 0, 0, src_width, src_height, gl_internal_format, - Bitmap::GetMipChainSize(src_width, src_height, format(), 1), + image::ComputeMipChainSize(src_width, src_height, format(), 1), src_data); } } @@ -873,9 +870,9 @@ bool TextureCUBEGL::Lock(CubeFace face, int level, void** data, int* pitch) { levels(), true); } *data = backing_bitmap_->GetFaceMipData(face, level); - unsigned int mip_width = Bitmap::GetMipDimension(level, edge_length()); + unsigned int mip_width = image::ComputeMipDimension(level, edge_length()); if (!IsCompressed()) { - *pitch = Bitmap::GetMipChainSize(mip_width, 1,format(), 1); + *pitch = image::ComputePitch(format(), mip_width); } else { unsigned blocks_across = (mip_width + 3) / 4; unsigned bytes_per_block = format() == Texture::DXT1 ? 8 : 16; diff --git a/o3d/core/cross/gl/texture_gl.h b/o3d/core/cross/gl/texture_gl.h index 14d0be7..6b97b7f 100644 --- a/o3d/core/cross/gl/texture_gl.h +++ b/o3d/core/cross/gl/texture_gl.h @@ -45,11 +45,11 @@ #pragma warning(disable : 4311) #endif -#ifdef OS_MACOSX -#include <OpenGL/gl.h> -#else -#include <GL/gl.h> -#endif +//#ifdef OS_MACOSX +//#include <OpenGL/gl.h> +//#else +//#include <GL/gl.h> +//#endif #include "core/cross/bitmap.h" #include "core/cross/texture.h" diff --git a/o3d/core/cross/material_test.cc b/o3d/core/cross/material_test.cc index b5feb1f..24d7a57 100644 --- a/o3d/core/cross/material_test.cc +++ b/o3d/core/cross/material_test.cc @@ -32,9 +32,13 @@ // This file implements unit tests for class Material. -#include "core/cross/client.h" #include "tests/common/win/testing_common.h" #include "core/cross/material.h" +#include "core/cross/object_manager.h" +#include "core/cross/pack.h" +#include "core/cross/semantic_manager.h" +#include "core/cross/service_dependency.h" +#include "core/cross/transformation_context.h" namespace o3d { diff --git a/o3d/core/cross/message_queue.cc b/o3d/core/cross/message_queue.cc index f77d019..7e24767 100644 --- a/o3d/core/cross/message_queue.cc +++ b/o3d/core/cross/message_queue.cc @@ -591,13 +591,14 @@ bool MessageQueue::ProcessUpdateTexture2D(ConnectedClient* client, } unsigned int mip_width = - Bitmap::GetMipDimension(level, texture_object->width()); + image::ComputeMipDimension(level, texture_object->width()); unsigned int mip_height = - Bitmap::GetMipDimension(level, texture_object->height()); + image::ComputeMipDimension(level, texture_object->height()); if (static_cast<unsigned>(number_of_bytes) != - Bitmap::GetMipChainSize(mip_width, mip_height, - texture_object->format(), 1)) { + image::ComputeMipChainSize(mip_width, mip_height, + texture_object->format(), + 1)) { O3D_ERROR(service_locator_) << "texture_size does not match size of texture level (" << offset << " + " << number_of_bytes << " > " << info->size_; @@ -608,7 +609,7 @@ bool MessageQueue::ProcessUpdateTexture2D(ConnectedClient* client, void *target_address = static_cast<char*>(info->mapped_address_) + offset; texture_object->SetRect( level, 0, 0, mip_width, mip_height, target_address, - Bitmap::GetMipChainSize(mip_width, 1, texture_object->format(), 1)); + image::ComputePitch(texture_object->format(), mip_width)); SendBooleanResponse(client->client_handle(), true); return true; diff --git a/o3d/core/cross/message_queue_test.cc b/o3d/core/cross/message_queue_test.cc index 3cefff0..5a0d30f 100644 --- a/o3d/core/cross/message_queue_test.cc +++ b/o3d/core/cross/message_queue_test.cc @@ -33,7 +33,10 @@ // Tests the functionality defined in MessageQueue.cc/h #include "core/cross/message_queue.h" -#include "core/cross/client.h" +#include "core/cross/object_manager.h" +#include "core/cross/pack.h" +#include "core/cross/service_dependency.h" +#include "core/cross/texture.h" #include "core/cross/types.h" #include "tests/common/win/testing_common.h" #include "base/condition_variable.h" diff --git a/o3d/core/cross/pack.cc b/o3d/core/cross/pack.cc index dee5b87..eb19e05 100644 --- a/o3d/core/cross/pack.cc +++ b/o3d/core/cross/pack.cc @@ -121,7 +121,7 @@ ArchiveRequest *Pack::CreateArchiveRequest() { // Creates a Texture object from a file in the current render context format. Texture* Pack::CreateTextureFromFile(const String& uri, const FilePath& filepath, - Bitmap::ImageFileType file_type, + image::ImageFileType file_type, bool generate_mipmaps) { if (!renderer_) { O3D_ERROR(service_locator()) << "No Render Device Available"; @@ -150,7 +150,7 @@ Texture* Pack::CreateTextureFromFile(const String& uri, // FilePath argument. The use of this method should be phased out Texture* Pack::CreateTextureFromFile(const String& uri, const String& filename, - Bitmap::ImageFileType file_type, + image::ImageFileType file_type, bool generate_mipmaps) { FilePath filepath = UTF8ToFilePath(filename); return CreateTextureFromFile(uri, @@ -213,7 +213,7 @@ Texture* Pack::CreateTextureFromRawData(RawData *raw_data, Bitmap::Ref bitmap(new Bitmap(service_locator())); - if (!bitmap->LoadFromRawData(raw_data, Bitmap::UNKNOWN, generate_mips)) { + if (!bitmap->LoadFromRawData(raw_data, image::UNKNOWN, generate_mips)) { O3D_ERROR(service_locator()) << "Failed to load bitmap from raw data \"" << uri << "\""; return NULL; @@ -225,7 +225,7 @@ Texture* Pack::CreateTextureFromRawData(RawData *raw_data, // Create a bitmap object. Bitmap* Pack::CreateBitmap(int width, int height, Texture::Format format) { - DCHECK(Bitmap::CheckImageDimensions(width, height)); + DCHECK(image::CheckImageDimensions(width, height)); Bitmap::Ref bitmap(new Bitmap(service_locator())); if (bitmap.IsNull()) { @@ -251,8 +251,7 @@ Bitmap* Pack::CreateBitmapFromRawData(RawData* raw_data) { << "Failed to create bitmap object."; return NULL; } - if (!bitmap->LoadFromRawData(raw_data, Bitmap::UNKNOWN, - false)) { + if (!bitmap->LoadFromRawData(raw_data, image::UNKNOWN, false)) { O3D_ERROR(service_locator()) << "Failed to load bitmap from raw data."; return NULL; @@ -281,8 +280,8 @@ Texture2D* Pack::CreateTexture2D(int width, } if (enable_render_surfaces) { - if (Bitmap::GetPOTSize(width) != static_cast<unsigned int>(width) || - Bitmap::GetPOTSize(height) != static_cast<unsigned int>(height)) { + if (image::ComputePOTSize(width) != static_cast<unsigned int>(width) || + image::ComputePOTSize(height) != static_cast<unsigned int>(height)) { O3D_ERROR(service_locator()) << "Textures with RenderSurfaces enabled must have power-of-two " "dimensions."; @@ -294,8 +293,7 @@ Texture2D* Pack::CreateTexture2D(int width, width, height, format, - (levels == 0) ? Bitmap::GetMipMapCount(width, - height) : levels, + (levels == 0) ? image::ComputeMipMapCount(width, height) : levels, enable_render_surfaces); if (!texture.IsNull()) { RegisterObject(texture); @@ -322,7 +320,7 @@ TextureCUBE* Pack::CreateTextureCUBE(int edge_length, if (enable_render_surfaces) { - if (Bitmap::GetPOTSize(edge_length) != + if (image::ComputePOTSize(edge_length) != static_cast<unsigned int>(edge_length)) { O3D_ERROR(service_locator()) << "Textures with RenderSurfaces enabled must have power-of-two " @@ -334,8 +332,8 @@ TextureCUBE* Pack::CreateTextureCUBE(int edge_length, TextureCUBE::Ref texture = renderer_->CreateTextureCUBE( edge_length, format, - (levels == 0) ? Bitmap::GetMipMapCount(edge_length, - edge_length) : levels, + (levels == 0) ? image::ComputeMipMapCount(edge_length, + edge_length) : levels, enable_render_surfaces); if (!texture.IsNull()) { RegisterObject(texture); @@ -359,8 +357,8 @@ RenderDepthStencilSurface* Pack::CreateDepthStencilSurface(int width, return NULL; } - if (Bitmap::GetPOTSize(width) != static_cast<unsigned int>(width) || - Bitmap::GetPOTSize(height) != static_cast<unsigned int>(height)) { + if (image::ComputePOTSize(width) != static_cast<unsigned int>(width) || + image::ComputePOTSize(height) != static_cast<unsigned int>(height)) { O3D_ERROR(service_locator()) << "Depth-stencil RenderSurfaces must have power-of-two dimensions."; return NULL; diff --git a/o3d/core/cross/pack.h b/o3d/core/cross/pack.h index 8832f02..9ce91d6 100644 --- a/o3d/core/cross/pack.h +++ b/o3d/core/cross/pack.h @@ -39,32 +39,34 @@ #include <vector> #include <set> -#include "core/cross/bitmap.h" -#include "core/cross/buffer.h" -#include "core/cross/effect.h" #include "core/cross/named_object.h" -#include "core/cross/sampler.h" -#include "core/cross/shape.h" -#include "core/cross/state.h" #include "core/cross/smart_ptr.h" -#include "core/cross/texture.h" #include "core/cross/transform.h" #include "core/cross/types.h" -#include "core/cross/render_node.h" +#include "core/cross/image_utils.h" -namespace o3d { - -// Type definitions ------------------------ +class FilePath; -// Array of object id's -typedef std::vector<Id> IdArray; +namespace o3d { +class Bitmap; class ArchiveRequest; class RawData; +class Texture; +class Texture2D; +class TextureCUBE; class FileRequest; class DrawContext; class IClassManager; class ObjectManager; +class RenderDepthStencilSurface; + +// Type definitions ------------------------ + +// Array of object id's +typedef std::vector<Id> IdArray; +// Array of Bitmaps. +typedef std::vector<Bitmap*> BitmapArray; // A Pack object functions as a container for O3D objects. All objects // inheriting from ObjectBase must be constructed and assigned a pack. The Pack @@ -200,14 +202,14 @@ class Pack : public NamedObject { // A pointer to the texture or NULL if it did not load Texture* CreateTextureFromFile(const String& uri, const FilePath& filepath, - Bitmap::ImageFileType file_type, + image::ImageFileType file_type, bool generate_mipmaps); // This version takes a String |filename| argument instead of the preferred // FilePath argument. The use of this method should be phased out. Texture* CreateTextureFromFile(const String& uri, const String& filename, - Bitmap::ImageFileType file_type, + image::ImageFileType file_type, bool generate_mipmaps); // Creates a new Texture object given a "raw-data" object which must contain @@ -223,16 +225,13 @@ class Pack : public NamedObject { // format: The format of the bitmap. // Returns: // A pointer to the bitmap obejct. - Bitmap* CreateBitmap(int width, int height, Texture::Format format); // Creates a new Bitmap object from RawData. // Parameters: // raw_data: contains the bitmap data in one of the know formats. - // file_type: the format of the bitmap data. If UNKNOW, the file - // type would determined from the extension. // Returns: - // A pointer to the bitmap object. + // An array of pointers to the bitmap objects. Bitmap* CreateBitmapFromRawData(RawData* raw_data); // Creates a new Texture2D object of the specified size and format and diff --git a/o3d/core/cross/pack_test.cc b/o3d/core/cross/pack_test.cc index 0b4732f..a32e2ea 100644 --- a/o3d/core/cross/pack_test.cc +++ b/o3d/core/cross/pack_test.cc @@ -32,8 +32,10 @@ // Tests for functionality in pack.cc/.h. -#include "core/cross/client.h" #include "core/cross/pack.h" +#include "core/cross/object_manager.h" +#include "core/cross/service_dependency.h" +#include "core/cross/transform.h" #include "tests/common/win/testing_common.h" namespace o3d { diff --git a/o3d/core/cross/param_array_test.cc b/o3d/core/cross/param_array_test.cc index 8be5801..8ffa04f 100644 --- a/o3d/core/cross/param_array_test.cc +++ b/o3d/core/cross/param_array_test.cc @@ -32,12 +32,15 @@ // Tests functionality of the ParamArray class -#include "core/cross/client.h" #include "tests/common/win/testing_common.h" #include "core/cross/id_manager.h" #include "core/cross/error.h" +#include "core/cross/object_manager.h" +#include "core/cross/pack.h" #include "core/cross/param_array.h" +#include "core/cross/service_dependency.h" #include "core/cross/standard_param.h" +#include "core/cross/transformation_context.h" namespace o3d { diff --git a/o3d/core/cross/param_object_test.cc b/o3d/core/cross/param_object_test.cc index 8eb03c0..c302877 100644 --- a/o3d/core/cross/param_object_test.cc +++ b/o3d/core/cross/param_object_test.cc @@ -34,9 +34,11 @@ #include <algorithm> #include "core/cross/param_object.h" -#include "core/cross/client.h" #include "tests/common/win/testing_common.h" #include "core/cross/error.h" +#include "core/cross/object_manager.h" +#include "core/cross/pack.h" +#include "core/cross/service_dependency.h" namespace o3d { diff --git a/o3d/core/cross/param_operation_test.cc b/o3d/core/cross/param_operation_test.cc index 2abe123..7906c35 100644 --- a/o3d/core/cross/param_operation_test.cc +++ b/o3d/core/cross/param_operation_test.cc @@ -32,9 +32,12 @@ // This file implements unit tests for various Param operations. -#include "core/cross/client.h" #include "tests/common/win/testing_common.h" #include "core/cross/param_operation.h" +#include "core/cross/error_status.h" +#include "core/cross/object_manager.h" +#include "core/cross/pack.h" +#include "core/cross/service_dependency.h" namespace o3d { diff --git a/o3d/core/cross/param_test.cc b/o3d/core/cross/param_test.cc index 3044acd..433c3d3 100644 --- a/o3d/core/cross/param_test.cc +++ b/o3d/core/cross/param_test.cc @@ -59,6 +59,12 @@ class TestTexture : public Texture { false) {} void* GetTextureHandle() const { return NULL; } virtual const RGBASwizzleIndices& GetABGR32FSwizzleIndices(); + virtual void SetFromBitmap(const Bitmap& bitmap) { + DCHECK(false); + } + virtual void GenerateMips(int source_level, int last_target_level) { + DCHECK(false); + } }; const Texture::RGBASwizzleIndices& TestTexture::GetABGR32FSwizzleIndices() { diff --git a/o3d/core/cross/primitive_test.cc b/o3d/core/cross/primitive_test.cc index 661e0ab..84765f2 100644 --- a/o3d/core/cross/primitive_test.cc +++ b/o3d/core/cross/primitive_test.cc @@ -32,10 +32,12 @@ // This file implements unit tests for class Primitive. -#include "core/cross/client.h" #include "tests/common/win/testing_common.h" #include "core/cross/primitive.h" #include "core/cross/fake_vertex_source.h" +#include "core/cross/object_manager.h" +#include "core/cross/pack.h" +#include "core/cross/service_dependency.h" namespace o3d { diff --git a/o3d/core/cross/ray_intersection_info_test.cc b/o3d/core/cross/ray_intersection_info_test.cc index 9c75fb6..2b6955a 100644 --- a/o3d/core/cross/ray_intersection_info_test.cc +++ b/o3d/core/cross/ray_intersection_info_test.cc @@ -32,9 +32,11 @@ // This file implements unit tests for class RayIntersectionInfo. -#include "core/cross/client.h" #include "tests/common/win/testing_common.h" #include "core/cross/ray_intersection_info.h" +#include "core/cross/object_manager.h" +#include "core/cross/pack.h" +#include "core/cross/service_dependency.h" namespace o3d { diff --git a/o3d/core/cross/render_node_test.cc b/o3d/core/cross/render_node_test.cc index 256e3a2..c0ea865 100644 --- a/o3d/core/cross/render_node_test.cc +++ b/o3d/core/cross/render_node_test.cc @@ -32,8 +32,12 @@ // Tests functionality defined in render_node.cc/h -#include "core/cross/client.h" #include "tests/common/win/testing_common.h" +#include "core/cross/render_node.h" +#include "core/cross/error_status.h" +#include "core/cross/object_manager.h" +#include "core/cross/pack.h" +#include "core/cross/service_dependency.h" namespace o3d { diff --git a/o3d/core/cross/skin_test.cc b/o3d/core/cross/skin_test.cc index ef4cd57..3060b1a 100644 --- a/o3d/core/cross/skin_test.cc +++ b/o3d/core/cross/skin_test.cc @@ -32,12 +32,15 @@ // Tests functionality of the Skin class -#include "core/cross/client.h" #include "tests/common/win/testing_common.h" #include "core/cross/error.h" +#include "core/cross/error_status.h" #include "core/cross/skin.h" #include "core/cross/pointer_utils.h" #include "core/cross/primitive.h" +#include "core/cross/object_manager.h" +#include "core/cross/pack.h" +#include "core/cross/service_dependency.h" #include "import/cross/memory_buffer.h" #include "import/cross/memory_stream.h" #include "serializer/cross/serializer_binary.h" diff --git a/o3d/core/cross/state_set_test.cc b/o3d/core/cross/state_set_test.cc index bd98fb8..6d784e5 100644 --- a/o3d/core/cross/state_set_test.cc +++ b/o3d/core/cross/state_set_test.cc @@ -32,9 +32,11 @@ // This file implements unit tests for class StateSet. -#include "core/cross/client.h" #include "tests/common/win/testing_common.h" #include "core/cross/state_set.h" +#include "core/cross/object_manager.h" +#include "core/cross/pack.h" +#include "core/cross/service_dependency.h" namespace o3d { diff --git a/o3d/core/cross/state_test.cc b/o3d/core/cross/state_test.cc index c9ea3d9..5b7faef 100644 --- a/o3d/core/cross/state_test.cc +++ b/o3d/core/cross/state_test.cc @@ -32,8 +32,10 @@ // This file implements unit tests for class State. -#include "core/cross/client.h" #include "tests/common/win/testing_common.h" +#include "core/cross/object_manager.h" +#include "core/cross/pack.h" +#include "core/cross/service_dependency.h" #include "core/cross/state.h" namespace o3d { diff --git a/o3d/core/cross/stream_bank_test.cc b/o3d/core/cross/stream_bank_test.cc index daee4ca..b8bf67b 100644 --- a/o3d/core/cross/stream_bank_test.cc +++ b/o3d/core/cross/stream_bank_test.cc @@ -32,9 +32,11 @@ // This file implements unit tests for class StreamBank. -#include "core/cross/client.h" #include "core/cross/skin.h" #include "core/cross/stream_bank.h" +#include "core/cross/object_manager.h" +#include "core/cross/pack.h" +#include "core/cross/service_dependency.h" #include "core/cross/pointer_utils.h" #include "core/cross/fake_vertex_source.h" #include "tests/common/win/testing_common.h" diff --git a/o3d/core/cross/texture.cc b/o3d/core/cross/texture.cc index 8f71fd8..2ef6c54 100644 --- a/o3d/core/cross/texture.cc +++ b/o3d/core/cross/texture.cc @@ -33,6 +33,7 @@ // This file contains the definition of the Texture2D and TextureCUBE classes. #include "core/cross/precompile.h" +#include <cmath> #include "core/cross/texture.h" #include "core/cross/bitmap.h" #include "core/cross/renderer.h" @@ -70,7 +71,8 @@ Texture2D::Texture2D(ServiceLocator* service_locator, ClientInfoManager* client_info_manager = service_locator->GetService<ClientInfoManager>(); client_info_manager->AdjustTextureMemoryUsed( - static_cast<int>(Bitmap::GetMipChainSize(width, height, format, levels))); + static_cast<int>(image::ComputeMipChainSize( + width, height, format, levels))); } Texture2D::~Texture2D() { @@ -83,18 +85,22 @@ Texture2D::~Texture2D() { ClientInfoManager* client_info_manager = service_locator()->GetService<ClientInfoManager>(); client_info_manager->AdjustTextureMemoryUsed( - -static_cast<int>(Bitmap::GetMipChainSize(width(), - height(), - format(), - levels()))); + -static_cast<int>(image::ComputeMipChainSize(width(), + height(), + format(), + levels()))); } -void Texture2D::DrawImage(Bitmap* src_img, +void Texture2D::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, int dest_mip) { - DCHECK(src_img->image_data()); + DCHECK(src_img.image_data()); + + if (dest_mip < 0 || dest_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); @@ -103,18 +109,19 @@ void Texture2D::DrawImage(Bitmap* src_img, // source and destination bitmaps. // if src or dest rectangle is out of boundary, // do nothing and return. - if (!Bitmap::AdjustDrawImageBoundary(&src_x, &src_y, - &src_width, &src_height, - src_img->width(), src_img->height(), - &dst_x, &dst_y, - &dst_width, &dst_height, - mip_width, mip_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, + mip_width, mip_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; @@ -122,22 +129,22 @@ void Texture2D::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() == mip_width && src_img->height() == mip_height && - static_cast<unsigned int>(src_width) == src_img->width() && - static_cast<unsigned int>(src_height) == src_img->height() && + src_img.width() == mip_width && src_img.height() == mip_height && + static_cast<unsigned int>(src_width) == src_img.width() && + 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(), - Bitmap::GetMipChainSize(src_img->width(), 1, format(), 1)); + src_img.image_data(), + src_img.GetMipPitch(0)); return; } - 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; @@ -149,15 +156,69 @@ void Texture2D::DrawImage(Bitmap* src_img, return; } - uint8* src_img_data = src_img->image_data(); + uint8* src_img_data = src_img.image_data(); + + image::LanczosScale(src_img_data, 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); +} + +void Texture2D::SetFromBitmap(const Bitmap& bitmap) { + DCHECK(bitmap.image_data()); + if (bitmap.width() != width() || bitmap.height() != height() || + bitmap.format() != format() || bitmap.is_cubemap()) { + O3D_ERROR(service_locator()) + << "bitmap must be the same format and dimensions as texture"; + return; + } + + int last_level = std::min<int>(bitmap.num_mipmaps(), levels()); + for (int level = 0; level < last_level; ++level) { + SetRect(level, 0, 0, + image::ComputeMipDimension(level, width()), + image::ComputeMipDimension(level, height()), + bitmap.GetMipData(level), + bitmap.GetMipPitch(level)); + } +} - Bitmap::LanczosScale(src_img_data, 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); +void Texture2D::GenerateMips(int source_level, int num_levels) { + if (source_level < 0 || source_level >= levels()) { + O3D_ERROR(service_locator()) << "source level out of range"; + return; + } + if (source_level + num_levels >= levels()) { + O3D_ERROR(service_locator()) << "num levels out of range"; + return; + } + + for (int ii = 0; ii < num_levels; ++ii) { + int level = source_level + ii; + Texture2D::LockHelper src_helper(this, level); + Texture2D::LockHelper dst_helper(this, level + 1); + const uint8* src_data = src_helper.GetDataAs<const uint8>(); + if (!src_data) { + O3D_ERROR(service_locator()) + << "could not lock source texture."; + return; + } + uint8* dst_data = dst_helper.GetDataAs<uint8>(); + if (!dst_data) { + O3D_ERROR(service_locator()) + << "could not lock destination texture."; + return; + } + + unsigned int src_width = image::ComputeMipDimension(level, width()); + unsigned int src_height = image::ComputeMipDimension(level, height()); + image::GenerateMipmap(src_width, src_height, format(), + src_data, src_helper.pitch(), + dst_data, dst_helper.pitch()); + } } ObjectBase::Ref Texture2D::Create(ServiceLocator* service_locator) { @@ -206,10 +267,10 @@ TextureCUBE::TextureCUBE(ServiceLocator* service_locator, ClientInfoManager* client_info_manager = service_locator->GetService<ClientInfoManager>(); client_info_manager->AdjustTextureMemoryUsed( - static_cast<int>(Bitmap::GetMipChainSize(edge_length, - edge_length, - format, - levels)) * 6); + static_cast<int>(image::ComputeMipChainSize(edge_length, + edge_length, + format, + levels)) * 6); } TextureCUBE::~TextureCUBE() { @@ -225,23 +286,32 @@ TextureCUBE::~TextureCUBE() { ClientInfoManager* client_info_manager = service_locator()->GetService<ClientInfoManager>(); client_info_manager->AdjustTextureMemoryUsed( - -static_cast<int>(Bitmap::GetMipChainSize(edge_length(), - edge_length(), - format(), - levels()) * 6)); + -static_cast<int>(image::ComputeMipChainSize(edge_length(), + edge_length(), + format(), + levels()) * 6)); } ObjectBase::Ref TextureCUBE::Create(ServiceLocator* service_locator) { return ObjectBase::Ref(); } -void TextureCUBE::DrawImage(Bitmap* src_img, +void TextureCUBE::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, CubeFace dest_face, int dest_mip) { - DCHECK(src_img->image_data()); + DCHECK(src_img.image_data()); + + 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()) << "Mip out of range"; + } unsigned int mip_length = std::max(1, edge_length() >> dest_mip); @@ -249,18 +319,19 @@ void TextureCUBE::DrawImage(Bitmap* src_img, // source and destination bitmaps. // if src or dest rectangle is out of boundary, // do nothing and return true. - if (!Bitmap::AdjustDrawImageBoundary(&src_x, &src_y, - &src_width, &src_height, - src_img->width(), src_img->height(), - &dst_x, &dst_y, - &dst_width, &dst_height, - mip_length, mip_length)) + 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, + mip_length, mip_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()) { + if (src_img.format() != format()) { O3D_ERROR(service_locator()) << "DrawImage does not support " << "different formats."; return; @@ -268,22 +339,22 @@ void TextureCUBE::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() == mip_length && src_img->height() == mip_length && - static_cast<unsigned int>(src_width) == src_img->width() && - static_cast<unsigned int>(src_height) == src_img->height() && + src_img.width() == mip_length && src_img.height() == mip_length && + static_cast<unsigned int>(src_width) == src_img.width() && + static_cast<unsigned int>(src_height) == src_img.height() && static_cast<unsigned int>(dst_width) == mip_length && static_cast<unsigned int>(dst_height) == mip_length) { SetRect(dest_face, dest_mip, 0, 0, mip_length, mip_length, - src_img->image_data(), - Bitmap::GetMipChainSize(src_img->width(), 1, format(), 1)); + src_img.image_data(), + src_img.GetMipPitch(0)); return; } - 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; @@ -295,15 +366,77 @@ void TextureCUBE::DrawImage(Bitmap* src_img, return; } - uint8* src_img_data = src_img->image_data(); + uint8* src_img_data = src_img.image_data(); + + image::LanczosScale(src_img_data, 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); +} + +void TextureCUBE::SetFromBitmap(const Bitmap& bitmap) { + DCHECK(bitmap.image_data()); + if (bitmap.width() != edge_length() || bitmap.height() != edge_length() || + bitmap.format() != format() || !bitmap.is_cubemap()) { + O3D_ERROR(service_locator()) + << "bitmap must be the same format and dimensions as texture"; + return; + } - Bitmap::LanczosScale(src_img_data, 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); + int last_level = std::min<int>(bitmap.num_mipmaps(), levels()); + for (int level = 0; level < last_level; ++level) { + for (int face = FACE_POSITIVE_X; face < NUMBER_OF_FACES; ++face) { + SetRect(static_cast<CubeFace>(face), level, 0, 0, + image::ComputeMipDimension(level, edge_length()), + image::ComputeMipDimension(level, edge_length()), + bitmap.GetFaceMipData(static_cast<CubeFace>(face), level), + bitmap.GetMipPitch(level)); + } + } +} + +void TextureCUBE::GenerateMips(int source_level, int num_levels) { + if (source_level < 0 || source_level >= levels()) { + O3D_ERROR(service_locator()) << "source level out of range"; + return; + } + if (source_level + num_levels >= levels()) { + O3D_ERROR(service_locator()) << "num levels out of range"; + return; + } + + for (int face = FACE_POSITIVE_X; face < NUMBER_OF_FACES; ++face) { + for (int ii = 0; ii < num_levels; ++ii) { + int level = source_level + ii; + TextureCUBE::LockHelper src_helper( + this, static_cast<TextureCUBE::CubeFace>(face), level); + TextureCUBE::LockHelper dst_helper( + this, static_cast<TextureCUBE::CubeFace>(face), level + 1); + const uint8* src_data = src_helper.GetDataAs<const uint8>(); + if (!src_data) { + O3D_ERROR(service_locator()) + << "could not lock source texture."; + return; + } + uint8* dst_data = dst_helper.GetDataAs<uint8>(); + if (!dst_data) { + O3D_ERROR(service_locator()) + << "could not lock destination texture."; + return; + } + + unsigned int src_edge_length = + std::max<unsigned int>(1U, edge_length() >> level); + + image::GenerateMipmap( + src_edge_length, src_edge_length, format(), + src_data, src_helper.pitch(), + dst_data, dst_helper.pitch()); + } + } } TextureCUBE::LockHelper::LockHelper( diff --git a/o3d/core/cross/texture.h b/o3d/core/cross/texture.h index 721a7ec..fdb1b2f 100644 --- a/o3d/core/cross/texture.h +++ b/o3d/core/cross/texture.h @@ -104,11 +104,6 @@ class Texture2D : public Texture { return height_param_->value(); } - // Sets a rectangular region of this texture. - // If the texture is a DXT format, the only acceptable values - // for left, top, width and height are 0, 0, texture->width, texture->height - // - // Parameters: // level: The mipmap level to modify // dst_left: The left edge of the rectangular area to modify. // dst_top: The top edge of the rectangular area to modify. @@ -146,11 +141,17 @@ class Texture2D : public Texture { // 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(Bitmap* source_img, int source_x, int source_y, + void DrawImage(const Bitmap& source_img, int source_x, int source_y, int source_width, int source_height, int dest_x, int dest_y, int dest_width, int dest_height, int dest_mip); + // Sets the contents of the texture from a Bitmap. + virtual void SetFromBitmap(const Bitmap& bitmap); + + // Generates mips. + virtual void GenerateMips(int source_level, int num_levels); + protected: // Returns a pointer to the internal texture data for the given mipmap level. // Lock must be called before the texture data can be modified. @@ -307,11 +308,17 @@ class TextureCUBE : public Texture { // 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(Bitmap* source_img, int source_x, int source_y, + void DrawImage(const Bitmap& source_img, int source_x, int source_y, int source_width, int source_height, int dest_x, int dest_y, int dest_width, int dest_height, CubeFace face, int dest_mip); + // Sets the contents of the texture from a Bitmap. + virtual void SetFromBitmap(const Bitmap& bitmap); + + // Generates mips. + virtual void GenerateMips(int source_level, int num_levels); + protected: // Returns a pointer to the internal texture data for the given face and // mipmap level. diff --git a/o3d/core/cross/texture_base.h b/o3d/core/cross/texture_base.h index 395480c..b8649b9 100644 --- a/o3d/core/cross/texture_base.h +++ b/o3d/core/cross/texture_base.h @@ -40,6 +40,7 @@ namespace o3d { +class Bitmap; class Pack; class Renderer; class RenderSurface; @@ -52,8 +53,6 @@ class Texture : public ParamObject { typedef SmartPointer<Texture> Ref; typedef WeakPointer<Texture> WeakPointerType; - enum Type { TEXTURE_1D, TEXTURE_2D, TEXTURE_3D, TEXTURE_CUBE }; - enum Format { UNKNOWN_FORMAT, XRGB8, // actual format in memory is B G R X @@ -115,6 +114,12 @@ class Texture : public ParamObject { return render_surfaces_enabled_; } + // Sets the contents of the texture from a Bitmap. + virtual void SetFromBitmap(const Bitmap& bitmap) = 0; + + // Generates mips. + virtual void GenerateMips(int source_level, int num_levels) = 0; + // Gets a RGBASwizzleIndices that contains a mapping from // RGBA to the internal format used by the graphics API. virtual const RGBASwizzleIndices& GetABGR32FSwizzleIndices() = 0; diff --git a/o3d/core/cross/texture_base_test.cc b/o3d/core/cross/texture_base_test.cc index 8b13973..a7780d37 100644 --- a/o3d/core/cross/texture_base_test.cc +++ b/o3d/core/cross/texture_base_test.cc @@ -58,11 +58,17 @@ class MockTexture : public Texture { virtual const RGBASwizzleIndices& GetABGR32FSwizzleIndices() {
return swizzle;
- };
+ }
virtual void* GetTextureHandle() const {
return NULL;
- };
+ }
+
+ virtual void SetFromBitmap(const Bitmap& bitmap) {
+ }
+
+ virtual void GenerateMips(int source_level, int num_levels) {
+ }
private:
DISALLOW_COPY_AND_ASSIGN(MockTexture);
diff --git a/o3d/core/cross/texture_test.cc b/o3d/core/cross/texture_test.cc index f14c87f..c9cb3ca 100644 --- a/o3d/core/cross/texture_test.cc +++ b/o3d/core/cross/texture_test.cc @@ -33,7 +33,7 @@ // This file implements unit tests for class Texture.
#include "tests/common/win/testing_common.h"
-#include "core/cross/texture_base.h"
+#include "core/cross/texture.h"
#include "core/cross/object_manager.h"
#include "core/cross/pack.h"
diff --git a/o3d/core/cross/transform_test.cc b/o3d/core/cross/transform_test.cc index 7ee4f23..c6fa213 100644 --- a/o3d/core/cross/transform_test.cc +++ b/o3d/core/cross/transform_test.cc @@ -34,10 +34,13 @@ #include <algorithm> -#include "core/cross/client.h" +#include "core/cross/transform.h" #include "core/cross/shape.h" #include "core/cross/primitive.h" #include "core/cross/material.h" +#include "core/cross/object_manager.h" +#include "core/cross/pack.h" +#include "core/cross/service_dependency.h" #include "tests/common/win/testing_common.h" namespace o3d { diff --git a/o3d/core/cross/tree_traversal_test.cc b/o3d/core/cross/tree_traversal_test.cc index 8ae0874..1cb1f8b 100644 --- a/o3d/core/cross/tree_traversal_test.cc +++ b/o3d/core/cross/tree_traversal_test.cc @@ -32,9 +32,13 @@ // This file implements unit tests for class TreeTraveral. -#include "core/cross/client.h" #include "tests/common/win/testing_common.h" #include "core/cross/tree_traversal.h" +#include "core/cross/object_manager.h" +#include "core/cross/pack.h" +#include "core/cross/service_dependency.h" +#include "core/cross/transformation_context.h" +#include "core/cross/draw_list_manager.h" namespace o3d { diff --git a/o3d/core/win/d3d9/texture_d3d9.cc b/o3d/core/win/d3d9/texture_d3d9.cc index 1fb9c4c..5c93f7b 100644 --- a/o3d/core/win/d3d9/texture_d3d9.cc +++ b/o3d/core/win/d3d9/texture_d3d9.cc @@ -98,8 +98,8 @@ HRESULT CreateTexture2DD3D9(RendererD3D9* renderer, *mip_height = bitmap->height(); if (*resize_to_pot) { - *mip_width = Bitmap::GetPOTSize(*mip_width); - *mip_height = Bitmap::GetPOTSize(*mip_height); + *mip_width = image::ComputePOTSize(*mip_width); + *mip_height = image::ComputePOTSize(*mip_height); } DWORD usage = (enable_render_surfaces) ? D3DUSAGE_RENDERTARGET : 0; @@ -135,7 +135,7 @@ HRESULT CreateTextureCUBED3D9(RendererD3D9* renderer, *resize_to_pot = !renderer->supports_npot() && !bitmap->IsPOT(); *edge_width = bitmap->width(); if (*resize_to_pot) { - *edge_width = Bitmap::GetPOTSize(*edge_width); + *edge_width = image::ComputePOTSize(*edge_width); } DWORD usage = (enable_render_surfaces) ? D3DUSAGE_RENDERTARGET : 0; @@ -220,7 +220,7 @@ void SetTextureRectUncompressed(Texture::Format format, unsigned src_height, uint8* dst, int dst_pitch) { - size_t bytes_per_line = Bitmap::GetMipChainSize(src_width, 1, format, 1); + size_t bytes_per_line = image::ComputePitch(format, src_width); for (unsigned yy = 0; yy < src_height; ++yy) { memcpy(dst, src, bytes_per_line); src += src_pitch; @@ -406,12 +406,12 @@ void Texture2DD3D9::UpdateBackedMipLevel(unsigned int level) { DCHECK_EQ(backing_bitmap_->format(), format()); DCHECK_EQ(backing_bitmap_->num_mipmaps(), levels()); - unsigned int mip_width = Bitmap::GetMipDimension(level, width()); - unsigned int mip_height = Bitmap::GetMipDimension(level, height()); + unsigned int mip_width = image::ComputeMipDimension(level, width()); + unsigned int mip_height = image::ComputeMipDimension(level, height()); unsigned int rect_width = mip_width; unsigned int rect_height = mip_height; - rect_width = std::max(1U, Bitmap::GetPOTSize(width()) >> level); - rect_height = std::max(1U, Bitmap::GetPOTSize(height()) >> level); + rect_width = std::max(1U, image::ComputePOTSize(width()) >> level); + rect_height = std::max(1U, image::ComputePOTSize(height()) >> level); RECT rect = {0, 0, rect_width, rect_height}; D3DLOCKED_RECT out_rect = {0}; @@ -427,15 +427,15 @@ void Texture2DD3D9::UpdateBackedMipLevel(unsigned int level) { const uint8 *mip_data = backing_bitmap_->GetMipData(level); if (resize_to_pot_) { - Bitmap::Scale(mip_width, mip_height, format(), mip_data, - rect_width, rect_height, - static_cast<uint8 *>(out_rect.pBits), - out_rect.Pitch); + image::Scale(mip_width, mip_height, format(), mip_data, + rect_width, rect_height, + static_cast<uint8 *>(out_rect.pBits), + out_rect.Pitch); } else { if (!IsCompressed()) { SetTextureRectUncompressed( format(), mip_data, - Bitmap::GetMipChainSize(mip_width, 1, format(), 1), + image::ComputePitch(format(), mip_width), mip_width, mip_height, dst, out_rect.Pitch); } else { @@ -500,8 +500,8 @@ void Texture2DD3D9::SetRect(int level, return; } - 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()); if (dst_left + src_width > mip_width || dst_top + src_height > mip_height) { @@ -569,9 +569,9 @@ bool Texture2DD3D9::Lock(int level, void** texture_data, int* pitch) { if (resize_to_pot_) { DCHECK(backing_bitmap_->image_data()); *texture_data = backing_bitmap_->GetMipData(level); - unsigned int mip_width = Bitmap::GetMipDimension(level, width()); - unsigned int mip_height = Bitmap::GetMipDimension(level, height()); - *pitch = Bitmap::GetMipChainSize(mip_width, 1, format(), 1); + unsigned int mip_width = image::ComputeMipDimension(level, width()); + unsigned int mip_height = image::ComputeMipDimension(level, height()); + *pitch = image::ComputePitch(format(), mip_width); locked_levels_ |= 1 << level; return true; } else { @@ -746,7 +746,7 @@ void TextureCUBED3D9::UpdateBackedMipLevel(TextureCUBE::CubeFace face, unsigned int mip_edge = std::max(1, edge_length() >> level); unsigned int rect_edge = mip_edge; if (resize_to_pot_) { - rect_edge = std::max(1U, Bitmap::GetPOTSize(edge_length()) >> level); + rect_edge = std::max(1U, image::ComputePOTSize(edge_length()) >> level); } RECT rect = {0, 0, rect_edge, rect_edge}; @@ -764,15 +764,15 @@ void TextureCUBED3D9::UpdateBackedMipLevel(TextureCUBE::CubeFace face, const uint8 *mip_data = backing_bitmap_->GetFaceMipData(face, level); if (resize_to_pot_) { - Bitmap::Scale(mip_edge, mip_edge, format(), mip_data, - rect_edge, rect_edge, - static_cast<uint8 *>(out_rect.pBits), - out_rect.Pitch); + image::Scale(mip_edge, mip_edge, format(), mip_data, + rect_edge, rect_edge, + static_cast<uint8 *>(out_rect.pBits), + out_rect.Pitch); } else { if (!IsCompressed()) { SetTextureRectUncompressed( format(), mip_data, - Bitmap::GetMipChainSize(mip_edge, 1, format(), 1), + image::ComputePitch(format(), mip_edge), mip_edge, mip_edge, dst, out_rect.Pitch); } else { @@ -847,7 +847,7 @@ void TextureCUBED3D9::SetRect(TextureCUBE::CubeFace face, return; } - unsigned mip_width = Bitmap::GetMipDimension(level, edge_length()); + unsigned mip_width = image::ComputeMipDimension(level, edge_length()); unsigned mip_height = mip_width; if (dst_left + src_width > mip_width || @@ -918,9 +918,9 @@ bool TextureCUBED3D9::Lock( if (resize_to_pot_) { DCHECK(backing_bitmap_->image_data()); *texture_data = backing_bitmap_->GetFaceMipData(face, level); - unsigned int mip_width = Bitmap::GetMipDimension(level, edge_length()); + unsigned int mip_width = image::ComputeMipDimension(level, edge_length()); unsigned int mip_height = mip_width; - *pitch = Bitmap::GetMipChainSize(mip_width, 1, format(), 1); + *pitch = image::ComputePitch(format(), mip_width); locked_levels_[face] |= 1 << level; return true; } else { diff --git a/o3d/import/cross/collada.cc b/o3d/import/cross/collada.cc index 0e88ae2..e04c32a 100644 --- a/o3d/import/cross/collada.cc +++ b/o3d/import/cross/collada.cc @@ -49,6 +49,7 @@ #include "core/cross/pack.h" #include "core/cross/param_operation.h" #include "core/cross/primitive.h" +#include "core/cross/sampler.h" #include "core/cross/skin.h" #include "core/cross/stream.h" #include "import/cross/collada.h" @@ -1686,7 +1687,7 @@ Texture* Collada::BuildTextureFromImage(FCDImage* image) { tex = Texture::Ref( pack_->CreateTextureFromFile(FilePathToUTF8(uri), file_path, - Bitmap::UNKNOWN, + image::UNKNOWN, options_.generate_mipmaps)); if (tex) { const fstring name(image->GetName()); diff --git a/o3d/import/cross/gz_compressor_test.cc b/o3d/import/cross/gz_compressor_test.cc index cd39499..3ca59d0 100644 --- a/o3d/import/cross/gz_compressor_test.cc +++ b/o3d/import/cross/gz_compressor_test.cc @@ -33,7 +33,6 @@ #include <sys/stat.h> #include <string> -#include "core/cross/client.h" #include "import/cross/memory_stream.h" #include "import/cross/memory_buffer.h" #include "import/cross/gz_decompressor.h" diff --git a/o3d/import/cross/gz_decompressor_test.cc b/o3d/import/cross/gz_decompressor_test.cc index ec79ad9..f2d1212 100644 --- a/o3d/import/cross/gz_decompressor_test.cc +++ b/o3d/import/cross/gz_decompressor_test.cc @@ -33,7 +33,6 @@ #include <sys/stat.h> #include <algorithm> -#include "core/cross/client.h" #include "import/cross/gz_decompressor.h" #include "import/cross/memory_buffer.h" #include "tests/common/win/testing_common.h" diff --git a/o3d/import/cross/precompile.h b/o3d/import/cross/precompile.h index e1daa2b..20671d6 100644 --- a/o3d/import/cross/precompile.h +++ b/o3d/import/cross/precompile.h @@ -42,6 +42,13 @@ #ifdef __cplusplus +#if defined(RENDERER_GL) +#include <GL/glew.h> +#if defined(OS_WIN) +#include <GL/wglew.h> +#endif +#endif // defined(RENDERER_GL) + #include <Cg/cg.h> #include <Cg/cgGL.h> #include <FCollada.h> diff --git a/o3d/import/cross/raw_data.h b/o3d/import/cross/raw_data.h index 1929b1a..092c800 100644 --- a/o3d/import/cross/raw_data.h +++ b/o3d/import/cross/raw_data.h @@ -46,8 +46,6 @@ #include "core/cross/param.h" #include "core/cross/types.h" -class FilePath; - namespace o3d { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/o3d/import/cross/raw_data_test.cc b/o3d/import/cross/raw_data_test.cc index 4399cd9..b4c5f86 100644 --- a/o3d/import/cross/raw_data_test.cc +++ b/o3d/import/cross/raw_data_test.cc @@ -32,7 +32,6 @@ // Tests functionality of the RawData class -#include "core/cross/client.h" #include "tests/common/win/testing_common.h" #include "utils/cross/file_path_utils.h" #include "base/file_path.h" diff --git a/o3d/import/cross/tar_generator_test.cc b/o3d/import/cross/tar_generator_test.cc index 5fdec8a..1659e98 100644 --- a/o3d/import/cross/tar_generator_test.cc +++ b/o3d/import/cross/tar_generator_test.cc @@ -30,7 +30,6 @@ */ -#include "core/cross/client.h" #include "import/cross/memory_buffer.h" #include "import/cross/memory_stream.h" #include "import/cross/tar_generator.h" diff --git a/o3d/import/cross/tar_processor_test.cc b/o3d/import/cross/tar_processor_test.cc index 2e1f0bd..4da0f97 100644 --- a/o3d/import/cross/tar_processor_test.cc +++ b/o3d/import/cross/tar_processor_test.cc @@ -30,7 +30,6 @@ */ -#include "core/cross/client.h" #include "import/cross/targz_processor.h" #include "tests/common/win/testing_common.h" #include "tests/common/cross/test_utils.h" diff --git a/o3d/import/cross/targz_generator_test.cc b/o3d/import/cross/targz_generator_test.cc index 7911387..e3331f3 100644 --- a/o3d/import/cross/targz_generator_test.cc +++ b/o3d/import/cross/targz_generator_test.cc @@ -33,7 +33,6 @@ #include <string> #include "base/file_util.h" -#include "core/cross/client.h" #include "import/cross/memory_stream.h" #include "import/cross/targz_generator.h" #include "tests/common/cross/test_utils.h" diff --git a/o3d/import/cross/targz_processor_test.cc b/o3d/import/cross/targz_processor_test.cc index a351ec8..37d70a4 100644 --- a/o3d/import/cross/targz_processor_test.cc +++ b/o3d/import/cross/targz_processor_test.cc @@ -30,7 +30,6 @@ */ -#include "core/cross/client.h" #include "import/cross/targz_processor.h" #include "tests/common/win/testing_common.h" diff --git a/o3d/plugin/cross/async_loading.cc b/o3d/plugin/cross/async_loading.cc index f38ef5d..dfcbcfe 100644 --- a/o3d/plugin/cross/async_loading.cc +++ b/o3d/plugin/cross/async_loading.cc @@ -90,8 +90,8 @@ class LoadTextureURLCallback : public StreamManager::FinishedCallback { // Unfortunately, TGA and DDS don't have standard MIME type, so we may // have to rely on the filename, or let the image loader figure it out by // itself (by trying every possible type). - Bitmap::ImageFileType image_type = - Bitmap::GetFileTypeFromMimeType(mime_type.c_str()); + o3d::image::ImageFileType image_type = + o3d::image::GetFileTypeFromMimeType(mime_type.c_str()); texture = Texture::Ref( request_->pack()->CreateTextureFromFile( request_->uri(), diff --git a/o3d/plugin/cross/o3d_glue.h b/o3d/plugin/cross/o3d_glue.h index c318ea5..6143db2 100644 --- a/o3d/plugin/cross/o3d_glue.h +++ b/o3d/plugin/cross/o3d_glue.h @@ -60,6 +60,7 @@ #include "core/cross/evaluation_counter.h" #include "core/cross/class_manager.h" #include "core/cross/client_info.h" +#include "core/cross/cursor.h" #include "core/cross/features.h" #include "core/cross/object_manager.h" #include "core/cross/error.h" diff --git a/o3d/plugin/idl/bitmap.idl b/o3d/plugin/idl/bitmap.idl index 066ca5a..a223f43 100644 --- a/o3d/plugin/idl/bitmap.idl +++ b/o3d/plugin/idl/bitmap.idl @@ -33,49 +33,29 @@ namespace o3d {
%[
-Bitmap provides an interface for basic image operations on bitmap,
-including scale and crop. The contents of bitmap can be created from
-RawData via pack.createBitmapFromRawData(), and also can be transfered
-to mip of a Texure2D or a specific face of TextureCUBE via methods
-in Texture.
+ Bitmap provides an interface for basic image operations on bitmap,
+ including scale and crop. The contents of bitmap can be created from
+ RawData via pack.createBitmapFromRawData(), and also can be transfered
+ to mip of a Texure2D or a specific face of TextureCUBE via methods
+ in Texture.
%]
[nocpp, include="core/cross/bitmap.h"]
class Bitmap : ParamObject {
%[
- enum ImageFileType {
- \li UNKNOWN, Image type unknown.
- \li TGA, image in TGA format.
- \li JPEG, image in JPEG format.
- \li PNG, image in PNG format.
- \li DDS, image in DDS format.
- };
+ Flips a bitmap vertically in place.
%]
- enum ImageFileType {
- UNKNOWN,
- TGA,
- JPEG,
- PNG,
- DDS
- };
+ void FlipVertically();
%[
- Copy pixels from source bitmap. Scales if the width and height of source
- and dest do not match.
- \param source_img source bitmap which would be drawn.
- \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 to draw.
- \param dest_height height of the dest image to draw.
+ Generates mip maps from the source level to lower levels.
+
+ You can currently only use this on XRGB8 and ARGB8 textures.
+
+ \param source_level The level to use as the source of the mips.
+ \param num_levels The number of levels to generate below the source level.
%]
- void DrawImage(Bitmap source_img, int source_x, int source_y,
- int source_width, int source_height,
- int dest_x, int dest_y,
- int dest_width, int dest_height);
+ void GenerateMips(int source_level, int num_levels);
%[
The width of the bitmap (read only).
@@ -87,6 +67,20 @@ class Bitmap : ParamObject { %]
[getter] int height_;
+ %[
+ The format of the bitmap (read only).
+ %]
+ [getter] Texture::Format format_;
+
+ %[
+ Number mip-maps (read only)
+ %]
+ [getter] int num_mipmaps_;
+
+ %[
+ Whether or not the bitmap is a cubemap.
+ %]
+ [getter] bool is_cubemap_;
}; // Bitmap
} // namespace o3d
diff --git a/o3d/plugin/idl/texture.idl b/o3d/plugin/idl/texture.idl index 763518e..54b705c 100644 --- a/o3d/plugin/idl/texture.idl +++ b/o3d/plugin/idl/texture.idl @@ -107,6 +107,29 @@ namespace o3d { True of all the alpha values in the texture are 1.0 %] [getter, getter, setter] bool alpha_is_one; + + %[ + Generates Mips. + \param source_level the mip to use as the source. + \param num_levels the number of mips from the source to generate. + %] + void GenerateMips(int source_level, int num_levels); + + %[ + Sets the content of the texture to the content of the bitmap. The texture + and the bitmap must be the same dimensions and the same format. + + \param bitmap The bitmap to copy data from. + %] + [userglue] + void SetFromBitmap(Bitmap bitmap); + + [verbatim=cpp_glue] %{ + void userglue_method_SetFromBitmap(o3d::Texture* self, + o3d::Bitmap* bitmap) { + self->SetFromBitmap(*bitmap); + } + %} }; // Texture %[ @@ -209,10 +232,25 @@ namespace o3d { \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, int source_width, int source_height, int dest_x, int dest_y, int dest_width, int dest_height, int dest_mip); + + [verbatim=cpp_glue] %{ + void userglue_method_DrawImage( + o3d::Texture2D* self, + o3d::Bitmap* source_img, int source_x, int source_y, + int source_width, int source_height, + int dest_x, int dest_y, + int dest_width, int dest_height, int dest_mip) { + self->DrawImage(*source_img, source_x, source_y, + source_width, source_height, + dest_x, dest_y, + dest_width, dest_height, dest_mip); + } +%} }; // Texture2D @@ -317,11 +355,27 @@ namespace o3d { \param face on which face the sourceImg would be drawn. \param dest_mip on which mip level the sourceImg would be drawn. %] + [userglue] void DrawImage(Bitmap source_img, int source_x, int source_y, int source_width, int source_height, int dest_x, int dest_y, int dest_width, int dest_height, CubeFace face, int dest_mip); + + [verbatim=cpp_glue] %{ + void userglue_method_DrawImage( + o3d::TextureCUBE* self, + o3d::Bitmap* source_img, int source_x, int source_y, + int source_width, int source_height, + int dest_x, int dest_y, + int dest_width, int dest_height, + o3d::TextureCUBE::CubeFace dest_face, int dest_mip) { + self->DrawImage(*source_img, source_x, source_y, + source_width, source_height, + dest_x, dest_y, + dest_width, dest_height, dest_face, dest_mip); + } + %} }; // TextureCUBE } // namespace o3d diff --git a/o3d/samples/bitmap-draw-image.html b/o3d/samples/bitmap-draw-image.html index 66471f1..1e3bac0 100644 --- a/o3d/samples/bitmap-draw-image.html +++ b/o3d/samples/bitmap-draw-image.html @@ -113,8 +113,6 @@ function makeShape(texture, effect) { // Make a transform for each quad.
var transform = g_pack.createObject('Transform');
-
- transform.translate(0, 0, 0);
transform.scale(hScale, 1, vScale);
transform.addShape(myShape);
transform.parent = g_client.root;
@@ -184,34 +182,28 @@ function initStep2(clientElements) { var bitmap2 = g_pack.createBitmapFromRawData(rawdata2);
var rawdata_hi = archiveInfo.getFileByURI('hi.jpg', true);
var bitmap_hi = g_pack.createBitmapFromRawData(rawdata_hi);
- var bitmap = g_pack.createBitmap(300, 300, g_o3d.Texture.XRGB8);
+ var texture = g_pack.createTexture2D(300, 300, g_o3d.Texture.XRGB8, 0,
+ false);
// draw image on bitmap.
// scale down on top left corner.
- bitmap.drawImage(bitmap1, 0, 0, 300, 300, 0, 0, 150, 150);
+ texture.drawImage(bitmap1, 0, 0, 300, 300, 0, 0, 150, 150, 0);
// scale up on top right corner.
- bitmap.drawImage(bitmap1, 0, 0, 100, 100, 150, 0, 150, 150);
+ texture.drawImage(bitmap1, 0, 0, 100, 100, 150, 0, 150, 150, 0);
// flip and draw part of the img on bottom left.
- bitmap.drawImage(bitmap1, 150, 0, 150, 150, 149, 299, -150, -150);
+ texture.drawImage(bitmap1, 150, 0, 150, 150, 149, 299, -150, -150, 0);
// draw out of boundary.
- bitmap.drawImage(bitmap1, 0, 0, 300, 300, 150, 150, 300, 300);
+ texture.drawImage(bitmap1, 0, 0, 300, 300, 150, 150, 300, 300, 0);
// draw o3d.
- bitmap.drawImage(bitmap_hi, 0, 0, 100, 50, 100, 125, 100, 50);
-
- var texture = g_pack.createTexture2D(300, 300, g_o3d.Texture.XRGB8,
- 0, false);
- if (texture) {
- // draw image on texture.
- texture.drawImage(bitmap, 0, 0, 300, 300, 0, 0, 300, 300, 0);
+ texture.drawImage(bitmap_hi, 0, 0, 100, 50, 100, 125, 100, 50, 0);
- // 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);
+ // 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);
- makeShape(texture, effect);
- }
+ makeShape(texture, effect);
}
}
- o3djs.event.addEventListener(o3dElement, 'wheel', scrollMe);
+ o3djs.event.addEventListener(o3dElement, 'wheel', scrollMe);
}
function scrollMe(e) {
diff --git a/o3d/tests/build.scons b/o3d/tests/build.scons index c9bc853..706cefd 100644 --- a/o3d/tests/build.scons +++ b/o3d/tests/build.scons @@ -203,6 +203,7 @@ tests = [ 'core/cross/field_test.cc', 'core/cross/float_n_test.cc', 'core/cross/function_test.cc', + 'core/cross/image_utils_test.cc', 'core/cross/material_test.cc', 'core/cross/math_utilities_test.cc', 'core/cross/matrix4_axis_rotation_test.cc', |