summaryrefslogtreecommitdiffstats
path: root/o3d
diff options
context:
space:
mode:
Diffstat (limited to 'o3d')
-rw-r--r--o3d/converter/cross/texture_stub.h54
-rw-r--r--o3d/core/cross/bitmap.cc268
-rw-r--r--o3d/core/cross/bitmap.h102
-rw-r--r--o3d/core/cross/bitmap_test.cc11
-rw-r--r--o3d/core/cross/buffer.cc1
-rw-r--r--o3d/core/cross/canvas.cc34
-rw-r--r--o3d/core/cross/command_buffer/texture_cb.cc61
-rw-r--r--o3d/core/cross/command_buffer/texture_cb.h43
-rw-r--r--o3d/core/cross/fake_vertex_source.cc1
-rw-r--r--o3d/core/cross/field.cc1
-rw-r--r--o3d/core/cross/field.h14
-rw-r--r--o3d/core/cross/gl/texture_gl.cc222
-rw-r--r--o3d/core/cross/gl/texture_gl.h45
-rw-r--r--o3d/core/cross/message_queue.cc40
-rw-r--r--o3d/core/cross/pointer_utils.h58
-rw-r--r--o3d/core/cross/renderer.cc14
-rw-r--r--o3d/core/cross/skin.cc1
-rw-r--r--o3d/core/cross/skin_test.cc1
-rw-r--r--o3d/core/cross/stream_bank_test.cc1
-rw-r--r--o3d/core/cross/texture.cc84
-rw-r--r--o3d/core/cross/texture.h217
-rw-r--r--o3d/core/cross/texture_base.cc1
-rw-r--r--o3d/core/cross/texture_base.h13
-rw-r--r--o3d/core/cross/texture_base_test.cc100
-rw-r--r--o3d/core/cross/texture_test.cc108
-rw-r--r--o3d/core/cross/vertex_source_test.cc1
-rw-r--r--o3d/core/win/d3d9/texture_d3d9.cc374
-rw-r--r--o3d/core/win/d3d9/texture_d3d9.h55
-rw-r--r--o3d/plugin/build.scons1
-rw-r--r--o3d/plugin/cross/texture_static_glue.cc388
-rw-r--r--o3d/plugin/idl/texture.idl246
-rw-r--r--o3d/plugin/plugin.gyp1
-rw-r--r--o3d/tests/build.scons2
33 files changed, 1976 insertions, 587 deletions
diff --git a/o3d/converter/cross/texture_stub.h b/o3d/converter/cross/texture_stub.h
index 78e971c..43888d4 100644
--- a/o3d/converter/cross/texture_stub.h
+++ b/o3d/converter/cross/texture_stub.h
@@ -62,12 +62,15 @@ class Texture2DStub : public Texture2D {
enable_render_surfaces) {}
virtual ~Texture2DStub() {}
- // Locks the image buffer of a given mipmap level for writing from main
- // memory.
- virtual bool Lock(int level, void** texture_data) { return true; }
-
- // Unlocks this texture and returns it to Stub control.
- virtual bool Unlock(int level) { return true; }
+ // Overridden from Texture2D
+ virtual void SetRect(int level,
+ unsigned left,
+ unsigned top,
+ unsigned width,
+ unsigned height,
+ const void* src_data,
+ int src_pitch) {
+ }
// Returns a RenderSurface object associated with a mip_level of a texture.
// Parameters:
@@ -88,6 +91,16 @@ class Texture2DStub : public Texture2D {
// RGBA to the internal format used by the rendering API.
virtual const RGBASwizzleIndices& GetABGR32FSwizzleIndices();
+ protected:
+ // Locks the image buffer of a given mipmap level for writing from main
+ // memory.
+ virtual bool Lock(int level, void** texture_data, int* pitch) {
+ return false;
+ }
+
+ // Unlocks this texture and returns it to Stub control.
+ virtual bool Unlock(int level) { return true; }
+
private:
DISALLOW_COPY_AND_ASSIGN(Texture2DStub);
};
@@ -111,14 +124,16 @@ class TextureCUBEStub : public TextureCUBE {
enable_render_surfaces) {}
virtual ~TextureCUBEStub() {}
- // Locks the image buffer of a given face and mipmap level for loading
- // from main memory.
- virtual bool Lock(CubeFace face, int level, void** texture_data) {
- return true;
- }
-
- // Unlocks the image buffer of a given face and mipmap level.
- virtual bool Unlock(CubeFace face, int level) { return true; }
+ // Overridden from TextureCUBE
+ virtual void SetRect(CubeFace face,
+ int level,
+ unsigned dst_left,
+ unsigned dst_top,
+ unsigned width,
+ unsigned height,
+ const void* src_data,
+ int src_pitch) {
+ };
// Returns a RenderSurface object associated with a given cube face and
// mip_level of a texture.
@@ -143,6 +158,17 @@ class TextureCUBEStub : public TextureCUBE {
// RGBA to the internal format used by the rendering API.
virtual const RGBASwizzleIndices& GetABGR32FSwizzleIndices();
+ protected:
+ // Locks the image buffer of a given face and mipmap level for loading
+ // from main memory.
+ virtual bool Lock(
+ CubeFace face, int level, void** texture_data, int* pitch) {
+ return false;
+ }
+
+ // Unlocks the image buffer of a given face and mipmap level.
+ virtual bool Unlock(CubeFace face, int level) { return true; }
+
private:
DISALLOW_COPY_AND_ASSIGN(TextureCUBEStub);
};
diff --git a/o3d/core/cross/bitmap.cc b/o3d/core/cross/bitmap.cc
index ecf00d6..4dbf330 100644
--- a/o3d/core/cross/bitmap.cc
+++ b/o3d/core/cross/bitmap.cc
@@ -44,6 +44,7 @@
#include "utils/cross/file_path_utils.h"
#include "base/file_path.h"
#include "base/file_util.h"
+#include "core/cross/texture.h"
#include "import/cross/raw_data.h"
#include "import/cross/memory_buffer.h"
#include "import/cross/memory_stream.h"
@@ -92,9 +93,9 @@ unsigned int Bitmap::GetBufferSize(unsigned int width,
switch (format) {
case Texture::XRGB8:
case Texture::ARGB8:
- return 4 * sizeof(unsigned char) * pixels; // NOLINT
+ return 4 * sizeof(uint8) * pixels; // NOLINT
case Texture::ABGR16F:
- return 4 * sizeof(unsigned short) * pixels; // NOLINT
+ return 4 * sizeof(uint16) * pixels; // NOLINT
case Texture::R32F:
return sizeof(float) * pixels; // NOLINT
case Texture::ABGR32F:
@@ -164,18 +165,109 @@ void Bitmap::Allocate(Texture::Format format,
AllocateData();
}
-unsigned char *Bitmap::GetMipData(unsigned int level,
- TextureCUBE::CubeFace face) const {
+uint8 *Bitmap::GetMipData(unsigned int level) const {
DCHECK(level < num_mipmaps_);
+ DCHECK(!is_cubemap_);
if (!image_data_.get()) return NULL;
- unsigned char *data = image_data_.get();
- if (is_cubemap_) {
+ uint8 *data = image_data_.get();
+ return data + GetMipChainSize(width_, height_, format_, 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(width_, height_, format_, num_mipmaps_);
}
return data + GetMipChainSize(width_, height_, format_, level);
}
+void Bitmap::SetRect(
+ 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 < num_mipmaps() && level >= 0);
+ unsigned mip_width;
+ unsigned mip_height;
+ Bitmap::GetMipSize(level, width(), height(), &mip_width, &mip_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 =
+ GetMipData(level) +
+ Bitmap::GetMipChainSize(mip_width, dst_top, format(), 1) +
+ Bitmap::GetMipChainSize(dst_left, 1, format(), 1);
+
+ const uint8* src = static_cast<const uint8*>(src_data);
+ if (!compressed) {
+ unsigned bytes_per_line = GetMipChainSize(src_width, 1, format(), 1);
+ int dst_pitch = Bitmap::GetMipChainSize(mip_width, 1, format(), 1);
+ for (unsigned yy = 0; yy < src_height; ++yy) {
+ memcpy(dst, src, bytes_per_line);
+ src += src_pitch;
+ dst += dst_pitch;
+ }
+ } else {
+ memcpy(dst,
+ src,
+ Bitmap::GetMipChainSize(mip_width, mip_height, format(), 1));
+ }
+}
+
+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 < num_mipmaps() && level >= 0);
+ unsigned mip_width;
+ unsigned mip_height;
+ Bitmap::GetMipSize(level, width(), height(), &mip_width, &mip_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) +
+ Bitmap::GetMipChainSize(mip_width, dst_top, format(), 1) +
+ Bitmap::GetMipChainSize(dst_left, 1, format(), 1);
+
+ const uint8* src = static_cast<const uint8*>(src_data);
+ if (!compressed) {
+ unsigned bytes_per_line = GetMipChainSize(src_width, 1, format(), 1);
+ int dst_pitch = Bitmap::GetMipChainSize(mip_width, 1, format(), 1);
+ for (unsigned yy = 0; yy < src_height; ++yy) {
+ memcpy(dst, src, bytes_per_line);
+ src += src_pitch;
+ dst += dst_pitch;
+ }
+ } else {
+ memcpy(dst,
+ src,
+ Bitmap::GetMipChainSize(mip_width, mip_height, format(), 1));
+ }
+}
+
bool Bitmap::LoadFromStream(MemoryReadStream *stream,
const String &filename,
@@ -340,8 +432,8 @@ void Bitmap::DrawImage(Bitmap* src_img,
return;
}
- unsigned char* src_img_data = src_img->image_data();
- unsigned char* dst_img_data = image_data();
+ uint8* src_img_data = src_img->image_data();
+ uint8* dst_img_data = image_data();
// crop part of image from src img, scale it in
// bilinear interpolation fashion, and paste it
@@ -349,7 +441,8 @@ void Bitmap::DrawImage(Bitmap* src_img,
LanczosScale(src_img_data, src_x, src_y,
src_width, src_height,
src_img->width_, src_img->height_,
- dst_img_data, dst_x, dst_y,
+ dst_img_data, width_,
+ dst_x, dst_y,
dst_width, dst_height,
width_, height_, components);
}
@@ -358,7 +451,7 @@ void Bitmap::LanczosScale(const uint8* src,
int src_x, int src_y,
int src_width, int src_height,
int src_img_width, int src_img_height,
- uint8* dest,
+ uint8* dest, int dest_pitch,
int dest_x, int dest_y,
int dest_width, int dest_height,
int dest_img_width, int dest_img_height,
@@ -379,23 +472,27 @@ void Bitmap::LanczosScale(const uint8* src,
LanczosResize1D(src, src_x, src_y, src_width, src_height,
src_img_width, src_img_height,
- temp.get(), temp_x, temp_y, temp_width,
+ temp.get(), temp_img_width * components,
+ temp_x, temp_y, temp_width,
temp_img_width, temp_img_height, true, components);
// Scale the temp buffer vertically to get the final result.
LanczosResize1D(temp.get(), temp_x, temp_y, temp_height, temp_width,
temp_img_width, temp_img_height,
- dest, dest_x, dest_y, dest_height,
+ dest, dest_pitch,
+ dest_x, dest_y, dest_height,
dest_img_width, dest_img_height, false, components);
}
void Bitmap::LanczosResize1D(const uint8* src, int src_x, int src_y,
int width, int height,
int src_bmp_width, int src_bmp_height,
- uint8* out, int dest_x, int dest_y,
+ uint8* out, int dest_pitch,
+ int dest_x, int dest_y,
int nwidth,
int dest_bmp_width, int dest_bmp_height,
bool isWidth, int components) {
+ int pitch = dest_pitch / components;
// calculate scale factor and init the weight array for lanczos filter.
float scale = fabs(static_cast<float>(width) / nwidth);
float support = kFilterSize * scale;
@@ -459,7 +556,7 @@ void Bitmap::LanczosResize1D(const uint8* src, int src_x, int src_y,
const uint8* inrow = src + ((src_bmp_height - (src_y + base_y) - 1) *
src_bmp_width + src_x + xmin) * components;
uint8* outpix = out + ((dest_bmp_height - (dest_y + base_y) - 1) *
- dest_bmp_width + dest_x + x) * components;
+ pitch + dest_x + x) * components;
int step = components;
if (width < 0)
step = -1 * step;
@@ -475,7 +572,7 @@ void Bitmap::LanczosResize1D(const uint8* src, int src_x, int src_y,
(src_y + xmin) - 1) * src_bmp_width) *
components;
uint8* outpix = out + (dest_x + base_y + (dest_bmp_height -
- (dest_y + x) - 1) * dest_bmp_width) * components;
+ (dest_y + x) - 1) * pitch) * components;
int step = src_bmp_width * components;
if (width < 0)
@@ -545,7 +642,7 @@ Bitmap::ImageFileType Bitmap::GetFileTypeFromMimeType(const char *mime_type) {
return Bitmap::UNKNOWN;
}
-void Bitmap::XYZToXYZA(unsigned char *image_data, int pixel_count) {
+void Bitmap::XYZToXYZA(uint8 *image_data, int pixel_count) {
// We do this pixel by pixel, starting from the end to avoid overlapping
// problems.
for (int i = pixel_count - 1; i >= 0; --i) {
@@ -556,9 +653,9 @@ void Bitmap::XYZToXYZA(unsigned char *image_data, int pixel_count) {
}
}
-void Bitmap::RGBAToBGRA(unsigned char *image_data, int pixel_count) {
+void Bitmap::RGBAToBGRA(uint8 *image_data, int pixel_count) {
for (int i = 0; i < pixel_count; ++i) {
- unsigned char c = image_data[i*4+0];
+ uint8 c = image_data[i*4+0];
image_data[i*4+0] = image_data[i*4+2];
image_data[i*4+2] = c;
}
@@ -580,10 +677,10 @@ static void FilterTexel(unsigned int x,
unsigned int y,
unsigned int dst_width,
unsigned int dst_height,
- unsigned char *dst_data,
+ uint8 *dst_data,
unsigned int src_width,
unsigned int src_height,
- const unsigned char *src_data,
+ const uint8 *src_data,
unsigned int components) {
DCHECK(Bitmap::CheckImageDimensions(src_width, src_height));
DCHECK(Bitmap::CheckImageDimensions(dst_width, dst_height));
@@ -660,7 +757,7 @@ static void FilterTexel(unsigned int x,
uint64 value = accum[c] / (src_height * src_width);
DCHECK_LE(value, 255u);
dst_data[(y * dst_width + x) * components + c] =
- static_cast<unsigned char>(value);
+ static_cast<uint8>(value);
}
}
@@ -668,7 +765,7 @@ bool Bitmap::GenerateMipmaps(unsigned int base_width,
unsigned int base_height,
Texture::Format format,
unsigned int num_mipmaps,
- unsigned char *data) {
+ uint8 *data) {
DCHECK(CheckImageDimensions(base_width, base_height));
unsigned int components = 0;
switch (format) {
@@ -687,13 +784,13 @@ bool Bitmap::GenerateMipmaps(unsigned int base_width,
return false;
}
DCHECK_GE(std::max(base_width, base_height) >> (num_mipmaps-1), 1u);
- unsigned char *mip_data = data;
+ uint8 *mip_data = data;
unsigned int mip_width = base_width;
unsigned int mip_height = base_height;
for (unsigned int level = 1; level < num_mipmaps; ++level) {
unsigned int prev_width = mip_width;
unsigned int prev_height = mip_height;
- unsigned char *prev_data = mip_data;
+ uint8 *prev_data = mip_data;
mip_data += components * mip_width * mip_height;
DCHECK_EQ(mip_data, data + GetMipChainSize(base_width, base_height, format,
level));
@@ -733,74 +830,105 @@ bool Bitmap::GenerateMipmaps(unsigned int base_width,
bool Bitmap::ScaleUpToPOT(unsigned int width,
unsigned int height,
Texture::Format format,
- const unsigned char *src,
- unsigned char *dst) {
+ const uint8 *src,
+ uint8 *dst,
+ int dst_pitch) {
DCHECK(CheckImageDimensions(width, height));
unsigned int components = 0;
switch (format) {
case Texture::XRGB8:
case Texture::ARGB8:
- components = 4;
- break;
case Texture::ABGR16F:
case Texture::R32F:
case Texture::ABGR32F:
+ break;
case Texture::DXT1:
case Texture::DXT3:
case Texture::DXT5:
case Texture::UNKNOWN_FORMAT:
- DLOG(ERROR) << "Up-scaling is not supported for format: " << format;
+ DCHECK(false);
return false;
}
unsigned int pot_width = GetPOTSize(width);
unsigned int pot_height = GetPOTSize(height);
if (pot_width == width && pot_height == height && src == dst)
return true;
- return Scale(width, height, format, src, pot_width, pot_height, dst);
+ return Scale(
+ width, height, format, src, pot_width, pot_height, dst, dst_pitch);
+}
+
+namespace {
+
+template <typename T>
+void PointScale(
+ unsigned components,
+ const uint8* src,
+ unsigned src_width,
+ unsigned src_height,
+ uint8* dst,
+ int dst_pitch,
+ unsigned dst_width,
+ unsigned dst_height) {
+ const T* use_src = reinterpret_cast<const T*>(src);
+ T* use_dst = reinterpret_cast<T*>(dst);
+ int pitch = dst_pitch / sizeof(*use_src) / components;
+ // Start from the end to be able to do it in place.
+ for (unsigned int y = dst_height - 1; y < dst_height; --y) {
+ // max value for y is dst_height - 1, which makes :
+ // base_y = (2*dst_height - 1) * src_height / (2 * dst_height)
+ // which is < src_height.
+ unsigned int base_y = ((y * 2 + 1) * src_height) / (dst_height * 2);
+ DCHECK_LT(base_y, src_height);
+ for (unsigned int x = dst_width - 1; x < dst_width; --x) {
+ unsigned int base_x = ((x * 2 + 1) * src_width) / (dst_width * 2);
+ DCHECK_LT(base_x, src_width);
+ for (unsigned int c = 0; c < components; ++c) {
+ use_dst[(y * pitch + x) * components + c] =
+ use_src[(base_y * src_width + base_x) * components + c];
+ }
+ }
+ }
}
+} // anonymous namespace
+
// Scales the image using basic point filtering.
bool Bitmap::Scale(unsigned int src_width,
unsigned int src_height,
Texture::Format format,
- const unsigned char *src,
+ const uint8 *src,
unsigned int dst_width,
unsigned int dst_height,
- unsigned char *dst) {
+ uint8 *dst,
+ int dst_pitch) {
DCHECK(CheckImageDimensions(src_width, src_height));
DCHECK(CheckImageDimensions(dst_width, dst_height));
- unsigned int components = 0;
switch (format) {
case Texture::XRGB8:
- case Texture::ARGB8:
- components = 4;
+ case Texture::ARGB8: {
+ PointScale<uint8>(4, src, src_width, src_height,
+ dst, dst_pitch, dst_width, dst_height);
break;
- case Texture::ABGR16F:
+ }
+ case Texture::ABGR16F: {
+ PointScale<uint16>(4, src, src_width, src_height,
+ dst, dst_pitch, dst_width, dst_height);
+ break;
+ }
case Texture::R32F:
- case Texture::ABGR32F:
+ case Texture::ABGR32F: {
+ PointScale<float>(format == Texture::R32F ? 1 : 4,
+ src, src_width, src_height,
+ dst, dst_pitch, dst_width, dst_height);
+ break;
+ }
case Texture::DXT1:
case Texture::DXT3:
case Texture::DXT5:
case Texture::UNKNOWN_FORMAT:
- DLOG(ERROR) << "Up-scaling is not supported for format: " << format;
+ DCHECK(false);
return false;
}
- // Start from the end to be able to do it in place.
- for (unsigned int y = dst_height - 1; y < dst_height; --y) {
- // max value for y is dst_height - 1, which makes :
- // base_y = (2*dst_height - 1) * src_height / (2 * dst_height)
- // which is < src_height.
- unsigned int base_y = ((y * 2 + 1) * src_height) / (dst_height * 2);
- DCHECK_LT(base_y, src_height);
- for (unsigned int x = dst_width - 1; x < dst_width; --x) {
- unsigned int base_x = ((x * 2 + 1) * src_width) / (dst_width * 2);
- DCHECK_LT(base_x, src_width);
- for (unsigned int c = 0; c < components; ++c) {
- dst[(y * dst_width + x) * components + c] =
- src[(base_y * src_width + base_x) * components + c];
- }
- }
- }
return true;
}
@@ -915,10 +1043,10 @@ bool Bitmap::CheckAlphaIsOne() const {
int faces = is_cubemap() ? 6 : 1;
for (int face = 0; face < faces; ++face) {
for (unsigned int level = 0; level < num_mipmaps(); ++level) {
- const unsigned char *data = GetMipData(
- level,
- static_cast<TextureCUBE::CubeFace>(face)) + 3;
- const unsigned char* end = data + Bitmap::GetBufferSize(
+ const uint8 *data = GetFaceMipData(
+ static_cast<TextureCUBE::CubeFace>(face),
+ level) + 3;
+ const uint8* end = data + Bitmap::GetBufferSize(
std::max(1U, width() >> level),
std::max(1U, height() >> level),
format());
@@ -936,10 +1064,10 @@ bool Bitmap::CheckAlphaIsOne() const {
int faces = is_cubemap() ? 6 : 1;
for (int face = 0; face < faces; ++face) {
for (unsigned int level = 0; level < num_mipmaps(); ++level) {
- const unsigned char *data = GetMipData(
- level,
- static_cast<TextureCUBE::CubeFace>(face));
- const unsigned char* end = data + Bitmap::GetBufferSize(
+ const uint8 *data = GetFaceMipData(
+ static_cast<TextureCUBE::CubeFace>(face),
+ level);
+ const uint8* end = data + Bitmap::GetBufferSize(
std::max(1U, width() >> level),
std::max(1U, height() >> level),
format());
@@ -965,10 +1093,10 @@ bool Bitmap::CheckAlphaIsOne() const {
int faces = is_cubemap() ? 6 : 1;
for (int face = 0; face < faces; ++face) {
for (unsigned int level = 0; level < num_mipmaps(); ++level) {
- const unsigned char *data = GetMipData(
- level,
- static_cast<TextureCUBE::CubeFace>(face)) + 6;
- const unsigned char* end = data + Bitmap::GetBufferSize(
+ const uint8 *data = GetFaceMipData(
+ static_cast<TextureCUBE::CubeFace>(face),
+ level) + 6;
+ const uint8* end = data + Bitmap::GetBufferSize(
std::max(1U, width() >> level),
std::max(1U, height() >> level),
format());
@@ -988,10 +1116,10 @@ bool Bitmap::CheckAlphaIsOne() const {
int faces = is_cubemap() ? 6 : 1;
for (int face = 0; face < faces; ++face) {
for (unsigned int level = 0; level < num_mipmaps(); ++level) {
- const unsigned char* data = GetMipData(
- level,
- static_cast<TextureCUBE::CubeFace>(face)) + 12;
- const unsigned char* end = data + Bitmap::GetBufferSize(
+ const uint8* data = GetFaceMipData(
+ static_cast<TextureCUBE::CubeFace>(face),
+ level) + 12;
+ const uint8* end = data + Bitmap::GetBufferSize(
std::max(1U, width() >> level),
std::max(1U, height() >> level),
format());
diff --git a/o3d/core/cross/bitmap.h b/o3d/core/cross/bitmap.h
index bebe6c6..87fab79 100644
--- a/o3d/core/cross/bitmap.h
+++ b/o3d/core/cross/bitmap.h
@@ -86,6 +86,18 @@ class Bitmap : public ParamObject {
width <= kMaxImageDimension && height < kMaxImageDimension;
}
+ // Computes the width and height of a mip.
+ static void GetMipSize(int level,
+ unsigned width,
+ unsigned height,
+ unsigned* mip_width,
+ unsigned* mip_height) {
+ unsigned w = width >> level;
+ unsigned h = height >> level;
+ *mip_width = w > 0 ? w : 1u;
+ *mip_height = h > 0 ? h : 1u;
+ }
+
// Creates a copy of a bitmap, copying the pixels as well.
// Parameters:
// source: the source bitmap.
@@ -125,7 +137,7 @@ class Bitmap : public ParamObject {
// Allocates a bitmap with initialized parameters.
// data is zero-initialized
void AllocateData() {
- image_data_.reset(new unsigned char[GetTotalSize()]);
+ image_data_.reset(new uint8[GetTotalSize()]);
memset(image_data_.get(), 0, GetTotalSize());
}
@@ -134,6 +146,49 @@ class Bitmap : public ParamObject {
image_data_.reset(NULL);
}
+ // 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 SetRect(int level,
+ unsigned dst_left,
+ unsigned dst_top,
+ unsigned width,
+ unsigned height,
+ 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() {
return (is_cubemap_ ? 6 : 1) *
@@ -145,15 +200,19 @@ class Bitmap : public ParamObject {
unsigned int height,
Texture::Format format);
+ // Gets the image data for a given mip-map level.
+ // Parameters:
+ // 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.
// level: mip level to get.
- // face: face of cube to get. This parameter is ignored if
- // this bitmap is not a cube map.
- unsigned char *GetMipData(unsigned int level,
- TextureCUBE::CubeFace face) const;
+ uint8 *GetFaceMipData(TextureCUBE::CubeFace face,
+ unsigned int level) const;
- unsigned char *image_data() const { return image_data_.get(); }
+ 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_; }
@@ -281,7 +340,7 @@ class Bitmap : public ParamObject {
int src_x, int src_y,
int src_width, int src_height,
int src_img_width, int src_img_height,
- uint8* dest,
+ uint8* dest, int dest_pitch,
int dest_x, int dest_y,
int dest_width, int dest_height,
int dest_img_width, int dest_img_height,
@@ -295,10 +354,10 @@ class Bitmap : public ParamObject {
// Adds filler alpha byte (0xff) after every pixel. Assumes buffer was
// allocated with enough storage)
// can convert RGB -> RGBA, BGR -> BGRA, etc.
- static void XYZToXYZA(unsigned char *image_data, int pixel_count);
+ static void XYZToXYZA(uint8 *image_data, int pixel_count);
// Swaps Red and Blue components in the image.
- static void RGBAToBGRA(unsigned char *image_data, int pixel_count);
+ static void RGBAToBGRA(uint8 *image_data, int pixel_count);
// Gets the number of mip-maps required for a full chain starting at
// width x height.
@@ -334,7 +393,7 @@ class Bitmap : public ParamObject {
unsigned int base_height,
Texture::Format format,
unsigned int num_mipmaps,
- unsigned char *data);
+ uint8 *data);
// Scales an image up to power-of-two textures, using point filtering.
// NOTE: this doesn't work for DXTC, or floating-point images.
@@ -345,13 +404,15 @@ class Bitmap : public ParamObject {
// format: the format of the data.
// src: the data containing the source data of the original image.
// dst: a buffer with enough space for the power-of-two version. Pixels are
- // written from the end to the beginning so dst can be the same buffer as
- // src.
+ // written from the end to the beginning so dst can be the same buffer
+ // as src.
+ // dst_pitch: Number of bytes across 1 row of pixels.
static bool ScaleUpToPOT(unsigned int width,
unsigned int height,
Texture::Format format,
- const unsigned char *src,
- unsigned char *dst);
+ const uint8 *src,
+ uint8 *dst,
+ int dst_pitch);
// Scales an image to an arbitrary size, using point filtering.
// NOTE: this doesn't work for DXTC, or floating-point images.
@@ -364,15 +425,17 @@ class Bitmap : public ParamObject {
// dst_width: the width of the target image.
// dst_height: the height of the target image.
// dst: a buffer with enough space for the target version. Pixels are
- // written from the end to the beginning so dst can be the same buffer as
- // src if the transformation is an upscaling.
+ // written from the end to the beginning so dst can be the same buffer
+ // as src if the transformation is an upscaling.
+ // dst_pitch: Number of bytes across 1 row of pixels.
static bool Scale(unsigned int src_width,
unsigned int src_height,
Texture::Format format,
- const unsigned char *src,
+ const uint8 *src,
unsigned int dst_width,
unsigned int dst_height,
- unsigned char *dst);
+ uint8 *dst,
+ int dst_pitch);
// adjust start points and boundaries when using DrawImage data
// in bitmap and textures.
@@ -455,7 +518,8 @@ class Bitmap : public ParamObject {
static void LanczosResize1D(const uint8* src, int src_x, int src_y,
int width, int height,
int src_bmp_width, int src_bmp_height,
- uint8* dest, int dest_x, int dest_y,
+ uint8* dest, int dest_pitch,
+ int dest_x, int dest_y,
int nwidth,
int dest_bmp_width, int dest_bmp_height,
bool isWidth, int components);
diff --git a/o3d/core/cross/bitmap_test.cc b/o3d/core/cross/bitmap_test.cc
index 230a589..3fe8be0 100644
--- a/o3d/core/cross/bitmap_test.cc
+++ b/o3d/core/cross/bitmap_test.cc
@@ -570,7 +570,7 @@ TEST_F(BitmapTest, LoadDDSFileDXT1Mipmap) {
EXPECT_EQ(256, bitmap->height());
EXPECT_EQ(9, bitmap->num_mipmaps());
for (unsigned int i = 0; i < bitmap->num_mipmaps(); ++i) {
- EXPECT_TRUE(bitmap->GetMipData(i, TextureCUBE::FACE_POSITIVE_X) != NULL);
+ EXPECT_TRUE(bitmap->GetMipData(i) != NULL);
}
EXPECT_TRUE(TestBitmapData(*bitmap, kdxt1_256x256_mipmap));
}
@@ -605,7 +605,7 @@ TEST_F(BitmapTest, LoadDDSFileDXT3Mipmap) {
EXPECT_EQ(256, bitmap->height());
EXPECT_EQ(9, bitmap->num_mipmaps());
for (unsigned int i = 0; i < bitmap->num_mipmaps(); ++i) {
- EXPECT_TRUE(bitmap->GetMipData(i, TextureCUBE::FACE_POSITIVE_X) != NULL);
+ EXPECT_TRUE(bitmap->GetMipData(i) != NULL);
}
EXPECT_TRUE(TestBitmapData(*bitmap, kdxt3_256x256_mipmap));
}
@@ -640,7 +640,7 @@ TEST_F(BitmapTest, LoadDDSFileDXT5Mipmap) {
EXPECT_EQ(256, bitmap->height());
EXPECT_EQ(9, bitmap->num_mipmaps());
for (unsigned int i = 0; i < bitmap->num_mipmaps(); ++i) {
- EXPECT_TRUE(bitmap->GetMipData(i, TextureCUBE::FACE_POSITIVE_X) != NULL);
+ EXPECT_TRUE(bitmap->GetMipData(i) != NULL);
}
EXPECT_TRUE(TestBitmapData(*bitmap, kdxt5_256x256_mipmap));
}
@@ -844,13 +844,14 @@ TEST_F(BitmapTest, ScaleUpToPOT) {
scoped_array<unsigned char> data(new unsigned char[dst_size]);
ASSERT_TRUE(data.get() != NULL);
// Check that scaling works when source and destination don't alias
- Bitmap::ScaleUpToPOT(kWidth, kHeight, format, kScaleUPDataNPOT, data.get());
+ Bitmap::ScaleUpToPOT(kWidth, kHeight, format, kScaleUPDataNPOT, data.get(),
+ 4 * 4);
EXPECT_EQ(0, memcmp(data.get(), kScaleUPDataPOT, dst_size));
// Check that scaling works when source and destination do alias
memset(data.get(), 0, dst_size);
memcpy(data.get(), kScaleUPDataNPOT, src_size);
- Bitmap::ScaleUpToPOT(kWidth, kHeight, format, data.get(), data.get());
+ Bitmap::ScaleUpToPOT(kWidth, kHeight, format, data.get(), data.get(), 4 * 4);
EXPECT_EQ(0, memcmp(data.get(), kScaleUPDataPOT, dst_size));
}
diff --git a/o3d/core/cross/buffer.cc b/o3d/core/cross/buffer.cc
index ba2eb0a..3cc5afb 100644
--- a/o3d/core/cross/buffer.cc
+++ b/o3d/core/cross/buffer.cc
@@ -35,6 +35,7 @@
#include "core/cross/precompile.h"
#include "core/cross/buffer.h"
#include "core/cross/client_info.h"
+#include "core/cross/pointer_utils.h"
#include "core/cross/renderer.h"
#include "core/cross/features.h"
#include "core/cross/error.h"
diff --git a/o3d/core/cross/canvas.cc b/o3d/core/cross/canvas.cc
index 26fabbd..7dccb2d 100644
--- a/o3d/core/cross/canvas.cc
+++ b/o3d/core/cross/canvas.cc
@@ -154,9 +154,8 @@ void Canvas::DrawBitmap(Texture2D* texture2d,
return;
}
- void* texture_data;
- Texture2DLockHelper lock_helper(texture2d, 0);
- texture_data = lock_helper.GetData();
+ Texture2D::LockHelper lock_helper(texture2d, 0);
+ uint8* texture_data = lock_helper.GetDataAs<uint8>();
if (!texture_data) {
return;
}
@@ -177,7 +176,11 @@ void Canvas::DrawBitmap(Texture2D* texture2d,
unsigned char* bitmap_data = static_cast<unsigned char*>(
bitmap.getPixels());
- memcpy(bitmap_data, texture_data, width * height * 4);
+ for (int yy = 0; yy < height; ++yy) {
+ memcpy(bitmap_data + yy * width,
+ texture_data + yy * lock_helper.pitch(),
+ width * 4);
+ }
if (texture2d->format() == Texture2D::XRGB8) {
// Set the alpha to 1
@@ -242,13 +245,8 @@ bool Canvas::CopyToTexture(Texture2D* texture_2d) {
int width = sk_bitmap_.width();
int height = sk_bitmap_.height();
- Texture2DLockHelper lock_helper_0(texture_2d, 0);
- void* texture_data = lock_helper_0.GetData();
- if (!texture_data) {
- return false;
- }
-
- memcpy(texture_data, sk_bitmap_.getPixels(), width * height * 4);
+ texture_2d->SetRect(0, 0, 0, width, height,
+ sk_bitmap_.getPixels(), width * 4);
// Fill in all the mipmap levels of the texture by drawing scaled down
// versions of the canvas bitmap contents.
@@ -256,21 +254,17 @@ bool Canvas::CopyToTexture(Texture2D* texture_2d) {
int levels = texture_2d->levels();
for (int i = 1; (!levels && width > 1 && height > 1) || i < levels; i++) {
- width = width >> 1;
- height = height >> 1;
+ width = std::max(1, width >> 1);
+ height = std::max(1, height >> 1);
bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
- Texture2DLockHelper lock_helper_n(texture_2d, i);
- texture_data = lock_helper_n.GetData();
- if (!texture_data) {
- return false;
- }
-
- bitmap.setPixels(texture_data);
+ scoped_array<uint8> buffer(new uint8[width * height * 4]);
+ bitmap.setPixels(buffer.get());
SkCanvas canvas(bitmap);
SkScalar scaleFactor = SkScalarDiv(SK_Scalar1, SkIntToScalar(1 << i));
canvas.scale(scaleFactor, scaleFactor);
canvas.drawBitmap(sk_bitmap_, 0, 0);
+ texture_2d->SetRect(i, 0, 0, width, height, bitmap.getPixels(), width * 4);
}
return true;
diff --git a/o3d/core/cross/command_buffer/texture_cb.cc b/o3d/core/cross/command_buffer/texture_cb.cc
index 3d530a7..ff03c6a 100644
--- a/o3d/core/cross/command_buffer/texture_cb.cc
+++ b/o3d/core/cross/command_buffer/texture_cb.cc
@@ -110,7 +110,7 @@ void UpdateResourceFromBitmap(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 char *mip_data = bitmap.GetMipData(level, face);
+ unsigned char *mip_data = bitmap.GetFaceMipData(face, level);
unsigned int mip_size =
Bitmap::GetBufferSize(mip_width, mip_height, bitmap.format());
if (resize_to_pot) {
@@ -130,7 +130,8 @@ void UpdateResourceFromBitmap(RendererCB *renderer,
// for the NPOT->POT case.
DCHECK(buffer);
Bitmap::Scale(mip_width, mip_height, bitmap.format(), mip_data,
- pot_width, pot_height, buffer);
+ pot_width, pot_height, buffer,
+ Bitmap::GetMipChainSize(pot_width, 1, bitmap.format(), 1));
mip_width = pot_width;
mip_height = pot_height;
mip_size = pot_size;
@@ -206,7 +207,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.GetMipData(level, face), buffer, mip_size);
+ memcpy(bitmap.GetFaceMipData(face, level), buffer, mip_size);
allocator->Free(buffer);
}
@@ -313,9 +314,20 @@ Texture2DCB* Texture2DCB::Create(ServiceLocator* service_locator,
return texture;
}
+void Texture2DCB::SetRect(int level,
+ unsigned dst_left,
+ unsigned dst_top,
+ unsigned src_width,
+ unsigned src_height,
+ const void* src_data,
+ int src_pitch) {
+ // TODO(gman): Someone needs to implement this.
+ DCHECK(false);
+}
+
// Locks the given mipmap level of this texture for loading from main memory,
// and returns a pointer to the buffer.
-bool Texture2DCB::Lock(int level, void** data) {
+bool Texture2DCB::Lock(int level, void** data, int* pitch) {
if (level >= levels() || level < 0) {
O3D_ERROR(service_locator())
<< "Trying to lock inexistent level " << level
@@ -332,7 +344,18 @@ bool Texture2DCB::Lock(int level, void** data) {
DCHECK_EQ(has_levels_, 0);
backing_bitmap_->Allocate(format(), width(), height(), levels(), false);
}
- *data = backing_bitmap_->GetMipData(level, TextureCUBE::FACE_POSITIVE_X);
+ *data = backing_bitmap_->GetMipData(level);
+ unsigned int mip_width;
+ unsigned int mip_height;
+ Bitmap::GetMipSize(level, width(), height(), &mip_width, &mip_height);
+ if (IsCompressed()) {
+ *pitch = Bitmap::GetMipChainSize(mip_width, 1,format(), 1);
+ } else {
+ unsigned blocks_across = (mip_width + 3) / 4;
+ unsigned bytes_per_block = format() == Texture::DXT1 ? 8 : 16;
+ unsigned bytes_per_row = bytes_per_block * blocks_across;
+ *pitch = bytes_per_row;
+ }
if (!HasLevel(level)) {
DCHECK(!resize_to_pot_);
DCHECK_EQ(backing_bitmap_->width(), width());
@@ -489,9 +512,21 @@ TextureCUBECB* TextureCUBECB::Create(ServiceLocator* service_locator,
return texture;
}
+void TextureCUBECB::SetRect(TextureCUBE::CubeFace face,
+ int level,
+ unsigned dst_left,
+ unsigned dst_top,
+ unsigned src_width,
+ unsigned src_height,
+ const void* src_data,
+ int src_pitch) {
+ // TODO(gman): Someone needs to implement this.
+ DCHECK(false);
+}
+
// Locks the given face and mipmap level of this texture for loading from
// main memory, and returns a pointer to the buffer.
-bool TextureCUBECB::Lock(CubeFace face, int level, void** data) {
+bool TextureCUBECB::Lock(CubeFace face, int level, void** data, int* pitch) {
if (level >= levels() || level < 0) {
O3D_ERROR(service_locator())
<< "Trying to lock inexistent level " << level
@@ -512,7 +547,19 @@ bool TextureCUBECB::Lock(CubeFace face, int level, void** data) {
backing_bitmap_->Allocate(format(), edge_length(), edge_length(),
levels(), true);
}
- *data = backing_bitmap_->GetMipData(level, face);
+ *data = backing_bitmap_->GetFaceMipData(face, level);
+ unsigned int mip_width;
+ unsigned int mip_height;
+ Bitmap::GetMipSize(level, edge_length(), edge_length(),
+ &mip_width, &mip_height);
+ if (IsCompressed()) {
+ *pitch = Bitmap::GetMipChainSize(mip_width, 1,format(), 1);
+ } else {
+ unsigned blocks_across = (mip_width + 3) / 4;
+ unsigned bytes_per_block = format() == Texture::DXT1 ? 8 : 16;
+ unsigned bytes_per_row = bytes_per_block * blocks_across;
+ *pitch = bytes_per_row;
+ }
if (!HasLevel(level, face)) {
// TODO: add some API so we don't have to copy back the data if we
// will rewrite it all.
diff --git a/o3d/core/cross/command_buffer/texture_cb.h b/o3d/core/cross/command_buffer/texture_cb.h
index ee525ac..e000a8e 100644
--- a/o3d/core/cross/command_buffer/texture_cb.h
+++ b/o3d/core/cross/command_buffer/texture_cb.h
@@ -64,12 +64,14 @@ class Texture2DCB : public Texture2D {
Bitmap *bitmap,
bool enable_render_surfaces);
- // Locks the image buffer of a given mipmap level for writing from main
- // memory.
- virtual bool Lock(int level, void** texture_data);
-
- // Unlocks this texture and returns it to OpenCB control.
- virtual bool Unlock(int level);
+ // Overridden from Texture2D
+ virtual void SetRect(int level,
+ unsigned left,
+ unsigned top,
+ unsigned width,
+ unsigned height,
+ const void* src_data,
+ int src_pitch);
// Returns a RenderSurface object associated with a mip_level of a texture.
// Parameters:
@@ -91,6 +93,12 @@ class Texture2DCB : public Texture2D {
// RGBA to the internal format used by the rendering API.
virtual const RGBASwizzleIndices& GetABGR32FSwizzleIndices();
+ protected:
+ // Overridden from Texture2D
+ virtual bool Lock(int level, void** texture_data, int* pitch);
+
+ // Overridden from Texture2D
+ virtual bool Unlock(int level);
private:
// Initializes the Texture2DCB from a preexisting OpenCB texture handle
@@ -133,12 +141,15 @@ class TextureCUBECB : public TextureCUBE {
Bitmap *bitmap,
bool enable_render_surfaces);
- // Locks the image buffer of a given face and mipmap level for loading
- // from main memory.
- virtual bool Lock(CubeFace face, int level, void** texture_data);
-
- // Unlocks the image buffer of a given face and mipmap level.
- virtual bool Unlock(CubeFace face, int level);
+ // Overridden from TextureCUBE
+ virtual void SetRect(CubeFace face,
+ int level,
+ unsigned dst_left,
+ unsigned dst_top,
+ unsigned width,
+ unsigned height,
+ const void* src_data,
+ int src_pitch);
// Returns a RenderSurface object associated with a given cube face and
// mip_level of a texture.
@@ -164,6 +175,14 @@ class TextureCUBECB : public TextureCUBE {
// RGBA to the internal format used by the rendering API.
virtual const RGBASwizzleIndices& GetABGR32FSwizzleIndices();
+ protected:
+ // Overridden from TextureCUBE
+ virtual bool Lock(
+ CubeFace face, int level, void** texture_data, int* pitch);
+
+ // Overridden from TextureCUBE
+ virtual bool Unlock(CubeFace face, int level);
+
private:
// Creates a texture from a pre-existing texture resource.
TextureCUBECB(ServiceLocator* service_locator,
diff --git a/o3d/core/cross/fake_vertex_source.cc b/o3d/core/cross/fake_vertex_source.cc
index c8e0b6f..c2bec2c 100644
--- a/o3d/core/cross/fake_vertex_source.cc
+++ b/o3d/core/cross/fake_vertex_source.cc
@@ -35,6 +35,7 @@
#include "core/cross/precompile.h"
#include "core/cross/fake_vertex_source.h"
+#include "core/cross/pointer_utils.h"
#include "core/cross/buffer.h"
namespace o3d {
diff --git a/o3d/core/cross/field.cc b/o3d/core/cross/field.cc
index 1ccbfde..79115d6 100644
--- a/o3d/core/cross/field.cc
+++ b/o3d/core/cross/field.cc
@@ -38,6 +38,7 @@
#include "core/cross/field.h"
#include "core/cross/error.h"
#include "core/cross/buffer.h"
+#include "core/cross/pointer_utils.h"
#include "core/cross/types.h"
#include "core/cross/renderer.h"
#include "import/cross/memory_stream.h"
diff --git a/o3d/core/cross/field.h b/o3d/core/cross/field.h
index 212b003..2a64098 100644
--- a/o3d/core/cross/field.h
+++ b/o3d/core/cross/field.h
@@ -42,20 +42,6 @@
namespace o3d {
-// Adds an arbitrary byte offset to a typed pointer.
-template <typename T>
-T AddPointerOffset(T pointer, unsigned offset) {
- return reinterpret_cast<T>(
- const_cast<uint8*>(reinterpret_cast<const uint8*>(pointer) + offset));
-}
-
-// Creates a typed pointer from a void pointer and an offset.
-template <typename T>
-T PointerFromVoidPointer(void* pointer, unsigned offset) {
- return reinterpret_cast<T>(
- const_cast<uint8*>(reinterpret_cast<const uint8*>(pointer) + offset));
-}
-
class Buffer;
class MemoryReadStream;
diff --git a/o3d/core/cross/gl/texture_gl.cc b/o3d/core/cross/gl/texture_gl.cc
index f904d3d..ff9588f 100644
--- a/o3d/core/cross/gl/texture_gl.cc
+++ b/o3d/core/cross/gl/texture_gl.cc
@@ -36,6 +36,7 @@
#include "core/cross/precompile.h"
#include "core/cross/error.h"
#include "core/cross/types.h"
+#include "core/cross/pointer_utils.h"
#include "core/cross/gl/renderer_gl.h"
#include "core/cross/gl/render_surface_gl.h"
#include "core/cross/gl/texture_gl.h"
@@ -154,11 +155,12 @@ 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 unsigned char *mip_data = bitmap.GetMipData(level, face);
+ const unsigned char *mip_data = bitmap.GetFaceMipData(face, level);
unsigned int mip_size =
Bitmap::GetBufferSize(mip_width, mip_height, bitmap.format());
scoped_array<unsigned char> temp_data;
if (resize_to_pot) {
+ DCHECK(!Texture::IsCompressedFormat(bitmap.format()));
unsigned int pot_width =
std::max(1U, Bitmap::GetPOTSize(bitmap.width()) >> level);
unsigned int pot_height =
@@ -167,7 +169,8 @@ static bool UpdateGLImageFromBitmap(GLenum target,
bitmap.format());
temp_data.reset(new unsigned char[pot_size]);
Bitmap::Scale(mip_width, mip_height, bitmap.format(), mip_data,
- pot_width, pot_height, temp_data.get());
+ pot_width, pot_height, temp_data.get(),
+ Bitmap::GetMipChainSize(pot_width, 1, bitmap.format(), 1));
mip_width = pot_width;
mip_height = pot_height;
mip_size = pot_size;
@@ -218,7 +221,7 @@ static bool CreateGLImagesAndUpload(GLenum target,
for (unsigned int i = 0; i < bitmap.num_mipmaps(); ++i) {
// Upload pixels directly if we can, otherwise it will be done with
// UpdateGLImageFromBitmap afterwards.
- unsigned char *data = resize_to_pot ? NULL : bitmap.GetMipData(i, face);
+ unsigned char *data = resize_to_pot ? NULL : bitmap.GetFaceMipData(face, i);
if (format) {
glTexImage2D(target, i, internal_format, mip_width, mip_height,
@@ -376,9 +379,96 @@ Texture2DGL::~Texture2DGL() {
CHECK_GL_ERROR();
}
+void Texture2DGL::SetRect(int level,
+ unsigned dst_left,
+ unsigned dst_top,
+ unsigned src_width,
+ unsigned src_height,
+ const void* src_data,
+ int src_pitch) {
+ if (level >= levels() || level < 0) {
+ O3D_ERROR(service_locator())
+ << "Trying to SetRect on non-existent level " << level
+ << " on Texture \"" << name() << "\"";
+ return;
+ }
+ if (render_surfaces_enabled()) {
+ O3D_ERROR(service_locator())
+ << "Attempting to SetRect a render-target texture: " << name();
+ return;
+ }
+
+ unsigned mip_width;
+ unsigned mip_height;
+ Bitmap::GetMipSize(level, width(), height(), &mip_width, &mip_height);
+
+ if (dst_left + src_width > mip_width ||
+ dst_top + src_height > mip_height) {
+ O3D_ERROR(service_locator())
+ << "SetRect(" << level << ", " << dst_left << ", " << dst_top << ", "
+ << src_width << ", " << src_height << ") out of range for texture << \""
+ << name() << "\"";
+ return;
+ }
+
+ bool entire_rect = dst_left == 0 && dst_top == 0 &&
+ src_width == mip_width && src_height == mip_height;
+ bool compressed = IsCompressed();
+
+ if (compressed && !entire_rect) {
+ O3D_ERROR(service_locator())
+ << "SetRect must be full rectangle for compressed textures";
+ return;
+ }
+
+ if (resize_to_pot_) {
+ DCHECK(backing_bitmap_->image_data());
+ DCHECK(!compressed);
+ // We need to update the backing mipmap and then use that to update the
+ // texture.
+ backing_bitmap_->SetRect(
+ level, dst_left, dst_top, src_width, src_height, src_data, src_pitch);
+ UpdateBackedMipLevel(level);
+ } else {
+ glBindTexture(GL_TEXTURE_2D, gl_texture_);
+ GLenum gl_internal_format = 0;
+ GLenum gl_data_type = 0;
+ GLenum gl_format = GLFormatFromO3DFormat(format(), &gl_internal_format,
+ &gl_data_type);
+ if (gl_format) {
+ if (src_pitch == Bitmap::GetMipChainSize(src_width, 1, format(), 1)) {
+ glTexSubImage2D(GL_TEXTURE_2D, level,
+ dst_left, dst_top,
+ src_width, src_height,
+ gl_format,
+ gl_data_type,
+ src_data);
+ } else {
+ for (int yy = 0; yy < src_height; ++yy) {
+ glTexSubImage2D(GL_TEXTURE_2D, level,
+ dst_left, dst_top + yy,
+ src_width, 1,
+ gl_format,
+ gl_data_type,
+ src_data);
+ src_data = AddPointerOffset<const void*>(src_data, src_pitch);
+ }
+ }
+ } else {
+ glCompressedTexSubImage2D(
+ GL_TEXTURE_2D, level, 0, 0, src_width, src_height,
+ gl_internal_format,
+ Bitmap::GetMipChainSize(src_width, src_height, format(), 1),
+ src_data);
+ }
+ }
+}
+
// Locks the given mipmap level of this texture for loading from main memory,
// and returns a pointer to the buffer.
-bool Texture2DGL::Lock(int level, void** data) {
+bool Texture2DGL::Lock(int level, void** data, int* pitch) {
+ DCHECK(data);
+ DCHECK(pitch);
DLOG(INFO) << "Texture2DGL Lock";
renderer_->MakeCurrentLazy();
if (level >= levels() || level < 0) {
@@ -397,7 +487,18 @@ bool Texture2DGL::Lock(int level, void** data) {
DCHECK_EQ(has_levels_, 0u);
backing_bitmap_->Allocate(format(), width(), height(), levels(), false);
}
- *data = backing_bitmap_->GetMipData(level, TextureCUBE::FACE_POSITIVE_X);
+ *data = backing_bitmap_->GetMipData(level);
+ unsigned int mip_width;
+ unsigned int mip_height;
+ Bitmap::GetMipSize(level, width(), height(), &mip_width, &mip_height);
+ if (IsCompressed()) {
+ *pitch = Bitmap::GetMipChainSize(mip_width, 1,format(), 1);
+ } else {
+ unsigned blocks_across = (mip_width + 3) / 4;
+ unsigned bytes_per_block = format() == Texture::DXT1 ? 8 : 16;
+ unsigned bytes_per_row = bytes_per_block * blocks_across;
+ *pitch = bytes_per_row;
+ }
if (!HasLevel(level)) {
// TODO: add some API so we don't have to copy back the data if we
// will rewrite it all.
@@ -651,9 +752,104 @@ RenderSurface::Ref TextureCUBEGL::GetRenderSurface(TextureCUBE::CubeFace face,
return render_surface;
}
+void TextureCUBEGL::SetRect(TextureCUBE::CubeFace face,
+ int level,
+ unsigned dst_left,
+ unsigned dst_top,
+ unsigned src_width,
+ unsigned src_height,
+ const void* src_data,
+ int src_pitch) {
+ if (static_cast<int>(face) < 0 || static_cast<int>(face) >= NUMBER_OF_FACES) {
+ O3D_ERROR(service_locator())
+ << "Trying to SetRect invalid face " << face << " on Texture \""
+ << name() << "\"";
+ return;
+ }
+ if (level >= levels() || level < 0) {
+ O3D_ERROR(service_locator())
+ << "Trying to SetRect non-existent level " << level
+ << " on Texture \"" << name() << "\"";
+ return;
+ }
+ if (render_surfaces_enabled()) {
+ O3D_ERROR(service_locator())
+ << "Attempting to SetRect a render-target texture: " << name();
+ return;
+ }
+
+ unsigned mip_width;
+ unsigned mip_height;
+ Bitmap::GetMipSize(
+ level, edge_length(), edge_length(), &mip_width, &mip_height);
+
+ if (dst_left + src_width > mip_width ||
+ dst_top + src_height > mip_height) {
+ O3D_ERROR(service_locator())
+ << "SetRect(" << level << ", " << dst_left << ", " << dst_top << ", "
+ << src_width << ", " << src_height << ") out of range for texture << \""
+ << name() << "\"";
+ return;
+ }
+
+ bool entire_rect = dst_left == 0 && dst_top == 0 &&
+ src_width == mip_width && src_height == mip_height;
+ bool compressed = IsCompressed();
+
+ if (compressed && !entire_rect) {
+ O3D_ERROR(service_locator())
+ << "SetRect must be full rectangle for compressed textures";
+ return;
+ }
+
+ if (resize_to_pot_) {
+ 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,
+ level, dst_left, dst_top, src_width, src_height, src_data, src_pitch);
+ UpdateBackedMipLevel(level, face);
+ } else {
+ // TODO(gman): Should this bind be using a FACE id?
+ glBindTexture(GL_TEXTURE_2D, gl_texture_);
+ GLenum gl_internal_format = 0;
+ GLenum gl_data_type = 0;
+ GLenum gl_format = GLFormatFromO3DFormat(format(), &gl_internal_format,
+ &gl_data_type);
+ int gl_face = kCubemapFaceList[face];
+ if (gl_format) {
+ if (src_pitch == Bitmap::GetMipChainSize(src_width, 1, format(), 1)) {
+ glTexSubImage2D(gl_face, level,
+ dst_left, dst_top,
+ src_width, src_height,
+ gl_format,
+ gl_data_type,
+ src_data);
+ } else {
+ for (int yy = 0; yy < src_height; ++yy) {
+ glTexSubImage2D(gl_face, level,
+ dst_left, dst_top + yy,
+ src_width, 1,
+ gl_format,
+ gl_data_type,
+ src_data);
+ src_data = AddPointerOffset<const void*>(src_data, src_pitch);
+ }
+ }
+ } else {
+ glCompressedTexSubImage2D(
+ GL_TEXTURE_2D, level, 0, 0, src_width, src_height,
+ gl_internal_format,
+ Bitmap::GetMipChainSize(src_width, src_height, format(), 1),
+ src_data);
+ }
+ }
+}
+
// Locks the given face and mipmap level of this texture for loading from
// main memory, and returns a pointer to the buffer.
-bool TextureCUBEGL::Lock(CubeFace face, int level, void** data) {
+bool TextureCUBEGL::Lock(CubeFace face, int level, void** data, int* pitch) {
DLOG(INFO) << "TextureCUBEGL Lock";
renderer_->MakeCurrentLazy();
if (level >= levels() || level < 0) {
@@ -676,7 +872,19 @@ bool TextureCUBEGL::Lock(CubeFace face, int level, void** data) {
backing_bitmap_->Allocate(format(), edge_length(), edge_length(),
levels(), true);
}
- *data = backing_bitmap_->GetMipData(level, face);
+ *data = backing_bitmap_->GetFaceMipData(face, level);
+ unsigned int mip_width;
+ unsigned int mip_height;
+ Bitmap::GetMipSize(level, edge_length(), edge_length(),
+ &mip_width, &mip_height);
+ if (IsCompressed()) {
+ *pitch = Bitmap::GetMipChainSize(mip_width, 1,format(), 1);
+ } else {
+ unsigned blocks_across = (mip_width + 3) / 4;
+ unsigned bytes_per_block = format() == Texture::DXT1 ? 8 : 16;
+ unsigned bytes_per_row = bytes_per_block * blocks_across;
+ *pitch = bytes_per_row;
+ }
GLenum gl_target = kCubemapFaceList[face];
if (!HasLevel(level, face)) {
// TODO: add some API so we don't have to copy back the data if we
diff --git a/o3d/core/cross/gl/texture_gl.h b/o3d/core/cross/gl/texture_gl.h
index a647d47..14d0be7 100644
--- a/o3d/core/cross/gl/texture_gl.h
+++ b/o3d/core/cross/gl/texture_gl.h
@@ -68,6 +68,15 @@ class Texture2DGL : public Texture2D {
virtual ~Texture2DGL();
+ // Overridden from Texture2D
+ virtual void SetRect(int level,
+ unsigned left,
+ unsigned top,
+ unsigned width,
+ unsigned height,
+ const void* src_data,
+ int src_pitch);
+
// Creates a new Texture2DGL with the given specs. If the GL texture
// creation fails then it returns NULL otherwise it returns a pointer to the
// newly created Texture object.
@@ -76,13 +85,6 @@ class Texture2DGL : public Texture2D {
Bitmap *bitmap,
bool enable_render_surfaces);
- // Locks the image buffer of a given mipmap level for writing from main
- // memory.
- virtual bool Lock(int level, void** texture_data);
-
- // Unlocks this texture and returns it to OpenGL control.
- virtual bool Unlock(int level);
-
// Returns the implementation-specific texture handle for this texture.
void* GetTextureHandle() const {
return reinterpret_cast<void*>(gl_texture_);
@@ -103,6 +105,13 @@ class Texture2DGL : public Texture2D {
// RGBA to the internal format used by the rendering API.
virtual const RGBASwizzleIndices& GetABGR32FSwizzleIndices();
+ protected:
+ // Overridden from Texture2D
+ virtual bool Lock(int level, void** texture_data, int* pitch);
+
+ // Overridden from Texture2D
+ virtual bool Unlock(int level);
+
private:
// Initializes the Texture2DGL from a preexisting OpenGL texture handle
// and raw Bitmap data.
@@ -151,12 +160,15 @@ class TextureCUBEGL : public TextureCUBE {
Bitmap *bitmap,
bool enable_render_surfaces);
- // Locks the image buffer of a given face and mipmap level for loading
- // from main memory.
- virtual bool Lock(CubeFace face, int level, void** texture_data);
-
- // Unlocks the image buffer of a given face and mipmap level.
- virtual bool Unlock(CubeFace face, int level);
+ // Overridden from TextureCUBE
+ virtual void SetRect(CubeFace face,
+ int level,
+ unsigned dst_left,
+ unsigned dst_top,
+ unsigned width,
+ unsigned height,
+ const void* src_data,
+ int src_pitch);
// Returns the implementation-specific texture handle for this texture.
virtual void* GetTextureHandle() const {
@@ -182,6 +194,13 @@ class TextureCUBEGL : public TextureCUBE {
// RGBA to the internal format used by the rendering API.
virtual const RGBASwizzleIndices& GetABGR32FSwizzleIndices();
+ protected:
+ // Overridden from TextureCUBE
+ virtual bool Lock(CubeFace face, int level, void** texture_data, int* pitch);
+
+ // Overridden from TextureCUBE
+ virtual bool Unlock(CubeFace face, int level);
+
private:
// Creates a texture from a pre-existing GL texture object.
TextureCUBEGL(ServiceLocator* service_locator,
diff --git a/o3d/core/cross/message_queue.cc b/o3d/core/cross/message_queue.cc
index bb5f8da..9e0f579 100644
--- a/o3d/core/cross/message_queue.cc
+++ b/o3d/core/cross/message_queue.cc
@@ -34,14 +34,14 @@
// the communication of external code (clients) with O3D (server) via the
// NativeClient IMC library.
+#include "core/cross/precompile.h"
#if defined(OS_MACOSX) | defined(OS_LINUX)
#include <sys/types.h>
#include <unistd.h>
#endif
-
-#include "core/cross/precompile.h"
#include "core/cross/message_queue.h"
#include "core/cross/object_manager.h"
+#include "core/cross/bitmap.h"
#include "core/cross/texture.h"
#include "core/cross/error.h"
@@ -146,10 +146,10 @@ MessageQueue::MessageQueue(ServiceLocator* service_locator)
// browsers running o3d at the same time as well as a count to
// distinguish between multiple instances of o3d running in the same
// browser.
- base::snprintf(server_socket_address_.path,
- sizeof(server_socket_address_.path),
- "%s%d%d", kServerSocketAddressPrefix, (proc_id & 0xFFFF),
- next_message_queue_id_);
+ ::base::snprintf(server_socket_address_.path,
+ sizeof(server_socket_address_.path),
+ "%s%d%d", kServerSocketAddressPrefix, (proc_id & 0xFFFF),
+ next_message_queue_id_);
next_message_queue_id_++;
}
@@ -521,9 +521,8 @@ bool MessageQueue::ProcessAllocateSharedMemory(ConnectedClient* client,
// bitmap using data stored in a shared memory region. The client sends the
// id of the shared memory region, an offset in that region, the id of the
// Texture object, the level to be modified and the number of bytes to copy.
-// TODO: Check that the number of bytes copied are equal to the size
-// occupied by that level in the texture. This is essentially asynchronous as
-// the client will not receive a response back from the server
+// This is essentially asynchronous as the client will not receive a response
+// back from the server
bool MessageQueue::ProcessUpdateTexture2D(ConnectedClient* client,
int message_length,
MessageId message_id,
@@ -591,20 +590,25 @@ bool MessageQueue::ProcessUpdateTexture2D(ConnectedClient* client,
return false;
}
- void* texture_data;
- bool locked = texture_object->Lock(level, &texture_data);
- if (!locked) {
- O3D_ERROR(service_locator_) << "Failed to lock texture";
+ unsigned int mip_width;
+ unsigned int mip_height;
+ Bitmap::GetMipSize(level, texture_object->width(), texture_object->height(),
+ &mip_width, &mip_height);
+
+
+ if (number_of_bytes != Bitmap::GetMipChainSize(mip_width, mip_height,
+ texture_object->format(), 1)) {
+ O3D_ERROR(service_locator_)
+ << "texture_size does not match size of texture level ("
+ << offset << " + " << number_of_bytes << " > " << info->size_;
SendBooleanResponse(client->client_handle(), false);
return false;
}
- // TODO: verify that we don't end up writing past the end of the
- // memory allocated for that texture level.
void *target_address = static_cast<char*>(info->mapped_address_) + offset;
- memcpy(texture_data, target_address, number_of_bytes);
-
- texture_object->Unlock(level);
+ texture_object->SetRect(
+ level, 0, 0, mip_width, mip_height, target_address,
+ Bitmap::GetMipChainSize(mip_width, 1, texture_object->format(), 1));
SendBooleanResponse(client->client_handle(), true);
return true;
diff --git a/o3d/core/cross/pointer_utils.h b/o3d/core/cross/pointer_utils.h
new file mode 100644
index 0000000..1cbd610
--- /dev/null
+++ b/o3d/core/cross/pointer_utils.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This file contains the declaration for a few templated function to help with
+// pointers.
+
+#ifndef O3D_CORE_CROSS_POINTER_UTILS_H_
+#define O3D_CORE_CROSS_POINTER_UTILS_H_
+
+#include "core/cross/types.h"
+
+namespace o3d {
+
+// Adds an arbitrary byte offset to a typed pointer.
+template <typename T>
+T AddPointerOffset(T pointer, unsigned offset) {
+ return reinterpret_cast<T>(
+ const_cast<uint8*>(reinterpret_cast<const uint8*>(pointer) + offset));
+}
+
+// Creates a typed pointer from a void pointer and an offset.
+template <typename T>
+T PointerFromVoidPointer(void* pointer, unsigned offset) {
+ return reinterpret_cast<T>(
+ const_cast<uint8*>(reinterpret_cast<const uint8*>(pointer) + offset));
+}
+
+} // namespace o3d
+
+#endif // O3D_CORE_CROSS_POINTER_UTILS_H_
diff --git a/o3d/core/cross/renderer.cc b/o3d/core/cross/renderer.cc
index fe80a1a..8d292d9 100644
--- a/o3d/core/cross/renderer.cc
+++ b/o3d/core/cross/renderer.cc
@@ -147,14 +147,9 @@ void Renderer::InitCommon() {
DCHECK(!error_sampler_.IsNull());
error_sampler_->set_name(O3D_STRING_CONSTANT("errorSampler"));
- // TODO: remove ifdef when textures are implemented on CB
-#ifndef RENDERER_CB
DCHECK(!texture.IsNull());
texture->set_name(O3D_STRING_CONSTANT("errorTexture"));
texture->set_alpha_is_one(true);
- void* texture_data;
- bool locked = texture->Lock(0, &texture_data);
- DCHECK(locked);
static unsigned char error_texture_data[] = {
0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00,
0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00,
@@ -189,14 +184,7 @@ void Renderer::InitCommon() {
0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00,
0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00,
};
- DCHECK(sizeof error_texture_data ==
- Bitmap::GetBufferSize(texture->width(),
- texture->height(),
- texture->format()));
- memcpy(texture_data, error_texture_data, sizeof error_texture_data);
- bool unlocked = texture->Unlock(0);
- DCHECK(unlocked);
-#endif
+ texture->SetRect(0, 0, 0, 8, 8, error_texture_data, 8 * 4);
error_sampler_->set_mag_filter(Sampler::POINT);
error_sampler_->set_min_filter(Sampler::POINT);
diff --git a/o3d/core/cross/skin.cc b/o3d/core/cross/skin.cc
index 507ae09..4349abe 100644
--- a/o3d/core/cross/skin.cc
+++ b/o3d/core/cross/skin.cc
@@ -35,6 +35,7 @@
#include "core/cross/precompile.h"
#include "core/cross/skin.h"
#include "core/cross/error.h"
+#include "core/cross/pointer_utils.h"
#include "import/cross/memory_stream.h"
#include "import/cross/raw_data.h"
diff --git a/o3d/core/cross/skin_test.cc b/o3d/core/cross/skin_test.cc
index 46a4358..5b1de83 100644
--- a/o3d/core/cross/skin_test.cc
+++ b/o3d/core/cross/skin_test.cc
@@ -36,6 +36,7 @@
#include "tests/common/win/testing_common.h"
#include "core/cross/error.h"
#include "core/cross/skin.h"
+#include "core/cross/pointer_utils.h"
#include "core/cross/primitive.h"
#include "import/cross/memory_buffer.h"
#include "import/cross/memory_stream.h"
diff --git a/o3d/core/cross/stream_bank_test.cc b/o3d/core/cross/stream_bank_test.cc
index b2d49c2..a154df3 100644
--- a/o3d/core/cross/stream_bank_test.cc
+++ b/o3d/core/cross/stream_bank_test.cc
@@ -35,6 +35,7 @@
#include "core/cross/client.h"
#include "core/cross/skin.h"
#include "core/cross/stream_bank.h"
+#include "core/cross/pointer_utils.h"
#include "core/cross/fake_vertex_source.h"
#include "tests/common/win/testing_common.h"
diff --git a/o3d/core/cross/texture.cc b/o3d/core/cross/texture.cc
index 008e2ef..8f71fd8 100644
--- a/o3d/core/cross/texture.cc
+++ b/o3d/core/cross/texture.cc
@@ -127,16 +127,9 @@ void Texture2D::DrawImage(Bitmap* src_img,
static_cast<unsigned int>(src_height) == src_img->height() &&
static_cast<unsigned int>(dst_width) == mip_width &&
static_cast<unsigned int>(dst_height) == mip_height) {
- void* data = NULL;
- if (!Lock(dest_mip, &data))
- return;
-
- uint8* mip_data = static_cast<uint8*>(data);
- unsigned int size = Bitmap::GetMipChainSize(mip_width, mip_height,
- format(), 1);
- memcpy(mip_data, src_img->image_data(), size);
- this->Unlock(dest_mip);
-
+ SetRect(dest_mip, 0, 0, mip_width, mip_height,
+ src_img->image_data(),
+ Bitmap::GetMipChainSize(src_img->width(), 1, format(), 1));
return;
}
if (src_img->format() == Texture::XRGB8 ||
@@ -150,43 +143,43 @@ void Texture2D::DrawImage(Bitmap* src_img,
return;
}
- void* data = NULL;
- if (!Lock(dest_mip, &data))
+ LockHelper helper(this, dest_mip);
+ uint8* mip_data = helper.GetDataAs<uint8>();
+ if (!mip_data) {
return;
+ }
uint8* src_img_data = src_img->image_data();
- uint8* mip_data = static_cast<uint8*>(data);
Bitmap::LanczosScale(src_img_data, src_x, src_y,
src_width, src_height,
src_img->width(), src_img->height(),
- mip_data, dst_x, dst_y,
+ mip_data, helper.pitch(),
+ dst_x, dst_y,
dst_width, dst_height,
mip_width, mip_height, components);
-
- this->Unlock(dest_mip);
}
ObjectBase::Ref Texture2D::Create(ServiceLocator* service_locator) {
return ObjectBase::Ref();
}
-Texture2DLockHelper::Texture2DLockHelper(Texture2D* texture, int level)
+Texture2D::LockHelper::LockHelper(Texture2D* texture, int level)
: texture_(texture),
level_(level),
data_(NULL),
locked_(false) {
}
-Texture2DLockHelper::~Texture2DLockHelper() {
+Texture2D::LockHelper::~LockHelper() {
if (locked_) {
texture_->Unlock(level_);
}
}
-void* Texture2DLockHelper::GetData() {
+void* Texture2D::LockHelper::GetData() {
if (!locked_) {
- locked_ = texture_->Lock(level_, &data_);
+ locked_ = texture_->Lock(level_, &data_, &pitch_);
if (!locked_) {
O3D_ERROR(texture_->service_locator())
<< "Unable to lock buffer '" << texture_->name() << "'";
@@ -280,17 +273,9 @@ void TextureCUBE::DrawImage(Bitmap* src_img,
static_cast<unsigned int>(src_height) == src_img->height() &&
static_cast<unsigned int>(dst_width) == mip_length &&
static_cast<unsigned int>(dst_height) == mip_length) {
- // get mip data by lock method.
- void* data = NULL;
- if (!Lock(dest_face, dest_mip, &data))
- return;
-
- uint8* mip_data = static_cast<uint8*>(data);
- unsigned int size = Bitmap::GetMipChainSize(mip_length, mip_length,
- format(), 1);
- memcpy(mip_data, src_img->image_data(), size);
- this->Unlock(dest_face, dest_mip);
-
+ SetRect(dest_face, dest_mip, 0, 0, mip_length, mip_length,
+ src_img->image_data(),
+ Bitmap::GetMipChainSize(src_img->width(), 1, format(), 1));
return;
}
if (src_img->format() == Texture::XRGB8 ||
@@ -304,22 +289,49 @@ void TextureCUBE::DrawImage(Bitmap* src_img,
return;
}
- void* data = NULL;
- if (!Lock(dest_face, dest_mip, &data)) {
+ LockHelper helper(this, dest_face, dest_mip);
+ uint8* mip_data = helper.GetDataAs<uint8>();
+ if (!mip_data) {
return;
}
uint8* src_img_data = src_img->image_data();
- uint8* mip_data = static_cast<uint8*>(data);
Bitmap::LanczosScale(src_img_data, src_x, src_y,
src_width, src_height,
src_img->width(), src_img->height(),
- mip_data, dst_x, dst_y,
+ mip_data, helper.pitch(),
+ dst_x, dst_y,
dst_width, dst_height,
mip_length, mip_length, components);
+}
+
+TextureCUBE::LockHelper::LockHelper(
+ TextureCUBE* texture,
+ CubeFace face,
+ int level)
+ : texture_(texture),
+ face_(face),
+ level_(level),
+ data_(NULL),
+ locked_(false) {
+}
+
+TextureCUBE::LockHelper::~LockHelper() {
+ if (locked_) {
+ texture_->Unlock(face_, level_);
+ }
+}
- this->Unlock(dest_face, dest_mip);
+void* TextureCUBE::LockHelper::GetData() {
+ if (!locked_) {
+ locked_ = texture_->Lock(face_, level_, &data_, &pitch_);
+ if (!locked_) {
+ O3D_ERROR(texture_->service_locator())
+ << "Unable to lock buffer '" << texture_->name() << "'";
+ }
+ }
+ return data_;
}
} // namespace o3d
diff --git a/o3d/core/cross/texture.h b/o3d/core/cross/texture.h
index 49ff0d2..721a7ec 100644
--- a/o3d/core/cross/texture.h
+++ b/o3d/core/cross/texture.h
@@ -49,6 +49,40 @@ class Bitmap;
class Texture2D : public Texture {
public:
typedef SmartPointer<Texture2D> Ref;
+
+ // Class to help lock Texture2D. Automatically unlocks texture in destructor.
+ class LockHelper {
+ public:
+ explicit LockHelper(Texture2D* texture, int level);
+ ~LockHelper();
+
+ int pitch() const {
+ return pitch_;
+ }
+
+ // Gets a pointer to the data of the buffer, locking the buffer if
+ // necessary.
+ // Returns:
+ // Pointer to data in buffer or NULL if there was an error.
+ void* GetData();
+
+ // Typed version of GetData
+ template <typename T>
+ T* GetDataAs() {
+ return reinterpret_cast<T*>(GetData());
+ }
+
+ private:
+ Texture2D* texture_;
+ int level_;
+ int pitch_;
+ void* data_;
+ bool locked_;
+
+ DISALLOW_COPY_AND_ASSIGN(LockHelper);
+ };
+
+
Texture2D(ServiceLocator* service_locator,
int width,
int height,
@@ -70,24 +104,26 @@ class Texture2D : public Texture {
return height_param_->value();
}
- // Returns a pointer to the internal texture data for the given mipmap level.
- // Lock must be called before the texture data can be modified.
+ // Sets a rectangular region of this texture.
+ // If the texture is a DXT format, the only acceptable values
+ // for left, top, width and height are 0, 0, texture->width, texture->height
+ //
// Parameters:
- // level: [in] the mipmap level to be modified
- // texture_data: [out] a pointer to the current texture data
- // Returns:
- // true if the operation succeeds
- virtual bool Lock(int level, void** texture_data) = 0;
-
- // Notifies the texture object that the internal texture data has been
- // been modified. Unlock must be called in conjunction with Lock. Modifying
- // the contents of the texture after Unlock has been called could lead to
- // unpredictable behavior.
- // Parameters:
- // level: [in] the mipmap level that was modified
- // Returns:
- // true if the operation succeeds
- virtual bool Unlock(int level) = 0;
+ // 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.
+ virtual void SetRect(int level,
+ unsigned dst_left,
+ unsigned dst_top,
+ unsigned width,
+ unsigned height,
+ const void* src_data,
+ int src_pitch) = 0;
// Returns a RenderSurface object associated with a mip_level of a texture.
// Parameters:
@@ -116,6 +152,27 @@ class Texture2D : public Texture {
int dest_width, int dest_height, int dest_mip);
protected:
+ // Returns a pointer to the internal texture data for the given mipmap level.
+ // Lock must be called before the texture data can be modified.
+ // Parameters:
+ // level: [in] the mipmap level to be modified
+ // texture_data: [out] a pointer to the current texture data
+ // pitch: bytes across 1 row of pixels if uncompressed format. bytes across 1
+ // row of blocks if compressed format.
+ // Returns:
+ // true if the operation succeeds
+ virtual bool Lock(int level, void** texture_data, int* pitch) = 0;
+
+ // Notifies the texture object that the internal texture data has been
+ // been modified. Unlock must be called in conjunction with Lock. Modifying
+ // the contents of the texture after Unlock has been called could lead to
+ // unpredictable behavior.
+ // Parameters:
+ // level: [in] the mipmap level that was modified
+ // Returns:
+ // true if the operation succeeds
+ virtual bool Unlock(int level) = 0;
+
// Returns true if the mip-map level has been locked.
bool IsLocked(unsigned int level) {
DCHECK_LT(static_cast<int>(level), levels());
@@ -138,32 +195,6 @@ class Texture2D : public Texture {
DISALLOW_COPY_AND_ASSIGN(Texture2D);
};
-// Class to help lock Texture2D. Automatically unlocks texture in destructor.
-class Texture2DLockHelper {
- public:
- explicit Texture2DLockHelper(Texture2D* texture, int level);
- ~Texture2DLockHelper();
-
- // Gets a pointer to the data of the buffer, locking the buffer if necessary.
- // Returns:
- // Pointer to data in buffer or NULL if there was an error.
- void* GetData();
-
- // Typed version of GetData
- template <typename T>
- T* GetDataAs() {
- return reinterpret_cast<T*>(GetData());
- }
-
- private:
- Texture2D* texture_;
- int level_;
- void* data_;
- bool locked_;
-
- DISALLOW_COPY_AND_ASSIGN(Texture2DLockHelper);
-};
-
class TextureCUBE : public Texture {
public:
typedef SmartPointer<TextureCUBE> Ref;
@@ -178,6 +209,40 @@ class TextureCUBE : public Texture {
NUMBER_OF_FACES,
};
+ // Class to help lock TextureCUBE.
+ // Automatically unlocks texture in destructor.
+ class LockHelper {
+ public:
+ explicit LockHelper(TextureCUBE* texture, CubeFace face, int level);
+ ~LockHelper();
+
+ int pitch() const {
+ return pitch_;
+ }
+
+ // Gets a pointer to the data of the buffer, locking the buffer if
+ // necessary.
+ // Returns:
+ // Pointer to data in buffer or NULL if there was an error.
+ void* GetData();
+
+ // Typed version of GetData
+ template <typename T>
+ T* GetDataAs() {
+ return reinterpret_cast<T*>(GetData());
+ }
+
+ private:
+ TextureCUBE* texture_;
+ CubeFace face_;
+ int level_;
+ int pitch_;
+ void* data_;
+ bool locked_;
+
+ DISALLOW_COPY_AND_ASSIGN(LockHelper);
+ };
+
static const char* kEdgeLengthParamName;
TextureCUBE(ServiceLocator* service_locator,
@@ -193,27 +258,28 @@ class TextureCUBE : public Texture {
return edge_length_param_->value();
}
- // Returns a pointer to the internal texture data for the given face and
- // mipmap level.
- // Lock must be called before the texture data can be modified.
+ // Sets a rectangular region of this texture.
+ // If the texture is a DXT format, the only acceptable values
+ // for left, top, width and height are 0, 0, texture->width, texture->height
+ //
// Parameters:
- // face: [in] the index of the cube face to be modified
- // level: [in] the mipmap level to be modified
- // texture_data: [out] a pointer to the current texture data
- // Returns:
- // true if the operation succeeds
- virtual bool Lock(CubeFace face, int level, void** texture_data) = 0;
-
- // Notifies the texture object that the internal texture data has been
- // been modified. Unlock must be called in conjunction with Lock.
- // Modifying the contents of the texture after Unlock has been called could
- // lead to unpredictable behavior.
- // Parameters:
- // face: [in] the index of the cube face that was modified
- // level: [in] the mipmap level that was modified
- // Returns:
- // true if the operation succeeds
- virtual bool Unlock(CubeFace face, int level) = 0;
+ // face: The face of the cube to modify.
+ // 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: buffer to get pixels from.
+ // src_pitch: If the format is uncompressed this is the number of bytes
+ // per row of pixels. If compressed this value is unused.
+ virtual void SetRect(CubeFace face,
+ int level,
+ unsigned dst_left,
+ unsigned dst_top,
+ unsigned width,
+ unsigned height,
+ const void* src_data,
+ int src_pitch) = 0;
// Returns a RenderSurface object associated with a given cube face and
// mip_level of a texture.
@@ -247,6 +313,31 @@ class TextureCUBE : public Texture {
int dest_height, CubeFace face, int dest_mip);
protected:
+ // Returns a pointer to the internal texture data for the given face and
+ // mipmap level.
+ // Lock must be called before the texture data can be modified.
+ // Parameters:
+ // face: [in] the index of the cube face to be modified
+ // level: [in] the mipmap level to be modified
+ // texture_data: [out] a pointer to the current texture data
+ // pitch: bytes across 1 row of pixels if uncompressed format. bytes across 1
+ // row of blocks if compressed format.
+ // Returns:
+ // true if the operation succeeds
+ virtual bool Lock(
+ CubeFace face, int level, void** texture_data, int* pitch) = 0;
+
+ // Notifies the texture object that the internal texture data has been
+ // been modified. Unlock must be called in conjunction with Lock.
+ // Modifying the contents of the texture after Unlock has been called could
+ // lead to unpredictable behavior.
+ // Parameters:
+ // face: [in] the index of the cube face that was modified
+ // level: [in] the mipmap level that was modified
+ // Returns:
+ // true if the operation succeeds
+ virtual bool Unlock(CubeFace face, int level) = 0;
+
// Returns true if the mip-map level has been locked.
bool IsLocked(unsigned int level, CubeFace face) {
DCHECK_LT(static_cast<int>(level), levels());
diff --git a/o3d/core/cross/texture_base.cc b/o3d/core/cross/texture_base.cc
index d4b2d19..b416ae5 100644
--- a/o3d/core/cross/texture_base.cc
+++ b/o3d/core/cross/texture_base.cc
@@ -35,6 +35,7 @@
#include "core/cross/precompile.h"
#include "core/cross/texture_base.h"
#include "core/cross/pack.h"
+#include "core/cross/bitmap.h"
namespace o3d {
diff --git a/o3d/core/cross/texture_base.h b/o3d/core/cross/texture_base.h
index c6a144d..395480c 100644
--- a/o3d/core/cross/texture_base.h
+++ b/o3d/core/cross/texture_base.h
@@ -90,6 +90,14 @@ class Texture : public ParamObject {
// Returns the implementation-specific texture handle.
virtual void* GetTextureHandle() const = 0;
+ static bool IsCompressedFormat(Format format) {
+ return format == DXT1 || format == DXT3 || format == DXT5;
+ }
+
+ bool IsCompressed() const {
+ return IsCompressedFormat(format_);
+ }
+
bool alpha_is_one() const { return alpha_is_one_; }
void set_alpha_is_one(bool value) { alpha_is_one_ = value; }
@@ -126,7 +134,8 @@ class Texture : public ParamObject {
}
// Whether or not to resize NPOT textures to POT when passing to the
- // underlying graphics API.
+ // 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);
@@ -161,7 +170,7 @@ class ParamTexture : public TypedRefParam<Texture> {
friend class IClassManager;
static ObjectBase::Ref Create(ServiceLocator* service_locator);
- O3D_DECL_CLASS(ParamTexture, RefParamBase)
+ O3D_DECL_CLASS(ParamTexture, RefParamBase);
DISALLOW_COPY_AND_ASSIGN(ParamTexture);
};
diff --git a/o3d/core/cross/texture_base_test.cc b/o3d/core/cross/texture_base_test.cc
new file mode 100644
index 0000000..8b13973
--- /dev/null
+++ b/o3d/core/cross/texture_base_test.cc
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file implements unit tests for class Texture.
+
+#include "tests/common/win/testing_common.h"
+#include "core/cross/texture_base.h"
+#include "core/cross/object_manager.h"
+
+namespace o3d {
+
+namespace {
+
+Texture::RGBASwizzleIndices swizzle;
+
+class MockTexture : public Texture {
+ public:
+ typedef SmartPointer<MockTexture> Ref;
+
+ 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) {
+ }
+
+ virtual const RGBASwizzleIndices& GetABGR32FSwizzleIndices() {
+ return swizzle;
+ };
+
+ virtual void* GetTextureHandle() const {
+ return NULL;
+ };
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockTexture);
+};
+
+} // anonymous namespace
+
+class TextureTest : public testing::Test {
+ protected:
+
+ TextureTest()
+ : object_manager_(g_service_locator) {
+ }
+
+ private:
+ ServiceDependency<ObjectManager> object_manager_;
+};
+
+TEST_F(TextureTest, Basic) {
+ MockTexture::Ref texture(new MockTexture(
+ g_service_locator,
+ Texture::XRGB8,
+ 1,
+ false,
+ false,
+ false));
+ ASSERT_TRUE(texture != NULL);
+ EXPECT_EQ(texture->format(), Texture::XRGB8);
+ EXPECT_EQ(texture->levels(), 1);
+ EXPECT_FALSE(texture->alpha_is_one());
+ EXPECT_FALSE(texture->render_surfaces_enabled());
+}
+
+} // namespace o3d
+
diff --git a/o3d/core/cross/texture_test.cc b/o3d/core/cross/texture_test.cc
new file mode 100644
index 0000000..f14c87f
--- /dev/null
+++ b/o3d/core/cross/texture_test.cc
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file implements unit tests for class Texture.
+
+#include "tests/common/win/testing_common.h"
+#include "core/cross/texture_base.h"
+#include "core/cross/object_manager.h"
+#include "core/cross/pack.h"
+
+namespace o3d {
+
+class Texture2DTest : public testing::Test {
+ protected:
+ Texture2DTest()
+ : object_manager_(g_service_locator) {
+ }
+
+ virtual void SetUp() {
+ pack_ = object_manager_->CreatePack();
+ }
+
+ virtual void TearDown() {
+ pack_->Destroy();
+ }
+
+ Pack* pack() { return pack_; }
+
+ private:
+ ServiceDependency<ObjectManager> object_manager_;
+ Pack* pack_;
+};
+
+TEST_F(Texture2DTest, Basic) {
+ Texture2D* texture = pack()->CreateTexture2D(8, 8, Texture::ARGB8, 1, false);
+ ASSERT_TRUE(texture != NULL);
+ EXPECT_TRUE(texture->IsA(Texture2D::GetApparentClass()));
+ EXPECT_TRUE(texture->IsA(Texture::GetApparentClass()));
+ EXPECT_TRUE(texture->IsA(ParamObject::GetApparentClass()));
+ EXPECT_EQ(texture->format(), Texture::ARGB8);
+ EXPECT_EQ(texture->levels(), 1);
+ EXPECT_FALSE(texture->render_surfaces_enabled());
+}
+
+class TextureCUBETest : public testing::Test {
+ protected:
+ TextureCUBETest()
+ : object_manager_(g_service_locator) {
+ }
+
+ virtual void SetUp() {
+ pack_ = object_manager_->CreatePack();
+ }
+
+ virtual void TearDown() {
+ pack_->Destroy();
+ }
+
+ Pack* pack() { return pack_; }
+
+ private:
+ ServiceDependency<ObjectManager> object_manager_;
+ Pack* pack_;
+};
+
+TEST_F(TextureCUBETest, Basic) {
+ TextureCUBE* texture =
+ pack()->CreateTextureCUBE(8, Texture::ARGB8, 1, false);
+ ASSERT_TRUE(texture != NULL);
+ EXPECT_TRUE(texture->IsA(TextureCUBE::GetApparentClass()));
+ EXPECT_TRUE(texture->IsA(Texture::GetApparentClass()));
+ EXPECT_TRUE(texture->IsA(ParamObject::GetApparentClass()));
+ EXPECT_EQ(texture->format(), Texture::ARGB8);
+ EXPECT_EQ(texture->levels(), 1);
+ EXPECT_FALSE(texture->render_surfaces_enabled());
+}
+
+} // namespace o3d
+
diff --git a/o3d/core/cross/vertex_source_test.cc b/o3d/core/cross/vertex_source_test.cc
index e64d3a3..cea3e2d 100644
--- a/o3d/core/cross/vertex_source_test.cc
+++ b/o3d/core/cross/vertex_source_test.cc
@@ -36,6 +36,7 @@
#include "tests/common/win/testing_common.h"
#include "core/cross/vertex_source.h"
#include "core/cross/fake_vertex_source.h"
+#include "core/cross/pointer_utils.h"
#include "core/cross/evaluation_counter.h"
namespace o3d {
diff --git a/o3d/core/win/d3d9/texture_d3d9.cc b/o3d/core/win/d3d9/texture_d3d9.cc
index 54ed901..489900f 100644
--- a/o3d/core/win/d3d9/texture_d3d9.cc
+++ b/o3d/core/win/d3d9/texture_d3d9.cc
@@ -213,6 +213,117 @@ class TextureSurfaceConstructor : public SurfaceConstructor {
DISALLOW_COPY_AND_ASSIGN(TextureSurfaceConstructor);
};
+void SetTextureRectUncompressed(Texture::Format format,
+ const uint8* src,
+ int src_pitch,
+ unsigned src_width,
+ unsigned src_height,
+ uint8* dst,
+ int dst_pitch) {
+ size_t bytes_per_line = Bitmap::GetMipChainSize(src_width, 1, format, 1);
+ for (unsigned yy = 0; yy < src_height; ++yy) {
+ memcpy(dst, src, bytes_per_line);
+ src += src_pitch;
+ dst += dst_pitch;
+ }
+}
+
+void SetTextureRectCompressed(Texture::Format format,
+ const uint8* src,
+ unsigned src_width,
+ unsigned src_height,
+ uint8* dst,
+ int dst_pitch) {
+ unsigned blocks_across = (src_width + 3) / 4;
+ unsigned blocks_down = (src_height + 3) / 4;
+ unsigned bytes_per_block = format == Texture::DXT1 ? 8 : 16;
+ unsigned bytes_per_row = bytes_per_block * blocks_across;
+ for (unsigned yy = 0; yy < blocks_down; ++yy) {
+ memcpy(dst, src, bytes_per_row);
+ src += bytes_per_row;
+ dst += dst_pitch;
+ }
+}
+
+void SetTextureRect(
+ ServiceLocator* service_locator,
+ IDirect3DTexture9* d3d_texture,
+ Texture::Format format,
+ int level,
+ unsigned dst_left,
+ unsigned dst_top,
+ unsigned src_width,
+ unsigned src_height,
+ const void* src_data,
+ int src_pitch) {
+ DCHECK(src_data);
+ bool compressed = Texture::IsCompressedFormat(format);
+
+ RECT rect = {dst_left, dst_top, src_width, src_height};
+ D3DLOCKED_RECT out_rect = {0};
+
+ if (!HR(d3d_texture->LockRect(
+ level, &out_rect, compressed ? NULL : &rect, 0))) {
+ O3D_ERROR(service_locator) << "Failed to Lock Texture2D (D3D9)";
+ return;
+ }
+
+ const uint8* src = static_cast<const uint8*>(src_data);
+ uint8* dst = static_cast<uint8*>(out_rect.pBits);
+ if (!compressed) {
+ SetTextureRectUncompressed(format, src, src_pitch, src_width, src_height,
+ dst, out_rect.Pitch);
+ } else {
+ SetTextureRectCompressed(
+ format, src, src_width, src_height, dst, out_rect.Pitch);
+ }
+ if (!HR(d3d_texture->UnlockRect(level))) {
+ O3D_ERROR(service_locator) << "Failed to Unlock Texture2D (D3D9)";
+ return;
+ }
+}
+
+void SetTextureFaceRect(
+ ServiceLocator* service_locator,
+ IDirect3DCubeTexture9* d3d_texture,
+ Texture::Format format,
+ 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);
+ bool compressed = Texture::IsCompressedFormat(format);
+
+ RECT rect = {dst_left, dst_top, src_width, src_height};
+ D3DLOCKED_RECT out_rect = {0};
+
+ D3DCUBEMAP_FACES d3d_face = DX9CubeFace(face);
+
+ if (!HR(d3d_texture->LockRect(
+ d3d_face, level, &out_rect, compressed ? NULL : &rect, 0))) {
+ O3D_ERROR(service_locator) << "Failed to Lock TextureCUBE (D3D9)";
+ return;
+ }
+
+ const uint8* src = static_cast<const uint8*>(src_data);
+ uint8* dst = static_cast<uint8*>(out_rect.pBits);
+ if (!compressed) {
+ SetTextureRectUncompressed(format, src, src_pitch, src_width, src_height,
+ dst, out_rect.Pitch);
+ } else {
+ SetTextureRectCompressed(
+ format, src, src_width, src_height, dst, out_rect.Pitch);
+ }
+ if (!HR(d3d_texture->UnlockRect(d3d_face, level))) {
+ O3D_ERROR(service_locator) << "Failed to Unlock TextureCUBE (D3D9)";
+ return;
+ }
+}
+
} // unnamed namespace
// Constructs a 2D texture object from the given (existing) D3D 2D texture.
@@ -267,11 +378,7 @@ Texture2DD3D9* Texture2DD3D9::Create(ServiceLocator* service_locator,
texture->backing_bitmap_->SetFrom(bitmap);
if (texture->backing_bitmap_->image_data()) {
for (unsigned int i = 0; i < bitmap->num_mipmaps(); ++i) {
- if (!texture->UpdateBackedMipLevel(i)) {
- DLOG(ERROR) << "Failed to upload bitmap to texture.";
- delete texture;
- return NULL;
- }
+ texture->UpdateBackedMipLevel(i);
mip_width = std::max(1U, mip_width >> 1);
mip_height = std::max(1U, mip_height >> 1);
}
@@ -291,7 +398,7 @@ Texture2DD3D9::~Texture2DD3D9() {
d3d_texture_ = NULL;
}
-bool Texture2DD3D9::UpdateBackedMipLevel(unsigned int level) {
+void Texture2DD3D9::UpdateBackedMipLevel(unsigned int level) {
DCHECK_LT(level, static_cast<unsigned int>(levels()));
DCHECK(backing_bitmap_->image_data());
DCHECK_EQ(backing_bitmap_->width(), width());
@@ -299,45 +406,49 @@ bool Texture2DD3D9::UpdateBackedMipLevel(unsigned int level) {
DCHECK_EQ(backing_bitmap_->format(), format());
DCHECK_EQ(backing_bitmap_->num_mipmaps(), levels());
- unsigned int mip_width = std::max(1, width() >> level);
- unsigned int mip_height = std::max(1, height() >> level);
+ unsigned int mip_width;
+ unsigned int mip_height;
+ Bitmap::GetMipSize(level, width(), height(), &mip_width, &mip_height);
unsigned int rect_width = mip_width;
unsigned int rect_height = mip_height;
- if (resize_to_pot_) {
- rect_width = std::max(1U, Bitmap::GetPOTSize(width()) >> level);
- rect_height = std::max(1U, Bitmap::GetPOTSize(height()) >> level);
- }
+ rect_width = std::max(1U, Bitmap::GetPOTSize(width()) >> level);
+ rect_height = std::max(1U, Bitmap::GetPOTSize(height()) >> level);
RECT rect = {0, 0, rect_width, rect_height};
- D3DLOCKED_RECT out_rect;
- out_rect.pBits = 0;
+ D3DLOCKED_RECT out_rect = {0};
if (!HR(d3d_texture_->LockRect(level, &out_rect, &rect, 0))) {
- DLOG(ERROR) << "Failed to lock texture level " << level << ".";
- return false;
+ O3D_ERROR(service_locator())
+ << "Failed to lock texture level " << level << ".";
+ return;
}
DCHECK(out_rect.pBits);
- // TODO: check that the returned pitch is what we expect.
+ uint8* dst = static_cast<uint8*>(out_rect.pBits);
- const unsigned char *mip_data =
- backing_bitmap_->GetMipData(level, TextureCUBE::FACE_POSITIVE_X);
+ const uint8 *mip_data = backing_bitmap_->GetMipData(level);
if (resize_to_pot_) {
Bitmap::Scale(mip_width, mip_height, format(), mip_data,
rect_width, rect_height,
- static_cast<unsigned char *>(out_rect.pBits));
+ static_cast<uint8 *>(out_rect.pBits),
+ out_rect.Pitch);
} else {
- unsigned int mip_size =
- Bitmap::GetBufferSize(mip_width, mip_height, format());
- memcpy(out_rect.pBits, mip_data, mip_size);
+ if (!IsCompressed()) {
+ SetTextureRectUncompressed(
+ format(), mip_data,
+ Bitmap::GetMipChainSize(mip_width, 1, format(), 1),
+ mip_width, mip_height,
+ dst, out_rect.Pitch);
+ } else {
+ SetTextureRectCompressed(
+ format(), mip_data, mip_width, mip_height, dst, out_rect.Pitch);
+ }
}
if (!HR(d3d_texture_->UnlockRect(level))) {
O3D_ERROR(service_locator())
<< "Failed to unlock texture level " << level << ".";
- return false;
}
- return true;
}
RenderSurface::Ref Texture2DD3D9::GetRenderSurface(int mip_level, Pack* pack) {
@@ -371,9 +482,75 @@ RenderSurface::Ref Texture2DD3D9::GetRenderSurface(int mip_level, Pack* pack) {
return render_surface;
}
+void Texture2DD3D9::SetRect(int level,
+ unsigned dst_left,
+ unsigned dst_top,
+ unsigned src_width,
+ unsigned src_height,
+ const void* src_data,
+ int src_pitch) {
+ if (level >= levels() || level < 0) {
+ O3D_ERROR(service_locator())
+ << "Trying to SetRect on non-existent level " << level
+ << " on Texture \"" << name() << "\"";
+ return;
+ }
+ if (render_surfaces_enabled()) {
+ O3D_ERROR(service_locator())
+ << "Attempting to SetRect a render-target texture: " << name();
+ return;
+ }
+
+ unsigned mip_width;
+ unsigned mip_height;
+ Bitmap::GetMipSize(level, width(), height(), &mip_width, &mip_height);
+
+ if (dst_left + src_width > mip_width ||
+ dst_top + src_height > mip_height) {
+ O3D_ERROR(service_locator())
+ << "SetRect(" << level << ", " << dst_left << ", " << dst_top << ", "
+ << src_width << ", " << src_height << ") out of range for texture << \""
+ << name() << "\"";
+ return;
+ }
+
+ bool entire_rect = dst_left == 0 && dst_top == 0 &&
+ src_width == mip_width && src_height == mip_height;
+ bool compressed = IsCompressed();
+
+ if (compressed && !entire_rect) {
+ O3D_ERROR(service_locator())
+ << "SetRect must be full rectangle for compressed textures";
+ return;
+ }
+
+ if (resize_to_pot_) {
+ DCHECK(backing_bitmap_->image_data());
+ DCHECK(!compressed);
+ // We need to update the backing mipmap and then use that to update the
+ // texture.
+ backing_bitmap_->SetRect(
+ level, dst_left, dst_top, src_width, src_height, src_data, src_pitch);
+ UpdateBackedMipLevel(level);
+ } else {
+ SetTextureRect(service_locator(),
+ d3d_texture_,
+ format(),
+ level,
+ dst_left,
+ dst_top,
+ src_width,
+ src_height,
+ src_data,
+ src_pitch);
+ }
+}
+
// Locks the given mipmap level of this texture for loading from main memory,
// and returns a pointer to the buffer.
-bool Texture2DD3D9::Lock(int level, void** texture_data) {
+bool Texture2DD3D9::Lock(int level, void** texture_data, int* pitch) {
+ DCHECK(texture_data);
+ DCHECK(pitch);
if (level >= levels() || level < 0) {
O3D_ERROR(service_locator())
<< "Trying to lock inexistent level " << level << " on Texture \""
@@ -393,8 +570,11 @@ bool Texture2DD3D9::Lock(int level, void** texture_data) {
}
if (resize_to_pot_) {
DCHECK(backing_bitmap_->image_data());
- *texture_data = backing_bitmap_->GetMipData(level,
- TextureCUBE::FACE_POSITIVE_X);
+ *texture_data = backing_bitmap_->GetMipData(level);
+ unsigned int mip_width;
+ unsigned int mip_height;
+ Bitmap::GetMipSize(level, width(), height(), &mip_width, &mip_height);
+ *pitch = Bitmap::GetMipChainSize(mip_width, 1, format(), 1);
locked_levels_ |= 1 << level;
return true;
} else {
@@ -403,6 +583,7 @@ bool Texture2DD3D9::Lock(int level, void** texture_data) {
if (HR(d3d_texture_->LockRect(level, &out_rect, &rect, 0))) {
*texture_data = out_rect.pBits;
+ *pitch = out_rect.Pitch;
locked_levels_ |= 1 << level;
return true;
} else {
@@ -429,7 +610,8 @@ bool Texture2DD3D9::Unlock(int level) {
}
bool result = false;
if (resize_to_pot_) {
- result = UpdateBackedMipLevel(level);
+ UpdateBackedMipLevel(level);
+ result = true;
} else {
result = HR(d3d_texture_->UnlockRect(level));
}
@@ -524,11 +706,7 @@ TextureCUBED3D9* TextureCUBED3D9::Create(ServiceLocator* service_locator,
for (int face = 0; face < 6; ++face) {
unsigned int mip_edge = edge;
for (unsigned int i = 0; i < bitmap->num_mipmaps(); ++i) {
- if (!texture->UpdateBackedMipLevel(i, static_cast<CubeFace>(face))) {
- DLOG(ERROR) << "Failed to upload bitmap to texture.";
- delete texture;
- return NULL;
- }
+ texture->UpdateBackedMipLevel(static_cast<CubeFace>(face), i);
mip_edge = std::max(1U, mip_edge >> 1);
}
}
@@ -558,8 +736,8 @@ TextureCUBED3D9::~TextureCUBED3D9() {
d3d_cube_texture_ = NULL;
}
-bool TextureCUBED3D9::UpdateBackedMipLevel(unsigned int level,
- TextureCUBE::CubeFace face) {
+void TextureCUBED3D9::UpdateBackedMipLevel(TextureCUBE::CubeFace face,
+ unsigned int level) {
DCHECK_LT(level, static_cast<unsigned int>(levels()));
DCHECK(backing_bitmap_->image_data());
DCHECK(backing_bitmap_->is_cubemap());
@@ -575,40 +753,45 @@ bool TextureCUBED3D9::UpdateBackedMipLevel(unsigned int level,
}
RECT rect = {0, 0, rect_edge, rect_edge};
- D3DLOCKED_RECT out_rect;
- out_rect.pBits = 0;
+ D3DLOCKED_RECT out_rect = {0};
+ D3DCUBEMAP_FACES d3d_face = DX9CubeFace(face);
- if (!HR(d3d_cube_texture_->LockRect(DX9CubeFace(face), level, &out_rect,
- &rect, 0))) {
+ if (!HR(d3d_cube_texture_->LockRect(d3d_face, level, &out_rect, &rect, 0))) {
O3D_ERROR(service_locator())
<< "Failed to lock texture level " << level << " face " << face << ".";
- return false;
+ return;
}
DCHECK(out_rect.pBits);
- // TODO: check that the returned pitch is what we expect.
+ uint8* dst = static_cast<uint8*>(out_rect.pBits);
- const unsigned char *mip_data = backing_bitmap_->GetMipData(level, face);
+ const uint8 *mip_data = backing_bitmap_->GetFaceMipData(face, level);
if (resize_to_pot_) {
Bitmap::Scale(mip_edge, mip_edge, format(), mip_data,
rect_edge, rect_edge,
- static_cast<unsigned char *>(out_rect.pBits));
+ static_cast<uint8 *>(out_rect.pBits),
+ out_rect.Pitch);
} else {
- unsigned int mip_size =
- Bitmap::GetBufferSize(mip_edge, mip_edge, format());
- memcpy(out_rect.pBits, mip_data, mip_size);
+ if (!IsCompressed()) {
+ SetTextureRectUncompressed(
+ format(), mip_data,
+ Bitmap::GetMipChainSize(mip_edge, 1, format(), 1),
+ mip_edge, mip_edge,
+ dst, out_rect.Pitch);
+ } else {
+ SetTextureRectCompressed(
+ format(), mip_data, mip_edge, mip_edge, dst, out_rect.Pitch);
+ }
}
- if (!HR(d3d_cube_texture_->UnlockRect(DX9CubeFace(face), level))) {
+ if (!HR(d3d_cube_texture_->UnlockRect(d3d_face, level))) {
O3D_ERROR(service_locator())
<< "Failed to unlock texture level " << level << " face " << face
<< ".";
- return false;
}
- return true;
}
-RenderSurface::Ref TextureCUBED3D9::GetRenderSurface(CubeFace face,
+RenderSurface::Ref TextureCUBED3D9::GetRenderSurface(TextureCUBE::CubeFace face,
int mip_level,
Pack* pack) {
if (!render_surfaces_enabled()) {
@@ -641,9 +824,85 @@ RenderSurface::Ref TextureCUBED3D9::GetRenderSurface(CubeFace face,
return render_surface;
}
+void TextureCUBED3D9::SetRect(TextureCUBE::CubeFace face,
+ int level,
+ unsigned dst_left,
+ unsigned dst_top,
+ unsigned src_width,
+ unsigned src_height,
+ const void* src_data,
+ int src_pitch) {
+ if (static_cast<int>(face) < 0 || static_cast<int>(face) >= NUMBER_OF_FACES) {
+ O3D_ERROR(service_locator())
+ << "Trying to SetRect invalid face " << face << " on Texture \""
+ << name() << "\"";
+ return;
+ }
+ if (level >= levels() || level < 0) {
+ O3D_ERROR(service_locator())
+ << "Trying to SetRect non-existent level " << level
+ << " on Texture \"" << name() << "\"";
+ return;
+ }
+ if (render_surfaces_enabled()) {
+ O3D_ERROR(service_locator())
+ << "Attempting to SetRect a render-target texture: " << name();
+ return;
+ }
+
+ unsigned mip_width;
+ unsigned mip_height;
+ Bitmap::GetMipSize(
+ level, edge_length(), edge_length(), &mip_width, &mip_height);
+
+ if (dst_left + src_width > mip_width ||
+ dst_top + src_height > mip_height) {
+ O3D_ERROR(service_locator())
+ << "SetRect(" << level << ", " << dst_left << ", " << dst_top << ", "
+ << src_width << ", " << src_height << ") out of range for texture << \""
+ << name() << "\"";
+ return;
+ }
+
+ bool entire_rect = dst_left == 0 && dst_top == 0 &&
+ src_width == mip_width && src_height == mip_height;
+ bool compressed = IsCompressed();
+
+ if (compressed && !entire_rect) {
+ O3D_ERROR(service_locator())
+ << "SetRect must be full rectangle for compressed textures";
+ return;
+ }
+
+ if (resize_to_pot_) {
+ 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,
+ level, dst_left, dst_top, src_width, src_height, src_data, src_pitch);
+ UpdateBackedMipLevel(face, level);
+ } else {
+ SetTextureFaceRect(service_locator(),
+ d3d_cube_texture_,
+ format(),
+ face,
+ level,
+ dst_left,
+ dst_top,
+ src_width,
+ src_height,
+ src_data,
+ src_pitch);
+ }
+}
+
// Locks the given face and mipmap level of this texture for loading from
// main memory, and returns a pointer to the buffer.
-bool TextureCUBED3D9::Lock(CubeFace face, int level, void** texture_data) {
+bool TextureCUBED3D9::Lock(
+ CubeFace face, int level, void** texture_data, int* pitch) {
+ DCHECK(texture_data);
+ DCHECK(pitch);
if (level >= levels() || level < 0) {
O3D_ERROR(service_locator())
<< "Trying to lock inexistent level " << level << " on Texture \""
@@ -663,7 +922,12 @@ bool TextureCUBED3D9::Lock(CubeFace face, int level, void** texture_data) {
}
if (resize_to_pot_) {
DCHECK(backing_bitmap_->image_data());
- *texture_data = backing_bitmap_->GetMipData(level, face);
+ *texture_data = backing_bitmap_->GetFaceMipData(face, level);
+ unsigned int mip_width;
+ unsigned int mip_height;
+ Bitmap::GetMipSize(
+ level, edge_length(), edge_length(), &mip_width, &mip_height);
+ *pitch = Bitmap::GetMipChainSize(mip_width, 1, format(), 1);
locked_levels_[face] |= 1 << level;
return true;
} else {
@@ -673,6 +937,7 @@ bool TextureCUBED3D9::Lock(CubeFace face, int level, void** texture_data) {
if (HR(d3d_cube_texture_->LockRect(DX9CubeFace(face), level,
&out_rect, &rect, 0))) {
*texture_data = out_rect.pBits;
+ *pitch = out_rect.Pitch;
locked_levels_[face] |= 1 << level;
return true;
} else {
@@ -699,7 +964,8 @@ bool TextureCUBED3D9::Unlock(CubeFace face, int level) {
}
bool result = false;
if (resize_to_pot_) {
- result = UpdateBackedMipLevel(level, face);
+ UpdateBackedMipLevel(face, level);
+ result = true;
} else {
result = HR(d3d_cube_texture_->UnlockRect(DX9CubeFace(face),
level));
diff --git a/o3d/core/win/d3d9/texture_d3d9.h b/o3d/core/win/d3d9/texture_d3d9.h
index 8a19913..5f10951 100644
--- a/o3d/core/win/d3d9/texture_d3d9.h
+++ b/o3d/core/win/d3d9/texture_d3d9.h
@@ -32,8 +32,8 @@
// This file contains the declarations for Texture2DD3D9 and TextureCUBED3D9.
-#ifndef O3D_CORE_WIN_D3D9_TEXTURE_D3D9_H__
-#define O3D_CORE_WIN_D3D9_TEXTURE_D3D9_H__
+#ifndef O3D_CORE_WIN_D3D9_TEXTURE_D3D9_H_
+#define O3D_CORE_WIN_D3D9_TEXTURE_D3D9_H_
#include <atlbase.h>
#include <vector>
@@ -65,13 +65,14 @@ class Texture2DD3D9 : public Texture2D {
virtual ~Texture2DD3D9();
- // Locks the image buffer of a given mipmap level for loading from
- // main memory. A pointer to the current contents of the texture is returned
- // in texture_data.
- virtual bool Lock(int level, void** texture_data);
-
- // Notifies DX9 that the texture data has been updated.
- virtual bool Unlock(int level);
+ // Overridden from Texture2D
+ virtual void SetRect(int level,
+ unsigned left,
+ unsigned top,
+ unsigned width,
+ unsigned height,
+ const void* src_data,
+ int src_pitch);
// Returns the implementation-specific texture handle for this texture.
virtual void* GetTextureHandle() const { return d3d_texture_; }
@@ -94,6 +95,13 @@ class Texture2DD3D9 : public Texture2D {
// RGBA to the internal format used by the rendering API.
virtual const RGBASwizzleIndices& GetABGR32FSwizzleIndices();
+ protected:
+ // Overridden from Texture2D
+ virtual bool Lock(int level, void** texture_data, int* pitch);
+
+ // Overridden from Texture2D
+ virtual bool Unlock(int level);
+
private:
// Initializes the Texture2DD3D9 from a DX9 texture.
Texture2DD3D9(ServiceLocator* service_locator,
@@ -104,7 +112,7 @@ class Texture2DD3D9 : public Texture2D {
// Updates a mip level, sending it from the backing bitmap to Direct3D,
// rescaling it if resize_to_pot_ is set.
- bool UpdateBackedMipLevel(unsigned int level);
+ void UpdateBackedMipLevel(unsigned int level);
// A pointer to the Direct3D 2D texture object containing this texture.
CComPtr<IDirect3DTexture9> d3d_texture_;
@@ -130,13 +138,15 @@ class TextureCUBED3D9 : public TextureCUBE {
virtual ~TextureCUBED3D9();
- // Locks the image buffer of a given face and mipmap level for loading from
- // main memory.
- bool Lock(CubeFace face, int level, void** texture_data);
-
- // Notifies DX9 that the image buffer of a given face and mipmap level has
- // been updated.
- bool Unlock(CubeFace face, int level);
+ // Overridden from TextureCUBE
+ virtual void SetRect(CubeFace face,
+ int level,
+ unsigned dst_left,
+ unsigned dst_top,
+ unsigned width,
+ unsigned height,
+ const void* src_data,
+ int src_pitch);
// Returns the implementation-specific texture handle for this texture.
virtual void* GetTextureHandle() const { return d3d_cube_texture_; }
@@ -163,6 +173,13 @@ class TextureCUBED3D9 : public TextureCUBE {
// RGBA to the internal format used by the rendering API.
virtual const RGBASwizzleIndices& GetABGR32FSwizzleIndices();
+ protected:
+ // Overridden from TextureCUBE
+ bool Lock(CubeFace face, int level, void** texture_data, int* pitch);
+
+ // Overridden from TextureCUBE
+ bool Unlock(CubeFace face, int level);
+
private:
TextureCUBED3D9(ServiceLocator* service_locator,
IDirect3DCubeTexture9* tex,
@@ -172,7 +189,7 @@ class TextureCUBED3D9 : public TextureCUBE {
// Updates a mip level, sending it from the backing bitmap to Direct3D,
// rescaling it if resize_to_pot_ is set.
- bool UpdateBackedMipLevel(unsigned int level, CubeFace face);
+ void UpdateBackedMipLevel(CubeFace face, unsigned int level);
// A pointer to the Direct3D cube texture object containing this texture.
CComPtr<IDirect3DCubeTexture9> d3d_cube_texture_;
@@ -185,4 +202,4 @@ class TextureCUBED3D9 : public TextureCUBE {
} // namespace o3d
-#endif // O3D_CORE_WIN_D3D9_TEXTURE_D3D9_H__
+#endif // O3D_CORE_WIN_D3D9_TEXTURE_D3D9_H_
diff --git a/o3d/plugin/build.scons b/o3d/plugin/build.scons
index 53d4dcf..d0a251c 100644
--- a/o3d/plugin/build.scons
+++ b/o3d/plugin/build.scons
@@ -194,6 +194,7 @@ inputs = AUTOGEN_CC_FILES + [
'cross/np_v8_bridge.cc',
'cross/out_of_memory.cc',
'cross/stream_manager.cc',
+ 'cross/texture_static_glue.cc',
'cross/config_common.cc',
]
diff --git a/o3d/plugin/cross/texture_static_glue.cc b/o3d/plugin/cross/texture_static_glue.cc
new file mode 100644
index 0000000..2e34786
--- /dev/null
+++ b/o3d/plugin/cross/texture_static_glue.cc
@@ -0,0 +1,388 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <vector>
+#include "core/cross/pointer_utils.h"
+#include "core/cross/error.h"
+#include "core/cross/math_utilities.h"
+#include "core/cross/texture.h"
+
+namespace {
+
+void SetRectCheck(o3d::Texture* self,
+ void* data,
+ int pitch,
+ o3d::Texture::Format format,
+ int destination_x,
+ int destination_y,
+ int texture_width,
+ int texture_height,
+ int source_width,
+ int source_height,
+ const std::vector<float>& values) {
+ unsigned num_components;
+ unsigned swizzle[4] = {2, 1, 0, 3};
+ switch (format) {
+ case o3d::Texture::XRGB8:
+ num_components = 3;
+ break;
+ case o3d::Texture::R32F:
+ swizzle[0] = 0;
+ num_components = 1;
+ break;
+ case o3d::Texture::ARGB8:
+ case o3d::Texture::ABGR16F:
+ num_components = 4;
+ break;
+ case o3d::Texture::ABGR32F: {
+ num_components = 4;
+ const o3d::Texture::RGBASwizzleIndices& indices =
+ self->GetABGR32FSwizzleIndices();
+ for (int ii = 0; ii < 4; ++ii) {
+ swizzle[ii] = indices[ii];
+ }
+ break;
+ }
+ default:
+ DCHECK(false);
+ return;
+ }
+
+ // clip
+ int source_x = 0;
+ int source_y = 0;
+ int copy_width = source_width;
+ int copy_height = source_height;
+
+ if (destination_x < 0) {
+ copy_width += destination_x;
+ source_x -= destination_x;
+ destination_x = 0;
+ }
+ if (destination_x + copy_width > static_cast<int>(texture_width)) {
+ copy_width -= destination_x + copy_width - texture_width;
+ }
+
+ if (destination_y < 0) {
+ copy_height += destination_y;
+ source_y -= destination_y;
+ destination_y = 0;
+ }
+ if (destination_y + copy_height > static_cast<int>(texture_height)) {
+ copy_height -= destination_y + copy_height - texture_height;
+ }
+
+ if (copy_width <= 0 || copy_height <= 0) {
+ return;
+ }
+
+ const float* source =
+ &values[0] +
+ (source_y * source_width + source_x) * num_components;
+ unsigned source_stride = (source_width - copy_width) * num_components;
+ switch (format) {
+ case o3d::Texture::ABGR16F: {
+ uint16* dest_line =
+ static_cast<uint16*>(data) +
+ (destination_y * texture_width + destination_x) * num_components;
+ while (copy_height > 0) {
+ uint16* destination = dest_line;
+ for (int xx = 0; xx < copy_width; ++xx) {
+ for (unsigned element = 0; element < num_components; ++element) {
+ destination[element] = Vectormath::Aos::FloatToHalf(
+ source[swizzle[element]]);
+ }
+ destination += num_components;
+ source += num_components;
+ }
+ dest_line = o3d::AddPointerOffset<uint16*>(dest_line, pitch);
+ source += source_stride;
+ --copy_height;
+ }
+ break;
+ }
+ case o3d::Texture::R32F:
+ case o3d::Texture::ABGR32F: {
+ float* dest_line =
+ static_cast<float*>(data) +
+ (destination_y * texture_width + destination_x) * num_components;
+ while (copy_height > 0) {
+ float* destination = dest_line;
+ for (int xx = 0; xx < copy_width; ++xx) {
+ for (unsigned element = 0; element < num_components; ++element) {
+ destination[element] = source[swizzle[element]];
+ }
+ destination += num_components;
+ source += num_components;
+ }
+ dest_line = o3d::AddPointerOffset<float*>(dest_line, pitch);
+ source += source_stride;
+ --copy_height;
+ }
+ break;
+ }
+ default: {
+ uint8* dest_line =
+ static_cast<uint8*>(data) +
+ (destination_y * texture_width + destination_x) * 4;
+ while (copy_height > 0) {
+ uint8* destination = dest_line;
+ for (int xx = 0; xx < copy_width; ++xx) {
+ destination[0] = static_cast<unsigned char>(
+ source[swizzle[0]] * 255.0f);
+ destination[1] = static_cast<unsigned char>(
+ source[swizzle[1]] * 255.0f);
+ destination[2] = static_cast<unsigned char>(
+ source[swizzle[2]] * 255.0f);
+ destination[3] = (num_components == 4) ?
+ static_cast<unsigned char>(source[swizzle[3]] * 255.0f) : 255;
+ destination += 4;
+ source += num_components;
+ }
+ dest_line = o3d::AddPointerOffset<uint8*>(dest_line, pitch);
+ source += source_stride;
+ --copy_height;
+ }
+ break;
+ }
+ }
+}
+
+void SetRectCheck2D(o3d::Texture2D* self,
+ int level,
+ int destination_x,
+ int destination_y,
+ int source_width,
+ const std::vector<float>& values,
+ bool check_needed) {
+ if (level < 0 || level >= self->levels()) {
+ O3D_ERROR(self->service_locator())
+ << "level (" << level << " out of range";
+ return;
+ }
+ if (values.empty() || source_width <= 0) {
+ return;
+ }
+ unsigned num_values = values.size();
+ unsigned texture_width = std::max(self->width() >> level, 1);
+ unsigned texture_height = std::max(self->height() >> level, 1);
+ unsigned num_components;
+ switch (self->format()) {
+ case o3d::Texture::XRGB8:
+ num_components = 3;
+ break;
+ case o3d::Texture::R32F:
+ num_components = 1;
+ break;
+ case o3d::Texture::ARGB8:
+ case o3d::Texture::ABGR16F:
+ num_components = 4;
+ break;
+ case o3d::Texture::ABGR32F: {
+ num_components = 4;
+ break;
+ }
+ default:
+ O3D_ERROR(self->service_locator())
+ << "Texture::Set not supported for this type of texture";
+ return;
+ }
+ if (num_values % num_components != 0) {
+ O3D_ERROR(self->service_locator())
+ << "The number of elements passed in must be a multiple of "
+ << num_components;
+ }
+ unsigned num_elements = num_values / num_components;
+ if (num_elements % source_width != 0) {
+ O3D_ERROR(self->service_locator())
+ << "The number of elements passed in must be a multiple of the "
+ << "width";
+ return;
+ }
+ unsigned source_height = num_elements / source_width;
+ if (check_needed) {
+ unsigned needed = num_components * texture_width * texture_height;
+ if (num_values != needed) {
+ O3D_ERROR(self->service_locator())
+ << "needed " << needed << " values but " << num_values
+ << " passed in.";
+ return;
+ }
+ }
+ o3d::Texture2D::LockHelper helper(self, level);
+ void* data = helper.GetData();
+ if (!data) {
+ O3D_ERROR(self->service_locator()) << "could not lock texture";
+ return;
+ }
+
+ SetRectCheck(self, data, helper.pitch(), self->format(),
+ destination_x, destination_y,
+ texture_width, texture_height,
+ source_width, source_height,
+ values);
+}
+
+void SetRectCheckCUBE(o3d::TextureCUBE* self,
+ o3d::TextureCUBE::CubeFace face,
+ int level,
+ int destination_x,
+ int destination_y,
+ int source_width,
+ const std::vector<float>& values,
+ bool check_needed) {
+ if (level < 0 || level >= self->levels()) {
+ O3D_ERROR(self->service_locator())
+ << "level (" << level << " out of range";
+ return;
+ }
+ if (values.empty() || source_width <= 0) {
+ return;
+ }
+ unsigned num_values = values.size();
+ unsigned texture_width = std::max(self->edge_length() >> level, 1);
+ unsigned texture_height = texture_width;
+ unsigned num_components;
+ switch (self->format()) {
+ case o3d::Texture::XRGB8:
+ num_components = 3;
+ break;
+ case o3d::Texture::R32F:
+ num_components = 1;
+ break;
+ case o3d::Texture::ARGB8:
+ case o3d::Texture::ABGR16F:
+ num_components = 4;
+ break;
+ case o3d::Texture::ABGR32F: {
+ num_components = 4;
+ break;
+ }
+ default:
+ O3D_ERROR(self->service_locator())
+ << "Texture::Set not supported for this type of texture";
+ return;
+ }
+ if (num_values % num_components != 0) {
+ O3D_ERROR(self->service_locator())
+ << "The number of elements passed in must be a multiple of "
+ << num_components;
+ }
+ unsigned num_elements = num_values / num_components;
+ if (num_elements % source_width != 0) {
+ O3D_ERROR(self->service_locator())
+ << "The number of elements passed in must be a multiple of the "
+ << "width";
+ return;
+ }
+ unsigned source_height = num_elements / source_width;
+ if (check_needed) {
+ unsigned needed = num_components * texture_width * texture_height;
+ if (num_values != needed) {
+ O3D_ERROR(self->service_locator())
+ << "needed " << needed << " values but " << num_values
+ << " passed in.";
+ return;
+ }
+ }
+ o3d::TextureCUBE::LockHelper helper(self, face, level);
+ void* data = helper.GetData();
+ if (!data) {
+ O3D_ERROR(self->service_locator()) << "could not lock texture";
+ return;
+ }
+
+ SetRectCheck(self, data, helper.pitch(), self->format(),
+ destination_x, destination_y,
+ texture_width, texture_height,
+ source_width, source_height,
+ values);
+}
+
+} // anonymous namespace
+
+namespace glue {
+namespace namespace_o3d {
+namespace class_Texture2D {
+
+void userglue_method_SetRect(o3d::Texture2D* self,
+ int level,
+ int destination_x,
+ int destination_y,
+ int source_width,
+ const std::vector<float>& values) {
+ SetRectCheck2D(self,
+ level,
+ destination_x,
+ destination_y,
+ source_width,
+ values,
+ false);
+}
+void userglue_method_Set(o3d::Texture2D* self,
+ int level,
+ const std::vector<float>& values) {
+ SetRectCheck2D(self, level, 0, 0, self->width(), values, true);
+}
+
+} // namespace class_Texture2D
+
+namespace class_TextureCUBE {
+
+void userglue_method_SetRect(o3d::TextureCUBE* self,
+ o3d::TextureCUBE::CubeFace face,
+ int level,
+ int destination_x,
+ int destination_y,
+ int source_width,
+ const std::vector<float>& values) {
+ SetRectCheckCUBE(self,
+ face,
+ level,
+ destination_x,
+ destination_y,
+ source_width,
+ values,
+ false);
+}
+void userglue_method_Set(o3d::TextureCUBE* self,
+ o3d::TextureCUBE::CubeFace face,
+ int level,
+ const std::vector<float>& values) {
+ SetRectCheckCUBE(self, face, level, 0, 0, self->edge_length(), values, true);
+}
+
+
+} // namespace class_Texture2D
+
+} // namespace namespace_o3d
+} // namespace glue
+
diff --git a/o3d/plugin/idl/texture.idl b/o3d/plugin/idl/texture.idl
index 81d1a5c..763518e 100644
--- a/o3d/plugin/idl/texture.idl
+++ b/o3d/plugin/idl/texture.idl
@@ -138,7 +138,7 @@ namespace o3d {
%]
RenderSurface? GetRenderSurface(int mip_level, Pack pack);
- // TODO: Add Get, GetRect and/or expose Bitmap.
+ // TODO: Add Get, GetRect.
%[
Sets the values of the data stored in the texture.
@@ -166,7 +166,7 @@ namespace o3d {
\param level the mip level to update.
\param values Values to be stored in the buffer.
%]
- [nocpp, userglue, include="core/cross/math_utilities.h"]
+ [nocpp, userglue]
void Set(int level, float[] values);
%[
@@ -187,7 +187,7 @@ namespace o3d {
\param values Values to be stored in the buffer.
\see o3d.Texture2D.set
%]
- [nocpp, userglue, include="core/cross/math_utilities.h"]
+ [nocpp, userglue]
void SetRect(int level,
int destination_x,
int destination_y,
@@ -213,204 +213,6 @@ namespace o3d {
int source_width, int source_height,
int dest_x, int dest_y,
int dest_width, int dest_height, int dest_mip);
-
- [verbatim=cpp_glue] %{
- void SetRectCheck(o3d::Texture2D* self,
- int level,
- int destination_x,
- int destination_y,
- int source_width,
- const std::vector<float>& values,
- bool check_needed) {
- if (level < 0 || level >= self->levels()) {
- O3D_ERROR(self->service_locator())
- << "level (" << level << " out of range";
- return;
- }
- if (values.empty() || source_width <= 0) {
- return;
- }
- unsigned num_values = values.size();
- unsigned texture_width = std::max(self->width() >> level, 1);
- unsigned texture_height = std::max(self->height() >> level, 1);
- unsigned num_components;
- unsigned swizzle[4] = {2, 1, 0, 3};
- switch (self->format()) {
- case o3d::Texture::XRGB8:
- num_components = 3;
- break;
- case o3d::Texture::R32F:
- swizzle[0] = 0;
- num_components = 1;
- break;
- case o3d::Texture::ARGB8:
- case o3d::Texture::ABGR16F:
- num_components = 4;
- break;
- case o3d::Texture::ABGR32F: {
- num_components = 4;
- const o3d::Texture::RGBASwizzleIndices& indices =
- self->GetABGR32FSwizzleIndices();
- for (int ii = 0; ii < 4; ++ii) {
- swizzle[ii] = indices[ii];
- }
- break;
- }
- default:
- O3D_ERROR(self->service_locator())
- << "Texture::Set not supported for this type of texture";
- return;
- }
- if (num_values % num_components != 0) {
- O3D_ERROR(self->service_locator())
- << "The number of elements passed in must be a multiple of "
- << num_components;
- }
- unsigned num_elements = num_values / num_components;
- if (num_elements % source_width != 0) {
- O3D_ERROR(self->service_locator())
- << "The number of elements passed in must be a multiple of the "
- << "width";
- return;
- }
- unsigned source_height = num_elements / source_width;
- if (check_needed) {
- unsigned needed = num_components * texture_width * texture_height;
- if (num_values != needed) {
- O3D_ERROR(self->service_locator())
- << "needed " << needed << " values but " << num_values
- << " passed in.";
- return;
- }
- }
-
- // clip
- int source_x = 0;
- int source_y = 0;
- int copy_width = source_width;
- int copy_height = source_height;
-
- if (destination_x < 0) {
- copy_width += destination_x;
- source_x -= destination_x;
- destination_x = 0;
- }
- if (destination_x + copy_width > static_cast<int>(texture_width)) {
- copy_width -= destination_x + copy_width - texture_width;
- }
-
- if (destination_y < 0) {
- copy_height += destination_y;
- source_y -= destination_y;
- destination_y = 0;
- }
- if (destination_y + copy_height > static_cast<int>(texture_height)) {
- copy_height -= destination_y + copy_height - texture_height;
- }
-
- if (copy_width <= 0 || copy_height <= 0) {
- return;
- }
-
- void* data;
- if (!self->Lock(level, &data)) {
- O3D_ERROR(self->service_locator()) << "could not lock texture";
- return;
- }
- const float* source =
- &values[0] +
- (source_y * source_width + source_x) * num_components;
- unsigned source_stride = (source_width - copy_width) * num_components;
- unsigned destination_stride =
- (texture_width - copy_width) * num_components;
- switch (self->format()) {
- case o3d::Texture::ABGR16F: {
- unsigned short* destination =
- static_cast<unsigned short*>(data) +
- (destination_y * texture_width + destination_x) * num_components;
- while (copy_height > 0) {
- for (int xx = 0; xx < copy_width; ++xx) {
- for (unsigned element = 0; element < num_components; ++element) {
- destination[element] = Vectormath::Aos::FloatToHalf(
- source[swizzle[element]]);
- }
- destination += num_components;
- source += num_components;
- }
- destination += destination_stride;
- source += source_stride;
- --copy_height;
- }
- break;
- }
- case o3d::Texture::R32F:
- case o3d::Texture::ABGR32F: {
- float* destination =
- static_cast<float*>(data) +
- (destination_y * texture_width + destination_x) * num_components;
- while (copy_height > 0) {
- for (int xx = 0; xx < copy_width; ++xx) {
- for (unsigned element = 0; element < num_components; ++element) {
- destination[element] = source[swizzle[element]];
- }
- destination += num_components;
- source += num_components;
- }
- destination += destination_stride;
- source += source_stride;
- --copy_height;
- }
- break;
- }
- default: {
- destination_stride = (texture_width - copy_width) * 4;
- uint8* destination =
- static_cast<uint8*>(data) +
- (destination_y * texture_width + destination_x) * 4;
- while (copy_height > 0) {
- for (int xx = 0; xx < copy_width; ++xx) {
- destination[0] = static_cast<unsigned char>(
- source[swizzle[0]] * 255.0f);
- destination[1] = static_cast<unsigned char>(
- source[swizzle[1]] * 255.0f);
- destination[2] = static_cast<unsigned char>(
- source[swizzle[2]] * 255.0f);
- destination[3] = (num_components == 4) ?
- static_cast<unsigned char>(source[swizzle[3]] * 255.0f) : 255;
- destination += 4;
- source += num_components;
- }
- destination += destination_stride;
- source += source_stride;
- --copy_height;
- }
- break;
- }
- }
- if (!self->Unlock(level)) {
- O3D_ERROR(self->service_locator()) << "could not unlock texture";
- }
- }
- void userglue_method_SetRect(o3d::Texture2D* self,
- int level,
- int destination_x,
- int destination_y,
- int source_width,
- const std::vector<float>& values) {
- SetRectCheck(self,
- level,
- destination_x,
- destination_y,
- source_width,
- values,
- false);
- }
- void userglue_method_Set(o3d::Texture2D* self,
- int level,
- const std::vector<float>& values) {
- SetRectCheck(self, level, 0, 0, self->width(), values, true);
- }
- %}
}; // Texture2D
@@ -458,6 +260,48 @@ namespace o3d {
RenderSurface? GetRenderSurface(CubeFace face, int mip_level, Pack pack);
%[
+ Sets the values of the data stored in the texture.
+
+ It is not recommend that you call this for large textures but it is useful
+ for making simple ramps or noise textures for shaders.
+
+ See o3d.Texture2D.set for details on formats.
+
+ \param face the face to update.
+ \param level the mip level to update.
+ \param values Values to be stored in the buffer.
+ %]
+ [nocpp, userglue]
+ void Set(CubeFace face, int level, float[] values);
+
+ %[
+ Sets a rectangular area of values in a texture.
+
+ Does clipping. In other words if you pass in a 10x10 pixel array
+ and give it destination of (-5, -5) it will only use the bottom 5x5
+ pixels of the array you passed in to set the top 5x5 pixels of the
+ texture.
+
+ See o3d.Texture2D.set for details on formats.
+
+ \param face the face to update.
+ \param level the mip level to update.
+ \param destination_x The x coordinate of the area in the texture to affect.
+ \param destination_y The y coordinate of the area in the texture to affect.
+ \param source_width The width of the area to effect. The height is
+ determined by the size of the array passed in.
+ \param values Values to be stored in the buffer.
+ \see o3d.Texture2D.set
+ %]
+ [nocpp, userglue]
+ void SetRect(CubeFace face,
+ int level,
+ int destination_x,
+ int destination_y,
+ int source_width,
+ float[] values);
+
+ %[
Copy pixels from source bitmap to certain mip level.
Scales if the width and height of source and dest do not match.
diff --git a/o3d/plugin/plugin.gyp b/o3d/plugin/plugin.gyp
index f241187..dc9d65b 100644
--- a/o3d/plugin/plugin.gyp
+++ b/o3d/plugin/plugin.gyp
@@ -61,6 +61,7 @@
'cross/plugin_main.h',
'cross/stream_manager.cc',
'cross/stream_manager.h',
+ 'cross/texture_static_glue.cc',
],
'conditions' : [
['OS != "linux"',
diff --git a/o3d/tests/build.scons b/o3d/tests/build.scons
index 7b4be1c..c9bc853 100644
--- a/o3d/tests/build.scons
+++ b/o3d/tests/build.scons
@@ -229,6 +229,8 @@ tests = [
'core/cross/state_test.cc',
'core/cross/stream_bank_test.cc',
'core/cross/stream_test.cc',
+ 'core/cross/texture_base_test.cc',
+ 'core/cross/texture_test.cc',
'core/cross/transform_test.cc',
'core/cross/tree_traversal_test.cc',
'core/cross/vector_map_test.cc',