summaryrefslogtreecommitdiffstats
path: root/o3d/core/cross/gl/texture_gl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'o3d/core/cross/gl/texture_gl.cc')
-rw-r--r--o3d/core/cross/gl/texture_gl.cc222
1 files changed, 215 insertions, 7 deletions
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