diff options
39 files changed, 1229 insertions, 1311 deletions
diff --git a/o3d/converter/cross/renderer_stub.cc b/o3d/converter/cross/renderer_stub.cc index 9f71be6..333f72a 100644 --- a/o3d/converter/cross/renderer_stub.cc +++ b/o3d/converter/cross/renderer_stub.cc @@ -141,24 +141,6 @@ Sampler::Ref RendererStub::CreateSampler(void) { return Sampler::Ref(new SamplerStub(service_locator())); } -Texture::Ref RendererStub::CreatePlatformSpecificTextureFromBitmap( - Bitmap *bitmap) { - if (bitmap->is_cubemap()) { - return Texture::Ref(new TextureCUBEStub(service_locator(), - bitmap->width(), - bitmap->format(), - bitmap->num_mipmaps(), - false)); - } else { - return Texture::Ref(new Texture2DStub(service_locator(), - bitmap->width(), - bitmap->height(), - bitmap->format(), - bitmap->num_mipmaps(), - false)); - } -} - Texture2D::Ref RendererStub::CreatePlatformSpecificTexture2D( int width, int height, diff --git a/o3d/converter/cross/renderer_stub.h b/o3d/converter/cross/renderer_stub.h index 9ebc860b..e6bd1eb 100644 --- a/o3d/converter/cross/renderer_stub.h +++ b/o3d/converter/cross/renderer_stub.h @@ -95,9 +95,6 @@ class RendererStub : public Renderer { explicit RendererStub(ServiceLocator* service_locator); // Overridden from Renderer. - virtual Texture::Ref CreatePlatformSpecificTextureFromBitmap(Bitmap* bitmap); - - // Overridden from Renderer. virtual void SetBackBufferPlatformSpecific(); // Overridden from Renderer. diff --git a/o3d/converter/cross/texture_stub.h b/o3d/converter/cross/texture_stub.h index 9ded546..b26107a 100644 --- a/o3d/converter/cross/texture_stub.h +++ b/o3d/converter/cross/texture_stub.h @@ -57,8 +57,6 @@ class Texture2DStub : public Texture2D { height, format, levels, - false, - false, enable_render_surfaces) {} virtual ~Texture2DStub() {} @@ -119,8 +117,6 @@ class TextureCUBEStub : public TextureCUBE { edge_length, format, levels, - false, - false, enable_render_surfaces) {} virtual ~TextureCUBEStub() {} diff --git a/o3d/core/cross/bitmap.cc b/o3d/core/cross/bitmap.cc index cdccc66..c2709ae 100644 --- a/o3d/core/cross/bitmap.cc +++ b/o3d/core/cross/bitmap.cc @@ -65,19 +65,46 @@ Bitmap::Bitmap(ServiceLocator* service_locator) width_(0), height_(0), num_mipmaps_(0), - is_cubemap_(false) {} + semantic_(IMAGE) { +} -unsigned int Bitmap::GetMipSize(unsigned int level) const { +size_t 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::SetContents(Texture::Format format, + unsigned int num_mipmaps, + unsigned int width, + unsigned int height, + Bitmap::Semantic semantic, + scoped_array<uint8>* image_data) { + DCHECK(image_data); + image_data_.reset(); + format_ = format; + num_mipmaps_ = num_mipmaps; + width_ = width; + height_ = height; + semantic_ = semantic; + image_data_.swap(*image_data); +} + +void Bitmap::SetFrom(Bitmap *source) { + DCHECK(source); + SetContents(source->format(), + source->num_mipmaps(), + source->width(), + source->height(), + source->semantic(), + &source->image_data_); +} + void Bitmap::Allocate(Texture::Format format, unsigned int width, unsigned int height, unsigned int num_mipmaps, - bool cube_map) { + Bitmap::Semantic semantic) { DCHECK(image::CheckImageDimensions(width, height)); switch (format) { case Texture::XRGB8: @@ -93,7 +120,6 @@ void Bitmap::Allocate(Texture::Format format, DLOG(FATAL) << "Trying to allocate a bitmap with invalid format"; break; } - DCHECK(!cube_map || (width == height)); DCHECK_LE(num_mipmaps, image::ComputeMipMapCount(width, height)); DCHECK_GT(num_mipmaps, 0u); @@ -101,30 +127,17 @@ void Bitmap::Allocate(Texture::Format format, width_ = width; height_ = height; num_mipmaps_ = num_mipmaps; - is_cubemap_ = cube_map; + semantic_ = semantic; AllocateData(); } uint8 *Bitmap::GetMipData(unsigned int level) const { DCHECK(level < num_mipmaps_); - DCHECK(!is_cubemap_); if (!image_data_.get()) return NULL; uint8 *data = image_data_.get(); return data + GetMipChainSize(level); } -uint8 *Bitmap::GetFaceMipData(TextureCUBE::CubeFace face, - unsigned int level) const { - DCHECK(level < num_mipmaps_); - if (!image_data_.get()) return NULL; - uint8 *data = image_data_.get(); - if (is_cubemap()) { - data += (face - TextureCUBE::FACE_POSITIVE_X) * - GetMipChainSize(num_mipmaps_); - } - return data + GetMipChainSize(level); -} - void Bitmap::SetRect( int level, unsigned dst_left, @@ -164,52 +177,14 @@ void Bitmap::SetRect( } } -void Bitmap::SetFaceRect( - TextureCUBE::CubeFace face, - int level, - unsigned dst_left, - unsigned dst_top, - unsigned src_width, - unsigned src_height, - const void* src_data, - int src_pitch) { - DCHECK(src_data); - DCHECK(level < static_cast<int>(num_mipmaps()) && level >= 0); - 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()); - bool entire_rect = dst_left == 0 && dst_top == 0 && - src_width == mip_width && src_height == mip_height; - DCHECK(!compressed || entire_rect); - - uint8* dst = - GetFaceMipData(face, level) + - 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 = 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, - image::ComputeMipChainSize(mip_width, mip_height, format(), 1)); - } -} - - -bool Bitmap::LoadFromStream(MemoryReadStream *stream, +bool Bitmap::LoadFromStream(ServiceLocator* service_locator, + MemoryReadStream *stream, const String &filename, image::ImageFileType file_type, - bool generate_mipmaps) { + BitmapRefArray* bitmaps) { + DCHECK(stream); + DCHECK(bitmaps); + BitmapRefArray::size_type first = bitmaps->size(); bool success = false; // If we don't know what type to load, try to detect it based on the file // name. @@ -219,16 +194,16 @@ bool Bitmap::LoadFromStream(MemoryReadStream *stream, switch (file_type) { case image::TGA: - success = LoadFromTGAStream(stream, filename, generate_mipmaps); + success = LoadFromTGAStream(service_locator, stream, filename, bitmaps); break; case image::DDS: - success = LoadFromDDSStream(stream, filename, generate_mipmaps); + success = LoadFromDDSStream(service_locator, stream, filename, bitmaps); break; case image::PNG: - success = LoadFromPNGStream(stream, filename, generate_mipmaps); + success = LoadFromPNGStream(service_locator, stream, filename, bitmaps); break; case image::JPEG: - success = LoadFromJPEGStream(stream, filename, generate_mipmaps); + success = LoadFromJPEGStream(service_locator, stream, filename, bitmaps); break; case image::UNKNOWN: default: @@ -243,28 +218,34 @@ bool Bitmap::LoadFromStream(MemoryReadStream *stream, // 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); + success = LoadFromDDSStream(service_locator, stream, filename, bitmaps); if (!success) { stream->Seek(0); - success = LoadFromPNGStream(stream, filename, generate_mipmaps); + success = LoadFromPNGStream(service_locator, stream, filename, bitmaps); } if (!success) { stream->Seek(0); - success = LoadFromJPEGStream(stream, filename, generate_mipmaps); + success = LoadFromJPEGStream(service_locator, stream, filename, bitmaps); } if (!success) { stream->Seek(0); - success = LoadFromTGAStream(stream, filename, generate_mipmaps); + success = LoadFromTGAStream(service_locator, stream, filename, bitmaps); } } if (success) { - Features* features = service_locator()->GetService<Features>(); + Features* features = service_locator->GetService<Features>(); DCHECK(features); if (features->flip_textures()) { - FlipVertically(); + // Only flip the bitmaps we added. + for (BitmapRefArray::size_type ii = first; ii < bitmaps->size(); ++ii) { + Bitmap* bitmap = (*bitmaps)[ii].Get(); + if (bitmap->semantic() == IMAGE) { + bitmap->FlipVertically(); + } + } } } else { DLOG(ERROR) << "Failed to load image \"" << filename @@ -275,9 +256,11 @@ bool Bitmap::LoadFromStream(MemoryReadStream *stream, // Given an arbitrary bitmap file, load it all into memory and then call our // stream loader -bool Bitmap::LoadFromFile(const FilePath &filepath, +bool Bitmap::LoadFromFile(ServiceLocator* service_locator, + const FilePath &filepath, image::ImageFileType file_type, - bool generate_mipmaps) { + BitmapRefArray* bitmaps) { + DCHECK(bitmaps); // Open the file. bool result = false; String filename = FilePathToUTF8(filepath); @@ -304,8 +287,8 @@ bool Bitmap::LoadFromFile(const FilePath &filepath, } else { // And create the bitmap from a memory stream MemoryReadStream stream(file_contents, file_length); - result = LoadFromStream(&stream, filename, file_type, - generate_mipmaps); + result = LoadFromStream(service_locator, + &stream, filename, file_type, bitmaps); } } } @@ -319,7 +302,9 @@ bool Bitmap::LoadFromFile(const FilePath &filepath, // decide which image format it is and call the correct loading function. bool Bitmap::LoadFromRawData(RawData *raw_data, image::ImageFileType file_type, - bool generate_mipmaps) { + BitmapRefArray* bitmaps) { + DCHECK(raw_data); + DCHECK(bitmaps); String filename = raw_data->uri(); // GetData() returns NULL if it, for example, cannot open the temporary data @@ -332,7 +317,8 @@ bool Bitmap::LoadFromRawData(RawData *raw_data, MemoryReadStream stream(data, raw_data->GetLength()); - return LoadFromStream(&stream, filename, file_type, generate_mipmaps); + return LoadFromStream(raw_data->service_locator(), + &stream, filename, file_type, bitmaps); } void Bitmap::DrawImage(const Bitmap& src_img, @@ -462,48 +448,38 @@ bool Bitmap::CheckAlphaIsOne() const { case Texture::XRGB8: return true; case Texture::ARGB8: { - int faces = is_cubemap() ? 6 : 1; - for (int face = 0; face < faces; ++face) { - for (unsigned int level = 0; level < num_mipmaps(); ++level) { - const uint8 *data = GetFaceMipData( - static_cast<TextureCUBE::CubeFace>(face), - level) + 3; - const uint8* end = data + image::ComputeBufferSize( - std::max(1U, width() >> level), - std::max(1U, height() >> level), - format()); - while (data < end) { - if (*data != 255) { - return false; - } - data += 4; + for (unsigned int level = 0; level < num_mipmaps(); ++level) { + const uint8* data = GetMipData(level) + 3; + const uint8* end = data + image::ComputeBufferSize( + std::max(1U, width() >> level), + std::max(1U, height() >> level), + format()); + while (data < end) { + if (*data != 255) { + return false; } + data += 4; } } break; } case Texture::DXT1: { - int faces = is_cubemap() ? 6 : 1; - for (int face = 0; face < faces; ++face) { - for (unsigned int level = 0; level < num_mipmaps(); ++level) { - const uint8 *data = GetFaceMipData( - static_cast<TextureCUBE::CubeFace>(face), - level); - const uint8* end = data + image::ComputeBufferSize( - std::max(1U, width() >> level), - std::max(1U, height() >> level), - format()); - DCHECK((end - data) % 8 == 0); - while (data < end) { - int color0 = static_cast<int>(data[0]) | - static_cast<int>(data[1]) << 8; - int color1 = static_cast<int>(data[2]) | - static_cast<int>(data[3]) << 8; - if (color0 < color1) { - return false; - } - data += 8; + for (unsigned int level = 0; level < num_mipmaps(); ++level) { + const uint8* data = GetMipData(level); + const uint8* end = data + image::ComputeBufferSize( + std::max(1U, width() >> level), + std::max(1U, height() >> level), + format()); + DCHECK((end - data) % 8 == 0); + while (data < end) { + int color0 = static_cast<int>(data[0]) | + static_cast<int>(data[1]) << 8; + int color1 = static_cast<int>(data[2]) | + static_cast<int>(data[3]) << 8; + if (color0 < color1) { + return false; } + data += 8; } } break; @@ -512,22 +488,17 @@ bool Bitmap::CheckAlphaIsOne() const { case Texture::DXT5: return false; case Texture::ABGR16F: { - int faces = is_cubemap() ? 6 : 1; - for (int face = 0; face < faces; ++face) { - for (unsigned int level = 0; level < num_mipmaps(); ++level) { - const uint8 *data = GetFaceMipData( - static_cast<TextureCUBE::CubeFace>(face), - level) + 6; - const uint8* end = data + image::ComputeBufferSize( - std::max(1U, width() >> level), - std::max(1U, height() >> level), - format()); - while (data < end) { - if (data[0] != 0x00 || data[1] != 0x3C) { - return false; - } - data += 8; + for (unsigned int level = 0; level < num_mipmaps(); ++level) { + const uint8* data = GetMipData(level) + 6; + const uint8* end = data + image::ComputeBufferSize( + std::max(1U, width() >> level), + std::max(1U, height() >> level), + format()); + while (data < end) { + if (data[0] != 0x00 || data[1] != 0x3C) { + return false; } + data += 8; } } break; @@ -535,22 +506,17 @@ bool Bitmap::CheckAlphaIsOne() const { case Texture::R32F: return true; case Texture::ABGR32F: { - int faces = is_cubemap() ? 6 : 1; - for (int face = 0; face < faces; ++face) { - for (unsigned int level = 0; level < num_mipmaps(); ++level) { - const uint8* data = GetFaceMipData( - static_cast<TextureCUBE::CubeFace>(face), - level) + 12; - const uint8* end = data + image::ComputeBufferSize( - std::max(1U, width() >> level), - std::max(1U, height() >> level), - format()); - while (data < end) { - if (*(reinterpret_cast<const float*>(data)) != 1.0f) { - return false; - } - data += 16; + for (unsigned int level = 0; level < num_mipmaps(); ++level) { + const uint8* data = GetMipData(level) + 12; + const uint8* end = data + image::ComputeBufferSize( + std::max(1U, width() >> level), + std::max(1U, height() >> level), + format()); + while (data < end) { + if (*(reinterpret_cast<const float*>(data)) != 1.0f) { + return false; } + data += 16; } } break; diff --git a/o3d/core/cross/bitmap.h b/o3d/core/cross/bitmap.h index a86b76a..a116ecb 100644 --- a/o3d/core/cross/bitmap.h +++ b/o3d/core/cross/bitmap.h @@ -41,7 +41,7 @@ #define O3D_CORE_CROSS_BITMAP_H_
#include <stdlib.h>
-
+#include <vector>
#include "base/cross/bits.h"
#include "core/cross/types.h"
#include "core/cross/texture.h"
@@ -56,27 +56,27 @@ class RawData; class Pack;
// Bitmap provides an API for basic image operations on bitmap images,
-// including scale and crop. The contents of bitmap can be created from
-// a RawData object via LoadFromRawData(), and also can be transfered
-// to mip of a Texure2D or a specific face of TextureCUBE via methods
-// in Texture.
+// including scale and crop. Bitmaps can be created from a RawData object via
+// LoadFromRawData(), and also can be transfered to mips of a Texure2D or a
+// specific face of TextureCUBE via methods in Texture.
class Bitmap : public ParamObject {
public:
typedef SmartPointer<Bitmap> Ref;
+ typedef std::vector<Bitmap::Ref> BitmapRefArray;
explicit Bitmap(ServiceLocator* service_locator);
virtual ~Bitmap() {}
enum Semantic {
- FACE_POSITIVE_X,
+ FACE_POSITIVE_X, // NOTE: These must match TextureCUBE::CubeFace
FACE_NEGATIVE_X,
FACE_POSITIVE_Y,
FACE_NEGATIVE_Y,
FACE_POSITIVE_Z,
FACE_NEGATIVE_Z,
- NORMAL,
- SLICE,
+ IMAGE, // normal 2d image
+ SLICE, // a slice of a 3d texture.
};
// Returns the pitch of the bitmap for a certain level.
@@ -89,7 +89,7 @@ class Bitmap : public ParamObject { // source: the source bitmap.
void CopyDeepFrom(const Bitmap &source) {
Allocate(source.format_, source.width_, source.height_,
- source.num_mipmaps_, source.is_cubemap_);
+ source.num_mipmaps_, source.semantic_);
memcpy(image_data(), source.image_data(), GetTotalSize());
}
@@ -97,15 +97,7 @@ class Bitmap : public ParamObject { // from the source bitmap.
// Parameters:
// source: the source bitmap.
- void SetFrom(Bitmap *source) {
- image_data_.reset();
- format_ = source->format_;
- width_ = source->width_;
- height_ = source->height_;
- num_mipmaps_ = source->num_mipmaps_;
- is_cubemap_ = source->is_cubemap_;
- image_data_.swap(source->image_data_);
- }
+ void SetFrom(Bitmap *source);
// Allocates an uninitialized bitmap with specified parameters.
// Parameters:
@@ -113,12 +105,11 @@ class Bitmap : public ParamObject { // width: the width of the base image.
// height: the height of the base image.
// num_mipmaps: the number of mip-maps.
- // cube_map: true if creating a cube map.
void Allocate(Texture::Format format,
unsigned int width,
unsigned int height,
unsigned int num_mipmaps,
- bool cube_map);
+ Semantic semantic);
// Allocates a bitmap with initialized parameters.
// data is zero-initialized
@@ -153,31 +144,9 @@ class Bitmap : public ParamObject { const void* src_data,
int src_pitch);
- // Sets a rectangular region of this bitmap.
- // If the bitmap is a DXT format, the only acceptable values
- // for left, top, width and height are 0, 0, bitmap->width, bitmap->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.
- // width: The width of the rectangular area to modify.
- // height: The of the rectangular area to modify.
- // src_data: The source pixels.
- // src_pitch: If the format is uncompressed this is the number of bytes
- // per row of pixels. If compressed this value is unused.
- void SetFaceRect(TextureCUBE::CubeFace face,
- int level,
- unsigned dst_left,
- unsigned dst_top,
- unsigned width,
- unsigned height,
- const void* src_data,
- int src_pitch);
-
// Gets the total size of the bitmap data, counting all faces and mip levels.
- unsigned int GetTotalSize() const {
- return (is_cubemap_ ? 6 : 1) * GetMipChainSize(num_mipmaps_);
+ size_t GetTotalSize() const {
+ return GetMipChainSize(num_mipmaps_);
}
// Gets the image data for a given mip-map level.
@@ -185,44 +154,34 @@ class Bitmap : public ParamObject { // level: mip level to get.
uint8 *GetMipData(unsigned int level) const;
- // Gets the image data for a given mip-map level and cube map face.
- // Parameters:
- // 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;
-
// Gets the size of mip.
- unsigned int GetMipSize(unsigned int level) const;
+ size_t GetMipSize(unsigned int level) const;
uint8 *image_data() const { return image_data_.get(); }
Texture::Format format() const { return format_; }
unsigned int width() const { return width_; }
unsigned int height() const { return height_; }
unsigned int num_mipmaps() const { return num_mipmaps_; }
- bool is_cubemap() const { return is_cubemap_; }
+ Semantic semantic() const {
+ return semantic_;
+ }
// Returns whether or not the dimensions of the bitmap are power-of-two.
bool IsPOT() const {
- return ((width_ & (width_ - 1)) == 0) && ((height_ & (height_ - 1)) == 0);
+ return image::IsPOT(width_, height_);
}
- void set_format(Texture::Format format) { format_ = format; }
- void set_width(unsigned int n) { width_ = n; }
- void set_height(unsigned int n) { height_ = n; }
- void set_num_mipmaps(unsigned int n) { num_mipmaps_ = n; }
- void set_is_cubemap(bool is_cubemap) { is_cubemap_ = is_cubemap; }
-
// Loads a bitmap from a file.
// Parameters:
// filename: the name of the file to load.
// file_type: the type of file to load. If UNKNOWN, the file type will be
// determined from the filename extension, 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 LoadFromFile(const FilePath &filepath,
- image::ImageFileType file_type,
- bool generate_mipmaps);
+ // bitmaps: An array to hold references to the loaded bitmaps.
+ static bool LoadFromFile(ServiceLocator* service_locator,
+ const FilePath &filepath,
+ image::ImageFileType file_type,
+ BitmapRefArray* bitmaps);
// Loads a bitmap from a RawData object.
// Parameters:
@@ -231,10 +190,10 @@ class Bitmap : public ParamObject { // will be determined from the extension from raw_data's uri
// 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 LoadFromRawData(RawData *raw_data,
- image::ImageFileType file_type,
- bool generate_mipmaps);
+ // bitmaps: An array to hold references to the loaded bitmaps.
+ static bool LoadFromRawData(RawData *raw_data,
+ image::ImageFileType file_type,
+ BitmapRefArray* bitmaps);
// Flips a bitmap vertically in place.
// This is needed instead of just using DrawImage because flipping DXT formats
@@ -269,7 +228,7 @@ class Bitmap : public ParamObject { // 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 {
+ size_t GetMipChainSize(unsigned int num_mipmaps) const {
return image::ComputeMipChainSize(width(), height(), format(), num_mipmaps);
}
@@ -280,20 +239,22 @@ class Bitmap : public ParamObject { friend class IClassManager;
static ObjectBase::Ref Create(ServiceLocator* service_locator);
- // pointer to the raw bitmap data
- scoped_array<uint8> image_data_;
- // format of the texture this is meant to represent.
- Texture::Format format_;
- // width of the bitmap in pixels.
- int width_;
- // height of the bitmap in pixels.
- int height_;
- // number of mipmap levels in this texture.
- unsigned int num_mipmaps_;
- // is this cube-map data
- bool is_cubemap_;
-
- // Loads a bitmap from a MemoryReadStream.
+ // Sets the contents of a Bitmap replacing any previous contents.
+ // Parameters:
+ // format: Format of the bitmap.
+ // num_mipmaps: The number of mipmaps.
+ // width: width in pixels.
+ // height: height in pixels.
+ // semantic: the semantic of the bitmap
+ // image_data: The image data. The bitmap will take ownership of this data.
+ void SetContents(Texture::Format format,
+ unsigned int num_mipmaps,
+ unsigned int width,
+ unsigned int height,
+ Semantic semantic,
+ scoped_array<uint8>* image_data);
+
+ // Loads bitmaps 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
@@ -302,27 +263,32 @@ class Bitmap : public ParamObject { // 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);
+ // bitmaps: An array to hold references to the loaded bitmaps.
+ static bool LoadFromStream(ServiceLocator* service_locator,
+ MemoryReadStream *stream,
+ const String &filename,
+ image::ImageFileType file_type,
+ BitmapRefArray* bitmaps);
+
+ static bool LoadFromPNGStream(ServiceLocator* service_locator,
+ MemoryReadStream *stream,
+ const String &filename,
+ BitmapRefArray* bitmaps);
+
+ static bool LoadFromTGAStream(ServiceLocator* service_locator,
+ MemoryReadStream *stream,
+ const String &filename,
+ BitmapRefArray* bitmaps);
+
+ static bool LoadFromDDSStream(ServiceLocator* service_locator,
+ MemoryReadStream *stream,
+ const String &filename,
+ BitmapRefArray* bitmaps);
+
+ static bool LoadFromJPEGStream(ServiceLocator* service_locator,
+ MemoryReadStream *stream,
+ const String &filename,
+ BitmapRefArray* bitmaps);
bool GenerateMipmaps(unsigned int base_width,
unsigned int base_height,
@@ -330,10 +296,25 @@ class Bitmap : public ParamObject { unsigned int num_mipmaps,
uint8 *data);
+ // pointer to the raw bitmap data
+ scoped_array<uint8> image_data_;
+ // format of the texture this is meant to represent.
+ Texture::Format format_;
+ // width of the bitmap in pixels.
+ int width_;
+ // height of the bitmap in pixels.
+ int height_;
+ // number of mipmap levels in this texture.
+ unsigned int num_mipmaps_;
+ // The purpose of the bitmap
+ Semantic semantic_;
+
O3D_DECL_CLASS(Bitmap, ParamObject);
DISALLOW_COPY_AND_ASSIGN(Bitmap);
};
+typedef Bitmap::BitmapRefArray BitmapRefArray;
+
class BitmapUncompressed : public Bitmap {
public:
explicit BitmapUncompressed(ServiceLocator* service_locator);
diff --git a/o3d/core/cross/bitmap_dds.cc b/o3d/core/cross/bitmap_dds.cc index b5ad5fa..2c4f8a9 100644 --- a/o3d/core/cross/bitmap_dds.cc +++ b/o3d/core/cross/bitmap_dds.cc @@ -248,7 +248,7 @@ static void FlipBGRAImage(unsigned int width, 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); + size_t 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. @@ -271,14 +271,12 @@ 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()); - } + 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()); } } @@ -286,9 +284,10 @@ void Bitmap::FlipVertically() { // 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. -bool Bitmap::LoadFromDDSStream(MemoryReadStream *stream, +bool Bitmap::LoadFromDDSStream(ServiceLocator* service_locator, + MemoryReadStream *stream, const String &filename, - bool generate_mipmaps) { + BitmapRefArray* bitmaps) { // Verify the file is a true .dds file char magic[4]; size_t bytes_read = stream->Read(magic, sizeof(magic)); @@ -297,7 +296,7 @@ bool Bitmap::LoadFromDDSStream(MemoryReadStream *stream, return false; } if (std::strncmp(magic, "DDS ", 4) != 0) { - DLOG(ERROR) << "DDS magic header not rcognised \"" << filename << "\""; + DLOG(ERROR) << "DDS magic header not recognized \"" << filename << "\""; return false; } // Get the DirectDraw Surface Descriptor @@ -390,7 +389,7 @@ bool Bitmap::LoadFromDDSStream(MemoryReadStream *stream, // Check that the advertised size is correct. if (dd_surface_descriptor.dwFlags & DDSD_LINEARSIZE) { - unsigned int expected_size = + size_t expected_size = image::ComputeBufferSize(dds_width, dds_height, format); if (expected_size != dd_surface_descriptor.dwLinearSize) { DLOG(ERROR) << "Advertised buffer size in \"" << filename @@ -449,26 +448,13 @@ bool Bitmap::LoadFromDDSStream(MemoryReadStream *stream, format = add_filler_alpha ? Texture::XRGB8 : Texture::ARGB8; } - if (is_dxtc && generate_mipmaps) { - DLOG(WARNING) << "Disabling mip-map generation for DXTC image."; - generate_mipmaps = false; - } - - // compute buffer size - unsigned int num_faces = is_cubemap ? 6 : 1; - // power-of-two dimensions. - unsigned int 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; + unsigned int num_bitmaps = is_cubemap ? 6 : 1; + size_t face_size = image::ComputeMipChainSize( + dds_width, dds_height, format, mip_count); + BitmapRefArray temp_bitmaps; - // Allocate and load bitmap data. - scoped_array<uint8> image_data(new uint8[buffer_size]); - - unsigned int disk_face_size = + size_t 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 @@ -477,57 +463,42 @@ bool Bitmap::LoadFromDDSStream(MemoryReadStream *stream, disk_face_size = components_per_pixel * disk_face_size / 4; } - for (unsigned int face = 0; face < num_faces; ++face) { - char *data = reinterpret_cast<char*>(image_data.get()) + face_size * face; + for (unsigned int face = 0; face < num_bitmaps; ++face) { + // Allocate and load bitmap data. + scoped_array<uint8> image_data(new uint8[face_size]); + + char *data = reinterpret_cast<char*>(image_data.get()); bytes_read = stream->Read(data, disk_face_size); if (bytes_read != disk_face_size) { DLOG(ERROR) << "DDS failed to read image data \"" << filename << "\""; return false; } - } - // Do pixel conversions on non-DXT images. - if (!is_dxtc) { - 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) { - uint8 *data = image_data.get() + face_size * face; + // Do pixel conversions on non-DXT images. + if (!is_dxtc) { + DCHECK(components_per_pixel == 3 || components_per_pixel == 4); + unsigned int pixel_count = disk_face_size / components_per_pixel; // convert to four components per pixel if necessary if (add_filler_alpha) { DCHECK_EQ(components_per_pixel, 3u); - image::XYZToXYZA(data, pixel_count); + image::XYZToXYZA(image_data.get(), pixel_count); } else { DCHECK_EQ(components_per_pixel, 4u); } - if (rgb_to_bgr) - image::RGBAToBGRA(data, pixel_count); - } - } - - if (final_mip_count > mip_count) { - // Generate the full mip-map chain using the last mip-map read, for each - // 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 = image::ComputeMipChainSize( - dds_width, dds_height, format, mip_count - 1); - for (unsigned int face = 0; face < num_faces; ++face) { - 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 << "\""; - return false; + if (rgb_to_bgr) { + image::RGBAToBGRA(image_data.get(), pixel_count); } } + Semantic semantic = is_cubemap ? static_cast<Semantic>(face) : IMAGE; + + Bitmap::Ref bitmap(new Bitmap(service_locator)); + bitmap->SetContents(format, mip_count, dds_width, dds_height, semantic, + &image_data); + temp_bitmaps.push_back(bitmap); } - // Update the Bitmap member variables. - image_data_.swap(image_data); - format_ = format; - width_ = dds_width; - height_ = dds_height; - num_mipmaps_ = final_mip_count; - is_cubemap_ = is_cubemap; + // Success. + bitmaps->insert(bitmaps->end(), temp_bitmaps.begin(), temp_bitmaps.end()); return true; } diff --git a/o3d/core/cross/bitmap_jpg.cc b/o3d/core/cross/bitmap_jpg.cc index bbb31d3..7b84490 100644 --- a/o3d/core/cross/bitmap_jpg.cc +++ b/o3d/core/cross/bitmap_jpg.cc @@ -132,9 +132,10 @@ METHODDEF(void) my_error_exit(j_common_ptr cinfo) { // Loads the raw RGB bitmap data from a compressed JPEG stream and converts // the result to 24- or 32-bit bitmap data. -bool Bitmap::LoadFromJPEGStream(MemoryReadStream *stream, +bool Bitmap::LoadFromJPEGStream(ServiceLocator* service_locator, + MemoryReadStream *stream, const String &filename, - bool generate_mipmaps) { + BitmapRefArray* bitmaps) { // Workspace for libjpeg decompression. struct jpeg_decompress_struct cinfo; // create our custom error handler. @@ -198,12 +199,9 @@ bool Bitmap::LoadFromJPEGStream(MemoryReadStream *stream, ERREXIT(&cinfo, JERR_QUANT_COMPONENTS); } unsigned int image_components = 4; - unsigned int num_mipmaps = - generate_mipmaps ? image::ComputeMipMapCount(width, height) : 1; Texture::Format format = Texture::XRGB8; // Allocate storage for the pixels. - unsigned int image_size = - image::ComputeMipChainSize(width, height, format, num_mipmaps); + size_t image_size = image::ComputeMipChainSize(width, height, format, 1); image_data.reset(new uint8[image_size]); if (image_data.get() == NULL) { DLOG(ERROR) << "JPEG memory allocation error \"" << filename << "\""; @@ -270,21 +268,10 @@ bool Bitmap::LoadFromJPEGStream(MemoryReadStream *stream, // Check for jpeg decompression warnings. DLOG(WARNING) << "JPEG decompression warnings: " << jerr.pub.num_warnings; - if (generate_mipmaps) { - if (!GenerateMipmaps(width, height, format, num_mipmaps, - image_data.get())) { - DLOG(ERROR) << "mip-map generation failed for \"" << filename << "\""; - return false; - } - } - // Success. - image_data_.swap(image_data); - width_ = width; - height_ = height; - format_ = format; - num_mipmaps_ = num_mipmaps; - + Bitmap::Ref bitmap(new Bitmap(service_locator)); + bitmap->SetContents(format, 1, width, height, IMAGE, &image_data); + bitmaps->push_back(bitmap); return true; } diff --git a/o3d/core/cross/bitmap_png.cc b/o3d/core/cross/bitmap_png.cc index 843bd83..9e30011 100644 --- a/o3d/core/cross/bitmap_png.cc +++ b/o3d/core/cross/bitmap_png.cc @@ -79,9 +79,11 @@ void StreamFlush(png_structp png_ptr) { } // anonymous namespace // Loads the raw RGB data from a compressed PNG file. -bool Bitmap::LoadFromPNGStream(MemoryReadStream *stream, +bool Bitmap::LoadFromPNGStream(ServiceLocator* service_locator, + MemoryReadStream *stream, const String &filename, - bool generate_mipmaps) { + BitmapRefArray* bitmaps) { + DCHECK(bitmaps); // Read the magic header. char magic[4]; size_t bytes_read = stream->Read(magic, sizeof(magic)); @@ -225,11 +227,8 @@ bool Bitmap::LoadFromPNGStream(MemoryReadStream *stream, png_read_update_info(png_ptr, info_ptr); // Allocate storage for the pixels. - unsigned int num_mipmaps = - generate_mipmaps ? image::ComputeMipMapCount(png_width, png_height) : 1; - // Allocate storage for the pixels. - unsigned int png_image_size = - image::ComputeMipChainSize(png_width, png_height, format, num_mipmaps); + size_t png_image_size = + image::ComputeMipChainSize(png_width, png_height, format, 1); image_data.reset(new uint8[png_image_size]); if (image_data.get() == NULL) { DLOG(ERROR) << "PNG image memory allocation error \"" << filename << "\""; @@ -263,20 +262,10 @@ bool Bitmap::LoadFromPNGStream(MemoryReadStream *stream, png_free(png_ptr, row_pointers); png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); - if (generate_mipmaps) { - if (!GenerateMipmaps(png_width, png_height, format, num_mipmaps, - image_data.get())) { - DLOG(ERROR) << "Mip-map generation failed for \"" << filename << "\""; - return false; - } - } - // Success. - image_data_.swap(image_data); - format_ = format; - width_ = png_width; - height_ = png_height; - num_mipmaps_ = num_mipmaps; + Bitmap::Ref bitmap(new Bitmap(service_locator)); + bitmap->SetContents(format, 1, png_width, png_height, IMAGE, &image_data); + bitmaps->push_back(bitmap); return true; } @@ -285,7 +274,6 @@ namespace { bool CreatePNGInUInt8Vector(const Bitmap& bitmap, std::vector<uint8>* buffer) { DCHECK(bitmap.format() == Texture::ARGB8); DCHECK(bitmap.num_mipmaps() == 1); - DCHECK(!bitmap.is_cubemap()); png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); @@ -336,7 +324,7 @@ String Bitmap::ToDataURL() { O3D_ERROR(service_locator()) << "Can only get data URL from ARGB8 images."; return dataurl::kEmptyDataURL; } - if (num_mipmaps_ != 1 || is_cubemap_) { + if (num_mipmaps_ != 1) { O3D_ERROR(service_locator()) << "Can only get data URL from 2d images with no mips."; return dataurl::kEmptyDataURL; diff --git a/o3d/core/cross/bitmap_test.cc b/o3d/core/cross/bitmap_test.cc index 4278469..6df10f2 100644 --- a/o3d/core/cross/bitmap_test.cc +++ b/o3d/core/cross/bitmap_test.cc @@ -353,15 +353,42 @@ bool PrintBitmapData(const Bitmap &bitmap, const char *name) { // ----------------------------------------------------------------------------- +TEST_F(BitmapTest, Basic) { + EXPECT_EQ(static_cast<int>(Bitmap::FACE_NEGATIVE_X), + static_cast<int>(TextureCUBE::FACE_NEGATIVE_X)); + EXPECT_EQ(static_cast<int>(Bitmap::FACE_NEGATIVE_Y), + static_cast<int>(TextureCUBE::FACE_NEGATIVE_Y)); + EXPECT_EQ(static_cast<int>(Bitmap::FACE_NEGATIVE_Z), + static_cast<int>(TextureCUBE::FACE_NEGATIVE_Z)); + EXPECT_EQ(static_cast<int>(Bitmap::FACE_POSITIVE_X), + static_cast<int>(TextureCUBE::FACE_POSITIVE_X)); + EXPECT_EQ(static_cast<int>(Bitmap::FACE_POSITIVE_Y), + static_cast<int>(TextureCUBE::FACE_POSITIVE_Y)); + EXPECT_EQ(static_cast<int>(Bitmap::FACE_POSITIVE_Z), + static_cast<int>(TextureCUBE::FACE_POSITIVE_Z)); + Bitmap::Ref bitmap(new Bitmap(g_service_locator)); + ASSERT_FALSE(bitmap.IsNull()); + EXPECT_TRUE(bitmap->IsA(Bitmap::GetApparentClass())); + EXPECT_TRUE(bitmap->IsA(ParamObject::GetApparentClass())); + EXPECT_TRUE(bitmap->image_data() == NULL); + EXPECT_EQ(Texture::UNKNOWN_FORMAT, bitmap->format()); + EXPECT_EQ(0, bitmap->width()); + EXPECT_EQ(0, bitmap->height()); + EXPECT_EQ(0, bitmap->num_mipmaps()); + EXPECT_EQ(Bitmap::IMAGE, bitmap->semantic()); +} + // Loads a 24 bit TGA file, checks it against the known data. TEST_F(BitmapTest, LoadTGAFile24bit) { // Load the texture object from a file. 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, image::TGA, false)); + BitmapRefArray bitmaps; + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, filepath, image::TGA, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap* bitmap = bitmaps[0].Get(); EXPECT_TRUE(bitmap->image_data() != NULL); - EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::XRGB8, bitmap->format()); EXPECT_EQ(256U, bitmap->width()); EXPECT_EQ(256U, bitmap->height()); @@ -373,10 +400,12 @@ TEST_F(BitmapTest, LoadTGAFile24bit) { 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, image::TGA, false)); + BitmapRefArray bitmaps; + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, filepath, image::TGA, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap* bitmap = bitmaps[0].Get(); EXPECT_TRUE(bitmap->image_data() != NULL); - EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::ARGB8, bitmap->format()); EXPECT_EQ(256U, bitmap->width()); EXPECT_EQ(256U, bitmap->height()); @@ -391,19 +420,22 @@ TEST_F(BitmapTest, LoadTGAFileTooLarge) { // but bails before reading the actual image bytes. 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, image::TGA, false)); - EXPECT_TRUE(bitmap->image_data() == NULL); + BitmapRefArray bitmaps; + EXPECT_FALSE(Bitmap::LoadFromFile( + g_service_locator, filepath, image::TGA, &bitmaps)); + EXPECT_EQ(0, bitmaps.size()); } // Loads a JPEG file, checks it against the known data. 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, image::JPEG, false)); + BitmapRefArray bitmaps; + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, filepath, image::JPEG, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap* bitmap = bitmaps[0].Get(); EXPECT_TRUE(bitmap->image_data() != NULL); - EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::XRGB8, bitmap->format()); EXPECT_EQ(256U, bitmap->width()); EXPECT_EQ(256U, bitmap->height()); @@ -415,19 +447,22 @@ TEST_F(BitmapTest, LoadJPEGFile) { 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, image::JPEG, false)); - EXPECT_TRUE(bitmap->image_data() == NULL); + BitmapRefArray bitmaps; + EXPECT_FALSE(Bitmap::LoadFromFile( + g_service_locator, filepath, image::JPEG, &bitmaps)); + EXPECT_EQ(0, bitmaps.size()); } // Loads a 24 bit PNG file, checks it against the known data. 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, image::PNG, false)); + BitmapRefArray bitmaps; + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, filepath, image::PNG, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap* bitmap = bitmaps[0].Get(); EXPECT_TRUE(bitmap->image_data() != NULL); - EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::XRGB8, bitmap->format()); EXPECT_EQ(256U, bitmap->width()); EXPECT_EQ(256U, bitmap->height()); @@ -440,10 +475,12 @@ TEST_F(BitmapTest, LoadPNGFile24bitInterlaced) { String filename = *g_program_path + "/bitmap_test/png-256x256-24bit-interlaced.png"; FilePath filepath = UTF8ToFilePath(filename); - Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_TRUE(bitmap->LoadFromFile(filepath, image::PNG, false)); + BitmapRefArray bitmaps; + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, filepath, image::PNG, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap* bitmap = bitmaps[0].Get(); EXPECT_TRUE(bitmap->image_data() != NULL); - EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::XRGB8, bitmap->format()); EXPECT_EQ(256U, bitmap->width()); EXPECT_EQ(256U, bitmap->height()); @@ -454,10 +491,12 @@ TEST_F(BitmapTest, LoadPNGFile24bitInterlaced) { 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, image::PNG, false)); + BitmapRefArray bitmaps; + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, filepath, image::PNG, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap* bitmap = bitmaps[0].Get(); EXPECT_TRUE(bitmap->image_data() != NULL); - EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::ARGB8, bitmap->format()); EXPECT_EQ(256U, bitmap->width()); EXPECT_EQ(256U, bitmap->height()); @@ -470,10 +509,12 @@ TEST_F(BitmapTest, LoadPNGFile8bitPalette) { String filename = *g_program_path + "/bitmap_test/png-256x256-8bit-palette.png"; FilePath filepath = UTF8ToFilePath(filename); - Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_TRUE(bitmap->LoadFromFile(filepath, image::PNG, false)); + BitmapRefArray bitmaps; + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, filepath, image::PNG, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap* bitmap = bitmaps[0].Get(); EXPECT_TRUE(bitmap->image_data() != NULL); - EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::XRGB8, bitmap->format()); EXPECT_EQ(256U, bitmap->width()); EXPECT_EQ(256U, bitmap->height()); @@ -486,10 +527,12 @@ TEST_F(BitmapTest, LoadPNGFile4bitPalette) { String filename = *g_program_path + "/bitmap_test/png-20x14-4bit-palette.png"; FilePath filepath = UTF8ToFilePath(filename); - Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_TRUE(bitmap->LoadFromFile(filepath, image::PNG, false)); + BitmapRefArray bitmaps; + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, filepath, image::PNG, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap* bitmap = bitmaps[0].Get(); EXPECT_TRUE(bitmap->image_data() != NULL); - EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::XRGB8, bitmap->format()); EXPECT_EQ(20U, bitmap->width()); EXPECT_EQ(14U, bitmap->height()); @@ -502,9 +545,10 @@ TEST_F(BitmapTest, LoadPNGFile4bitPalette) { 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, image::PNG, false)); - EXPECT_TRUE(bitmap->image_data() == NULL); + BitmapRefArray bitmaps; + EXPECT_FALSE(Bitmap::LoadFromFile( + g_service_locator, filepath, image::PNG, &bitmaps)); + EXPECT_EQ(0, bitmaps.size()); } // NOTE: Having trouble recognising the alpha channel in a PNG @@ -514,10 +558,12 @@ TEST_F(BitmapTest, LoadPNGFile8bitPaletteAlpha) { String filename = *g_program_path + "/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, image::PNG, false)); + BitmapRefArray bitmaps; + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, filepath, image::PNG, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap* bitmap = bitmaps[0].Get(); EXPECT_TRUE(bitmap->image_data() != NULL); - EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::ARGB8, bitmap->format()); EXPECT_EQ(256U, bitmap->width()); EXPECT_EQ(256U, bitmap->height()); @@ -529,10 +575,12 @@ TEST_F(BitmapTest, LoadPNGFile8bitPaletteAlpha) { 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, image::DDS, false)); + BitmapRefArray bitmaps; + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, filepath, image::DDS, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap* bitmap = bitmaps[0].Get(); EXPECT_TRUE(bitmap->image_data() != NULL); - EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::DXT1, bitmap->format()); EXPECT_EQ(256U, bitmap->width()); EXPECT_EQ(256U, bitmap->height()); @@ -545,10 +593,12 @@ TEST_F(BitmapTest, LoadDDSFileDXT1Alpha) { String filename = *g_program_path + "/bitmap_test/dds-dxt1-256x256-alpha.dds"; FilePath filepath = UTF8ToFilePath(filename); - Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_TRUE(bitmap->LoadFromFile(filepath, image::DDS, false)); + BitmapRefArray bitmaps; + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, filepath, image::DDS, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap* bitmap = bitmaps[0].Get(); EXPECT_TRUE(bitmap->image_data() != NULL); - EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::DXT1, bitmap->format()); EXPECT_EQ(256U, bitmap->width()); EXPECT_EQ(256U, bitmap->height()); @@ -561,10 +611,12 @@ TEST_F(BitmapTest, LoadDDSFileDXT1Mipmap) { String filename = *g_program_path + "/bitmap_test/dds-dxt1-256x256-mipmap.dds"; FilePath filepath = UTF8ToFilePath(filename); - Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_TRUE(bitmap->LoadFromFile(filepath, image::DDS, false)); + BitmapRefArray bitmaps; + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, filepath, image::DDS, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap* bitmap = bitmaps[0].Get(); EXPECT_TRUE(bitmap->image_data() != NULL); - EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::DXT1, bitmap->format()); EXPECT_EQ(256U, bitmap->width()); EXPECT_EQ(256U, bitmap->height()); @@ -580,10 +632,12 @@ TEST_F(BitmapTest, LoadDDSFileDXT3) { String filename = *g_program_path + "/bitmap_test/dds-dxt3-256x256-alpha.dds"; FilePath filepath = UTF8ToFilePath(filename); - Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_TRUE(bitmap->LoadFromFile(filepath, image::DDS, false)); + BitmapRefArray bitmaps; + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, filepath, image::DDS, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap* bitmap = bitmaps[0].Get(); EXPECT_TRUE(bitmap->image_data() != NULL); - EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::DXT3, bitmap->format()); EXPECT_EQ(256U, bitmap->width()); EXPECT_EQ(256U, bitmap->height()); @@ -596,10 +650,12 @@ TEST_F(BitmapTest, LoadDDSFileDXT3Mipmap) { String filename = *g_program_path + "/bitmap_test/dds-dxt3-256x256-mipmap.dds"; FilePath filepath = UTF8ToFilePath(filename); - Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_TRUE(bitmap->LoadFromFile(filepath, image::DDS, false)); + BitmapRefArray bitmaps; + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, filepath, image::DDS, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap* bitmap = bitmaps[0].Get(); EXPECT_TRUE(bitmap->image_data() != NULL); - EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::DXT3, bitmap->format()); EXPECT_EQ(256U, bitmap->width()); EXPECT_EQ(256U, bitmap->height()); @@ -615,10 +671,12 @@ TEST_F(BitmapTest, LoadDDSFileDXT5) { String filename = *g_program_path + "/bitmap_test/dds-dxt5-256x256-alpha.dds"; FilePath filepath = UTF8ToFilePath(filename); - Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_TRUE(bitmap->LoadFromFile(filepath, image::DDS, false)); + BitmapRefArray bitmaps; + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, filepath, image::DDS, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap* bitmap = bitmaps[0].Get(); EXPECT_TRUE(bitmap->image_data() != NULL); - EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::DXT5, bitmap->format()); EXPECT_EQ(256U, bitmap->width()); EXPECT_EQ(256U, bitmap->height()); @@ -631,10 +689,12 @@ TEST_F(BitmapTest, LoadDDSFileDXT5Mipmap) { String filename = *g_program_path + "/bitmap_test/dds-dxt5-256x256-mipmap.dds"; FilePath filepath = UTF8ToFilePath(filename); - Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - EXPECT_TRUE(bitmap->LoadFromFile(filepath, image::DDS, false)); + BitmapRefArray bitmaps; + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, filepath, image::DDS, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap* bitmap = bitmaps[0].Get(); EXPECT_TRUE(bitmap->image_data() != NULL); - EXPECT_FALSE(bitmap->is_cubemap()); EXPECT_EQ(Texture::DXT5, bitmap->format()); EXPECT_EQ(256U, bitmap->width()); EXPECT_EQ(256U, bitmap->height()); @@ -652,9 +712,10 @@ TEST_F(BitmapTest, LoadDDSFileTooLarge) { // but bails before reading the actual image bytes. 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, image::DDS, false)); - EXPECT_TRUE(bitmap->image_data() == NULL); + BitmapRefArray bitmaps; + EXPECT_FALSE(Bitmap::LoadFromFile( + g_service_locator, filepath, image::DDS, &bitmaps)); + EXPECT_EQ(0, bitmaps.size()); } static uint8 kpng_8x4_drawImage[128] = { @@ -943,30 +1004,41 @@ TEST_F(BitmapTest, DrawImage) { // path of dest image. String fname_dst = *g_program_path + "/bitmap_test/png-8x4-24bit-drawimage-dest.png"; - + BitmapRefArray bitmaps; // load three src bitmaps in different sizes from files. String filename_2x2_src = *g_program_path + "/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), - image::PNG, false)); + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, UTF8ToFilePath(filename_2x2_src), + image::PNG, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap::Ref bitmap_2x2_src(bitmaps[0]); 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), - image::PNG, false)); + bitmaps.clear(); + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, UTF8ToFilePath(filename_4x4_src), + image::PNG, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap::Ref bitmap_4x4_src(bitmaps[0]); 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), - image::PNG, false)); + bitmaps.clear(); + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, UTF8ToFilePath(filename_8x8_src), + image::PNG, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap::Ref bitmap_8x8_src(bitmaps[0]); // 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), - image::PNG, false)); + bitmaps.clear(); + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, UTF8ToFilePath(fname_dst), + image::PNG, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap::Ref bitmap_dest_top_left(bitmaps[0]); // 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)); @@ -975,85 +1047,118 @@ TEST_F(BitmapTest, DrawImage) { 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), - image::PNG, false)); + bitmaps.clear(); + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, UTF8ToFilePath(fname_dst), + image::PNG, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap::Ref bitmap_dest_top(bitmaps[0]); 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), - image::PNG, false)); + bitmaps.clear(); + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, UTF8ToFilePath(fname_dst), + image::PNG, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap::Ref bitmap_dest_top_right(bitmaps[0]); bitmap_dest_top_right->DrawImage(*bitmap_4x4_src, 0, 0, 4, 4, 5, -1, 4, 4); 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), - image::PNG, false)); + bitmaps.clear(); + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, UTF8ToFilePath(fname_dst), + image::PNG, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap::Ref bitmap_dest_right(bitmaps[0]); 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), - image::PNG, false)); + bitmaps.clear(); + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, UTF8ToFilePath(fname_dst), + image::PNG, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap::Ref bitmap_dest_bottom_right(bitmaps[0]); bitmap_dest_bottom_right->DrawImage(*bitmap_4x4_src, 0, 0, 4, 4, 5, 1, 4, 4); 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), - image::PNG, false)); + bitmaps.clear(); + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, UTF8ToFilePath(fname_dst), + image::PNG, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap::Ref bitmap_dest_bottom(bitmaps[0]); 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), - image::PNG, false)); + bitmaps.clear(); + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, UTF8ToFilePath(fname_dst), + image::PNG, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap::Ref bitmap_dest_bottom_left(bitmaps[0]); bitmap_dest_bottom_left->DrawImage(*bitmap_4x4_src, 0, 0, 4, 4, -1, 1, 4, 4); 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), - image::PNG, false)); + bitmaps.clear(); + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, UTF8ToFilePath(fname_dst), + image::PNG, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap::Ref bitmap_dest_left(bitmaps[0]); 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), - image::PNG, false)); + bitmaps.clear(); + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, UTF8ToFilePath(fname_dst), + image::PNG, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap::Ref bitmap_dest_scale_up(bitmaps[0]); bitmap_dest_scale_up->DrawImage(*bitmap_2x2_src, 0, 0, 2, 2, 0, 0, 8, 4); 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), - image::PNG, false)); + bitmaps.clear(); + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, UTF8ToFilePath(fname_dst), + image::PNG, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap::Ref bitmap_dest_scale_down(bitmaps[0]); bitmap_dest_scale_down->DrawImage(*bitmap_8x8_src, 0, 0, 8, 8, 0, 0, 4, 4); 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), - image::PNG, false)); + bitmaps.clear(); + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, UTF8ToFilePath(fname_dst), + image::PNG, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap::Ref bitmap_dest_scale_out(bitmaps[0]); bitmap_dest_scale_out->DrawImage(*bitmap_8x8_src, 0, 0, 8, 8, -2, -4, 12, 12); 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), - image::PNG, false)); + bitmaps.clear(); + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, UTF8ToFilePath(fname_dst), + image::PNG, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap::Ref bitmap_dest_flip(bitmaps[0]); 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)); @@ -1061,15 +1166,21 @@ TEST_F(BitmapTest, DrawImage) { String fname_dst_argb8 = *g_program_path + "/bitmap_test/" + "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), - image::PNG, false)); + bitmaps.clear(); + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, UTF8ToFilePath(fname_dst_argb8), + image::PNG, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap::Ref bitmap_dest_argb8(bitmaps[0]); 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), - image::PNG, false)); + bitmaps.clear(); + EXPECT_TRUE(Bitmap::LoadFromFile( + g_service_locator, UTF8ToFilePath(fname_src_argb8), + image::PNG, &bitmaps)); + ASSERT_EQ(1, bitmaps.size()); + Bitmap::Ref bitmap_src_argb8(bitmaps[0]); 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 c85cca9..e31736a 100644 --- a/o3d/core/cross/bitmap_tga.cc +++ b/o3d/core/cross/bitmap_tga.cc @@ -51,9 +51,10 @@ namespace o3d { // Loads the header information and raw RGB{A} data from an uncompressed // 24-bit or 32-bit TGA stream into the Bitmap object. -bool Bitmap::LoadFromTGAStream(MemoryReadStream *stream, +bool Bitmap::LoadFromTGAStream(ServiceLocator* service_locator, + MemoryReadStream *stream, const String &filename, - bool generate_mipmaps) { + BitmapRefArray* bitmaps) { // Read the magic header. uint8 file_magic[12]; if (stream->Read(file_magic, sizeof(file_magic)) != sizeof(file_magic)) { @@ -62,7 +63,7 @@ bool Bitmap::LoadFromTGAStream(MemoryReadStream *stream, } // Match the first few bytes of the TGA header to confirm we can read this // format. Multibyte values are stored little endian. - const uint8 kTargaMagic[12] = { + static 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) @@ -109,11 +110,9 @@ bool Bitmap::LoadFromTGAStream(MemoryReadStream *stream, // pixels contained in the file. unsigned int pixel_count = tga_width * tga_height; // Allocate storage for the pixels. - unsigned int num_mipmaps = - generate_mipmaps ? image::ComputeMipMapCount(tga_width, tga_height) : 1; Texture::Format format = components == 3 ? Texture::XRGB8 : Texture::ARGB8; - unsigned int image_size = - image::ComputeMipChainSize(tga_width, tga_height, format, num_mipmaps); + size_t image_size = + image::ComputeMipChainSize(tga_width, tga_height, format, 1); scoped_array<uint8> image_data(new uint8[image_size]); if (image_data.get() == NULL) { DLOG(ERROR) << "Targa file memory allocation error \"" << filename << "\""; @@ -131,26 +130,16 @@ bool Bitmap::LoadFromTGAStream(MemoryReadStream *stream, image::XYZToXYZA(image_data.get(), pixel_count); } - if (generate_mipmaps) { - if (!GenerateMipmaps(tga_width, tga_height, format, num_mipmaps, - image_data.get())) { - DLOG(ERROR) << "mip-map generation failed for \"" << filename << "\""; - return false; - } - } - // Success. - image_data_.swap(image_data); - width_ = tga_width; - height_ = tga_height; - format_ = format; - num_mipmaps_ = num_mipmaps; + Bitmap::Ref bitmap(new Bitmap(service_locator)); + bitmap->SetContents(format, 1, tga_width, tga_height, IMAGE, &image_data); + bitmaps->push_back(bitmap); // 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(); + bitmap->FlipVertically(); return true; } diff --git a/o3d/core/cross/command_buffer/renderer_cb.cc b/o3d/core/cross/command_buffer/renderer_cb.cc index 9de0617..c5d3641 100644 --- a/o3d/core/cross/command_buffer/renderer_cb.cc +++ b/o3d/core/cross/command_buffer/renderer_cb.cc @@ -292,25 +292,6 @@ Effect::Ref RendererCB::CreateEffect() { return Effect::Ref(new EffectCB(service_locator(), this)); } -// Attempts to create a Texture with the given bitmap, automatically -// determining whether the to create a 2D texture, cube texture, etc. If -// creation fails the method returns NULL. -// Parameters: -// bitmap: The bitmap specifying the dimensions, format and content of the -// new texture. The created texture takes ownership of the bitmap -// data. -// Returns: -// A ref-counted pointer to the texture or NULL if it did not load. -Texture::Ref RendererCB::CreatePlatformSpecificTextureFromBitmap( - Bitmap *bitmap) { - if (bitmap->is_cubemap()) { - return Texture::Ref(TextureCUBECB::Create(service_locator(), bitmap, - false)); - } else { - return Texture::Ref(Texture2DCB::Create(service_locator(), bitmap, false)); - } -} - // Creates and returns a platform-specific Texture2D object. It allocates // the necessary resources to store texture data for the given image size // and format. @@ -320,12 +301,8 @@ Texture2D::Ref RendererCB::CreatePlatformSpecificTexture2D( Texture::Format format, int levels, bool enable_render_surfaces) { - Bitmap::Ref bitmap = Bitmap::Ref(new Bitmap(service_locator())); - bitmap->set_format(format); - bitmap->set_width(width); - bitmap->set_height(height); - bitmap->set_num_mipmaps(levels); - return Texture2D::Ref(Texture2DCB::Create(service_locator(), bitmap, + return Texture2D::Ref(Texture2DCB::Create(service_locator(), format, levels, + width, height, enable_render_surfaces)); } @@ -337,13 +314,8 @@ TextureCUBE::Ref RendererCB::CreatePlatformSpecificTextureCUBE( Texture::Format format, int levels, bool enable_render_surfaces) { - Bitmap::Ref bitmap = Bitmap::Ref(new Bitmap(service_locator())); - bitmap->set_format(format); - bitmap->set_width(edge); - bitmap->set_height(edge); - bitmap->set_num_mipmaps(levels); - bitmap->set_is_cubemap(true); - return TextureCUBE::Ref(TextureCUBECB::Create(service_locator(), bitmap, + return TextureCUBE::Ref(TextureCUBECB::Create(service_locator(), format, + levels, edge, enable_render_surfaces)); } diff --git a/o3d/core/cross/command_buffer/renderer_cb.h b/o3d/core/cross/command_buffer/renderer_cb.h index e7f8963..5df7936 100644 --- a/o3d/core/cross/command_buffer/renderer_cb.h +++ b/o3d/core/cross/command_buffer/renderer_cb.h @@ -212,9 +212,6 @@ class RendererCB : public Renderer { RenderDepthStencilSurface* depth_surface); // Overridden from Renderer. - virtual Texture::Ref CreatePlatformSpecificTextureFromBitmap(Bitmap* bitmap); - - // Overridden from Renderer. virtual Texture2D::Ref CreatePlatformSpecificTexture2D( int width, int height, diff --git a/o3d/core/cross/command_buffer/texture_cb.cc b/o3d/core/cross/command_buffer/texture_cb.cc index 88c529b..56b7e55 100644 --- a/o3d/core/cross/command_buffer/texture_cb.cc +++ b/o3d/core/cross/command_buffer/texture_cb.cc @@ -103,47 +103,21 @@ void UpdateResourceFromBitmap(RendererCB *renderer, ResourceID texture_id, unsigned int level, TextureCUBE::CubeFace face, - const Bitmap &bitmap, - bool resize_to_pot) { + const Bitmap &bitmap) { DCHECK(bitmap.image_data()); FencedAllocatorWrapper *allocator = renderer->allocator(); CommandBufferHelper *helper = renderer->helper(); unsigned int mip_width = std::max(1U, bitmap.width() >> level); unsigned int mip_height = std::max(1U, bitmap.height() >> level); - unsigned char *mip_data = bitmap.GetFaceMipData(face, level); - unsigned int mip_size = + unsigned char *mip_data = bitmap.GetMipData(level); + size_t mip_size = image::ComputeBufferSize(mip_width, mip_height, bitmap.format()); - if (resize_to_pot) { - unsigned int pot_width = - std::max(1U, image::ComputePOTSize(bitmap.width()) >> level); - unsigned int pot_height = - 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 - // makes 32MB for ABGR16F (the size of the transfer buffer). - // TODO: 32MB for the transfer buffer can be big (e.g. if there are - // multiple renderers). We'll want to implement a way to upload the texture - // by bits that fit into an arbitrarily small buffer, but that is complex - // for the NPOT->POT case. - DCHECK(buffer); - 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; - mip_data = buffer; - } else { - unsigned char *buffer = allocator->AllocTyped<unsigned char>(mip_size); - DCHECK(buffer); - memcpy(buffer, mip_data, mip_size); - mip_data = buffer; - } + unsigned char *buffer = allocator->AllocTyped<unsigned char>(mip_size); + DCHECK(buffer); + memcpy(buffer, mip_data, mip_size); + mip_data = buffer; - unsigned int pitch = image::ComputeBufferSize(mip_width, 1, bitmap.format()); + size_t pitch = image::ComputeBufferSize(mip_width, 1, bitmap.format()); CommandBufferEntry args[10]; args[0].value_uint32 = texture_id; @@ -179,12 +153,12 @@ void CopyBackResourceToBitmap(RendererCB *renderer, CommandBufferHelper *helper = renderer->helper(); unsigned int mip_width = std::max(1U, bitmap.width() >> level); unsigned int mip_height = std::max(1U, bitmap.height() >> level); - unsigned int mip_size = + size_t mip_size = image::ComputeBufferSize(mip_width, mip_height, bitmap.format()); unsigned char *buffer = allocator->AllocTyped<unsigned char>(mip_size); DCHECK(buffer); - unsigned int pitch = image::ComputeBufferSize(mip_width, 1, bitmap.format()); + size_t pitch = image::ComputeBufferSize(mip_width, 1, bitmap.format()); CommandBufferEntry args[10]; args[0].value_uint32 = texture_id; @@ -207,7 +181,7 @@ void CopyBackResourceToBitmap(RendererCB *renderer, args[9].value_uint32 = allocator->GetOffset(buffer); helper->AddCommand(command_buffer::GET_TEXTURE_DATA, 10, args); helper->Finish(); - memcpy(bitmap.GetFaceMipData(face, level), buffer, mip_size); + memcpy(bitmap.GetMipData(level), buffer, mip_size); allocator->Free(buffer); } @@ -223,23 +197,23 @@ static const unsigned int kMaxTextureSize = 2048; // exit. Texture2DCB::Texture2DCB(ServiceLocator* service_locator, ResourceID resource_id, - const Bitmap &bitmap, - bool resize_to_pot, + Texture::Format format, + int levels, + int width, + int height, bool enable_render_surfaces) : Texture2D(service_locator, - bitmap.width(), - bitmap.height(), - bitmap.format(), - bitmap.num_mipmaps(), - bitmap.CheckAlphaIsOne(), - resize_to_pot, + width, + height, + format, + levels, enable_render_surfaces), renderer_(static_cast<RendererCB*>( service_locator->GetService<Renderer>())), resource_id_(resource_id), has_levels_(0), backing_bitmap_(Bitmap::Ref(new Bitmap(service_locator))) { - DCHECK_NE(format(), Texture::UNKNOWN_FORMAT); + DCHECK_NE(format, Texture::UNKNOWN_FORMAT); } Texture2DCB::~Texture2DCB() { @@ -252,65 +226,42 @@ Texture2DCB::~Texture2DCB() { // Creates a new texture object from scratch. Texture2DCB* Texture2DCB::Create(ServiceLocator* service_locator, - Bitmap *bitmap, + Texture::Format format, + int levels, + int width, + int height, bool enable_render_surfaces) { - DCHECK_NE(bitmap->format(), Texture::UNKNOWN_FORMAT); - DCHECK(!bitmap->is_cubemap()); + DCHECK_NE(format, Texture::UNKNOWN_FORMAT); RendererCB *renderer = static_cast<RendererCB *>( service_locator->GetService<Renderer>()); - texture::Format cb_format = CBFormatFromO3DFormat(bitmap->format()); + texture::Format cb_format = CBFormatFromO3DFormat(format); if (cb_format == texture::NUM_FORMATS) { O3D_ERROR(service_locator) << "Unsupported format in Texture2DCB::Create."; return NULL; } - if (bitmap->width() > kMaxTextureSize || - bitmap->height() > kMaxTextureSize) { - O3D_ERROR(service_locator) << "Texture dimensions (" << bitmap->width() - << ", " << bitmap->height() << ") too big."; + if (width > kMaxTextureSize || height > kMaxTextureSize) { + O3D_ERROR(service_locator) << "Texture dimensions (" << width + << ", " << height << ") too big."; return NULL; } - bool resize_to_pot = !renderer->supports_npot() && !bitmap->IsPOT(); - - unsigned int mip_width = bitmap->width(); - unsigned int mip_height = bitmap->height(); - if (resize_to_pot) { - mip_width = image::ComputePOTSize(mip_width); - mip_height = image::ComputePOTSize(mip_height); - } - ResourceID texture_id = renderer->texture_ids().AllocateID(); CommandBufferEntry args[3]; args[0].value_uint32 = texture_id; args[1].value_uint32 = - create_texture_2d_cmd::Width::MakeValue(mip_width) | - create_texture_2d_cmd::Height::MakeValue(mip_height); + create_texture_2d_cmd::Width::MakeValue(width) | + create_texture_2d_cmd::Height::MakeValue(height); args[2].value_uint32 = - create_texture_2d_cmd::Levels::MakeValue(bitmap->num_mipmaps()) | + create_texture_2d_cmd::Levels::MakeValue(levels) | create_texture_2d_cmd::Format::MakeValue(cb_format) | create_texture_2d_cmd::Flags::MakeValue(0); renderer->helper()->AddCommand(command_buffer::CREATE_TEXTURE_2D, 3, args); - if (bitmap->image_data()) { - for (unsigned int i = 0; i < bitmap->num_mipmaps(); ++i) { - UpdateResourceFromBitmap(renderer, texture_id, i, - TextureCUBE::FACE_POSITIVE_X, *bitmap, true); - } - } Texture2DCB *texture = new Texture2DCB(service_locator, texture_id, - *bitmap, resize_to_pot, + format, levels, width, height, enable_render_surfaces); - // Setup the backing bitmap. - texture->backing_bitmap_->SetFrom(bitmap); - if (texture->backing_bitmap_->image_data()) { - if (resize_to_pot) { - texture->has_levels_ = (1 << bitmap->num_mipmaps()) - 1; - } else { - texture->backing_bitmap_->FreeData(); - } - } return texture; } @@ -342,7 +293,8 @@ bool Texture2DCB::Lock(int level, void** data, int* pitch) { } if (!backing_bitmap_->image_data()) { DCHECK_EQ(has_levels_, 0); - backing_bitmap_->Allocate(format(), width(), height(), levels(), false); + backing_bitmap_->Allocate(format(), width(), height(), levels(), + Bitmap::IMAGE); } *data = backing_bitmap_->GetMipData(level); unsigned int mip_width = image::ComputeMipDimension(level, width()); @@ -356,12 +308,10 @@ bool Texture2DCB::Lock(int level, void** data, int* pitch) { *pitch = bytes_per_row; } if (!HasLevel(level)) { - DCHECK(!resize_to_pot_); DCHECK_EQ(backing_bitmap_->width(), width()); DCHECK_EQ(backing_bitmap_->height(), height()); DCHECK_EQ(backing_bitmap_->format(), format()); DCHECK_GT(backing_bitmap_->num_mipmaps(), level); - DCHECK(!backing_bitmap_->is_cubemap()); CopyBackResourceToBitmap(renderer_, resource_id_, level, TextureCUBE::FACE_POSITIVE_X, *backing_bitmap_.Get()); @@ -391,13 +341,12 @@ bool Texture2DCB::Unlock(int level) { DCHECK_EQ(backing_bitmap_->height(), height()); DCHECK_EQ(backing_bitmap_->format(), format()); DCHECK_GT(backing_bitmap_->num_mipmaps(), level); - DCHECK(!backing_bitmap_->is_cubemap()); DCHECK(HasLevel(level)); UpdateResourceFromBitmap(renderer_, resource_id_, level, TextureCUBE::FACE_POSITIVE_X, - *backing_bitmap_.Get(), resize_to_pot_); + *backing_bitmap_.Get()); locked_levels_ &= ~(1 << level); - if (!resize_to_pot_ && (locked_levels_ == 0)) { + if (locked_levels_ == 0) { backing_bitmap_->FreeData(); has_levels_ = 0; } @@ -418,22 +367,21 @@ const Texture::RGBASwizzleIndices& Texture2DCB::GetABGR32FSwizzleIndices() { // Creates a texture from a pre-existing texture resource. TextureCUBECB::TextureCUBECB(ServiceLocator* service_locator, ResourceID resource_id, - const Bitmap &bitmap, - bool resize_to_pot, + Texture::Format format, + int levels, + int edge_length, bool enable_render_surfaces) : TextureCUBE(service_locator, - bitmap.width(), - bitmap.format(), - bitmap.num_mipmaps(), - bitmap.CheckAlphaIsOne(), - resize_to_pot, + edge_length, + format, + levels, enable_render_surfaces), renderer_(static_cast<RendererCB*>( service_locator->GetService<Renderer>())), - resource_id_(resource_id), - backing_bitmap_(Bitmap::Ref(new Bitmap(service_locator))) { - for (unsigned int i = 0; i < 6; ++i) { - has_levels_[i] = 0; + resource_id_(resource_id) { + for (int ii = 0; ii < static_cast<int>(NUMBER_OF_FACES); ++ii) { + backing_bitmaps_[ii] = Bitmap::Ref(new Bitmap(service_locator)); + has_levels_[ii] = 0; } } @@ -447,67 +395,39 @@ TextureCUBECB::~TextureCUBECB() { // Create a new Cube texture from scratch. TextureCUBECB* TextureCUBECB::Create(ServiceLocator* service_locator, - Bitmap *bitmap, + Texture::Format format, + int levels, + int edge_length, bool enable_render_surfaces) { - DCHECK_NE(bitmap->format(), Texture::UNKNOWN_FORMAT); - DCHECK(bitmap->is_cubemap()); - DCHECK_EQ(bitmap->width(), bitmap->height()); + DCHECK_NE(format, Texture::UNKNOWN_FORMAT); RendererCB *renderer = static_cast<RendererCB *>( service_locator->GetService<Renderer>()); - texture::Format cb_format = CBFormatFromO3DFormat(bitmap->format()); + texture::Format cb_format = CBFormatFromO3DFormat(format); if (cb_format == texture::NUM_FORMATS) { O3D_ERROR(service_locator) << "Unsupported format in Texture2DCB::Create."; return NULL; } - if (bitmap->width() > kMaxTextureSize) { - O3D_ERROR(service_locator) << "Texture dimensions (" << bitmap->width() - << ", " << bitmap->height() << ") too big."; + if (edge_length > kMaxTextureSize) { + O3D_ERROR(service_locator) << "Texture dimensions (" << edge_length + << ", " << edge_length << ") too big."; return NULL; } - bool resize_to_pot = !renderer->supports_npot() && !bitmap->IsPOT(); - - unsigned int mip_width = bitmap->width(); - unsigned int mip_height = bitmap->height(); - if (resize_to_pot) { - mip_width = image::ComputePOTSize(mip_width); - mip_height = image::ComputePOTSize(mip_height); - } - ResourceID texture_id = renderer->texture_ids().AllocateID(); CommandBufferEntry args[3]; args[0].value_uint32 = texture_id; - args[1].value_uint32 = create_texture_cube_cmd::Side::MakeValue(mip_width); + args[1].value_uint32 = create_texture_cube_cmd::Side::MakeValue(edge_length); args[2].value_uint32 = - create_texture_cube_cmd::Levels::MakeValue(bitmap->num_mipmaps()) | + create_texture_cube_cmd::Levels::MakeValue(levels) | create_texture_cube_cmd::Format::MakeValue(cb_format) | create_texture_cube_cmd::Flags::MakeValue(0); renderer->helper()->AddCommand(command_buffer::CREATE_TEXTURE_CUBE, 3, args); - if (bitmap->image_data()) { - for (unsigned int face = 0; face < 6; ++face) { - for (unsigned int i = 0; i < bitmap->num_mipmaps(); ++i) { - UpdateResourceFromBitmap(renderer, texture_id, i, - static_cast<CubeFace>(face), *bitmap, true); - } - } - } TextureCUBECB* texture = - new TextureCUBECB(service_locator, texture_id, *bitmap, - resize_to_pot, enable_render_surfaces); - - // Setup the backing bitmap. - texture->backing_bitmap_->SetFrom(bitmap); - if (texture->backing_bitmap_->image_data()) { - if (resize_to_pot) { - for (unsigned int face = 0; face < 6; ++face) { - texture->has_levels_[face] = (1 << bitmap->num_mipmaps()) - 1; - } - } else { - texture->backing_bitmap_->FreeData(); - } - } + new TextureCUBECB(service_locator, texture_id, format, levels, + edge_length, enable_render_surfaces); + return texture; } @@ -539,15 +459,14 @@ bool TextureCUBECB::Lock(CubeFace face, int level, void** data, int* pitch) { << "\" is already locked."; return false; } - if (!backing_bitmap_->image_data()) { - for (unsigned int i = 0; i < 6; ++i) { - DCHECK_EQ(has_levels_[i], 0); - } - backing_bitmap_->Allocate(format(), edge_length(), edge_length(), - levels(), true); + Bitmap* backing_bitmap = backing_bitmaps_[face].Get(); + if (!backing_bitmap->image_data()) { + DCHECK_EQ(has_levels_[face], 0); + backing_bitmap->Allocate(format(), edge_length(), edge_length(), levels(), + Bitmap::IMAGE); } - *data = backing_bitmap_->GetFaceMipData(face, level); - unsigned int mip_width = image::ComputeMipDimension(level, edge_length()); + *data = backing_bitmap->GetMipData(level); + unsigned int mip_width = image::ComputeMipDimension(level, edge_length()); if (!IsCompressed()) { *pitch = image::ComputePitch(format(), mip_width); } else { @@ -559,15 +478,12 @@ bool TextureCUBECB::Lock(CubeFace face, int level, void** data, int* pitch) { if (!HasLevel(level, face)) { // TODO: add some API so we don't have to copy back the data if we // will rewrite it all. - DCHECK(!resize_to_pot_); - DCHECK_EQ(backing_bitmap_->width(), edge_length()); - DCHECK_EQ(backing_bitmap_->height(), edge_length()); - DCHECK_EQ(backing_bitmap_->format(), format()); - DCHECK_GT(backing_bitmap_->num_mipmaps(), level); - DCHECK(backing_bitmap_->is_cubemap()); + DCHECK_EQ(backing_bitmap->width(), edge_length()); + DCHECK_EQ(backing_bitmap->height(), edge_length()); + DCHECK_EQ(backing_bitmap->format(), format()); + DCHECK_GT(backing_bitmap->num_mipmaps(), level); CopyBackResourceToBitmap(renderer_, resource_id_, level, - TextureCUBE::FACE_POSITIVE_X, - *backing_bitmap_.Get()); + TextureCUBE::FACE_POSITIVE_X, *backing_bitmap); has_levels_[face] |= 1 << level; } locked_levels_[face] |= 1 << level; @@ -589,30 +505,19 @@ bool TextureCUBECB::Unlock(CubeFace face, int level) { << "\" is not locked."; return false; } - DCHECK(backing_bitmap_->image_data()); - DCHECK_EQ(backing_bitmap_->width(), edge_length()); - DCHECK_EQ(backing_bitmap_->height(), edge_length()); - DCHECK_EQ(backing_bitmap_->format(), format()); - DCHECK_GT(backing_bitmap_->num_mipmaps(), level); - DCHECK(backing_bitmap_->is_cubemap()); + Bitmap* backing_bitmap = backing_bitmaps_[face].Get(); + DCHECK(backing_bitmap->image_data()); + DCHECK_EQ(backing_bitmap->width(), edge_length()); + DCHECK_EQ(backing_bitmap->height(), edge_length()); + DCHECK_EQ(backing_bitmap->format(), format()); + DCHECK_GT(backing_bitmap->num_mipmaps(), level); DCHECK(HasLevel(level, face)); UpdateResourceFromBitmap(renderer_, resource_id_, level, face, - *backing_bitmap_.Get(), resize_to_pot_); + *backing_bitmap); locked_levels_[face] &= ~(1 << level); - if (!resize_to_pot_) { - bool has_locked_level = false; - for (unsigned int i = 0; i < 6; ++i) { - if (locked_levels_[i]) { - has_locked_level = true; - break; - } - } - if (!has_locked_level) { - backing_bitmap_->FreeData(); - for (unsigned int i = 0; i < 6; ++i) { - has_levels_[i] = 0; - } - } + if (locked_levels_[face] == 0) { + backing_bitmap->FreeData(); + has_levels_[face] = 0; } return false; } diff --git a/o3d/core/cross/command_buffer/texture_cb.h b/o3d/core/cross/command_buffer/texture_cb.h index c08cfcd..6ccf9cc 100644 --- a/o3d/core/cross/command_buffer/texture_cb.h +++ b/o3d/core/cross/command_buffer/texture_cb.h @@ -61,7 +61,10 @@ class Texture2DCB : public Texture2D { // created Texture object. // The created texture takes ownership of the bitmap data. static Texture2DCB* Create(ServiceLocator* service_locator, - Bitmap *bitmap, + Texture::Format format, + int levels, + int width, + int height, bool enable_render_surfaces); // Overridden from Texture2D @@ -106,8 +109,10 @@ class Texture2DCB : public Texture2D { // The texture takes ownership of the bitmap data. Texture2DCB(ServiceLocator* service_locator, command_buffer::ResourceID resource_id, - const Bitmap &bitmap, - bool resize_npot, + Texture::Format format, + int levels, + int width, + int height, bool enable_render_surfaces); // Returns true if the backing bitmap has the data for the level. @@ -138,7 +143,9 @@ class TextureCUBECB : public TextureCUBE { // Create a new Cube texture from scratch. static TextureCUBECB* TextureCUBECB::Create(ServiceLocator* service_locator, - Bitmap *bitmap, + Texture::Format format, + int levels, + int edge_length, bool enable_render_surfaces); // Overridden from TextureCUBE @@ -187,8 +194,9 @@ class TextureCUBECB : public TextureCUBE { // Creates a texture from a pre-existing texture resource. TextureCUBECB(ServiceLocator* service_locator, command_buffer::ResourceID texture, - const Bitmap &bitmap, - bool resize_to_pot, + Texture::Format format, + int levels, + int edge_length, bool enable_render_surfaces); @@ -201,9 +209,8 @@ class TextureCUBECB : public TextureCUBE { RendererCB* renderer_; command_buffer::ResourceID resource_id_; - // A bitmap used to back the NPOT textures on POT-only hardware, and to back - // the pixel buffer for Lock(). - Bitmap::Ref backing_bitmap_; + // Bitmaps used to back the NPOT textures on POT-only hardware. + Bitmap::Ref backing_bitmaps_[NUMBER_OF_FACES]; // Bitfields that indicates mip levels that are currently stored in the // backing bitmap, one per face. diff --git a/o3d/core/cross/gl/renderer_gl.cc b/o3d/core/cross/gl/renderer_gl.cc index 4a8b215..c4a0a30 100644 --- a/o3d/core/cross/gl/renderer_gl.cc +++ b/o3d/core/cross/gl/renderer_gl.cc @@ -692,7 +692,7 @@ Renderer::InitStatus RendererGL::InitCommonGL() { return GPU_NOT_UP_TO_SPEC; } - SetSupportsNPOT(GLEW_ARB_texture_non_power_of_two); + SetSupportsNPOT(GLEW_ARB_texture_non_power_of_two != 0); #ifdef OS_MACOSX // The Radeon X1600 says it supports NPOT, but in most situations it doesn't. @@ -1115,7 +1115,7 @@ void RendererGL::Destroy() { bool RendererGL::MakeCurrent() { #ifdef OS_WIN if (!device_context_ || !gl_context_) return false; - bool result = ::wglMakeCurrent(device_context_, gl_context_); + bool result = ::wglMakeCurrent(device_context_, gl_context_) != 0; if (result) current_renderer_ = this; return result; #endif @@ -1493,28 +1493,6 @@ ParamCache* RendererGL::CreatePlatformSpecificParamCache() { } -// Attempts to create a Texture with the given bitmap, automatically -// determining whether the to create a 2D texture, cube texture, etc. If -// creation fails the method returns NULL. -// Parameters: -// bitmap: The bitmap specifying the dimensions, format and content of the -// new texture. The created texture takes ownership of the bitmap -// data. -// Returns: -// A ref-counted pointer to the texture or NULL if it did not load. -Texture::Ref RendererGL::CreatePlatformSpecificTextureFromBitmap( - Bitmap* bitmap) { - if (bitmap->is_cubemap()) { - return Texture::Ref(TextureCUBEGL::Create(service_locator(), - bitmap, - false)); - } else { - return Texture::Ref(Texture2DGL::Create(service_locator(), - bitmap, - false)); - } -} - Texture2D::Ref RendererGL::CreatePlatformSpecificTexture2D( int width, int height, @@ -1523,13 +1501,11 @@ Texture2D::Ref RendererGL::CreatePlatformSpecificTexture2D( bool enable_render_surfaces) { DLOG(INFO) << "RendererGL CreateTexture2D"; MakeCurrentLazy(); - Bitmap::Ref bitmap = Bitmap::Ref(new Bitmap(service_locator())); - bitmap->set_format(format); - bitmap->set_width(width); - bitmap->set_height(height); - bitmap->set_num_mipmaps(levels); return Texture2D::Ref(Texture2DGL::Create(service_locator(), - bitmap, + format, + levels, + width, + height, enable_render_surfaces)); } @@ -1540,14 +1516,10 @@ TextureCUBE::Ref RendererGL::CreatePlatformSpecificTextureCUBE( bool enable_render_surfaces) { DLOG(INFO) << "RendererGL CreateTextureCUBE"; MakeCurrentLazy(); - Bitmap::Ref bitmap = Bitmap::Ref(new Bitmap(service_locator())); - bitmap->set_format(format); - bitmap->set_width(edge_length); - bitmap->set_height(edge_length); - bitmap->set_num_mipmaps(levels); - bitmap->set_is_cubemap(true); return TextureCUBE::Ref(TextureCUBEGL::Create(service_locator(), - bitmap, + format, + levels, + edge_length, enable_render_surfaces)); } @@ -1563,7 +1535,7 @@ RenderDepthStencilSurface::Ref RendererGL::CreateDepthStencilSurface( Bitmap::Ref RendererGL::TakeScreenshot() {; MakeCurrentLazy(); Bitmap::Ref bitmap = Bitmap::Ref(new Bitmap(service_locator())); - bitmap->Allocate(Texture::ARGB8, width(), height(), 1, false); + bitmap->Allocate(Texture::ARGB8, width(), height(), 1, Bitmap::IMAGE); // Note: glReadPixels captures the alpha component of the frame buffer as well // as the color components, the browser usually ignores the alpha channel when diff --git a/o3d/core/cross/gl/renderer_gl.h b/o3d/core/cross/gl/renderer_gl.h index 534ea9c..2ced616 100644 --- a/o3d/core/cross/gl/renderer_gl.h +++ b/o3d/core/cross/gl/renderer_gl.h @@ -204,9 +204,6 @@ class RendererGL : public Renderer { RenderDepthStencilSurface* depth_surface); // Overridden from Renderer. - virtual Texture::Ref CreatePlatformSpecificTextureFromBitmap(Bitmap* bitmap); - - // Overridden from Renderer. virtual Texture2D::Ref CreatePlatformSpecificTexture2D( int width, int height, diff --git a/o3d/core/cross/gl/texture_gl.cc b/o3d/core/cross/gl/texture_gl.cc index 24208c0..309a59e 100644 --- a/o3d/core/cross/gl/texture_gl.cc +++ b/o3d/core/cross/gl/texture_gl.cc @@ -155,8 +155,8 @@ static bool UpdateGLImageFromBitmap(GLenum target, DCHECK(bitmap.image_data()); unsigned int mip_width = std::max(1U, bitmap.width() >> level); unsigned int mip_height = std::max(1U, bitmap.height() >> level); - const uint8 *mip_data = bitmap.GetFaceMipData(face, level); - unsigned int mip_size = + const uint8 *mip_data = bitmap.GetMipData(level); + size_t mip_size = image::ComputeBufferSize(mip_width, mip_height, bitmap.format()); scoped_array<uint8> temp_data; if (resize_to_pot) { @@ -165,8 +165,8 @@ static bool UpdateGLImageFromBitmap(GLenum target, std::max(1U, image::ComputePOTSize(bitmap.width()) >> level); unsigned int pot_height = std::max(1U, image::ComputePOTSize(bitmap.height()) >> level); - unsigned int pot_size = image::ComputeBufferSize(pot_width, pot_height, - bitmap.format()); + size_t pot_size = image::ComputeBufferSize(pot_width, pot_height, + bitmap.format()); temp_data.reset(new uint8[pot_size]); image::Scale(mip_width, mip_height, bitmap.format(), mip_data, pot_width, pot_height, temp_data.get(), @@ -192,15 +192,18 @@ static bool UpdateGLImageFromBitmap(GLenum target, // Creates the array of GL images for a particular face and upload the pixel // data from the bitmap. -static bool CreateGLImagesAndUpload(GLenum target, - GLenum internal_format, - GLenum format, - GLenum type, - TextureCUBE::CubeFace face, - const Bitmap &bitmap, - bool resize_to_pot) { - unsigned int mip_width = bitmap.width(); - unsigned int mip_height = bitmap.height(); +static bool CreateGLImages(GLenum target, + GLenum internal_format, + GLenum gl_format, + GLenum type, + TextureCUBE::CubeFace face, + Texture::Format format, + int levels, + int width, + int height, + bool resize_to_pot) { + unsigned int mip_width = width; + unsigned int mip_height = height; if (resize_to_pot) { mip_width = image::ComputePOTSize(mip_width); mip_height = image::ComputePOTSize(mip_height); @@ -210,38 +213,25 @@ static bool CreateGLImagesAndUpload(GLenum target, // do that, otherwise we'll pass an empty buffer. In that case, prepare it // here once for all. scoped_array<uint8> temp_data; - if (!bitmap.image_data()) { - unsigned int size = image::ComputeBufferSize(mip_width, mip_height, - bitmap.format()); - temp_data.reset(new uint8[size]); - memset(temp_data.get(), 0, size); - } - for (unsigned int i = 0; i < bitmap.num_mipmaps(); ++i) { - if (resize_to_pot && bitmap.image_data()) { - if (!UpdateGLImageFromBitmap(target, i, face, bitmap, true)) { - DLOG(ERROR) << "UpdateGLImageFromBitmap failed"; + size_t size = image::ComputeBufferSize(mip_width, mip_height, format); + temp_data.reset(new uint8[size]); + memset(temp_data.get(), 0, size); + + for (unsigned int i = 0; i < levels; ++i) { + if (gl_format) { + glTexImage2D(target, i, internal_format, mip_width, mip_height, + 0, format, type, temp_data.get()); + if (glGetError() != GL_NO_ERROR) { + DLOG(ERROR) << "glTexImage2D failed"; return false; } } else { - uint8 *data = resize_to_pot ? NULL : bitmap.GetFaceMipData(face, i); - data = data ? data : temp_data.get(); - if (format) { - glTexImage2D(target, i, internal_format, mip_width, mip_height, - 0, format, type, data); - if (glGetError() != GL_NO_ERROR) { - DLOG(ERROR) << "glTexImage2D failed"; - return false; - } - } else { - 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, data); - if (glGetError() != GL_NO_ERROR) { - DLOG(ERROR) << "glCompressedTexImage2D failed"; - return false; - } + size_t mip_size = image::ComputeBufferSize(mip_width, mip_height, format); + glCompressedTexImage2DARB(target, i, internal_format, mip_width, + mip_height, 0, mip_size, temp_data.get()); + if (glGetError() != GL_NO_ERROR) { + DLOG(ERROR) << "glCompressedTexImage2D failed"; + return false; } } mip_width = std::max(1U, mip_width >> 1); @@ -256,39 +246,43 @@ static bool CreateGLImagesAndUpload(GLenum target, // NOTE: the Texture2DGL now owns the GL texture and will destroy it on exit. Texture2DGL::Texture2DGL(ServiceLocator* service_locator, GLint texture, - const Bitmap &bitmap, + Texture::Format format, + int levels, + int width, + int height, bool resize_to_pot, bool enable_render_surfaces) : Texture2D(service_locator, - bitmap.width(), - bitmap.height(), - bitmap.format(), - bitmap.num_mipmaps(), - bitmap.CheckAlphaIsOne(), - resize_to_pot, + width, + height, + format, + levels, enable_render_surfaces), + resize_to_pot_(resize_to_pot), renderer_(static_cast<RendererGL*>( service_locator->GetService<Renderer>())), gl_texture_(texture), backing_bitmap_(Bitmap::Ref(new Bitmap(service_locator))), has_levels_(0) { DLOG(INFO) << "Texture2DGL Construct from GLint"; - DCHECK_NE(format(), Texture::UNKNOWN_FORMAT); + DCHECK_NE(format, Texture::UNKNOWN_FORMAT); } // Creates a new texture object from scratch. Texture2DGL* Texture2DGL::Create(ServiceLocator* service_locator, - Bitmap *bitmap, + Texture::Format format, + int levels, + int width, + int height, bool enable_render_surfaces) { DLOG(INFO) << "Texture2DGL Create"; - DCHECK_NE(bitmap->format(), Texture::UNKNOWN_FORMAT); - DCHECK(!bitmap->is_cubemap()); + DCHECK_NE(format, Texture::UNKNOWN_FORMAT); RendererGL *renderer = static_cast<RendererGL *>( service_locator->GetService<Renderer>()); renderer->MakeCurrentLazy(); GLenum gl_internal_format = 0; GLenum gl_data_type = 0; - GLenum gl_format = GLFormatFromO3DFormat(bitmap->format(), + GLenum gl_format = GLFormatFromO3DFormat(format, &gl_internal_format, &gl_data_type); if (gl_internal_format == 0) { @@ -296,18 +290,19 @@ Texture2DGL* Texture2DGL::Create(ServiceLocator* service_locator, return NULL; } - bool resize_to_pot = !renderer->supports_npot() && !bitmap->IsPOT(); + bool resize_to_pot = !renderer->supports_npot() && + !image::IsPOT(width, height); // Creates the OpenGL texture object, with all the required mip levels. GLuint gl_texture = 0; glGenTextures(1, &gl_texture); glBindTexture(GL_TEXTURE_2D, gl_texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, - bitmap->num_mipmaps()-1); + levels - 1); - if (!CreateGLImagesAndUpload(GL_TEXTURE_2D, gl_internal_format, gl_format, - gl_data_type, TextureCUBE::FACE_POSITIVE_X, - *bitmap, resize_to_pot)) { + if (!CreateGLImages(GL_TEXTURE_2D, gl_internal_format, gl_format, + gl_data_type, TextureCUBE::FACE_POSITIVE_X, + format, levels, width, height, resize_to_pot)) { DLOG(ERROR) << "Failed to create texture images."; glDeleteTextures(1, &gl_texture); return NULL; @@ -328,26 +323,18 @@ Texture2DGL* Texture2DGL::Create(ServiceLocator* service_locator, << ", GLuint=" << gl_texture << ")"; Texture2DGL *texture = new Texture2DGL(service_locator, gl_texture, - *bitmap, + format, + levels, + width, + height, resize_to_pot, enable_render_surfaces); - // Setup the backing bitmap. - texture->backing_bitmap_->SetFrom(bitmap); - if (texture->backing_bitmap_->image_data()) { - if (resize_to_pot) { - texture->has_levels_ = (1 << bitmap->num_mipmaps()) - 1; - } else { - texture->backing_bitmap_->FreeData(); - } - } else { - // If no backing store was provided to the routine, and the hardware does - // not support npot textures, allocate a 0-initialized mip-chain here - // for use during Texture2DGL::Lock. - if (resize_to_pot) { - texture->backing_bitmap_->AllocateData(); - texture->has_levels_ = (1 << bitmap->num_mipmaps()) - 1; - } + // If the hardware does not support npot textures, allocate a 0-initialized + // mip-chain here for use during Texture2DGL::Lock. + if (resize_to_pot) { + texture->backing_bitmap_->AllocateData(); + texture->has_levels_ = (1 << levels) - 1; } CHECK_GL_ERROR(); return texture; @@ -481,7 +468,8 @@ bool Texture2DGL::Lock(int level, void** data, int* pitch) { } if (!backing_bitmap_->image_data()) { DCHECK_EQ(has_levels_, 0u); - backing_bitmap_->Allocate(format(), width(), height(), levels(), false); + backing_bitmap_->Allocate(format(), width(), height(), levels(), + Bitmap::IMAGE); } *data = backing_bitmap_->GetMipData(level); unsigned int mip_width = image::ComputeMipDimension(level, width()); @@ -579,23 +567,24 @@ const Texture::RGBASwizzleIndices& Texture2DGL::GetABGR32FSwizzleIndices() { // Creates a texture from a pre-existing GL texture object. TextureCUBEGL::TextureCUBEGL(ServiceLocator* service_locator, GLint texture, - const Bitmap &bitmap, + Texture::Format format, + int levels, + int edge_length, bool resize_to_pot, bool enable_render_surfaces) : TextureCUBE(service_locator, - bitmap.width(), - bitmap.format(), - bitmap.num_mipmaps(), - bitmap.CheckAlphaIsOne(), - resize_to_pot, + edge_length, + format, + levels, enable_render_surfaces), + resize_to_pot_(resize_to_pot), renderer_(static_cast<RendererGL*>( service_locator->GetService<Renderer>())), - gl_texture_(texture), - backing_bitmap_(Bitmap::Ref(new Bitmap(service_locator))) { + gl_texture_(texture) { DLOG(INFO) << "TextureCUBEGL Construct"; - for (unsigned int i = 0; i < 6; ++i) { - has_levels_[i] = 0; + for (int ii = 0; ii < static_cast<int>(NUMBER_OF_FACES); ++ii) { + backing_bitmaps_[ii] = Bitmap::Ref(new Bitmap(service_locator)); + has_levels_[ii] = 0; } } @@ -620,22 +609,23 @@ static const int kCubemapFaceList[] = { // Create a new Cube texture from scratch. TextureCUBEGL* TextureCUBEGL::Create(ServiceLocator* service_locator, - Bitmap *bitmap, + Texture::Format format, + int levels, + int edge_length, bool enable_render_surfaces) { DLOG(INFO) << "TextureCUBEGL Create"; CHECK_GL_ERROR(); - DCHECK(bitmap->is_cubemap()); - DCHECK_EQ(bitmap->width(), bitmap->height()); RendererGL *renderer = static_cast<RendererGL *>( service_locator->GetService<Renderer>()); renderer->MakeCurrentLazy(); - bool resize_to_pot = !renderer->supports_npot() && !bitmap->IsPOT(); + bool resize_to_pot = !renderer->supports_npot() && + !image::IsPOT(edge_length, edge_length); // Get gl formats GLenum gl_internal_format = 0; GLenum gl_data_type = 0; - GLenum gl_format = GLFormatFromO3DFormat(bitmap->format(), + GLenum gl_format = GLFormatFromO3DFormat(format, &gl_internal_format, &gl_data_type); if (gl_internal_format == 0) { @@ -648,13 +638,14 @@ TextureCUBEGL* TextureCUBEGL::Create(ServiceLocator* service_locator, glGenTextures(1, &gl_texture); glBindTexture(GL_TEXTURE_CUBE_MAP, gl_texture); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, - bitmap->num_mipmaps()-1); + levels - 1); - for (int face = 0; face < 6; ++face) { - CreateGLImagesAndUpload(kCubemapFaceList[face], gl_internal_format, - gl_format, gl_data_type, - static_cast<CubeFace>(face), *bitmap, - resize_to_pot); + for (int face = 0; face < static_cast<int>(NUMBER_OF_FACES); ++face) { + CreateGLImages(kCubemapFaceList[face], gl_internal_format, + gl_format, gl_data_type, + static_cast<CubeFace>(face), + format, levels, edge_length, edge_length, + resize_to_pot); } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, @@ -667,28 +658,17 @@ TextureCUBEGL* TextureCUBEGL::Create(ServiceLocator* service_locator, // from the Bitmap information. TextureCUBEGL* texture = new TextureCUBEGL(service_locator, gl_texture, - *bitmap, + format, + levels, + edge_length, resize_to_pot, enable_render_surfaces); - // Setup the backing bitmap, and upload the data if we have any. - texture->backing_bitmap_->SetFrom(bitmap); - if (texture->backing_bitmap_->image_data()) { - if (resize_to_pot) { - for (unsigned int face = 0; face < 6; ++face) { - texture->has_levels_[face] = (1 << bitmap->num_mipmaps()) - 1; - } - } else { - texture->backing_bitmap_->FreeData(); - } - } else { - // If no backing store was provided to the routine, and the hardware does - // not support npot textures, allocate a 0-initialized mip-chain here - // for use during TextureCUBEGL::Lock. - if (resize_to_pot) { - texture->backing_bitmap_->AllocateData(); - for (unsigned int face = 0; face < 6; ++face) { - texture->has_levels_[face] = (1 << bitmap->num_mipmaps()) - 1; - } + // If the hardware does not support npot textures, allocate a 0-initialized + // mip-chain here for use during TextureCUBEGL::Lock. + if (resize_to_pot) { + for (int face = 0; face < static_cast<int>(NUMBER_OF_FACES); ++face) { + texture->backing_bitmaps_[face]->AllocateData(); + texture->has_levels_[face] = (1 << levels) - 1; } } CHECK_GL_ERROR(); @@ -698,17 +678,16 @@ TextureCUBEGL* TextureCUBEGL::Create(ServiceLocator* service_locator, void TextureCUBEGL::UpdateBackedMipLevel(unsigned int level, TextureCUBE::CubeFace face) { + Bitmap* backing_bitmap = backing_bitmaps_[face].Get(); DCHECK_LT(static_cast<int>(level), levels()); - DCHECK(backing_bitmap_->image_data()); - DCHECK(backing_bitmap_->is_cubemap()); - DCHECK_EQ(backing_bitmap_->width(), static_cast<unsigned int>(edge_length())); - DCHECK_EQ(backing_bitmap_->height(), - static_cast<unsigned int>(edge_length())); - DCHECK_EQ(backing_bitmap_->format(), format()); + DCHECK(backing_bitmap->image_data()); + DCHECK_EQ(backing_bitmap->width(), static_cast<unsigned int>(edge_length())); + DCHECK_EQ(backing_bitmap->height(), static_cast<unsigned int>(edge_length())); + DCHECK_EQ(backing_bitmap->format(), format()); DCHECK(HasLevel(level, face)); glBindTexture(GL_TEXTURE_2D, gl_texture_); UpdateGLImageFromBitmap(kCubemapFaceList[face], level, face, - *backing_bitmap_.Get(), + *backing_bitmap, resize_to_pot_); } @@ -795,11 +774,12 @@ void TextureCUBEGL::SetRect(TextureCUBE::CubeFace face, } if (resize_to_pot_) { - DCHECK(backing_bitmap_->image_data()); + Bitmap* backing_bitmap = backing_bitmaps_[face].Get(); + DCHECK(backing_bitmap->image_data()); DCHECK(!compressed); // We need to update the backing mipmap and then use that to update the // texture. - backing_bitmap_->SetFaceRect(face, + backing_bitmap->SetRect( level, dst_left, dst_top, src_width, src_height, src_data, src_pitch); UpdateBackedMipLevel(level, face); } else { @@ -858,14 +838,15 @@ bool TextureCUBEGL::Lock(CubeFace face, int level, void** data, int* pitch) { << "\" is already locked."; return false; } - if (!backing_bitmap_->image_data()) { + Bitmap* backing_bitmap = backing_bitmaps_[face].Get(); + if (!backing_bitmap->image_data()) { for (unsigned int i = 0; i < 6; ++i) { DCHECK_EQ(has_levels_[i], 0u); } - backing_bitmap_->Allocate(format(), edge_length(), edge_length(), - levels(), true); + backing_bitmap->Allocate(format(), edge_length(), edge_length(), levels(), + Bitmap::IMAGE); } - *data = backing_bitmap_->GetFaceMipData(face, level); + *data = backing_bitmap->GetMipData(level); unsigned int mip_width = image::ComputeMipDimension(level, edge_length()); if (!IsCompressed()) { *pitch = image::ComputePitch(format(), mip_width); @@ -912,6 +893,7 @@ bool TextureCUBEGL::Unlock(CubeFace face, int level) { return false; } UpdateBackedMipLevel(level, face); + Bitmap* backing_bitmap = backing_bitmaps_[face].Get(); locked_levels_[face] &= ~(1 << level); if (!resize_to_pot_) { bool has_locked_level = false; @@ -922,7 +904,7 @@ bool TextureCUBEGL::Unlock(CubeFace face, int level) { } } if (!has_locked_level) { - backing_bitmap_->FreeData(); + backing_bitmap->FreeData(); for (unsigned int i = 0; i < 6; ++i) { has_levels_[i] = 0; } diff --git a/o3d/core/cross/gl/texture_gl.h b/o3d/core/cross/gl/texture_gl.h index 567bf2b..a107de6 100644 --- a/o3d/core/cross/gl/texture_gl.h +++ b/o3d/core/cross/gl/texture_gl.h @@ -82,7 +82,10 @@ class Texture2DGL : public Texture2D { // newly created Texture object. // The created texture takes ownership of the bitmap data. static Texture2DGL* Create(ServiceLocator* service_locator, - Bitmap *bitmap, + Texture::Format format, + int levels, + int width, + int height, bool enable_render_surfaces); // Returns the implementation-specific texture handle for this texture. @@ -118,7 +121,10 @@ class Texture2DGL : public Texture2D { // The texture takes ownership of the bitmap data. Texture2DGL(ServiceLocator* service_locator, GLint texture, - const Bitmap &bitmap, + Texture::Format format, + int levels, + int width, + int height, bool resize_npot, bool enable_render_surfaces); @@ -132,6 +138,10 @@ class Texture2DGL : public Texture2D { return (has_levels_ & (1 << level)) != 0; } + // Whether or not this texture needs to be resized from NPOT to pot behind + // the scenes. + bool resize_to_pot_; + RendererGL* renderer_; // The handle of the OpenGL texture object. @@ -157,7 +167,9 @@ class TextureCUBEGL : public TextureCUBE { // Create a new Cube texture from scratch. static TextureCUBEGL* Create(ServiceLocator* service_locator, - Bitmap *bitmap, + Texture::Format format, + int levels, + int edge_length, bool enable_render_surfaces); // Overridden from TextureCUBE @@ -205,7 +217,9 @@ class TextureCUBEGL : public TextureCUBE { // Creates a texture from a pre-existing GL texture object. TextureCUBEGL(ServiceLocator* service_locator, GLint texture, - const Bitmap &bitmap, + Texture::Format format, + int levels, + int edge_length, bool resize_to_pot, bool enable_render_surfaces); @@ -219,14 +233,17 @@ class TextureCUBEGL : public TextureCUBE { return (has_levels_[face] & (1 << level)) != 0; } + // Whether or not this texture needs to be resized from NPOT to pot behind + // the scenes. + bool resize_to_pot_; + RendererGL* renderer_; // The handle of the OpenGL texture object. GLuint gl_texture_; - // A bitmap used to back the NPOT textures on POT-only hardware, and to back - // the pixel buffer for Lock(). - Bitmap::Ref backing_bitmap_; + // Bitmaps used to back the NPOT textures on POT-only hardware. + Bitmap::Ref backing_bitmaps_[NUMBER_OF_FACES]; // Bitfields that indicates mip levels that are currently stored in the // backing bitmap, one per face. diff --git a/o3d/core/cross/image_utils.cc b/o3d/core/cross/image_utils.cc index 3e96634..5570d2b 100644 --- a/o3d/core/cross/image_utils.cc +++ b/o3d/core/cross/image_utils.cc @@ -37,15 +37,17 @@ #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.
-unsigned int ComputeBufferSize(unsigned int width,
- unsigned int height,
- Texture::Format format) {
+size_t ComputeBufferSize(unsigned int width,
+ unsigned int height,
+ Texture::Format format) {
DCHECK(CheckImageDimensions(width, height));
unsigned int pixels = width * height;
switch (format) {
@@ -75,12 +77,12 @@ unsigned int ComputeBufferSize(unsigned int width, // 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 ComputeMipChainSize(unsigned int base_width,
- unsigned int base_height,
- Texture::Format format,
- unsigned int num_mipmaps) {
+size_t ComputeMipChainSize(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;
+ 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) {
@@ -122,22 +124,21 @@ bool ScaleUpToPOT(unsigned int width, }
unsigned int GetNumComponentsForFormat(o3d::Texture::Format format) {
- unsigned int components = 0;
switch (format) {
case o3d::Texture::XRGB8:
case o3d::Texture::ARGB8:
- components = 4;
- break;
case o3d::Texture::ABGR16F:
- case o3d::Texture::R32F:
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 components;
+ return 0;
}
namespace {
@@ -400,15 +401,19 @@ void LanczosResize1D(const uint8* src, int src_x, int src_y, // 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,
- uint8 *dst_data,
+ void *dst_data,
int dst_pitch,
unsigned int src_width,
unsigned int src_height,
- const uint8 *src_data,
+ const void *src_data,
int src_pitch,
unsigned int components) {
DCHECK(image::CheckImageDimensions(src_width, src_height));
@@ -420,6 +425,12 @@ void FilterTexel(unsigned int x, DCHECK_LE(static_cast<int>(src_width), src_pitch);
DCHECK_LE(static_cast<int>(dst_width), dst_pitch);
+ const OriginalType* src = static_cast<const OriginalType*>(src_data);
+ OriginalType* dst = static_cast<OriginalType*>(dst_data);
+
+ DCHECK_EQ(src_pitch % (components * sizeof(*src)), 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
@@ -429,10 +440,12 @@ void FilterTexel(unsigned int x, // 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;
+ 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
@@ -446,7 +459,7 @@ void FilterTexel(unsigned int x, // 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};
+ 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
@@ -480,21 +493,119 @@ void FilterTexel(unsigned int x, }
DCHECK(y_contrib > 0);
DCHECK(y_contrib <= dst_height);
- unsigned int contrib = x_contrib * y_contrib;
+ WorkType contrib = static_cast<WorkType>(x_contrib * y_contrib);
for (unsigned int c = 0; c < components; ++c) {
- accum[c] +=
- contrib * src_data[(src_y * src_pitch + src_x) * 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) {
- uint64 value = accum[c] / (src_height * src_width);
- DCHECK_LE(value, 255u);
- dst_data[(y * dst_pitch + x) * components + c] =
- static_cast<uint8>(value);
+ 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.
@@ -595,34 +706,31 @@ bool GenerateMipmap(unsigned int src_width, DLOG(ERROR) << "Mip-map generation not supported for format: " << format;
return false;
}
- unsigned int mip_width = std::max(1U, src_width >> 1);
- unsigned int mip_height = std::max(1U, src_height >> 1);
- if (mip_width * 2 == src_width && mip_height * 2 == src_height) {
- 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;
- unsigned int value = src_data[offset]; // (2x, 2y)
- value += src_data[offset + components]; // (2x+1, 2y)
- value += src_data[offset + src_width * components]; // (2x, 2y+1)
- value +=
- src_data[offset + (src_width + 1) * components]; // (2x+1, 2y+1)
- dst_data[(y * dst_pitch + 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, dst_data, dst_pitch,
- src_width, src_height, src_data, src_pitch, components);
- }
- }
+ 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;
}
diff --git a/o3d/core/cross/image_utils.h b/o3d/core/cross/image_utils.h index 2b6212e..e37d8eb 100644 --- a/o3d/core/cross/image_utils.h +++ b/o3d/core/cross/image_utils.h @@ -58,6 +58,10 @@ enum ImageFileType { unsigned int GetNumComponentsForFormat(Texture::Format format);
+inline bool IsPOT(unsigned width, unsigned height) {
+ return ((width & (width - 1)) == 0) && ((height & (height - 1)) == 0);
+}
+
inline bool CheckImageDimensions(unsigned int width, unsigned int height) {
return width <= kMaxImageDimension && height <= kMaxImageDimension;
}
@@ -83,10 +87,10 @@ inline unsigned ComputeMipDimension(int level, unsigned dimension) { // Computes the size of the buffer containing a mip-map chain, given its base
// width, height, format and number of mip-map levels.
-unsigned int ComputeMipChainSize(unsigned int base_width,
- unsigned int base_height,
- Texture::Format format,
- unsigned int num_mipmaps);
+size_t ComputeMipChainSize(unsigned int base_width,
+ unsigned int base_height,
+ Texture::Format format,
+ unsigned int num_mipmaps);
inline int ComputePitch(Texture::Format format, unsigned width) {
if (Texture::IsCompressedFormat(format)) {
@@ -94,7 +98,7 @@ inline int ComputePitch(Texture::Format format, unsigned width) { unsigned bytes_per_block = format == Texture::DXT1 ? 8u : 16u;
return bytes_per_block * blocks_across;
} else {
- return ComputeMipChainSize(width, 1u, format, 1u);
+ return static_cast<int>(ComputeMipChainSize(width, 1u, format, 1u));
}
}
@@ -107,9 +111,9 @@ inline int ComputeMipPitch(Texture::Format format, }
// Computes the number of bytes of a bitmap pixel buffer.
-unsigned int ComputeBufferSize(unsigned int width,
- unsigned int height,
- Texture::Format format);
+size_t ComputeBufferSize(unsigned int width,
+ unsigned int height,
+ Texture::Format format);
// Crop part of an image from src, scale it to an arbitrary size
// and paste in dest image. Utility function for all DrawImage
diff --git a/o3d/core/cross/image_utils_test.cc b/o3d/core/cross/image_utils_test.cc index 4f6a1c3..b7ca6f6 100644 --- a/o3d/core/cross/image_utils_test.cc +++ b/o3d/core/cross/image_utils_test.cc @@ -119,11 +119,9 @@ TEST_F(ImageTest, ScaleUpToPOT) { const unsigned int kPOTHeight = image::ComputePOTSize(kHeight); ASSERT_EQ(kPOTHeight, 4u); const Texture::Format format = Texture::ARGB8; - unsigned int src_size = - image::ComputeBufferSize(kWidth, kHeight, format); + size_t src_size = image::ComputeBufferSize(kWidth, kHeight, format); ASSERT_EQ(sizeof(kScaleUPDataNPOT), src_size); - unsigned int dst_size = - image::ComputeBufferSize(kPOTWidth, kPOTHeight, format); + size_t dst_size = image::ComputeBufferSize(kPOTWidth, kPOTHeight, format); ASSERT_EQ(sizeof(kScaleUPDataPOT), dst_size); scoped_array<uint8> data(new uint8[dst_size]); ASSERT_TRUE(data.get() != NULL); @@ -173,14 +171,12 @@ TEST_F(ImageTest, GenerateMipmapsPOT) { const Texture::Format format = Texture::ARGB8; unsigned int mipmaps = image::ComputeMipMapCount(kWidth, kHeight); EXPECT_EQ(3u, mipmaps); - unsigned int size = - image::ComputeMipChainSize(kWidth, kHeight, format, mipmaps); + size_t size = image::ComputeMipChainSize(kWidth, kHeight, format, mipmaps); ASSERT_EQ(sizeof(kMipmapDataPOT), size); scoped_array<uint8> data(new uint8[size]); ASSERT_TRUE(data.get() != NULL); // Copy first level into the buffer. - unsigned int base_size = - image::ComputeMipChainSize(kWidth, kHeight, format, 1); + size_t base_size = image::ComputeMipChainSize(kWidth, kHeight, format, 1); memcpy(data.get(), kMipmapDataPOT, base_size); image::GenerateMipmap( kWidth, kHeight, format, @@ -244,14 +240,12 @@ TEST_F(ImageTest, GenerateMipmapsNPOT) { const Texture::Format format = Texture::ARGB8; unsigned int mipmaps = image::ComputeMipMapCount(kWidth, kHeight); EXPECT_EQ(3u, mipmaps); - unsigned int size = - image::ComputeMipChainSize(kWidth, kHeight, format, mipmaps); + size_t size = image::ComputeMipChainSize(kWidth, kHeight, format, mipmaps); ASSERT_EQ(sizeof(kMipmapDataNPOT), size); scoped_array<uint8> data(new uint8[size]); ASSERT_TRUE(data.get() != NULL); // Copy first level into the buffer. - unsigned int base_size = - image::ComputeMipChainSize(kWidth, kHeight, format, 1); + size_t base_size = image::ComputeMipChainSize(kWidth, kHeight, format, 1); memcpy(data.get(), kMipmapDataNPOT, base_size); image::GenerateMipmap( kWidth, kHeight, format, diff --git a/o3d/core/cross/pack.cc b/o3d/core/cross/pack.cc index eb19e05..a874c02 100644 --- a/o3d/core/cross/pack.cc +++ b/o3d/core/cross/pack.cc @@ -42,6 +42,7 @@ #include "import/cross/memory_buffer.h" #include "import/cross/memory_stream.h" #include "core/cross/file_request.h" +#include "core/cross/image_utils.h" #include "core/cross/render_node.h" #include "core/cross/iclass_manager.h" #include "core/cross/object_manager.h" @@ -123,26 +124,20 @@ Texture* Pack::CreateTextureFromFile(const String& uri, const FilePath& filepath, image::ImageFileType file_type, bool generate_mipmaps) { - if (!renderer_) { - O3D_ERROR(service_locator()) << "No Render Device Available"; - return NULL; - } - String filename = FilePathToUTF8(filepath); DLOG(INFO) << "CreateTextureFromFile(uri='" << uri << "', filename='" << filename << "')"; - // TODO: Add support for volume texture when we have code to load - // them - Bitmap::Ref bitmap(new Bitmap(service_locator())); - if (!bitmap->LoadFromFile(filepath, file_type, generate_mipmaps)) { + // TODO(gman): Add support for volume texture when we have code to load them. + BitmapRefArray bitmaps; + if (!Bitmap::LoadFromFile(service_locator(), filepath, file_type, &bitmaps)) { O3D_ERROR(service_locator()) << "Failed to load bitmap file \"" << uri << "\""; return NULL; } - return CreateTextureFromBitmap(bitmap, uri); + return CreateTextureFromBitmaps(bitmaps, uri, generate_mipmaps); } // Creates a Texture object from a file in the current render context format. @@ -160,28 +155,87 @@ Texture* Pack::CreateTextureFromFile(const String& uri, } // Creates a Texture object from a bitmap in the current render context format. -Texture* Pack::CreateTextureFromBitmap(Bitmap *bitmap, const String& uri) { - DCHECK(bitmap); - - if (!renderer_) { - O3D_ERROR(service_locator()) << "No Render Device Available"; +Texture* Pack::CreateTextureFromBitmaps( + const BitmapRefArray& bitmaps, const String& uri, bool generate_mipmaps) { + if (bitmaps.empty()) { return NULL; } - - if (bitmap->width() > static_cast<unsigned int>(Texture::MAX_DIMENSION) || - bitmap->height() > static_cast<unsigned int>(Texture::MAX_DIMENSION)) { - O3D_ERROR(service_locator()) - << "Texture (uri='" << uri - << "', size=" << bitmap->width() << "x" << bitmap->height() - << ", mips=" << bitmap->num_mipmaps()<< ") is larger than the " - << "maximum texture size which is (" << Texture::MAX_DIMENSION - << "x" << Texture::MAX_DIMENSION << ")"; - return NULL; + unsigned width = bitmaps[0]->width(); + unsigned height = bitmaps[0]->height(); + + BitmapRefArray temp_bitmaps; + for (BitmapRefArray::size_type ii = 0; ii < bitmaps.size(); ++ii) { + temp_bitmaps.push_back(bitmaps[ii]); + Bitmap* bitmap = temp_bitmaps[ii].Get(); + if (bitmap->width() > static_cast<unsigned int>(Texture::MAX_DIMENSION) || + bitmap->height() > static_cast<unsigned int>(Texture::MAX_DIMENSION)) { + O3D_ERROR(service_locator()) + << "Bitmap (uri='" << uri + << "', size=" << bitmap->width() << "x" << bitmap->height() + << ", mips=" << bitmap->num_mipmaps()<< ") is larger than the " + << "maximum texture size which is (" << Texture::MAX_DIMENSION + << "x" << Texture::MAX_DIMENSION << ")"; + return NULL; + } + if (bitmap->width() != width || bitmap->height() != height) { + O3D_ERROR(service_locator()) << "Bitmaps are not all the same dimensions"; + return NULL; + } + if (generate_mipmaps) { + unsigned total_mips = image::ComputeMipMapCount( + bitmap->width(), bitmap->height()); + // If we don't already have mips and we could use them then make them. + if (bitmap->num_mipmaps() == 1 && total_mips > 1) { + // Create a new Bitmap with mips + Bitmap::Ref new_bitmap(new Bitmap(service_locator())); + new_bitmap->Allocate(bitmap->format(), + bitmap->width(), + bitmap->height(), + total_mips, + bitmap->semantic()); + new_bitmap->SetRect(0, 0, 0, bitmap->width(), bitmap->height(), + bitmap->GetMipData(0), bitmap->GetMipPitch(0)); + new_bitmap->GenerateMips(0, total_mips - 1); + temp_bitmaps[ii] = new_bitmap; + } + } } - Texture::Ref texture = renderer_->CreateTextureFromBitmap(bitmap); + // Figure out what kind of texture to make. + // TODO(gman): Refactor to check semantics to distinguish between CUBE and + // VOLUME textures. + Texture::Ref texture; + if (temp_bitmaps.size() == 1) { + Bitmap* bitmap = temp_bitmaps[0].Get(); + Texture2D::Ref texture_2d = renderer_->CreateTexture2D( + bitmap->width(), + bitmap->height(), + bitmap->format(), + bitmap->num_mipmaps(), + false); + if (!texture_2d.IsNull()) { + texture = Texture::Ref(texture_2d.Get()); + texture_2d->SetFromBitmap(*bitmap); + } + } else if (temp_bitmaps.size() == 6) { + Bitmap* bitmap = temp_bitmaps[0].Get(); + TextureCUBE::Ref texture_cube = renderer_->CreateTextureCUBE( + bitmap->width(), + bitmap->format(), + bitmap->num_mipmaps(), + false); + if (!texture_cube.IsNull()) { + texture = Texture::Ref(texture_cube.Get()); + for (unsigned ii = 0; ii < 6; ++ii) { + texture_cube->SetFromBitmap(static_cast<TextureCUBE::CubeFace>(ii), + *temp_bitmaps[ii].Get()); + } + } + } if (!texture.IsNull()) { + // TODO(gman): remove this. Maybe set the name? or make uri an offical + // Texture param. ParamString* param = texture->CreateParam<ParamString>( O3D_STRING_CONSTANT("uri")); DCHECK(param != NULL); @@ -191,8 +245,8 @@ Texture* Pack::CreateTextureFromBitmap(Bitmap *bitmap, const String& uri) { } else { O3D_ERROR(service_locator()) << "Unable to create texture (uri='" << uri - << "', size=" << bitmap->width() << "x" << bitmap->height() - << ", mips=" << bitmap->num_mipmaps()<< ")"; + << "', size=" << width << "x" << height + << ", mips=" << temp_bitmaps[0]->num_mipmaps() << ")"; } return texture.Get(); @@ -211,20 +265,18 @@ Texture* Pack::CreateTextureFromRawData(RawData *raw_data, DLOG(INFO) << "CreateTextureFromRawData(uri='" << uri << "')"; - - Bitmap::Ref bitmap(new Bitmap(service_locator())); - if (!bitmap->LoadFromRawData(raw_data, image::UNKNOWN, generate_mips)) { + BitmapRefArray bitmap_refs; + if (!Bitmap::LoadFromRawData(raw_data, image::UNKNOWN, &bitmap_refs)) { O3D_ERROR(service_locator()) << "Failed to load bitmap from raw data \"" << uri << "\""; return NULL; } - return CreateTextureFromBitmap(bitmap, uri); + return CreateTextureFromBitmaps(bitmap_refs, uri, generate_mips); } // Create a bitmap object. -Bitmap* Pack::CreateBitmap(int width, int height, - Texture::Format format) { +Bitmap* Pack::CreateBitmap(int width, int height, Texture::Format format) { DCHECK(image::CheckImageDimensions(width, height)); Bitmap::Ref bitmap(new Bitmap(service_locator())); @@ -233,7 +285,7 @@ Bitmap* Pack::CreateBitmap(int width, int height, << "Failed to create bitmap object."; return NULL; } - bitmap->Allocate(format, width, height, 1, false); + bitmap->Allocate(format, width, height, 1, Bitmap::IMAGE); if (!bitmap->image_data()) { O3D_ERROR(service_locator()) << "Failed to allocate memory for bitmap."; @@ -244,20 +296,18 @@ Bitmap* Pack::CreateBitmap(int width, int height, } // Create a new bitmap object from rawdata. -Bitmap* Pack::CreateBitmapFromRawData(RawData* raw_data) { - Bitmap::Ref bitmap(new Bitmap(service_locator())); - if (bitmap.IsNull()) { - O3D_ERROR(service_locator()) - << "Failed to create bitmap object."; - return NULL; - } - if (!bitmap->LoadFromRawData(raw_data, image::UNKNOWN, false)) { +std::vector<Bitmap*> Pack::CreateBitmapsFromRawData(RawData* raw_data) { + BitmapRefArray bitmap_refs; + if (!Bitmap::LoadFromRawData(raw_data, image::UNKNOWN, &bitmap_refs)) { O3D_ERROR(service_locator()) << "Failed to load bitmap from raw data."; - return NULL; } - RegisterObject(bitmap); - return bitmap.Get(); + std::vector<Bitmap*> bitmaps(bitmap_refs.size(), NULL); + for (BitmapRefArray::size_type ii = 0; ii < bitmap_refs.size(); ++ii) { + RegisterObject(bitmap_refs[ii]); + bitmaps[ii] = bitmap_refs[ii].Get(); + } + return bitmaps; } // Creates a Texture2D object and allocates the necessary resources for it. diff --git a/o3d/core/cross/pack.h b/o3d/core/cross/pack.h index 9ce91d6..753dce8 100644 --- a/o3d/core/cross/pack.h +++ b/o3d/core/cross/pack.h @@ -44,6 +44,7 @@ #include "core/cross/transform.h" #include "core/cross/types.h" #include "core/cross/image_utils.h" +#include "core/cross/bitmap.h" class FilePath; @@ -227,12 +228,12 @@ class Pack : public NamedObject { // A pointer to the bitmap obejct. Bitmap* CreateBitmap(int width, int height, Texture::Format format); - // Creates a new Bitmap object from RawData. + // Creates a new Bitmaps from RawData. // Parameters: // raw_data: contains the bitmap data in one of the know formats. // Returns: - // An array of pointers to the bitmap objects. - Bitmap* CreateBitmapFromRawData(RawData* raw_data); + // bitmaps: A vector of pointers to bitmaps. If empty there was an error. + std::vector<Bitmap*> Pack::CreateBitmapsFromRawData(RawData* raw_data); // Creates a new Texture2D object of the specified size and format and // reserves the necessary resources for it. @@ -428,7 +429,8 @@ class Pack : public NamedObject { Renderer* renderer_; // helper function - Texture* CreateTextureFromBitmap(Bitmap *bitmap, const String& uri); + Texture* CreateTextureFromBitmaps( + const BitmapRefArray& bitmaps, const String& uri, bool generate_mips); // The set of objects owned by the pack. This container contains all of the // references that force the lifespan of the contained objects to match diff --git a/o3d/core/cross/param_test.cc b/o3d/core/cross/param_test.cc index 433c3d3..551655d 100644 --- a/o3d/core/cross/param_test.cc +++ b/o3d/core/cross/param_test.cc @@ -55,8 +55,7 @@ namespace { class TestTexture : public Texture { public: explicit TestTexture(ServiceLocator* service_locator) - : Texture(service_locator, UNKNOWN_FORMAT, 1, true, false, - false) {} + : Texture(service_locator, UNKNOWN_FORMAT, 1, false) { } void* GetTextureHandle() const { return NULL; } virtual const RGBASwizzleIndices& GetABGR32FSwizzleIndices(); virtual void SetFromBitmap(const Bitmap& bitmap) { diff --git a/o3d/core/cross/renderer.cc b/o3d/core/cross/renderer.cc index 24c1e4a..48c9c05 100644 --- a/o3d/core/cross/renderer.cc +++ b/o3d/core/cross/renderer.cc @@ -310,15 +310,6 @@ void Renderer::SetViewport(const Float4& rectangle, const Float2& depth_range) { depth_range[1]); } -Texture::Ref Renderer::CreateTextureFromBitmap(Bitmap* bitmap) { - if (!IsSupportedTextureFormat(bitmap->format(), - features_.Get(), - service_locator())) { - return Texture::Ref(NULL); - } - return CreatePlatformSpecificTextureFromBitmap(bitmap); -} - Texture2D::Ref Renderer::CreateTexture2D(int width, int height, Texture::Format format, diff --git a/o3d/core/cross/renderer.h b/o3d/core/cross/renderer.h index d766b24..d07d10e 100644 --- a/o3d/core/cross/renderer.h +++ b/o3d/core/cross/renderer.h @@ -314,17 +314,6 @@ class Renderer { // Frees a Param Cache. void FreeParamCache(ParamCache* param_cache); - // Attempts to create a Texture with the given bitmap, automatically - // determining whether the to create a 2D texture, cube texture, etc. If - // creation fails the method returns NULL. - // Parameters: - // bitmap: The bitmap specifying the dimensions, format and content of the - // new texture. The created texture takes ownership of the bitmap - // data. - // Returns: - // A ref-counted pointer to the texture or NULL if it did not load. - Texture::Ref CreateTextureFromBitmap(Bitmap* bitmap); - // Creates and returns a platform specific Texture2D object. It allocates // the necessary resources to store texture data for the given image size // and format. @@ -534,10 +523,6 @@ class Renderer { // Creates a platform specific ParamCache. virtual ParamCache* CreatePlatformSpecificParamCache() = 0; - // Platform specific version of CreateTextureFromBitmap. - virtual Texture::Ref CreatePlatformSpecificTextureFromBitmap( - Bitmap* bitmap) = 0; - // Platform specific version of CreateTexture2D virtual Texture2D::Ref CreatePlatformSpecificTexture2D( int width, diff --git a/o3d/core/cross/renderer_test.cc b/o3d/core/cross/renderer_test.cc index 9982d12..e0b35d8 100644 --- a/o3d/core/cross/renderer_test.cc +++ b/o3d/core/cross/renderer_test.cc @@ -120,44 +120,6 @@ TEST_F(RendererTest, OffScreen) { } #endif -// TODO: add InitAndDestroyGL and InitAndDestroyMock -TEST_F(RendererTest, Creates2DTextureFromBitmap) { - Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - bitmap->Allocate(Texture::ARGB8, 16, 32, 2, false); - memset(bitmap->image_data(), 0x34, bitmap->GetTotalSize()); - - Client client(g_service_locator); - client.Init(); - - Texture::Ref texture = g_renderer->CreateTextureFromBitmap(bitmap); - ASSERT_TRUE(NULL != texture); - EXPECT_EQ(Texture::ARGB8, texture->format()); - EXPECT_EQ(2, texture->levels()); - - Texture2D::Ref texture2D(down_cast<Texture2D*>(texture.Get())); - ASSERT_TRUE(NULL != texture2D); - EXPECT_EQ(16, texture2D->width()); - EXPECT_EQ(32, texture2D->height()); -} - -TEST_F(RendererTest, CreatesCubeTextureFromBitmap) { - Bitmap::Ref bitmap(new Bitmap(g_service_locator)); - bitmap->Allocate(Texture::ARGB8, 16, 16, 2, true); - memset(bitmap->image_data(), 0x34, bitmap->GetTotalSize()); - - Client client(g_service_locator); - client.Init(); - - Texture::Ref texture = g_renderer->CreateTextureFromBitmap(bitmap); - ASSERT_TRUE(NULL != texture); - EXPECT_EQ(Texture::ARGB8, texture->format()); - EXPECT_EQ(2, texture->levels()); - - TextureCUBE::Ref textureCube(down_cast<TextureCUBE*>(texture.Get())); - ASSERT_TRUE(NULL != textureCube); - EXPECT_EQ(16, textureCube->edge_length()); -} - // Tests SetViewport TEST_F(RendererTest, SetViewport) { ErrorStatus error_status(g_service_locator); diff --git a/o3d/core/cross/texture.cc b/o3d/core/cross/texture.cc index 837817f..10e1289 100644 --- a/o3d/core/cross/texture.cc +++ b/o3d/core/cross/texture.cc @@ -57,11 +57,8 @@ Texture2D::Texture2D(ServiceLocator* service_locator, int height, Format format, int levels, - bool alpha_is_one, - bool resize_to_pot, bool enable_render_surfaces) - : Texture(service_locator, format, levels, alpha_is_one, - resize_to_pot, enable_render_surfaces), + : Texture(service_locator, format, levels, enable_render_surfaces), locked_levels_(0) { RegisterReadOnlyParamRef(kWidthParamName, &width_param_); RegisterReadOnlyParamRef(kHeightParamName, &height_param_); @@ -171,7 +168,7 @@ void Texture2D::SetFromBitmap(const Bitmap& bitmap) { DCHECK(bitmap.image_data()); if (bitmap.width() != static_cast<unsigned>(width()) || bitmap.height() != static_cast<unsigned>(height()) || - bitmap.format() != format() || bitmap.is_cubemap()) { + bitmap.format() != format()) { O3D_ERROR(service_locator()) << "bitmap must be the same format and dimensions as texture"; return; @@ -254,11 +251,8 @@ TextureCUBE::TextureCUBE(ServiceLocator* service_locator, int edge_length, Format format, int levels, - bool alpha_is_one, - bool resize_to_pot, bool enable_render_surfaces) - : Texture(service_locator, format, levels, alpha_is_one, - resize_to_pot, enable_render_surfaces) { + : Texture(service_locator, format, levels, enable_render_surfaces) { for (unsigned int i = 0; i < 6; ++i) { locked_levels_[i] = 0; } @@ -378,11 +372,11 @@ void TextureCUBE::DrawImage(const Bitmap& src_img, mip_length, mip_length, components); } -void TextureCUBE::SetFromBitmap(const Bitmap& bitmap) { +void TextureCUBE::SetFromBitmap(CubeFace face, const Bitmap& bitmap) { DCHECK(bitmap.image_data()); if (bitmap.width() != static_cast<unsigned>(edge_length()) || bitmap.height() != static_cast<unsigned>(edge_length()) || - bitmap.format() != format() || !bitmap.is_cubemap()) { + bitmap.format() != format()) { O3D_ERROR(service_locator()) << "bitmap must be the same format and dimensions as texture"; return; @@ -390,13 +384,11 @@ void TextureCUBE::SetFromBitmap(const Bitmap& bitmap) { 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)); - } + SetRect(face, level, 0, 0, + image::ComputeMipDimension(level, edge_length()), + image::ComputeMipDimension(level, edge_length()), + bitmap.GetMipData(level), + bitmap.GetMipPitch(level)); } } diff --git a/o3d/core/cross/texture.h b/o3d/core/cross/texture.h index fdb1b2f..c16c884 100644 --- a/o3d/core/cross/texture.h +++ b/o3d/core/cross/texture.h @@ -88,8 +88,6 @@ class Texture2D : public Texture { int height, Format format, int levels, - bool alpha_is_one, - bool resize_to_pot, bool enable_render_surfaces); virtual ~Texture2D(); @@ -147,9 +145,9 @@ class Texture2D : public Texture { int dest_width, int dest_height, int dest_mip); // Sets the contents of the texture from a Bitmap. - virtual void SetFromBitmap(const Bitmap& bitmap); + void SetFromBitmap(const Bitmap& bitmap); - // Generates mips. + // Overridden from Texture. virtual void GenerateMips(int source_level, int num_levels); protected: @@ -250,8 +248,6 @@ class TextureCUBE : public Texture { int edge_length, Format format, int levels, - bool alpha_is_one, - bool resize_to_pot, bool enable_render_surfaces); virtual ~TextureCUBE(); @@ -314,9 +310,9 @@ class TextureCUBE : public Texture { int dest_height, CubeFace face, int dest_mip); // Sets the contents of the texture from a Bitmap. - virtual void SetFromBitmap(const Bitmap& bitmap); + void SetFromBitmap(CubeFace face, const Bitmap& bitmap); - // Generates mips. + // Overridden from Texture. virtual void GenerateMips(int source_level, int num_levels); protected: diff --git a/o3d/core/cross/texture_base.cc b/o3d/core/cross/texture_base.cc index b416ae5..f9825fb 100644 --- a/o3d/core/cross/texture_base.cc +++ b/o3d/core/cross/texture_base.cc @@ -48,12 +48,9 @@ const char* Texture::kLevelsParamName = Texture::Texture(ServiceLocator* service_locator, Format format, int levels, - bool alpha_is_one, - bool resize_to_pot, bool enable_render_surfaces) : ParamObject(service_locator), - resize_to_pot_(resize_to_pot), - alpha_is_one_(alpha_is_one), + alpha_is_one_(false), format_(format), weak_pointer_manager_(this), render_surfaces_enabled_(enable_render_surfaces) { diff --git a/o3d/core/cross/texture_base.h b/o3d/core/cross/texture_base.h index b8649b9..1c40d55 100644 --- a/o3d/core/cross/texture_base.h +++ b/o3d/core/cross/texture_base.h @@ -79,8 +79,6 @@ class Texture : public ParamObject { Texture(ServiceLocator* service_locator, Format format, int levels, - bool alpha_is_one, - bool resize_to_pot, bool enable_render_surfaces); virtual ~Texture() {} @@ -114,9 +112,6 @@ 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; @@ -138,11 +133,6 @@ class Texture : public ParamObject { format_ = format; } - // Whether or not to resize NPOT textures to POT when passing to the - // underlying graphics API. This should only be true in the if the texture - // is not POT and if it is not compressed. - bool resize_to_pot_; - static void RegisterSurface(RenderSurface* surface, Pack* pack); private: diff --git a/o3d/core/cross/texture_base_test.cc b/o3d/core/cross/texture_base_test.cc index a7780d37..5f11c8f 100644 --- a/o3d/core/cross/texture_base_test.cc +++ b/o3d/core/cross/texture_base_test.cc @@ -49,11 +49,8 @@ class MockTexture : public Texture { MockTexture(ServiceLocator* service_locator,
Texture::Format format,
int levels,
- bool alpha_is_one,
- bool resize_to_pot,
bool enable_render_surfaces)
- : Texture(service_locator, format, levels, alpha_is_one, resize_to_pot,
- enable_render_surfaces) {
+ : Texture(service_locator, format, levels, enable_render_surfaces) {
}
virtual const RGBASwizzleIndices& GetABGR32FSwizzleIndices() {
@@ -92,8 +89,6 @@ TEST_F(TextureTest, Basic) { g_service_locator,
Texture::XRGB8,
1,
- false,
- false,
false));
ASSERT_TRUE(texture != NULL);
EXPECT_EQ(texture->format(), Texture::XRGB8);
diff --git a/o3d/core/win/d3d9/renderer_d3d9.cc b/o3d/core/win/d3d9/renderer_d3d9.cc index 035f615..29142eb 100644 --- a/o3d/core/win/d3d9/renderer_d3d9.cc +++ b/o3d/core/win/d3d9/renderer_d3d9.cc @@ -1606,30 +1606,6 @@ ParamCache* RendererD3D9::CreatePlatformSpecificParamCache() { return new ParamCacheD3D9(service_locator()); } -// Attempts to create a Texture with the given bitmap, automatically -// determining whether the to create a 2D texture, cube texture, etc. If -// creation fails the method returns NULL. -// Parameters: -// bitmap: The bitmap specifying the dimensions, format and content of the -// new texture. The created texture takes ownership of the bitmap -// data. -// Returns: -// A ref-counted pointer to the texture or NULL if it did not load. -Texture::Ref RendererD3D9::CreatePlatformSpecificTextureFromBitmap( - Bitmap* bitmap) { - if (bitmap->is_cubemap()) { - return Texture::Ref(TextureCUBED3D9::Create(service_locator(), - bitmap, - this, - false)); - } else { - return Texture::Ref(Texture2DD3D9::Create(service_locator(), - bitmap, - this, - false)); - } -} - // Attempts to create a Texture2D with the given specs. If creation fails // then the method returns NULL. Texture2D::Ref RendererD3D9::CreatePlatformSpecificTexture2D( @@ -1638,32 +1614,26 @@ Texture2D::Ref RendererD3D9::CreatePlatformSpecificTexture2D( Texture::Format format, int levels, bool enable_render_surfaces) { - Bitmap::Ref bitmap = Bitmap::Ref(new Bitmap(service_locator())); - bitmap->set_format(format); - bitmap->set_width(width); - bitmap->set_height(height); - bitmap->set_num_mipmaps(levels); return Texture2D::Ref(Texture2DD3D9::Create(service_locator(), - bitmap, + format, + levels, + width, + height, this, enable_render_surfaces)); } -// Attempts to create a Texture2D with the given specs. If creation fails +// Attempts to create a TextureCUBE with the given specs. If creation fails // then the method returns NULL. TextureCUBE::Ref RendererD3D9::CreatePlatformSpecificTextureCUBE( int edge_length, Texture::Format format, int levels, bool enable_render_surfaces) { - Bitmap::Ref bitmap = Bitmap::Ref(new Bitmap(service_locator())); - bitmap->set_format(format); - bitmap->set_width(edge_length); - bitmap->set_height(edge_length); - bitmap->set_num_mipmaps(levels); - bitmap->set_is_cubemap(true); return TextureCUBE::Ref(TextureCUBED3D9::Create(service_locator(), - bitmap, + format, + levels, + edge_length, this, enable_render_surfaces)); } @@ -1744,7 +1714,7 @@ Bitmap::Ref RendererD3D9::TakeScreenshot() { surface_description.Width, surface_description.Height, 1, - false); + Bitmap::IMAGE); bitmap->SetRect(0, 0, 0, surface_description.Width, surface_description.Height, diff --git a/o3d/core/win/d3d9/renderer_d3d9.h b/o3d/core/win/d3d9/renderer_d3d9.h index f81a6c7..7d6f9bb 100644 --- a/o3d/core/win/d3d9/renderer_d3d9.h +++ b/o3d/core/win/d3d9/renderer_d3d9.h @@ -194,9 +194,6 @@ class RendererD3D9 : public Renderer { float max_z); // Overridden from Renderer. - virtual Texture::Ref CreatePlatformSpecificTextureFromBitmap(Bitmap* bitmap); - - // Overridden from Renderer. virtual Texture2D::Ref CreatePlatformSpecificTexture2D( int width, int height, diff --git a/o3d/core/win/d3d9/texture_d3d9.cc b/o3d/core/win/d3d9/texture_d3d9.cc index 5c93f7b..13c3d3b 100644 --- a/o3d/core/win/d3d9/texture_d3d9.cc +++ b/o3d/core/win/d3d9/texture_d3d9.cc @@ -82,20 +82,23 @@ static D3DCUBEMAP_FACES DX9CubeFace(TextureCUBE::CubeFace face) { return D3DCUBEMAP_FACE_FORCE_DWORD; } -// Constructs an Direct3D texture object. Out variable return the status of +// Constructs an Direct3D texture object. Out variable returns the status of // the constructed texture including if resize to POT is required, and the // actual mip dimensions used. HRESULT CreateTexture2DD3D9(RendererD3D9* renderer, - Bitmap* bitmap, + Texture::Format format, + int levels, + int width, + int height, bool enable_render_surfaces, bool* resize_to_pot, unsigned int* mip_width, unsigned int* mip_height, IDirect3DTexture9** d3d_texture) { IDirect3DDevice9 *d3d_device = renderer->d3d_device(); - *resize_to_pot = !renderer->supports_npot() && !bitmap->IsPOT(); - *mip_width = bitmap->width(); - *mip_height = bitmap->height(); + *resize_to_pot = !renderer->supports_npot() && !image::IsPOT(width, height); + *mip_width = width; + *mip_height = height; if (*resize_to_pot) { *mip_width = image::ComputePOTSize(*mip_width); @@ -104,56 +107,59 @@ HRESULT CreateTexture2DD3D9(RendererD3D9* renderer, DWORD usage = (enable_render_surfaces) ? D3DUSAGE_RENDERTARGET : 0; D3DPOOL pool = (enable_render_surfaces) ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED; - D3DFORMAT format = DX9Format(bitmap->format()); + D3DFORMAT d3d_format = DX9Format(format); HRESULT tex_result = d3d_device->CreateTexture(*mip_width, *mip_height, - bitmap->num_mipmaps(), + levels, usage, - format, + d3d_format, pool, d3d_texture, NULL); if (!HR(tex_result)) { DLOG(ERROR) << "2D texture creation failed with the following parameters: " << "(" << *mip_width << " x " << *mip_height << ") x " - << bitmap->num_mipmaps() << "; format = " << format; + << levels << "; format = " << format; } return tex_result; } -// Constructs an Direct3D cube texture object. Out variable return the +// Constructs an Direct3D cube texture object. Out variable returns the // status of the constructed texture including if resize to POT is required, // and the actual mip edge length used. HRESULT CreateTextureCUBED3D9(RendererD3D9* renderer, - Bitmap* bitmap, + int edge_length, + Texture::Format format, + int levels, bool enable_render_surfaces, bool* resize_to_pot, unsigned int* edge_width, IDirect3DCubeTexture9** d3d_texture) { IDirect3DDevice9 *d3d_device = renderer->d3d_device(); - *resize_to_pot = !renderer->supports_npot() && !bitmap->IsPOT(); - *edge_width = bitmap->width(); + *resize_to_pot = !renderer->supports_npot() && + !image::IsPOT(edge_length, edge_length); + *edge_width = edge_length; if (*resize_to_pot) { *edge_width = image::ComputePOTSize(*edge_width); } DWORD usage = (enable_render_surfaces) ? D3DUSAGE_RENDERTARGET : 0; D3DPOOL pool = (enable_render_surfaces) ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED; - D3DFORMAT format = DX9Format(bitmap->format()); + D3DFORMAT d3d_format = DX9Format(format); HRESULT tex_result = d3d_device->CreateCubeTexture(*edge_width, - bitmap->num_mipmaps(), + levels, usage, - format, + d3d_format, pool, d3d_texture, NULL); if (!HR(tex_result)) { DLOG(ERROR) << "CUBE texture creation failed with the following " << "parameters: " - << "(" << edge_width << " x " << edge_width << ") x " - << bitmap->num_mipmaps() << "; format = " << format; + << "(" << *edge_width << " x " << *edge_width << ") x " + << levels << "; format = " << format; } return tex_result; @@ -329,17 +335,19 @@ void SetTextureFaceRect( // Constructs a 2D texture object from the given (existing) D3D 2D texture. Texture2DD3D9::Texture2DD3D9(ServiceLocator* service_locator, IDirect3DTexture9* tex, - const Bitmap &bitmap, + Texture::Format format, + int levels, + int width, + int height, bool resize_to_pot, bool enable_render_surfaces) : Texture2D(service_locator, - bitmap.width(), - bitmap.height(), - bitmap.format(), - bitmap.num_mipmaps(), - bitmap.CheckAlphaIsOne(), - resize_to_pot, + width, + height, + format, + levels, enable_render_surfaces), + resize_to_pot_(resize_to_pot), d3d_texture_(tex), backing_bitmap_(Bitmap::Ref(new Bitmap(service_locator))) { DCHECK(tex); @@ -350,16 +358,21 @@ Texture2DD3D9::Texture2DD3D9(ServiceLocator* service_locator, // returns it. This is the safe way to create a Texture2DD3D9 object that // contains a valid D3D9 texture. Texture2DD3D9* Texture2DD3D9::Create(ServiceLocator* service_locator, - Bitmap* bitmap, + Texture::Format format, + int levels, + int width, + int height, RendererD3D9* renderer, bool enable_render_surfaces) { - DCHECK_NE(bitmap->format(), Texture::UNKNOWN_FORMAT); - DCHECK(!bitmap->is_cubemap()); + DCHECK_NE(format, Texture::UNKNOWN_FORMAT); CComPtr<IDirect3DTexture9> d3d_texture; bool resize_to_pot; unsigned int mip_width, mip_height; if (!HR(CreateTexture2DD3D9(renderer, - bitmap, + format, + levels, + width, + height, enable_render_surfaces, &resize_to_pot, &mip_width, @@ -371,23 +384,14 @@ Texture2DD3D9* Texture2DD3D9::Create(ServiceLocator* service_locator, Texture2DD3D9 *texture = new Texture2DD3D9(service_locator, d3d_texture, - *bitmap, + format, + levels, + width, + height, resize_to_pot, enable_render_surfaces); - - texture->backing_bitmap_->SetFrom(bitmap); - if (texture->backing_bitmap_->image_data()) { - for (unsigned int i = 0; i < bitmap->num_mipmaps(); ++i) { - texture->UpdateBackedMipLevel(i); - mip_width = std::max(1U, mip_width >> 1); - mip_height = std::max(1U, mip_height >> 1); - } - if (!resize_to_pot) - texture->backing_bitmap_->FreeData(); - } else { - if (resize_to_pot) { - texture->backing_bitmap_->AllocateData(); - } + if (resize_to_pot) { + texture->backing_bitmap_->AllocateData(); } return texture; @@ -637,7 +641,10 @@ bool Texture2DD3D9::OnResetDevice() { bool resize_to_pot; unsigned int mip_width, mip_height; return HR(CreateTexture2DD3D9(renderer_d3d9, - backing_bitmap_, + format(), + levels(), + width(), + height(), render_surfaces_enabled(), &resize_to_pot, &mip_width, @@ -654,36 +661,42 @@ const Texture::RGBASwizzleIndices& Texture2DD3D9::GetABGR32FSwizzleIndices() { // Constructs a cube texture object from the given (existing) D3D Cube texture. TextureCUBED3D9::TextureCUBED3D9(ServiceLocator* service_locator, IDirect3DCubeTexture9* tex, - const Bitmap& bitmap, + int edge_length, + Texture::Format format, + int levels, bool resize_to_pot, bool enable_render_surfaces) : TextureCUBE(service_locator, - bitmap.width(), - bitmap.format(), - bitmap.num_mipmaps(), - bitmap.CheckAlphaIsOne(), - resize_to_pot, + edge_length, + format, + levels, enable_render_surfaces), - d3d_cube_texture_(tex), - backing_bitmap_(Bitmap::Ref(new Bitmap(service_locator))) { + resize_to_pot_(resize_to_pot), + d3d_cube_texture_(tex) { + for (int ii = 0; ii < static_cast<int>(NUMBER_OF_FACES); ++ii) { + backing_bitmaps_[ii] = Bitmap::Ref(new Bitmap(service_locator)); + } } // Attempts to create a D3D9 CubeTexture with the given specs. If creation // fails the method returns NULL. Otherwise, it wraps around the newly created // texture a TextureCUBED3D9 object and returns a pointer to it. TextureCUBED3D9* TextureCUBED3D9::Create(ServiceLocator* service_locator, - Bitmap *bitmap, + Texture::Format format, + int levels, + int edge_length, RendererD3D9 *renderer, bool enable_render_surfaces) { - DCHECK_NE(bitmap->format(), Texture::UNKNOWN_FORMAT); - DCHECK(bitmap->is_cubemap()); - DCHECK_EQ(bitmap->width(), bitmap->height()); + DCHECK_NE(format, Texture::UNKNOWN_FORMAT); + DCHECK_GE(levels, 1); CComPtr<IDirect3DCubeTexture9> d3d_texture; bool resize_to_pot; unsigned int edge; if (!HR(CreateTextureCUBED3D9(renderer, - bitmap, + edge_length, + format, + levels, enable_render_surfaces, &resize_to_pot, &edge, @@ -694,24 +707,14 @@ TextureCUBED3D9* TextureCUBED3D9::Create(ServiceLocator* service_locator, TextureCUBED3D9 *texture = new TextureCUBED3D9(service_locator, d3d_texture, - *bitmap, + edge_length, + format, + levels, resize_to_pot, enable_render_surfaces); - - texture->backing_bitmap_->SetFrom(bitmap); - if (texture->backing_bitmap_->image_data()) { - for (int face = 0; face < 6; ++face) { - unsigned int mip_edge = edge; - for (unsigned int i = 0; i < bitmap->num_mipmaps(); ++i) { - texture->UpdateBackedMipLevel(static_cast<CubeFace>(face), i); - mip_edge = std::max(1U, mip_edge >> 1); - } - } - if (!resize_to_pot) - texture->backing_bitmap_->FreeData(); - } else { - if (resize_to_pot) { - texture->backing_bitmap_->AllocateData(); + if (resize_to_pot) { + for (int ii = 0; ii < static_cast<int>(NUMBER_OF_FACES); ++ii) { + texture->backing_bitmaps_[ii]->AllocateData(); } } @@ -735,13 +738,13 @@ TextureCUBED3D9::~TextureCUBED3D9() { void TextureCUBED3D9::UpdateBackedMipLevel(TextureCUBE::CubeFace face, unsigned int level) { + Bitmap* backing_bitmap = backing_bitmaps_[face].Get(); DCHECK_LT(level, static_cast<unsigned int>(levels())); - DCHECK(backing_bitmap_->image_data()); - DCHECK(backing_bitmap_->is_cubemap()); - DCHECK_EQ(backing_bitmap_->width(), edge_length()); - DCHECK_EQ(backing_bitmap_->height(), edge_length()); - DCHECK_EQ(backing_bitmap_->format(), format()); - DCHECK_EQ(backing_bitmap_->num_mipmaps(), levels()); + DCHECK(backing_bitmap->image_data()); + DCHECK_EQ(backing_bitmap->width(), edge_length()); + DCHECK_EQ(backing_bitmap->height(), edge_length()); + DCHECK_EQ(backing_bitmap->format(), format()); + DCHECK_EQ(backing_bitmap->num_mipmaps(), levels()); unsigned int mip_edge = std::max(1, edge_length() >> level); unsigned int rect_edge = mip_edge; @@ -762,7 +765,7 @@ void TextureCUBED3D9::UpdateBackedMipLevel(TextureCUBE::CubeFace face, DCHECK(out_rect.pBits); uint8* dst = static_cast<uint8*>(out_rect.pBits); - const uint8 *mip_data = backing_bitmap_->GetFaceMipData(face, level); + const uint8 *mip_data = backing_bitmap->GetMipData(level); if (resize_to_pot_) { image::Scale(mip_edge, mip_edge, format(), mip_data, rect_edge, rect_edge, @@ -870,11 +873,12 @@ void TextureCUBED3D9::SetRect(TextureCUBE::CubeFace face, } if (resize_to_pot_) { - DCHECK(backing_bitmap_->image_data()); + Bitmap* backing_bitmap = backing_bitmaps_[face].Get(); + DCHECK(backing_bitmap->image_data()); DCHECK(!compressed); // We need to update the backing mipmap and then use that to update the // texture. - backing_bitmap_->SetFaceRect(face, + backing_bitmap->SetRect( level, dst_left, dst_top, src_width, src_height, src_data, src_pitch); UpdateBackedMipLevel(face, level); } else { @@ -916,8 +920,9 @@ bool TextureCUBED3D9::Lock( return false; } if (resize_to_pot_) { - DCHECK(backing_bitmap_->image_data()); - *texture_data = backing_bitmap_->GetFaceMipData(face, level); + Bitmap* backing_bitmap = backing_bitmaps_[face].Get(); + DCHECK(backing_bitmap->image_data()); + *texture_data = backing_bitmap->GetMipData(level); unsigned int mip_width = image::ComputeMipDimension(level, edge_length()); unsigned int mip_height = mip_width; *pitch = image::ComputePitch(format(), mip_width); @@ -988,7 +993,9 @@ bool TextureCUBED3D9::OnResetDevice() { bool resize_to_pot; unsigned int mip_edge; return HR(CreateTextureCUBED3D9(renderer_d3d9, - backing_bitmap_, + edge_length(), + format(), + levels(), render_surfaces_enabled(), &resize_to_pot, &mip_edge, diff --git a/o3d/core/win/d3d9/texture_d3d9.h b/o3d/core/win/d3d9/texture_d3d9.h index 5f10951..311f096 100644 --- a/o3d/core/win/d3d9/texture_d3d9.h +++ b/o3d/core/win/d3d9/texture_d3d9.h @@ -59,7 +59,10 @@ class Texture2DD3D9 : public Texture2D { // creation fails then it returns NULL otherwise it returns a pointer to the // newly created Texture object. static Texture2DD3D9* Create(ServiceLocator* service_locator, - Bitmap* bitmap, + Texture::Format format, + int levels, + int width, + int height, RendererD3D9* renderer, bool enable_render_surfaces); @@ -106,7 +109,10 @@ class Texture2DD3D9 : public Texture2D { // Initializes the Texture2DD3D9 from a DX9 texture. Texture2DD3D9(ServiceLocator* service_locator, IDirect3DTexture9* tex, - const Bitmap& bitmap, + Texture::Format format, + int levels, + int width, + int height, bool resize_to_pot, bool enable_render_surfaces); @@ -114,6 +120,10 @@ class Texture2DD3D9 : public Texture2D { // rescaling it if resize_to_pot_ is set. void UpdateBackedMipLevel(unsigned int level); + // Whether or not this texture needs to be resized from NPOT to pot behind + // the scenes. + bool resize_to_pot_; + // A pointer to the Direct3D 2D texture object containing this texture. CComPtr<IDirect3DTexture9> d3d_texture_; @@ -132,7 +142,9 @@ class TextureCUBED3D9 : public TextureCUBE { // creation fails then it returns NULL otherwise it returns a pointer to the // newly created Texture object. static TextureCUBED3D9* Create(ServiceLocator* service_locator, - Bitmap* bitmap, + Texture::Format format, + int levels, + int edge_length, RendererD3D9* renderer, bool enable_render_surfaces); @@ -183,10 +195,16 @@ class TextureCUBED3D9 : public TextureCUBE { private: TextureCUBED3D9(ServiceLocator* service_locator, IDirect3DCubeTexture9* tex, - const Bitmap& bitmap, + int edge_length, + Texture::Format format, + int levels, bool resize_to_pot, bool enable_render_surfaces); + // Whether or not this texture needs to be resized from NPOT to pot behind + // the scenes. + bool resize_to_pot_; + // Updates a mip level, sending it from the backing bitmap to Direct3D, // rescaling it if resize_to_pot_ is set. void UpdateBackedMipLevel(CubeFace face, unsigned int level); @@ -194,8 +212,8 @@ class TextureCUBED3D9 : public TextureCUBE { // A pointer to the Direct3D cube texture object containing this texture. CComPtr<IDirect3DCubeTexture9> d3d_cube_texture_; - // A bitmap used to back the NPOT textures on POT-only hardware. - Bitmap::Ref backing_bitmap_; + // Bitmaps used to back the NPOT textures on POT-only hardware. + Bitmap::Ref backing_bitmaps_[NUMBER_OF_FACES]; DISALLOW_COPY_AND_ASSIGN(TextureCUBED3D9); }; diff --git a/o3d/plugin/idl/bitmap.idl b/o3d/plugin/idl/bitmap.idl index a223f43..76cca4c 100644 --- a/o3d/plugin/idl/bitmap.idl +++ b/o3d/plugin/idl/bitmap.idl @@ -34,15 +34,40 @@ 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.
+ including scale and crop. A Bitmap can be created from RawData via
+ pack.createBitmapsFromRawData(), and also can be transferred to mip of a
+ Texure2D or a specific face of TextureCUBE via methods in Texture.
%]
[nocpp, include="core/cross/bitmap.h"]
class Bitmap : ParamObject {
%[
+ After loading an array of Bitmaps with pack.createBitmapsFromRawData
+ you can inspect their semantic to see what they were intended for. This is
+ mostly to distinguish between 6 bitmaps that are faces of a cubemap and 6
+ bitmaps that are slices of a 3d texture.
+
+ \li FACE_POSITIVE_X, 1 face of a cubemap
+ \li FACE_NEGATIVE_X, 1 face of a cubemap
+ \li FACE_POSITIVE_Y, 1 face of a cubemap
+ \li FACE_NEGATIVE_Y, 1 face of a cubemap
+ \li FACE_POSITIVE_Z, 1 face of a cubemap
+ \li FACE_NEGATIVE_Z, 1 face of a cubemap
+ \li IMAGE, normal 2d image
+ \li SLICE, a slice of a 3d texture.
+ %]
+ enum Semantic {
+ FACE_POSITIVE_X,
+ FACE_NEGATIVE_X,
+ FACE_POSITIVE_Y,
+ FACE_NEGATIVE_Y,
+ FACE_POSITIVE_Z,
+ FACE_NEGATIVE_Z,
+ IMAGE,
+ SLICE
+ };
+
+ %[
Flips a bitmap vertically in place.
%]
void FlipVertically();
@@ -78,9 +103,9 @@ class Bitmap : ParamObject { [getter] int num_mipmaps_;
%[
- Whether or not the bitmap is a cubemap.
+ The Semantic of the bitmap.
%]
- [getter] bool is_cubemap_;
+ [getter] Semantic semantic_;
}; // Bitmap
} // namespace o3d
diff --git a/o3d/plugin/idl/pack.idl b/o3d/plugin/idl/pack.idl index a6a46aa..6880aed 100644 --- a/o3d/plugin/idl/pack.idl +++ b/o3d/plugin/idl/pack.idl @@ -322,8 +322,7 @@ typedef Bitmap[] BitmapArray; \param raw_data contains the bitmap data in a supported format. \return An Array of Bitmaps object. %] - //BitmapArray CreateBitmapsFromRawData(RawData raw_data); - Bitmap CreateBitmapFromRawData(RawData raw_data); + BitmapArray CreateBitmapsFromRawData(RawData raw_data); }; // Pack } // namespace o3d diff --git a/o3d/plugin/idl/texture.idl b/o3d/plugin/idl/texture.idl index d74a386..dcaf4e7 100644 --- a/o3d/plugin/idl/texture.idl +++ b/o3d/plugin/idl/texture.idl @@ -115,21 +115,6 @@ namespace o3d { %] 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 %[ @@ -238,6 +223,22 @@ namespace o3d { int height); %[ + 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::Texture2D* self, + o3d::Bitmap* bitmap) { + self->SetFromBitmap(*bitmap); + } + %} + + %[ Copy pixels from source bitmap to certain mip level. Scales if the width and height of source and dest do not match. @@ -294,12 +295,13 @@ namespace o3d { The names of each of the six faces of a cube map texture. %] - enum CubeFace { FACE_POSITIVE_X, - FACE_NEGATIVE_X, - FACE_POSITIVE_Y, - FACE_NEGATIVE_Y, - FACE_POSITIVE_Z, - FACE_NEGATIVE_Z }; + enum CubeFace { + FACE_POSITIVE_X, + FACE_NEGATIVE_X, + FACE_POSITIVE_Y, + FACE_NEGATIVE_Y, + FACE_POSITIVE_Z, + FACE_NEGATIVE_Z }; %[ The length of each edge of the cube, in texels. @@ -382,6 +384,24 @@ namespace o3d { int height); %[ + Sets the content of a face of the texture to the content of the bitmap. The + texture and the bitmap must be the same dimensions and the same format. + + \param face The face to set. + \param bitmap The bitmap to copy data from. + %] + [userglue] + void SetFromBitmap(CubeFace face, Bitmap bitmap); + + [verbatim=cpp_glue] %{ + void userglue_method_SetFromBitmap(o3d::TextureCUBE* self, + o3d::TextureCUBE::CubeFace face, + o3d::Bitmap* bitmap) { + self->SetFromBitmap(face, *bitmap); + } + %} + + %[ Copy pixels from source bitmap to certain mip level. Scales if the width and height of source and dest do not match. |