summaryrefslogtreecommitdiffstats
path: root/o3d
diff options
context:
space:
mode:
authormaf@google.com <maf@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-12 23:22:09 +0000
committermaf@google.com <maf@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-12 23:22:09 +0000
commit7aaa8425b4700dd7427e1e146b090ff694fea0fc (patch)
treea91065f3ab5446d933811034e31903633802efcb /o3d
parentc74e80bdba0edd3e4f30b2316579cfb88d17ad9f (diff)
downloadchromium_src-7aaa8425b4700dd7427e1e146b090ff694fea0fc.zip
chromium_src-7aaa8425b4700dd7427e1e146b090ff694fea0fc.tar.gz
chromium_src-7aaa8425b4700dd7427e1e146b090ff694fea0fc.tar.bz2
Lots of changes needed to build with GCC in Chrome.
Review URL: http://codereview.chromium.org/164364 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@23246 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d')
-rw-r--r--o3d/core/cross/gl/texture_gl.cc2
-rw-r--r--o3d/core/cross/image_utils.cc1645
-rw-r--r--o3d/core/cross/message_queue.cc5
-rw-r--r--o3d/core/cross/renderer.cc6
-rw-r--r--o3d/utils/cross/base64_test.cc10
5 files changed, 836 insertions, 832 deletions
diff --git a/o3d/core/cross/gl/texture_gl.cc b/o3d/core/cross/gl/texture_gl.cc
index 1c57288..31bb464 100644
--- a/o3d/core/cross/gl/texture_gl.cc
+++ b/o3d/core/cross/gl/texture_gl.cc
@@ -217,7 +217,7 @@ static bool CreateGLImages(GLenum target,
temp_data.reset(new uint8[size]);
memset(temp_data.get(), 0, size);
- for (unsigned int i = 0; i < levels; ++i) {
+ for (int i = 0; i < levels; ++i) {
if (gl_format) {
glTexImage2D(target, i, internal_format, mip_width, mip_height,
0, gl_format, type, temp_data.get());
diff --git a/o3d/core/cross/image_utils.cc b/o3d/core/cross/image_utils.cc
index 8c1eecb..ca1eec4 100644
--- a/o3d/core/cross/image_utils.cc
+++ b/o3d/core/cross/image_utils.cc
@@ -1,821 +1,824 @@
-
-/*
- * Copyright 2009, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-
-// This file contains the functions to help with images.
-
-// The precompiled header must appear before anything else.
-#include "core/cross/precompile.h"
-
-#include "core/cross/image_utils.h"
-#include "core/cross/pointer_utils.h"
-#include "core/cross/math_utilities.h"
-
-namespace o3d {
-namespace image {
-
-// Computes the size of the buffer containing a an image, given its width,
-// height and format.
-size_t ComputeBufferSize(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.
-size_t ComputeMipChainSize(unsigned int base_width,
- unsigned int base_height,
- Texture::Format format,
- unsigned int num_mipmaps) {
- DCHECK(CheckImageDimensions(base_width, base_height));
- size_t 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 += ComputeBufferSize(mip_width, mip_height, format);
- mip_width = std::max(1U, mip_width >> 1);
- mip_height = std::max(1U, mip_height >> 1);
- }
- return total_size;
-}
-
-// Scales the image using basic point filtering.
-bool 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 = ComputePOTSize(width);
- unsigned int pot_height = ComputePOTSize(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);
-}
-
-unsigned int GetNumComponentsForFormat(o3d::Texture::Format format) {
- switch (format) {
- case o3d::Texture::XRGB8:
- case o3d::Texture::ARGB8:
- case o3d::Texture::ABGR16F:
- case o3d::Texture::ABGR32F:
- return 4;
- case o3d::Texture::R32F:
- return 1;
- case o3d::Texture::DXT1:
- case o3d::Texture::DXT3:
- case o3d::Texture::DXT5:
- case o3d::Texture::UNKNOWN_FORMAT:
- break;
- }
- return 0;
-}
-
-bool CanMakeMips(o3d::Texture::Format format) {
- return GetNumComponentsForFormat(format) != 0;
-}
-
-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);
-}
-
-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 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;
-}
-
-
-namespace {
-
-// utility function called in AdjustDrawImageBoundary.
-// help to adjust a specific dimension,
-// if start point or ending point is out of boundary.
-bool AdjustDrawImageBoundHelper(int* src_a, int* dest_a,
- int* src_length, int* dest_length,
- int src_bmp_length) {
- if (*src_length == 0 || *dest_length == 0)
- 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;
- }
-
- return true;
-}
-
-void 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);
- }
- }
- }
- }
-}
-
-// 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.
-template <typename OriginalType,
- typename WorkType,
- WorkType convert_to_work(OriginalType value),
- OriginalType convert_to_original(WorkType)>
-void FilterTexel(unsigned int x,
- unsigned int y,
- unsigned int dst_width,
- unsigned int dst_height,
- void *dst_data,
- int dst_pitch,
- unsigned int src_width,
- unsigned int src_height,
- const void *src_data,
- int src_pitch,
- unsigned int components) {
- DCHECK(image::CheckImageDimensions(src_width, src_height));
- DCHECK(image::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);
- DCHECK_LE(static_cast<int>(src_width), src_pitch);
- DCHECK_LE(static_cast<int>(dst_width), dst_pitch);
-
- const OriginalType* src = static_cast<const OriginalType*>(src_data);
- OriginalType* dst = static_cast<OriginalType*>(dst_data);
-
- DCHECK_EQ(src_pitch % (components * sizeof(*src)), 0);
- DCHECK_EQ(dst_pitch % (components * sizeof(*dst)), 0);
-
- src_pitch /= components;
- dst_pitch /= components;
- // the texel at (x, y) represents the square of texture coordinates
- // [x/dst_w, (x+1)/dst_w) x [y/dst_h, (y+1)/dst_h).
- // This takes contributions from the texels:
- // [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);
- WorkType 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);
- WorkType contrib = static_cast<WorkType>(x_contrib * y_contrib);
- for (unsigned int c = 0; c < components; ++c) {
- accum[c] += contrib *
- convert_to_work(src[(src_y * src_pitch + src_x) * components + c]);
- }
- }
- }
- for (unsigned int c = 0; c < components; ++c) {
- WorkType value = accum[c] / static_cast<WorkType>(src_height * src_width);
- dst[(y * dst_pitch + x) * components + c] = convert_to_original(value);
- }
-}
-
-template <typename OriginalType,
- typename WorkType,
- typename FilterType,
- WorkType convert_to_work(OriginalType value),
- OriginalType convert_from_work(WorkType),
- FilterType convert_to_filter(OriginalType value),
- OriginalType convert_from_filter(FilterType)>
-void GenerateMip(unsigned int components,
- unsigned int src_width,
- unsigned int src_height,
- const void *src_data,
- int src_pitch,
- void *dst_data,
- int dst_pitch) {
- unsigned int mip_width = std::max(1U, src_width >> 1);
- unsigned int mip_height = std::max(1U, src_height >> 1);
-
- const OriginalType* src = static_cast<const OriginalType*>(src_data);
- OriginalType* dst = static_cast<OriginalType*>(dst_data);
-
- if (mip_width * 2 == src_width && mip_height * 2 == src_height) {
- DCHECK_EQ(src_pitch % (components * sizeof(*src)), 0);
- DCHECK_EQ(dst_pitch % (components * sizeof(*dst)), 0);
- src_pitch /= components;
- dst_pitch /= components;
- // Easy case: every texel maps to exactly 4 texels in the previous level.
- for (unsigned int y = 0; y < mip_height; ++y) {
- for (unsigned int x = 0; x < mip_width; ++x) {
- for (unsigned int c = 0; c < components; ++c) {
- // Average the 4 texels.
- unsigned int offset = (y * 2 * src_pitch + x * 2) * components + c;
- WorkType value = convert_to_work(src[offset]); // (2x, 2y)
- value += convert_to_work(src[offset + components]); // (2x+1, 2y)
- value += convert_to_work(src[offset + src_width * components]);
- // (2x, 2y+1)
- value += convert_to_work(src[offset + (src_width + 1) * components]);
- // (2x+1, 2y+1)
- dst[(y * dst_pitch + x) * components + c] =
- convert_from_work(value / static_cast<WorkType>(4));
- }
- }
- }
- } else {
- for (unsigned int y = 0; y < mip_height; ++y) {
- for (unsigned int x = 0; x < mip_width; ++x) {
- FilterTexel<OriginalType,
- FilterType,
- convert_to_filter,
- convert_from_filter>(
- x, y, mip_width, mip_height, dst_data, dst_pitch,
- src_width, src_height, src_data, src_pitch, components);
- }
- }
- }
-}
-
-uint32 UInt8ToUInt32(uint8 value) {
- return static_cast<uint32>(value);
-};
-
-uint8 UInt32ToUInt8(uint32 value) {
- return static_cast<uint8>(value);
-};
-
-uint64 UInt8ToUInt64(uint8 value) {
- return static_cast<uint64>(value);
-};
-
-uint8 UInt64ToUInt8(uint64 value) {
- return static_cast<uint8>(value);
-};
-
-float FloatToFloat(float value) {
- return value;
-}
-
-double FloatToDouble(float value) {
- return static_cast<double>(value);
-}
-
-float DoubleToFloat(double value) {
- return static_cast<float>(value);
-}
-
-float HalfToFloat(uint16 value) {
- return Vectormath::Aos::HalfToFloat(value);
-}
-
-uint16 FloatToHalf(float value) {
- return Vectormath::Aos::FloatToHalf(value);
-}
-
-double HalfToDouble(uint16 value) {
- return static_cast<double>(Vectormath::Aos::HalfToFloat(value));
-}
-
-uint16 DoubleToHalf(double value) {
- return Vectormath::Aos::FloatToHalf(static_cast<float>(value));
-}
-
-} // anonymous namespace
-
-// Adjust boundaries when using DrawImage function in bitmap or texture.
-bool AdjustDrawImageBoundary(int* src_x, int* src_y,
- int* src_width, int* src_height,
- int src_bmp_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;
-}
-
-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 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);
-}
-
-bool GenerateMipmap(unsigned int src_width,
- unsigned int src_height,
- Texture::Format format,
- const uint8 *src_data,
- int src_pitch,
- uint8 *dst_data,
- int dst_pitch) {
- unsigned int components = GetNumComponentsForFormat(format);
- if (components == 0) {
- DLOG(ERROR) << "Mip-map generation not supported for format: " << format;
- return false;
- }
-
- switch (format) {
- case Texture::ARGB8:
- case Texture::XRGB8:
- GenerateMip<uint8, uint32, uint64,
- UInt8ToUInt32, UInt32ToUInt8,
- UInt8ToUInt64, UInt64ToUInt8>(
- components, src_width, src_height, src_data, src_pitch,
- dst_data, dst_pitch);
- break;
- case Texture::ABGR16F:
- GenerateMip<uint16, float, double,
- HalfToFloat, FloatToHalf,
- HalfToDouble, DoubleToHalf>(
- components, src_width, src_height, src_data, src_pitch,
- dst_data, dst_pitch);
- break;
- case Texture::ABGR32F:
- case Texture::R32F:
- GenerateMip<float, float, double,
- FloatToFloat, FloatToFloat,
- FloatToDouble, DoubleToFloat>(
- components, src_width, src_height, src_data, src_pitch,
- dst_data, dst_pitch);
- break;
- }
- return true;
-}
-
-ImageFileType 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;
- }
-}
-
-namespace {
-
-struct MimeTypeToFileType {
- const char *mime_type;
- ImageFileType file_type;
-};
-
-const MimeTypeToFileType mime_type_map[] = {
- {"image/png", PNG},
- {"image/jpeg", JPEG},
- // No official MIME type for TGA or DDS.
-};
-
-} // anonymous namespace
-
-ImageFileType GetFileTypeFromMimeType(const char *mime_type) {
- for (unsigned int i = 0u; i < arraysize(mime_type_map); ++i) {
- if (!strcmp(mime_type, mime_type_map[i].mime_type))
- return mime_type_map[i].file_type;
- }
- return UNKNOWN;
-}
-
-void 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 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;
- }
-}
-
-} // namespace image
-} // namespace o3d
-
-
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file contains the functions to help with images.
+
+// The precompiled header must appear before anything else.
+#include "core/cross/precompile.h"
+
+#include "core/cross/image_utils.h"
+#include "core/cross/pointer_utils.h"
+#include "core/cross/math_utilities.h"
+
+namespace o3d {
+namespace image {
+
+// Computes the size of the buffer containing a an image, given its width,
+// height and format.
+size_t ComputeBufferSize(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.
+size_t ComputeMipChainSize(unsigned int base_width,
+ unsigned int base_height,
+ Texture::Format format,
+ unsigned int num_mipmaps) {
+ DCHECK(CheckImageDimensions(base_width, base_height));
+ size_t 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 += ComputeBufferSize(mip_width, mip_height, format);
+ mip_width = std::max(1U, mip_width >> 1);
+ mip_height = std::max(1U, mip_height >> 1);
+ }
+ return total_size;
+}
+
+// Scales the image using basic point filtering.
+bool 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 = ComputePOTSize(width);
+ unsigned int pot_height = ComputePOTSize(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);
+}
+
+unsigned int GetNumComponentsForFormat(o3d::Texture::Format format) {
+ switch (format) {
+ case o3d::Texture::XRGB8:
+ case o3d::Texture::ARGB8:
+ case o3d::Texture::ABGR16F:
+ case o3d::Texture::ABGR32F:
+ return 4;
+ case o3d::Texture::R32F:
+ return 1;
+ case o3d::Texture::DXT1:
+ case o3d::Texture::DXT3:
+ case o3d::Texture::DXT5:
+ case o3d::Texture::UNKNOWN_FORMAT:
+ break;
+ }
+ return 0;
+}
+
+bool CanMakeMips(o3d::Texture::Format format) {
+ return GetNumComponentsForFormat(format) != 0;
+}
+
+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);
+}
+
+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 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;
+}
+
+
+namespace {
+
+// utility function called in AdjustDrawImageBoundary.
+// help to adjust a specific dimension,
+// if start point or ending point is out of boundary.
+bool AdjustDrawImageBoundHelper(int* src_a, int* dest_a,
+ int* src_length, int* dest_length,
+ int src_bmp_length) {
+ if (*src_length == 0 || *dest_length == 0)
+ 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;
+ }
+
+ return true;
+}
+
+void 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);
+ }
+ }
+ }
+ }
+}
+
+// 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.
+template <typename OriginalType,
+ typename WorkType,
+ WorkType convert_to_work(OriginalType value),
+ OriginalType convert_to_original(WorkType)>
+void FilterTexel(unsigned int x,
+ unsigned int y,
+ unsigned int dst_width,
+ unsigned int dst_height,
+ void *dst_data,
+ int dst_pitch,
+ unsigned int src_width,
+ unsigned int src_height,
+ const void *src_data,
+ int src_pitch,
+ unsigned int components) {
+ DCHECK(image::CheckImageDimensions(src_width, src_height));
+ DCHECK(image::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);
+ DCHECK_LE(static_cast<int>(src_width), src_pitch);
+ DCHECK_LE(static_cast<int>(dst_width), dst_pitch);
+
+ const OriginalType* src = static_cast<const OriginalType*>(src_data);
+ OriginalType* dst = static_cast<OriginalType*>(dst_data);
+
+ DCHECK_EQ(src_pitch % (components * sizeof(*src)), 0u);
+ DCHECK_EQ(dst_pitch % (components * sizeof(*dst)), 0u);
+
+ src_pitch /= components;
+ dst_pitch /= components;
+ // the texel at (x, y) represents the square of texture coordinates
+ // [x/dst_w, (x+1)/dst_w) x [y/dst_h, (y+1)/dst_h).
+ // This takes contributions from the texels:
+ // [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);
+ WorkType 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);
+ WorkType contrib = static_cast<WorkType>(x_contrib * y_contrib);
+ for (unsigned int c = 0; c < components; ++c) {
+ accum[c] += contrib *
+ convert_to_work(src[(src_y * src_pitch + src_x) * components + c]);
+ }
+ }
+ }
+ for (unsigned int c = 0; c < components; ++c) {
+ WorkType value = accum[c] / static_cast<WorkType>(src_height * src_width);
+ dst[(y * dst_pitch + x) * components + c] = convert_to_original(value);
+ }
+}
+
+template <typename OriginalType,
+ typename WorkType,
+ typename FilterType,
+ WorkType convert_to_work(OriginalType value),
+ OriginalType convert_from_work(WorkType),
+ FilterType convert_to_filter(OriginalType value),
+ OriginalType convert_from_filter(FilterType)>
+void GenerateMip(unsigned int components,
+ unsigned int src_width,
+ unsigned int src_height,
+ const void *src_data,
+ int src_pitch,
+ void *dst_data,
+ int dst_pitch) {
+ unsigned int mip_width = std::max(1U, src_width >> 1);
+ unsigned int mip_height = std::max(1U, src_height >> 1);
+
+ const OriginalType* src = static_cast<const OriginalType*>(src_data);
+ OriginalType* dst = static_cast<OriginalType*>(dst_data);
+
+ if (mip_width * 2 == src_width && mip_height * 2 == src_height) {
+ DCHECK_EQ(src_pitch % (components * sizeof(*src)), 0u);
+ DCHECK_EQ(dst_pitch % (components * sizeof(*dst)), 0u);
+ src_pitch /= components;
+ dst_pitch /= components;
+ // Easy case: every texel maps to exactly 4 texels in the previous level.
+ for (unsigned int y = 0; y < mip_height; ++y) {
+ for (unsigned int x = 0; x < mip_width; ++x) {
+ for (unsigned int c = 0; c < components; ++c) {
+ // Average the 4 texels.
+ unsigned int offset = (y * 2 * src_pitch + x * 2) * components + c;
+ WorkType value = convert_to_work(src[offset]); // (2x, 2y)
+ value += convert_to_work(src[offset + components]); // (2x+1, 2y)
+ value += convert_to_work(src[offset + src_width * components]);
+ // (2x, 2y+1)
+ value += convert_to_work(src[offset + (src_width + 1) * components]);
+ // (2x+1, 2y+1)
+ dst[(y * dst_pitch + x) * components + c] =
+ convert_from_work(value / static_cast<WorkType>(4));
+ }
+ }
+ }
+ } else {
+ for (unsigned int y = 0; y < mip_height; ++y) {
+ for (unsigned int x = 0; x < mip_width; ++x) {
+ FilterTexel<OriginalType,
+ FilterType,
+ convert_to_filter,
+ convert_from_filter>(
+ x, y, mip_width, mip_height, dst_data, dst_pitch,
+ src_width, src_height, src_data, src_pitch, components);
+ }
+ }
+ }
+}
+
+uint32 UInt8ToUInt32(uint8 value) {
+ return static_cast<uint32>(value);
+};
+
+uint8 UInt32ToUInt8(uint32 value) {
+ return static_cast<uint8>(value);
+};
+
+uint64 UInt8ToUInt64(uint8 value) {
+ return static_cast<uint64>(value);
+};
+
+uint8 UInt64ToUInt8(uint64 value) {
+ return static_cast<uint8>(value);
+};
+
+float FloatToFloat(float value) {
+ return value;
+}
+
+double FloatToDouble(float value) {
+ return static_cast<double>(value);
+}
+
+float DoubleToFloat(double value) {
+ return static_cast<float>(value);
+}
+
+float HalfToFloat(uint16 value) {
+ return Vectormath::Aos::HalfToFloat(value);
+}
+
+uint16 FloatToHalf(float value) {
+ return Vectormath::Aos::FloatToHalf(value);
+}
+
+double HalfToDouble(uint16 value) {
+ return static_cast<double>(Vectormath::Aos::HalfToFloat(value));
+}
+
+uint16 DoubleToHalf(double value) {
+ return Vectormath::Aos::FloatToHalf(static_cast<float>(value));
+}
+
+} // anonymous namespace
+
+// Adjust boundaries when using DrawImage function in bitmap or texture.
+bool AdjustDrawImageBoundary(int* src_x, int* src_y,
+ int* src_width, int* src_height,
+ int src_bmp_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;
+}
+
+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 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);
+}
+
+bool GenerateMipmap(unsigned int src_width,
+ unsigned int src_height,
+ Texture::Format format,
+ const uint8 *src_data,
+ int src_pitch,
+ uint8 *dst_data,
+ int dst_pitch) {
+ unsigned int components = GetNumComponentsForFormat(format);
+ if (components == 0) {
+ DLOG(ERROR) << "Mip-map generation not supported for format: " << format;
+ return false;
+ }
+
+ switch (format) {
+ case Texture::ARGB8:
+ case Texture::XRGB8:
+ GenerateMip<uint8, uint32, uint64,
+ UInt8ToUInt32, UInt32ToUInt8,
+ UInt8ToUInt64, UInt64ToUInt8>(
+ components, src_width, src_height, src_data, src_pitch,
+ dst_data, dst_pitch);
+ break;
+ case Texture::ABGR16F:
+ GenerateMip<uint16, float, double,
+ HalfToFloat, FloatToHalf,
+ HalfToDouble, DoubleToHalf>(
+ components, src_width, src_height, src_data, src_pitch,
+ dst_data, dst_pitch);
+ break;
+ case Texture::ABGR32F:
+ case Texture::R32F:
+ GenerateMip<float, float, double,
+ FloatToFloat, FloatToFloat,
+ FloatToDouble, DoubleToFloat>(
+ components, src_width, src_height, src_data, src_pitch,
+ dst_data, dst_pitch);
+ break;
+ default:
+ DLOG(ERROR) << "Mip-map generation not supported for format: " << format;
+ return false;
+ break;
+ }
+ return true;
+}
+
+ImageFileType 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;
+ }
+}
+
+namespace {
+
+struct MimeTypeToFileType {
+ const char *mime_type;
+ ImageFileType file_type;
+};
+
+const MimeTypeToFileType mime_type_map[] = {
+ {"image/png", PNG},
+ {"image/jpeg", JPEG},
+ // No official MIME type for TGA or DDS.
+};
+
+} // anonymous namespace
+
+ImageFileType GetFileTypeFromMimeType(const char *mime_type) {
+ for (unsigned int i = 0u; i < arraysize(mime_type_map); ++i) {
+ if (!strcmp(mime_type, mime_type_map[i].mime_type))
+ return mime_type_map[i].file_type;
+ }
+ return UNKNOWN;
+}
+
+void 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 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;
+ }
+}
+
+} // namespace image
+} // namespace o3d
+
+
diff --git a/o3d/core/cross/message_queue.cc b/o3d/core/cross/message_queue.cc
index 139a34b..61b63d0 100644
--- a/o3d/core/cross/message_queue.cc
+++ b/o3d/core/cross/message_queue.cc
@@ -345,14 +345,15 @@ bool MessageQueue::ProcessClientRequest(ConnectedClient* client,
IMCMessage::MessageId message_id,
nacl::MessageHeader* header,
nacl::Handle* handles) {
- static size_t expected_message_lengths[] = {
+ static int expected_message_lengths[] = {
#define O3D_IMC_MESSAGE_OP(id, class_name) sizeof(class_name),
O3D_IMC_MESSAGE_LIST(O3D_IMC_MESSAGE_OP)
#undef O3D_IMC_MESSAGE_OP
};
if (message_id == IMCMessage::INVALID_ID ||
- message_id >= arraysize(expected_message_lengths)) {
+ static_cast<unsigned>(message_id) >=
+ arraysize(expected_message_lengths)) {
LOG(ERROR) << "Unrecognized message id " << message_id;
return false;
}
diff --git a/o3d/core/cross/renderer.cc b/o3d/core/cross/renderer.cc
index 48c9c05..0d7b342 100644
--- a/o3d/core/cross/renderer.cc
+++ b/o3d/core/cross/renderer.cc
@@ -94,8 +94,7 @@ bool IsSupportedTextureFormat(Texture::Format format,
} // anonymous namespace
Renderer::Renderer(ServiceLocator* service_locator)
- : supports_npot_(false),
- clear_client_(true),
+ : clear_client_(true),
need_to_render_(true),
current_render_surface_(NULL),
current_depth_surface_(NULL),
@@ -116,7 +115,8 @@ Renderer::Renderer(ServiceLocator* service_locator)
render_width_(0),
render_height_(0),
dest_x_offset_(0),
- dest_y_offset_(0) {
+ dest_y_offset_(0),
+ supports_npot_(false) {
}
Renderer::~Renderer() {
diff --git a/o3d/utils/cross/base64_test.cc b/o3d/utils/cross/base64_test.cc
index 205ce7b..b6d3aea 100644
--- a/o3d/utils/cross/base64_test.cc
+++ b/o3d/utils/cross/base64_test.cc
@@ -41,11 +41,11 @@ class Base64Test : public testing::Test {
};
TEST_F(Base64Test, GetEncodeLength) {
- EXPECT_EQ(0, base64::GetEncodeLength(0));
- EXPECT_EQ(4, base64::GetEncodeLength(1));
- EXPECT_EQ(4, base64::GetEncodeLength(2));
- EXPECT_EQ(4, base64::GetEncodeLength(3));
- EXPECT_EQ(8, base64::GetEncodeLength(4));
+ EXPECT_EQ(0u, base64::GetEncodeLength(0));
+ EXPECT_EQ(4u, base64::GetEncodeLength(1));
+ EXPECT_EQ(4u, base64::GetEncodeLength(2));
+ EXPECT_EQ(4u, base64::GetEncodeLength(3));
+ EXPECT_EQ(8u, base64::GetEncodeLength(4));
}
TEST_F(Base64Test, Encode) {