diff options
author | Steve Block <steveblock@google.com> | 2011-05-06 11:45:16 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2011-05-12 13:44:10 +0100 |
commit | cad810f21b803229eb11403f9209855525a25d57 (patch) | |
tree | 29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/html/canvas/WebGLTexture.cpp | |
parent | 121b0cf4517156d0ac5111caf9830c51b69bae8f (diff) | |
download | external_webkit-cad810f21b803229eb11403f9209855525a25d57.zip external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2 |
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/html/canvas/WebGLTexture.cpp')
-rw-r--r-- | Source/WebCore/html/canvas/WebGLTexture.cpp | 355 |
1 files changed, 355 insertions, 0 deletions
diff --git a/Source/WebCore/html/canvas/WebGLTexture.cpp b/Source/WebCore/html/canvas/WebGLTexture.cpp new file mode 100644 index 0000000..2982e51 --- /dev/null +++ b/Source/WebCore/html/canvas/WebGLTexture.cpp @@ -0,0 +1,355 @@ +/* + * Copyright (C) 2009 Apple 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: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 "config.h" + +#if ENABLE(3D_CANVAS) + +#include "WebGLTexture.h" + +#include "WebGLFramebuffer.h" +#include "WebGLRenderingContext.h" + +namespace WebCore { + +PassRefPtr<WebGLTexture> WebGLTexture::create(WebGLRenderingContext* ctx) +{ + return adoptRef(new WebGLTexture(ctx)); +} + +WebGLTexture::WebGLTexture(WebGLRenderingContext* ctx) + : WebGLObject(ctx) + , m_target(0) + , m_minFilter(GraphicsContext3D::NEAREST_MIPMAP_LINEAR) + , m_magFilter(GraphicsContext3D::LINEAR) + , m_wrapS(GraphicsContext3D::REPEAT) + , m_wrapT(GraphicsContext3D::REPEAT) + , m_isNPOT(false) + , m_isComplete(false) + , m_needToUseBlackTexture(false) +{ + setObject(context()->graphicsContext3D()->createTexture()); +} + +void WebGLTexture::setTarget(unsigned long target, int maxLevel) +{ + if (!object()) + return; + // Target is finalized the first time bindTexture() is called. + if (m_target) + return; + switch (target) { + case GraphicsContext3D::TEXTURE_2D: + m_target = target; + m_info.resize(1); + m_info[0].resize(maxLevel); + break; + case GraphicsContext3D::TEXTURE_CUBE_MAP: + m_target = target; + m_info.resize(6); + for (int ii = 0; ii < 6; ++ii) + m_info[ii].resize(maxLevel); + break; + } +} + +void WebGLTexture::setParameteri(unsigned long pname, int param) +{ + if (!object() || !m_target) + return; + switch (pname) { + case GraphicsContext3D::TEXTURE_MIN_FILTER: + switch (param) { + case GraphicsContext3D::NEAREST: + case GraphicsContext3D::LINEAR: + case GraphicsContext3D::NEAREST_MIPMAP_NEAREST: + case GraphicsContext3D::LINEAR_MIPMAP_NEAREST: + case GraphicsContext3D::NEAREST_MIPMAP_LINEAR: + case GraphicsContext3D::LINEAR_MIPMAP_LINEAR: + m_minFilter = param; + break; + } + break; + case GraphicsContext3D::TEXTURE_MAG_FILTER: + switch (param) { + case GraphicsContext3D::NEAREST: + case GraphicsContext3D::LINEAR: + m_magFilter = param; + break; + } + break; + case GraphicsContext3D::TEXTURE_WRAP_S: + switch (param) { + case GraphicsContext3D::CLAMP_TO_EDGE: + case GraphicsContext3D::MIRRORED_REPEAT: + case GraphicsContext3D::REPEAT: + m_wrapS = param; + break; + } + break; + case GraphicsContext3D::TEXTURE_WRAP_T: + switch (param) { + case GraphicsContext3D::CLAMP_TO_EDGE: + case GraphicsContext3D::MIRRORED_REPEAT: + case GraphicsContext3D::REPEAT: + m_wrapT = param; + break; + } + break; + default: + return; + } + update(); +} + +void WebGLTexture::setParameterf(unsigned long pname, float param) +{ + if (!object() || !m_target) + return; + int iparam = static_cast<int>(param); + setParameteri(pname, iparam); +} + +void WebGLTexture::setLevelInfo(unsigned long target, int level, unsigned long internalFormat, int width, int height, unsigned long type) +{ + if (!object() || !m_target) + return; + // We assume level, internalFormat, width, height, and type have all been + // validated already. + int index = mapTargetToIndex(target); + if (index < 0) + return; + m_info[index][level].setInfo(internalFormat, width, height, type); + update(); +} + +void WebGLTexture::generateMipmapLevelInfo() +{ + if (!object() || !m_target) + return; + if (!canGenerateMipmaps()) + return; + if (!m_isComplete) { + for (size_t ii = 0; ii < m_info.size(); ++ii) { + const LevelInfo& info0 = m_info[ii][0]; + int width = info0.width; + int height = info0.height; + int levelCount = computeLevelCount(width, height); + for (int level = 1; level < levelCount; ++level) { + width = std::max(1, width >> 1); + height = std::max(1, height >> 1); + LevelInfo& info = m_info[ii][level]; + info.setInfo(info0.internalFormat, width, height, info0.type); + } + } + m_isComplete = true; + } + m_needToUseBlackTexture = false; +} + +unsigned long WebGLTexture::getInternalFormat(unsigned long target, int level) const +{ + const LevelInfo* info = getLevelInfo(target, level); + if (!info) + return 0; + return info->internalFormat; +} + +unsigned long WebGLTexture::getType(unsigned long target, int level) const +{ + const LevelInfo* info = getLevelInfo(target, level); + if (!info) + return 0; + return info->type; +} + +int WebGLTexture::getWidth(unsigned long target, int level) const +{ + const LevelInfo* info = getLevelInfo(target, level); + if (!info) + return 0; + return info->width; +} + +int WebGLTexture::getHeight(unsigned long target, int level) const +{ + const LevelInfo* info = getLevelInfo(target, level); + if (!info) + return 0; + return info->height; +} + +bool WebGLTexture::isNPOT(unsigned width, unsigned height) +{ + if (!width || !height) + return false; + if ((width & (width - 1)) || (height & (height - 1))) + return true; + return false; +} + +bool WebGLTexture::isNPOT() const +{ + if (!object()) + return false; + return m_isNPOT; +} + +bool WebGLTexture::needToUseBlackTexture() const +{ + if (!object()) + return false; + return m_needToUseBlackTexture; +} + +void WebGLTexture::deleteObjectImpl(Platform3DObject object) +{ + context()->graphicsContext3D()->deleteTexture(object); +} + +int WebGLTexture::mapTargetToIndex(unsigned long target) const +{ + if (m_target == GraphicsContext3D::TEXTURE_2D) { + if (target == GraphicsContext3D::TEXTURE_2D) + return 0; + } else if (m_target == GraphicsContext3D::TEXTURE_CUBE_MAP) { + switch (target) { + case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X: + return 0; + case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X: + return 1; + case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y: + return 2; + case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y: + return 3; + case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z: + return 4; + case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z: + return 5; + } + } + return -1; +} + +bool WebGLTexture::canGenerateMipmaps() +{ + if (isNPOT()) + return false; + const LevelInfo& first = m_info[0][0]; + for (size_t ii = 0; ii < m_info.size(); ++ii) { + const LevelInfo& info = m_info[ii][0]; + if (!info.valid + || info.width != first.width || info.height != first.height + || info.internalFormat != first.internalFormat || info.type != first.type) + return false; + } + return true; +} + +int WebGLTexture::computeLevelCount(int width, int height) +{ + // return 1 + log2Floor(std::max(width, height)); + int n = std::max(width, height); + if (n <= 0) + return 0; + int log = 0; + int value = n; + for (int ii = 4; ii >= 0; --ii) { + int shift = (1 << ii); + int x = (value >> shift); + if (x) { + value = x; + log += shift; + } + } + ASSERT(value == 1); + return log + 1; +} + +void WebGLTexture::update() +{ + m_isNPOT = false; + for (size_t ii = 0; ii < m_info.size(); ++ii) { + if (isNPOT(m_info[ii][0].width, m_info[ii][0].height)) { + m_isNPOT = true; + break; + } + } + m_isComplete = true; + const LevelInfo& first = m_info[0][0]; + int levelCount = computeLevelCount(first.width, first.height); + if (levelCount < 1) + m_isComplete = false; + else { + for (size_t ii = 0; ii < m_info.size() && m_isComplete; ++ii) { + const LevelInfo& info0 = m_info[ii][0]; + if (!info0.valid + || info0.width != first.width || info0.height != first.height + || info0.internalFormat != first.internalFormat || info0.type != first.type) { + m_isComplete = false; + break; + } + int width = info0.width; + int height = info0.height; + for (int level = 1; level < levelCount; ++level) { + width = std::max(1, width >> 1); + height = std::max(1, height >> 1); + const LevelInfo& info = m_info[ii][level]; + if (!info.valid + || info.width != width || info.height != height + || info.internalFormat != info0.internalFormat || info.type != info0.type) { + m_isComplete = false; + break; + } + + } + } + } + + m_needToUseBlackTexture = false; + // NPOT + if (m_isNPOT && ((m_minFilter != GraphicsContext3D::NEAREST && m_minFilter != GraphicsContext3D::LINEAR) + || m_wrapS != GraphicsContext3D::CLAMP_TO_EDGE || m_wrapT != GraphicsContext3D::CLAMP_TO_EDGE)) + m_needToUseBlackTexture = true; + // Completeness + if (!m_isComplete && m_minFilter != GraphicsContext3D::NEAREST && m_minFilter != GraphicsContext3D::LINEAR) + m_needToUseBlackTexture = true; +} + +const WebGLTexture::LevelInfo* WebGLTexture::getLevelInfo(unsigned long target, int level) const +{ + if (!object() || !m_target) + return 0; + int targetIndex = mapTargetToIndex(target); + if (targetIndex < 0 || targetIndex >= static_cast<int>(m_info.size())) + return 0; + if (level < 0 || level >= static_cast<int>(m_info[targetIndex].size())) + return 0; + return &(m_info[targetIndex][level]); +} + +} + +#endif // ENABLE(3D_CANVAS) |