WebCore/html/canvas/WebGLTexture.cpp
changeset 0 4f2f89ce4247
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebCore/html/canvas/WebGLTexture.cpp	Fri Sep 17 09:02:29 2010 +0300
@@ -0,0 +1,316 @@
+/*
+ * 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 "WebGLRenderingContext.h"
+
+namespace WebCore {
+    
+PassRefPtr<WebGLTexture> WebGLTexture::create(WebGLRenderingContext* ctx)
+{
+    return adoptRef(new WebGLTexture(ctx));
+}
+
+WebGLTexture::WebGLTexture(WebGLRenderingContext* ctx)
+    : CanvasObject(ctx)
+    , cubeMapRWrapModeInitialized(false)
+    , 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)
+        return;
+    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;
+}
+
+unsigned long WebGLTexture::getInternalFormat() const
+{
+    if (!object() || !m_target)
+        return 0;
+    return m_info[0][0].internalFormat;
+}
+
+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::_deleteObject(Platform3DObject object)
+{
+    context()->graphicsContext3D()->deleteTexture(object);
+}
+
+int WebGLTexture::mapTargetToIndex(unsigned long target)
+{
+    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;
+}
+
+}
+
+#endif // ENABLE(3D_CANVAS)