| Index: webkit/api/src/GraphicsContext3D.cpp
|
| ===================================================================
|
| --- webkit/api/src/GraphicsContext3D.cpp (revision 0)
|
| +++ webkit/api/src/GraphicsContext3D.cpp (revision 0)
|
| @@ -0,0 +1,2012 @@
|
| +/*
|
| + * Copyright (C) 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 "config.h"
|
| +
|
| +#if ENABLE(3D_CANVAS)
|
| +
|
| +#include "GraphicsContext3D.h"
|
| +
|
| +#include "CachedImage.h"
|
| +#include "CanvasBuffer.h"
|
| +#include "CanvasByteArray.h"
|
| +#include "CanvasFloatArray.h"
|
| +#include "CanvasFramebuffer.h"
|
| +#include "CanvasIntArray.h"
|
| +#include "CanvasObject.h"
|
| +#include "CanvasProgram.h"
|
| +#include "CanvasRenderbuffer.h"
|
| +#include "CanvasRenderingContext3D.h"
|
| +#include "CanvasShader.h"
|
| +#include "CanvasTexture.h"
|
| +#include "CanvasUnsignedByteArray.h"
|
| +#include "CString.h"
|
| +#include "HTMLCanvasElement.h"
|
| +#include "HTMLImageElement.h"
|
| +#include "ImageBuffer.h"
|
| +#include "ImageData.h"
|
| +#include "NotImplemented.h"
|
| +#include <wtf/FastMalloc.h>
|
| +
|
| +#include <stdio.h>
|
| +
|
| +#if PLATFORM(WIN_OS)
|
| +#include <windows.h>
|
| +#endif
|
| +
|
| +#include "GL/glew.h"
|
| +
|
| +#include "NativeImageSkia.h"
|
| +
|
| +using namespace std;
|
| +
|
| +namespace WebCore {
|
| +
|
| +// GraphicsContext3DInternal -----------------------------------------------------
|
| +
|
| +// Uncomment this to render to a separate window for debugging
|
| +// #define RENDER_TO_DEBUGGING_WINDOW
|
| +
|
| +#define EXTRACT(val) (val == NULL ? 0 : val->object())
|
| +
|
| +class GraphicsContext3DInternal {
|
| +public:
|
| + GraphicsContext3DInternal();
|
| + ~GraphicsContext3DInternal();
|
| +
|
| + void checkError() const;
|
| + bool makeContextCurrent();
|
| +
|
| + PlatformGraphicsContext3D platformGraphicsContext3D() const;
|
| + Platform3DObject platformTexture() const;
|
| +
|
| + void reshape(int width, int height);
|
| +
|
| + void beginPaint(CanvasRenderingContext3D* context);
|
| +
|
| + bool validateTextureTarget(int target);
|
| + bool validateTextureParameter(int param);
|
| +
|
| + void activeTexture(unsigned long texture);
|
| + void bindBuffer(unsigned long target,
|
| + CanvasBuffer* buffer);
|
| + void bindTexture(unsigned long target,
|
| + CanvasTexture* texture);
|
| + void bufferDataImpl(unsigned long target, int size, const void* data, unsigned long usage);
|
| + void colorMask(bool red, bool green, bool blue, bool alpha);
|
| + void depthMask(bool flag);
|
| + void disable(unsigned long cap);
|
| + void disableVertexAttribArray(unsigned long index);
|
| + void enable(unsigned long cap);
|
| + void enableVertexAttribArray(unsigned long index);
|
| + void useProgram(CanvasProgram* program);
|
| + void vertexAttribPointer(unsigned long indx, int size, int type, bool normalized,
|
| + unsigned long stride, unsigned long offset);
|
| + void viewportImpl(long x, long y, unsigned long width, unsigned long height);
|
| +
|
| +private:
|
| + unsigned int m_texture;
|
| + unsigned int m_fbo;
|
| + unsigned int m_depthBuffer;
|
| +
|
| + // Objects for flipping the render output vertically
|
| + unsigned int m_altTexture;
|
| + unsigned int m_quadVBO;
|
| + unsigned int m_quadProgram;
|
| + unsigned int m_quadTexLocation;
|
| +
|
| + // Storage for saving/restoring buffer, vertex attribute,
|
| + // blending, and program state when drawing flipped quad
|
| + unsigned int m_currentProgram;
|
| + bool m_blendEnabled;
|
| + bool m_depthTestEnabled;
|
| + bool m_depthMaskEnabled;
|
| + bool m_colorMask[4];
|
| + unsigned int m_boundArrayBuffer;
|
| + class VertexAttribPointerState {
|
| + public:
|
| + VertexAttribPointerState();
|
| +
|
| + bool enabled;
|
| + unsigned long buffer;
|
| + unsigned long indx;
|
| + int size;
|
| + int type;
|
| + bool normalized;
|
| + unsigned long stride;
|
| + unsigned long offset;
|
| + };
|
| + VertexAttribPointerState m_vertexAttribPointerState[1];
|
| + unsigned int m_activeTextureUnit;
|
| + class TextureUnitState {
|
| + public:
|
| + TextureUnitState();
|
| +
|
| + unsigned long target;
|
| + unsigned int texture;
|
| + };
|
| + TextureUnitState m_textureUnitState[1];
|
| + int m_viewport[4];
|
| +
|
| +#if PLATFORM(WIN_OS)
|
| + HWND m_canvasWindow;
|
| + HDC m_canvasDC;
|
| + HGLRC m_contextObj;
|
| +#else
|
| + #error Must port GraphicsContext3D to your platform
|
| +#endif
|
| +};
|
| +
|
| +GraphicsContext3DInternal::VertexAttribPointerState::VertexAttribPointerState()
|
| + : enabled(false)
|
| + , buffer(0)
|
| + , indx(0)
|
| + , size(0)
|
| + , type(0)
|
| + , normalized(false)
|
| + , stride(0)
|
| + , offset(0)
|
| +{
|
| +}
|
| +
|
| +GraphicsContext3DInternal::TextureUnitState::TextureUnitState()
|
| + : target(0)
|
| + , texture(0)
|
| +{
|
| +}
|
| +
|
| +GraphicsContext3DInternal::GraphicsContext3DInternal()
|
| + : m_texture(0)
|
| + , m_fbo(0)
|
| + , m_depthBuffer(0)
|
| + , m_altTexture(0)
|
| + , m_quadVBO(0)
|
| + , m_quadProgram(0)
|
| + , m_quadTexLocation(0)
|
| + , m_currentProgram(0)
|
| + , m_blendEnabled(false)
|
| + , m_depthTestEnabled(false)
|
| + , m_depthMaskEnabled(true)
|
| + , m_boundArrayBuffer(0)
|
| + , m_activeTextureUnit(0)
|
| +#if PLATFORM(WIN_OS)
|
| + , m_canvasWindow(NULL)
|
| + , m_canvasDC(NULL)
|
| + , m_contextObj(NULL)
|
| +#else
|
| +#error Must port to your platform
|
| +#endif
|
| +{
|
| + for (int i = 0; i < 4; i++) {
|
| + m_viewport[i] = 0;
|
| + m_colorMask[i] = true;
|
| + }
|
| +#if PLATFORM(WIN_OS)
|
| + WNDCLASS wc;
|
| + if (!GetClassInfo(GetModuleHandle(NULL), L"CANVASGL", &wc)) {
|
| + ZeroMemory(&wc, sizeof(WNDCLASS));
|
| + wc.style = CS_OWNDC;
|
| + wc.hInstance = GetModuleHandle(NULL);
|
| + wc.lpfnWndProc = DefWindowProc;
|
| + wc.lpszClassName = L"CANVASGL";
|
| +
|
| + if (!RegisterClass(&wc)) {
|
| + printf("GraphicsContext3D: RegisterClass failed\n");
|
| + return;
|
| + }
|
| + }
|
| +
|
| + m_canvasWindow = CreateWindow(L"CANVASGL", L"CANVASGL",
|
| + WS_CAPTION,
|
| + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
| + CW_USEDEFAULT, NULL, NULL, GetModuleHandle(NULL), NULL);
|
| + if (!m_canvasWindow) {
|
| + printf("GraphicsContext3DInternal: CreateWindow failed\n");
|
| + return;
|
| + }
|
| +
|
| + // get the device context
|
| + m_canvasDC = GetDC(m_canvasWindow);
|
| + if (!m_canvasDC) {
|
| + printf("GraphicsContext3DInternal: GetDC failed\n");
|
| + return;
|
| + }
|
| +
|
| + // find default pixel format
|
| + PIXELFORMATDESCRIPTOR pfd;
|
| + ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR));
|
| + pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
| + pfd.nVersion = 1;
|
| + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL
|
| +#ifdef RENDER_TO_DEBUGGING_WINDOW
|
| + | PFD_DOUBLEBUFFER
|
| +#endif // RENDER_TO_DEBUGGING_WINDOW
|
| + ;
|
| + int pixelformat = ChoosePixelFormat(m_canvasDC, &pfd);
|
| +
|
| + // set the pixel format for the dc
|
| + if (!SetPixelFormat(m_canvasDC, pixelformat, &pfd)) {
|
| + printf("GraphicsContext3D: SetPixelFormat failed\n");
|
| + return;
|
| + }
|
| +
|
| + // create rendering context
|
| + m_contextObj = wglCreateContext(m_canvasDC);
|
| + if (!m_contextObj) {
|
| + printf("GraphicsContext3D: wglCreateContext failed\n");
|
| + return;
|
| + }
|
| +
|
| + if (!wglMakeCurrent(m_canvasDC, m_contextObj)) {
|
| + printf("GraphicsContext3D: wglMakeCurrent failed\n");
|
| + return;
|
| + }
|
| +
|
| +#ifdef RENDER_TO_DEBUGGING_WINDOW
|
| + typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval);
|
| + PFNWGLSWAPINTERVALEXTPROC setSwapInterval = NULL;
|
| + setSwapInterval = (PFNWGLSWAPINTERVALEXTPROC) wglGetProcAddress("wglSwapIntervalEXT");
|
| + if (setSwapInterval != NULL)
|
| + setSwapInterval(1);
|
| +#endif // RENDER_TO_DEBUGGING_WINDOW
|
| +
|
| +#else
|
| +#error Must port to your platform
|
| +#endif
|
| +
|
| + // Initialize GLEW and check for GL 2.0 support by the drivers.
|
| + GLenum glewInitResult = glewInit();
|
| + if (!glewIsSupported("GL_VERSION_2_0")) {
|
| + printf("GraphicsContext3D: OpenGL 2.0 not supported\n");
|
| + return;
|
| + }
|
| +}
|
| +
|
| +GraphicsContext3DInternal::~GraphicsContext3DInternal()
|
| +{
|
| + makeContextCurrent();
|
| +#ifndef RENDER_TO_DEBUGGING_WINDOW
|
| + glDeleteRenderbuffersEXT(1, &m_depthBuffer);
|
| + glDeleteTextures(1, &m_texture);
|
| + glDeleteTextures(1, &m_altTexture);
|
| + glDeleteFramebuffersEXT(1, &m_fbo);
|
| +#endif // !RENDER_TO_DEBUGGING_WINDOW
|
| +#if PLATFORM(WIN_OS)
|
| + wglMakeCurrent(NULL, NULL);
|
| + wglDeleteContext(m_contextObj);
|
| + ReleaseDC(m_canvasWindow, m_canvasDC);
|
| + DestroyWindow(m_canvasWindow);
|
| +#else
|
| +#error Must port to your platform
|
| +#endif
|
| + m_contextObj = NULL;
|
| +}
|
| +
|
| +void GraphicsContext3DInternal::checkError() const
|
| +{
|
| + // FIXME: This needs to only be done in the debug context. It
|
| + // will need to throw an exception on error.
|
| + GLenum error = glGetError();
|
| + if (error != GL_NO_ERROR) {
|
| + printf("GL Error : %x\n", error);
|
| + notImplemented();
|
| + }
|
| +}
|
| +
|
| +bool GraphicsContext3DInternal::makeContextCurrent()
|
| +{
|
| +#if PLATFORM(WIN_OS)
|
| + if (wglGetCurrentContext() != m_contextObj)
|
| + if (wglMakeCurrent(m_canvasDC, m_contextObj))
|
| + return true;
|
| +#else
|
| +#error Must port to your platform
|
| +#endif
|
| + return false;
|
| +}
|
| +
|
| +PlatformGraphicsContext3D GraphicsContext3DInternal::platformGraphicsContext3D() const
|
| +{
|
| + return m_contextObj;
|
| +}
|
| +
|
| +Platform3DObject GraphicsContext3DInternal::platformTexture() const
|
| +{
|
| + return m_texture;
|
| +}
|
| +
|
| +static int createTextureObject()
|
| +{
|
| + GLuint texture = 0;
|
| + glGenTextures(1, &texture);
|
| + glBindTexture(GL_TEXTURE_2D, texture);
|
| + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
| + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
| + return texture;
|
| +}
|
| +
|
| +void GraphicsContext3DInternal::reshape(int width, int height)
|
| +{
|
| +#ifdef RENDER_TO_DEBUGGING_WINDOW
|
| + SetWindowPos(m_canvasWindow, HWND_TOP, 0, 0, width, height,
|
| + SWP_NOMOVE);
|
| + ShowWindow(m_canvasWindow, SW_SHOW);
|
| +#endif
|
| +
|
| + makeContextCurrent();
|
| +
|
| +#ifndef RENDER_TO_DEBUGGING_WINDOW
|
| + if (m_texture == 0) {
|
| + // Generate the texture objects
|
| + m_texture = createTextureObject();
|
| + m_altTexture = createTextureObject();
|
| +
|
| + // Generate the framebuffer object
|
| + glGenFramebuffersEXT(1, &m_fbo);
|
| +
|
| + // Generate the depth buffer
|
| + glGenRenderbuffersEXT(1, &m_depthBuffer);
|
| +
|
| + checkError();
|
| + }
|
| +
|
| + // Reallocate the color and depth buffers
|
| + glBindTexture(GL_TEXTURE_2D, m_texture);
|
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
| + glBindTexture(GL_TEXTURE_2D, m_altTexture);
|
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
| + glBindTexture(GL_TEXTURE_2D, 0);
|
| +
|
| + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
|
| + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthBuffer);
|
| + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height);
|
| + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
|
| +
|
| + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_texture, 0);
|
| + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthBuffer);
|
| + GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
|
| + if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
|
| + printf("GraphicsContext3D: framebuffer was incomplete\n");
|
| +
|
| + // FIXME: cleanup.
|
| + notImplemented();
|
| + }
|
| +#endif // RENDER_TO_DEBUGGING_WINDOW
|
| +
|
| + glClear(GL_COLOR_BUFFER_BIT);
|
| + viewportImpl(0, 0, width, height);
|
| +}
|
| +
|
| +void GraphicsContext3DInternal::beginPaint(CanvasRenderingContext3D* context)
|
| +{
|
| + makeContextCurrent();
|
| +
|
| +#ifdef RENDER_TO_DEBUGGING_WINDOW
|
| + SwapBuffers(m_canvasDC);
|
| +#else
|
| + if (m_quadVBO == 0) {
|
| + // Prepare necessary objects for rendering.
|
| + glGenBuffers(1, &m_quadVBO);
|
| + GLfloat vertices[] = {-1.0f, -1.0f,
|
| + 1.0f, -1.0f,
|
| + 1.0f, 1.0f,
|
| + -1.0f, -1.0f,
|
| + 1.0f, 1.0f,
|
| + -1.0f, 1.0f};
|
| + glBindBuffer(GL_ARRAY_BUFFER, m_quadVBO);
|
| + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
| + // Vertex shader does vertical flip.
|
| + const GLchar* vertexShaderSrc =
|
| + "attribute vec2 g_Position;\n"
|
| + "varying vec2 texCoord;\n"
|
| + "void main()\n"
|
| + "{\n"
|
| + " texCoord = vec2((g_Position.x + 1.0) * 0.5,\n"
|
| + " (1.0 - g_Position.y) * 0.5);\n"
|
| + " gl_Position = vec4(g_Position, 0.0, 1.0);\n"
|
| + "}\n";
|
| + // Fragment shader does optional premultiplication of alpha
|
| + // into color channels.
|
| + const GLchar* fragmentShaderNoPremultSrc =
|
| + "varying vec2 texCoord;\n"
|
| + "uniform sampler2D texSampler;\n"
|
| + "void main()\n"
|
| + "{\n"
|
| + " gl_FragColor = texture2D(texSampler, texCoord);\n"
|
| + "}\n";
|
| + const GLchar* fragmentShaderPremultSrc =
|
| + "varying vec2 texCoord;\n"
|
| + "uniform sampler2D texSampler;\n"
|
| + "void main()\n"
|
| + "{\n"
|
| + " vec4 color = texture2D(texSampler, texCoord);\n"
|
| + " gl_FragColor = vec4(color.r * color.a,\n"
|
| + " color.g * color.a,\n"
|
| + " color.b * color.a,\n"
|
| + " color.a);\n"
|
| + "}\n";
|
| + GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
|
| + glShaderSource(vertexShader, 1, &vertexShaderSrc, NULL);
|
| + checkError();
|
| + GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
|
| + // FIXME: hook up fragmentShaderPremultSrc based on canvas
|
| + // context attributes.
|
| + glShaderSource(fragmentShader, 1, &fragmentShaderNoPremultSrc, NULL);
|
| + checkError();
|
| + m_quadProgram = glCreateProgram();
|
| + glAttachShader(m_quadProgram, vertexShader);
|
| + glAttachShader(m_quadProgram, fragmentShader);
|
| + glBindAttribLocation(m_quadProgram, 0, "g_Position");
|
| + glLinkProgram(m_quadProgram);
|
| + checkError();
|
| + glDeleteShader(vertexShader);
|
| + glDeleteShader(fragmentShader);
|
| + m_quadTexLocation = glGetUniformLocation(m_quadProgram, "texSampler");
|
| + checkError();
|
| + }
|
| +
|
| + // We've just rendered a frame into m_texture. Bind m_altTexture
|
| + // as the framebuffer texture, and draw m_texture on to a quad,
|
| + // flipping it vertically and performing alpha premultiplication
|
| + // and color channel swizzling. Then read back the FBO.
|
| + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_altTexture, 0);
|
| + glUseProgram(m_quadProgram);
|
| + glActiveTexture(GL_TEXTURE0);
|
| + glBindTexture(GL_TEXTURE_2D, m_texture);
|
| + glUniform1i(m_quadTexLocation, 0);
|
| + glBindBuffer(GL_ARRAY_BUFFER, m_quadVBO);
|
| + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
|
| + glEnableVertexAttribArray(0);
|
| + glDisable(GL_DEPTH_TEST);
|
| + glDisable(GL_BLEND);
|
| + glDepthMask(false);
|
| + glColorMask(true, true, true, true);
|
| +
|
| + HTMLCanvasElement* canvas = context->canvas();
|
| + ImageBuffer* imageBuffer = canvas->buffer();
|
| + const SkBitmap& bitmap = *imageBuffer->context()->platformContext()->bitmap();
|
| + ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config);
|
| + glViewport(0, 0, bitmap.width(), bitmap.height());
|
| +
|
| + glDrawArrays(GL_TRIANGLES, 0, 6);
|
| +
|
| + // Read back the frame buffer.
|
| + SkAutoLockPixels bitmapLock(bitmap);
|
| + glReadPixels(0, 0, bitmap.width(), bitmap.height(), GL_BGRA, GL_UNSIGNED_BYTE, bitmap.getPixels());
|
| +
|
| + // Restore the previous FBO state.
|
| + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_texture, 0);
|
| +
|
| + // Restore the user's OpenGL state.
|
| + glUseProgram(m_currentProgram);
|
| + const VertexAttribPointerState& state = m_vertexAttribPointerState[0];
|
| + if (state.buffer) {
|
| + glBindBuffer(GL_ARRAY_BUFFER, state.buffer);
|
| + glVertexAttribPointer(state.indx, state.size, state.type, state.normalized,
|
| + state.stride, reinterpret_cast<void*>(static_cast<intptr_t>(state.offset)));
|
| + }
|
| + glBindBuffer(GL_ARRAY_BUFFER, m_boundArrayBuffer);
|
| + if (state.enabled)
|
| + glEnableVertexAttribArray(0);
|
| + else
|
| + glDisableVertexAttribArray(0);
|
| + const TextureUnitState& texState = m_textureUnitState[0];
|
| + glBindTexture(texState.target, texState.texture);
|
| + glActiveTexture(m_activeTextureUnit);
|
| + if (m_blendEnabled)
|
| + glEnable(GL_BLEND);
|
| + if (m_depthTestEnabled)
|
| + glEnable(GL_DEPTH_TEST);
|
| + glDepthMask(m_depthMaskEnabled);
|
| + glColorMask(m_colorMask[0], m_colorMask[1], m_colorMask[2], m_colorMask[3]);
|
| + glViewport(m_viewport[0], m_viewport[1],
|
| + m_viewport[2], m_viewport[3]);
|
| +#endif // RENDER_TO_DEBUGGING_WINDOW
|
| +}
|
| +
|
| +bool GraphicsContext3DInternal::validateTextureTarget(int target)
|
| +{
|
| + return (target == GL_TEXTURE_2D ||
|
| + target == GL_TEXTURE_CUBE_MAP);
|
| +}
|
| +
|
| +bool GraphicsContext3DInternal::validateTextureParameter(int param)
|
| +{
|
| + return (param == GL_TEXTURE_MAG_FILTER ||
|
| + param == GL_TEXTURE_MIN_FILTER ||
|
| + param == GL_TEXTURE_WRAP_S ||
|
| + param == GL_TEXTURE_WRAP_T);
|
| +}
|
| +
|
| +void GraphicsContext3DInternal::activeTexture(unsigned long texture)
|
| +{
|
| + // FIXME: query number of textures available.
|
| + if (texture < GL_TEXTURE0 || texture > GL_TEXTURE0+32)
|
| + // FIXME: raise exception.
|
| + return;
|
| +
|
| + makeContextCurrent();
|
| + m_activeTextureUnit = texture;
|
| + glActiveTexture(texture);
|
| +}
|
| +
|
| +void GraphicsContext3DInternal::bindBuffer(unsigned long target,
|
| + CanvasBuffer* buffer)
|
| +{
|
| + makeContextCurrent();
|
| + GLuint bufID = EXTRACT(buffer);
|
| + if (target == GL_ARRAY_BUFFER)
|
| + m_boundArrayBuffer = bufID;
|
| + glBindBuffer(target, bufID);
|
| +}
|
| +
|
| +// If we didn't have to hack GL_TEXTURE_WRAP_R for cube maps,
|
| +// we could just use:
|
| +// GL_SAME_METHOD_2_X2(BindTexture, bindTexture, unsigned long, CanvasTexture*)
|
| +void GraphicsContext3DInternal::bindTexture(unsigned long target,
|
| + CanvasTexture* texture)
|
| +{
|
| + makeContextCurrent();
|
| + unsigned int textureObject = EXTRACT(texture);
|
| +
|
| + if (m_activeTextureUnit == 0) {
|
| + TextureUnitState& state = m_textureUnitState[m_activeTextureUnit];
|
| + state.target = target;
|
| + state.texture = textureObject;
|
| + }
|
| +
|
| + glBindTexture(target, textureObject);
|
| +
|
| + // FIXME: GL_TEXTURE_WRAP_R isn't exposed in the OpenGL ES 2.0
|
| + // API. On desktop OpenGL implementations it seems necessary to
|
| + // set this wrap mode to GL_CLAMP_TO_EDGE to get correct behavior
|
| + // of cube maps.
|
| + if (texture != NULL) {
|
| + if (target == GL_TEXTURE_CUBE_MAP) {
|
| + if (!texture->isCubeMapRWrapModeInitialized()) {
|
| + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
| + texture->setCubeMapRWrapModeInitialized(true);
|
| + }
|
| + } else
|
| + texture->setCubeMapRWrapModeInitialized(false);
|
| + }
|
| +}
|
| +
|
| +void GraphicsContext3DInternal::bufferDataImpl(unsigned long target, int size, const void* data, unsigned long usage)
|
| +{
|
| + makeContextCurrent();
|
| + // FIXME: make this verification more efficient.
|
| + GLint binding = 0;
|
| + GLenum binding_target = GL_ARRAY_BUFFER_BINDING;
|
| + if (target == GL_ELEMENT_ARRAY_BUFFER)
|
| + binding_target = GL_ELEMENT_ARRAY_BUFFER_BINDING;
|
| + glGetIntegerv(binding_target, &binding);
|
| + if (binding <= 0) {
|
| + // FIXME: raise exception.
|
| + // LogMessagef(("bufferData: no buffer bound"));
|
| + return;
|
| + }
|
| +
|
| + glBufferData(target,
|
| + size,
|
| + data,
|
| + usage);
|
| +}
|
| +
|
| +void GraphicsContext3DInternal::colorMask(bool red, bool green, bool blue, bool alpha)
|
| +{
|
| + makeContextCurrent();
|
| + m_colorMask[0] = red;
|
| + m_colorMask[1] = green;
|
| + m_colorMask[2] = blue;
|
| + m_colorMask[3] = alpha;
|
| + glColorMask(red, green, blue, alpha);
|
| +}
|
| +
|
| +void GraphicsContext3DInternal::depthMask(bool flag)
|
| +{
|
| + makeContextCurrent();
|
| + m_depthMaskEnabled = flag;
|
| + glDepthMask(flag);
|
| +}
|
| +
|
| +void GraphicsContext3DInternal::disable(unsigned long cap)
|
| +{
|
| + makeContextCurrent();
|
| + switch (cap) {
|
| + case GL_BLEND:
|
| + m_blendEnabled = false;
|
| + case GL_DEPTH_TEST:
|
| + m_depthTestEnabled = false;
|
| + default:
|
| + break;
|
| + }
|
| + glDisable(cap);
|
| +}
|
| +
|
| +void GraphicsContext3DInternal::disableVertexAttribArray(unsigned long index)
|
| +{
|
| + makeContextCurrent();
|
| + if (index == 0) {
|
| + m_vertexAttribPointerState[0].enabled = false;
|
| + }
|
| + glDisableVertexAttribArray(index);
|
| +}
|
| +
|
| +void GraphicsContext3DInternal::enable(unsigned long cap)
|
| +{
|
| + makeContextCurrent();
|
| + switch (cap) {
|
| + case GL_BLEND:
|
| + m_blendEnabled = true;
|
| + case GL_DEPTH_TEST:
|
| + m_depthTestEnabled = true;
|
| + default:
|
| + break;
|
| + }
|
| + glEnable(cap);
|
| +}
|
| +
|
| +void GraphicsContext3DInternal::enableVertexAttribArray(unsigned long index)
|
| +{
|
| + makeContextCurrent();
|
| + if (index == 0)
|
| + m_vertexAttribPointerState[0].enabled = true;
|
| + glEnableVertexAttribArray(index);
|
| +}
|
| +
|
| +void GraphicsContext3DInternal::useProgram(CanvasProgram* program)
|
| +{
|
| + makeContextCurrent();
|
| + m_currentProgram = EXTRACT(program);
|
| + glUseProgram(m_currentProgram);
|
| +}
|
| +
|
| +void GraphicsContext3DInternal::vertexAttribPointer(unsigned long indx, int size, int type, bool normalized,
|
| + unsigned long stride, unsigned long offset)
|
| +{
|
| + makeContextCurrent();
|
| +
|
| + if (m_boundArrayBuffer <= 0) {
|
| + // FIXME: raise exception.
|
| + // LogMessagef(("bufferData: no buffer bound"));
|
| + return;
|
| + }
|
| +
|
| + if (indx == 0) {
|
| + VertexAttribPointerState& state = m_vertexAttribPointerState[0];
|
| + state.buffer = m_boundArrayBuffer;
|
| + state.indx = indx;
|
| + state.size = size;
|
| + state.type = type;
|
| + state.normalized = normalized;
|
| + state.stride = stride;
|
| + state.offset = offset;
|
| + }
|
| +
|
| + glVertexAttribPointer(indx, size, type, normalized, stride,
|
| + reinterpret_cast<void*>(static_cast<intptr_t>(offset)));
|
| +}
|
| +
|
| +void GraphicsContext3DInternal::viewportImpl(long x, long y, unsigned long width, unsigned long height)
|
| +{
|
| + m_viewport[0] = x;
|
| + m_viewport[1] = y;
|
| + m_viewport[2] = width;
|
| + m_viewport[3] = height;
|
| + glViewport(x, y, width, height);
|
| +}
|
| +
|
| +// GraphicsContext3D -----------------------------------------------------
|
| +
|
| +#define GRAPHICS_CONTEXT_NAME GraphicsContext3D
|
| +
|
| +/* Helper macros for when we're just wrapping a gl method, so that
|
| + * we can avoid having to type this 500 times. Note that these MUST
|
| + * NOT BE USED if we need to check any of the parameters.
|
| + */
|
| +
|
| +#define GL_SAME_METHOD_0(glname, name) \
|
| +void GRAPHICS_CONTEXT_NAME::##name() \
|
| +{ \
|
| + makeContextCurrent(); gl##glname(); \
|
| +}
|
| +
|
| +#define GL_SAME_METHOD_1(glname, name, t1) \
|
| +void GRAPHICS_CONTEXT_NAME::##name(t1 a1) \
|
| +{ \
|
| + makeContextCurrent(); gl##glname(a1); \
|
| +}
|
| +
|
| +#define GL_SAME_METHOD_1_X(glname, name, t1) \
|
| +void GRAPHICS_CONTEXT_NAME::##name(t1 a1) \
|
| +{ \
|
| + makeContextCurrent(); gl##glname(EXTRACT(a1)); \
|
| +}
|
| +
|
| +#define GL_SAME_METHOD_2(glname, name, t1, t2) \
|
| +void GRAPHICS_CONTEXT_NAME::##name(t1 a1, t2 a2) \
|
| +{ \
|
| + makeContextCurrent(); gl##glname(a1,a2); \
|
| +}
|
| +
|
| +#define GL_SAME_METHOD_2_X12(glname, name, t1, t2) \
|
| +void GRAPHICS_CONTEXT_NAME::##name(t1 a1, t2 a2) \
|
| +{ \
|
| + makeContextCurrent(); gl##glname(EXTRACT(a1),EXTRACT(a2)); \
|
| +}
|
| +
|
| +#define GL_SAME_METHOD_2_X2(glname, name, t1, t2) \
|
| +void GRAPHICS_CONTEXT_NAME::##name(t1 a1, t2 a2) \
|
| +{ \
|
| + makeContextCurrent(); gl##glname(a1,EXTRACT(a2)); \
|
| +}
|
| +
|
| +#define GL_SAME_METHOD_3(glname, name, t1, t2, t3) \
|
| +void GRAPHICS_CONTEXT_NAME::##name(t1 a1, t2 a2, t3 a3) \
|
| +{ \
|
| + makeContextCurrent(); gl##glname(a1,a2,a3); \
|
| +}
|
| +
|
| +#define GL_SAME_METHOD_3_X12(glname, name, t1, t2, t3) \
|
| +void GRAPHICS_CONTEXT_NAME::##name(t1 a1, t2 a2, t3 a3) \
|
| +{ \
|
| + makeContextCurrent(); gl##glname(EXTRACT(a1),EXTRACT(a2),a3); \
|
| +}
|
| +
|
| +#define GL_SAME_METHOD_3_X2(glname, name, t1, t2, t3) \
|
| +void GRAPHICS_CONTEXT_NAME::##name(t1 a1, t2 a2, t3 a3) \
|
| +{ \
|
| + makeContextCurrent(); gl##glname(a1,EXTRACT(a2),a3); \
|
| +}
|
| +
|
| +#define GL_SAME_METHOD_4(glname, name, t1, t2, t3, t4) \
|
| +void GRAPHICS_CONTEXT_NAME::##name(t1 a1, t2 a2, t3 a3, t4 a4) \
|
| +{ \
|
| + makeContextCurrent(); gl##glname(a1,a2,a3,a4); \
|
| +}
|
| +
|
| +#define GL_SAME_METHOD_4_X4(glname, name, t1, t2, t3, t4) \
|
| +void GRAPHICS_CONTEXT_NAME::##name(t1 a1, t2 a2, t3 a3, t4 a4) \
|
| +{ \
|
| + makeContextCurrent(); gl##glname(a1,a2,a3,EXTRACT(a4)); \
|
| +}
|
| +
|
| +#define GL_SAME_METHOD_5(glname, name, t1, t2, t3, t4, t5) \
|
| +void GRAPHICS_CONTEXT_NAME::##name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5) \
|
| +{ \
|
| + makeContextCurrent(); gl##glname(a1,a2,a3,a4,a5); \
|
| +}
|
| +
|
| +#define GL_SAME_METHOD_5_X4(glname, name, t1, t2, t3, t4, t5) \
|
| +void GRAPHICS_CONTEXT_NAME::##name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5) \
|
| +{ \
|
| + makeContextCurrent(); gl##glname(a1,a2,a3,EXTRACT(a4),a5); \
|
| +}
|
| +
|
| +#define GL_SAME_METHOD_6(glname, name, t1, t2, t3, t4, t5, t6) \
|
| +void GRAPHICS_CONTEXT_NAME::##name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6) \
|
| +{ \
|
| + makeContextCurrent(); gl##glname(a1,a2,a3,a4,a5,a6); \
|
| +}
|
| +
|
| +#define GL_SAME_METHOD_8(glname, name, t1, t2, t3, t4, t5, t6, t7, t8) \
|
| +void GRAPHICS_CONTEXT_NAME::##name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6, t7 a7, t8 a8) \
|
| +{ \
|
| + makeContextCurrent(); gl##glname(a1,a2,a3,a4,a5,a6,a7,a8); \
|
| +}
|
| +
|
| +GraphicsContext3D::GraphicsContext3D()
|
| + : m_currentWidth(0)
|
| + , m_currentHeight(0)
|
| + , m_internal(new GraphicsContext3DInternal())
|
| +{
|
| +}
|
| +
|
| +GraphicsContext3D::~GraphicsContext3D()
|
| +{
|
| +}
|
| +
|
| +PlatformGraphicsContext3D GraphicsContext3D::platformGraphicsContext3D() const
|
| +{
|
| + return m_internal->platformGraphicsContext3D();
|
| +}
|
| +
|
| +Platform3DObject GraphicsContext3D::platformTexture() const
|
| +{
|
| + return m_internal->platformTexture();
|
| +}
|
| +
|
| +void GraphicsContext3D::checkError() const
|
| +{
|
| + m_internal->checkError();
|
| +}
|
| +
|
| +void GraphicsContext3D::makeContextCurrent()
|
| +{
|
| + m_internal->makeContextCurrent();
|
| +}
|
| +
|
| +void GraphicsContext3D::reshape(int width, int height)
|
| +{
|
| + if (width == m_currentWidth && height == m_currentHeight)
|
| + return;
|
| +
|
| + m_currentWidth = width;
|
| + m_currentHeight = height;
|
| +
|
| + m_internal->reshape(width, height);
|
| +}
|
| +
|
| +void GraphicsContext3D::beginPaint(CanvasRenderingContext3D* context)
|
| +{
|
| + m_internal->beginPaint(context);
|
| +}
|
| +
|
| +void GraphicsContext3D::endPaint()
|
| +{
|
| +}
|
| +
|
| +int GraphicsContext3D::sizeInBytes(int type)
|
| +{
|
| + switch (type) {
|
| + case GL_BYTE:
|
| + return sizeof(GLbyte);
|
| + case GL_UNSIGNED_BYTE:
|
| + return sizeof(GLubyte);
|
| + case GL_SHORT:
|
| + return sizeof(GLshort);
|
| + case GL_UNSIGNED_SHORT:
|
| + return sizeof(GLushort);
|
| + case GL_INT:
|
| + return sizeof(GLint);
|
| + case GL_UNSIGNED_INT:
|
| + return sizeof(GLuint);
|
| + case GL_FLOAT:
|
| + return sizeof(GLfloat);
|
| + default:
|
| + return 0;
|
| + }
|
| +}
|
| +
|
| +unsigned GraphicsContext3D::createBuffer()
|
| +{
|
| + makeContextCurrent();
|
| + GLuint o;
|
| + glGenBuffers(1, &o);
|
| + return o;
|
| +}
|
| +
|
| +unsigned GraphicsContext3D::createFramebuffer()
|
| +{
|
| + makeContextCurrent();
|
| + GLuint o;
|
| + glGenFramebuffers(1, &o);
|
| + return o;
|
| +}
|
| +
|
| +unsigned GraphicsContext3D::createProgram()
|
| +{
|
| + makeContextCurrent();
|
| + return glCreateProgram();
|
| +}
|
| +
|
| +unsigned GraphicsContext3D::createRenderbuffer()
|
| +{
|
| + makeContextCurrent();
|
| + GLuint o;
|
| + glGenRenderbuffers(1, &o);
|
| + return o;
|
| +}
|
| +
|
| +unsigned GraphicsContext3D::createShader(ShaderType type)
|
| +{
|
| + makeContextCurrent();
|
| + return glCreateShader((type == FRAGMENT_SHADER) ? GL_FRAGMENT_SHADER : GL_VERTEX_SHADER);
|
| +}
|
| +
|
| +unsigned GraphicsContext3D::createTexture()
|
| +{
|
| + makeContextCurrent();
|
| + GLuint o;
|
| + glGenTextures(1, &o);
|
| + return o;
|
| +}
|
| +
|
| +void GraphicsContext3D::deleteBuffer(unsigned buffer)
|
| +{
|
| + makeContextCurrent();
|
| + glDeleteBuffers(1, &buffer);
|
| +}
|
| +
|
| +void GraphicsContext3D::deleteFramebuffer(unsigned framebuffer)
|
| +{
|
| + makeContextCurrent();
|
| + glDeleteFramebuffers(1, &framebuffer);
|
| +}
|
| +
|
| +void GraphicsContext3D::deleteProgram(unsigned program)
|
| +{
|
| + makeContextCurrent();
|
| + glDeleteProgram(program);
|
| +}
|
| +
|
| +void GraphicsContext3D::deleteRenderbuffer(unsigned renderbuffer)
|
| +{
|
| + makeContextCurrent();
|
| + glDeleteRenderbuffers(1, &renderbuffer);
|
| +}
|
| +
|
| +void GraphicsContext3D::deleteShader(unsigned shader)
|
| +{
|
| + makeContextCurrent();
|
| + glDeleteShader(shader);
|
| +}
|
| +
|
| +void GraphicsContext3D::deleteTexture(unsigned texture)
|
| +{
|
| + makeContextCurrent();
|
| + glDeleteTextures(1, &texture);
|
| +}
|
| +
|
| +void GraphicsContext3D::activeTexture(unsigned long texture)
|
| +{
|
| + m_internal->activeTexture(texture);
|
| +}
|
| +
|
| +GL_SAME_METHOD_2_X12(AttachShader, attachShader, CanvasProgram*, CanvasShader*)
|
| +
|
| +void GraphicsContext3D::bindAttribLocation(CanvasProgram* program,
|
| + unsigned long index,
|
| + const String& name)
|
| +{
|
| + if (!program)
|
| + return;
|
| + makeContextCurrent();
|
| + glBindAttribLocation(EXTRACT(program), index, name.utf8().data());
|
| +}
|
| +
|
| +void GraphicsContext3D::bindBuffer(unsigned long target,
|
| + CanvasBuffer* buffer)
|
| +{
|
| + m_internal->bindBuffer(target, buffer);
|
| +}
|
| +
|
| +GL_SAME_METHOD_2_X2(BindFramebuffer, bindFramebuffer, unsigned long, CanvasFramebuffer*)
|
| +
|
| +GL_SAME_METHOD_2_X2(BindRenderbuffer, bindRenderbuffer, unsigned long, CanvasRenderbuffer*)
|
| +
|
| +// If we didn't have to hack GL_TEXTURE_WRAP_R for cube maps,
|
| +// we could just use:
|
| +// GL_SAME_METHOD_2_X2(BindTexture, bindTexture, unsigned long, CanvasTexture*)
|
| +void GraphicsContext3D::bindTexture(unsigned long target,
|
| + CanvasTexture* texture)
|
| +{
|
| + m_internal->bindTexture(target, texture);
|
| +}
|
| +
|
| +GL_SAME_METHOD_4(BlendColor, blendColor, double, double, double, double)
|
| +
|
| +GL_SAME_METHOD_1(BlendEquation, blendEquation, unsigned long)
|
| +
|
| +GL_SAME_METHOD_2(BlendEquationSeparate, blendEquationSeparate, unsigned long, unsigned long)
|
| +
|
| +GL_SAME_METHOD_2(BlendFunc, blendFunc, unsigned long, unsigned long)
|
| +
|
| +GL_SAME_METHOD_4(BlendFuncSeparate, blendFuncSeparate, unsigned long, unsigned long, unsigned long, unsigned long)
|
| +
|
| +void GraphicsContext3D::bufferData(unsigned long target, int size, unsigned long usage)
|
| +{
|
| + m_internal->bufferDataImpl(target, size, NULL, usage);
|
| +}
|
| +
|
| +void GraphicsContext3D::bufferData(unsigned long target, CanvasArray* array, unsigned long usage)
|
| +{
|
| + m_internal->bufferDataImpl(target, array->sizeInBytes(), array->baseAddress(), usage);
|
| +}
|
| +
|
| +void GraphicsContext3D::bufferSubData(unsigned long target, long offset, CanvasArray* array)
|
| +{
|
| + if (!array || !array->length())
|
| + return;
|
| +
|
| + makeContextCurrent();
|
| + // FIXME: make this verification more efficient.
|
| + GLint binding = 0;
|
| + GLenum binding_target = GL_ARRAY_BUFFER_BINDING;
|
| + if (target == GL_ELEMENT_ARRAY_BUFFER)
|
| + binding_target = GL_ELEMENT_ARRAY_BUFFER_BINDING;
|
| + glGetIntegerv(binding_target, &binding);
|
| + if (binding <= 0) {
|
| + // FIXME: raise exception.
|
| + // LogMessagef(("bufferSubData: no buffer bound"));
|
| + return;
|
| + }
|
| + glBufferSubData(target, offset, array->sizeInBytes(), array->baseAddress());
|
| +}
|
| +
|
| +unsigned long GraphicsContext3D::checkFramebufferStatus(unsigned long target)
|
| +{
|
| + makeContextCurrent();
|
| + return glCheckFramebufferStatus(target);
|
| +}
|
| +
|
| +GL_SAME_METHOD_1(Clear, clear, unsigned long)
|
| +
|
| +GL_SAME_METHOD_4(ClearColor, clearColor, double, double, double, double)
|
| +
|
| +GL_SAME_METHOD_1(ClearDepth, clearDepth, double)
|
| +
|
| +GL_SAME_METHOD_1(ClearStencil, clearStencil, long)
|
| +
|
| +void GraphicsContext3D::colorMask(bool red, bool green, bool blue, bool alpha)
|
| +{
|
| + m_internal->colorMask(red, green, blue, alpha);
|
| +}
|
| +
|
| +GL_SAME_METHOD_1_X(CompileShader, compileShader, CanvasShader*)
|
| +
|
| +GL_SAME_METHOD_8(CopyTexImage2D, copyTexImage2D, unsigned long, long, unsigned long, long, long, unsigned long, unsigned long, long)
|
| +
|
| +GL_SAME_METHOD_8(CopyTexSubImage2D, copyTexSubImage2D, unsigned long, long, long, long, long, long, unsigned long, unsigned long)
|
| +
|
| +GL_SAME_METHOD_1(CullFace, cullFace, unsigned long)
|
| +
|
| +GL_SAME_METHOD_1(DepthFunc, depthFunc, unsigned long)
|
| +
|
| +void GraphicsContext3D::depthMask(bool flag)
|
| +{
|
| + m_internal->depthMask(flag);
|
| +}
|
| +
|
| +GL_SAME_METHOD_2(DepthRange, depthRange, double, double)
|
| +
|
| +void GraphicsContext3D::detachShader(CanvasProgram* program, CanvasShader* shader)
|
| +{
|
| + if (!program || !shader)
|
| + return;
|
| +
|
| + makeContextCurrent();
|
| + glDetachShader(EXTRACT(program), EXTRACT(shader));
|
| +}
|
| +
|
| +void GraphicsContext3D::disable(unsigned long cap)
|
| +{
|
| + m_internal->disable(cap);
|
| +}
|
| +
|
| +void GraphicsContext3D::disableVertexAttribArray(unsigned long index)
|
| +{
|
| + m_internal->disableVertexAttribArray(index);
|
| +}
|
| +
|
| +void GraphicsContext3D::drawArrays(unsigned long mode, long first, long count)
|
| +{
|
| + switch (mode) {
|
| + case GL_TRIANGLES:
|
| + case GL_TRIANGLE_STRIP:
|
| + case GL_TRIANGLE_FAN:
|
| + case GL_POINTS:
|
| + case GL_LINE_STRIP:
|
| + case GL_LINE_LOOP:
|
| + case GL_LINES:
|
| + break;
|
| + default:
|
| + // FIXME: output log message, raise exception.
|
| + // LogMessage(NS_LITERAL_CSTRING("drawArrays: invalid mode"));
|
| + // return NS_ERROR_DOM_SYNTAX_ERR;
|
| + return;
|
| + }
|
| +
|
| + if (first+count < first || first+count < count) {
|
| + // FIXME: output log message, raise exception.
|
| + // LogMessage(NS_LITERAL_CSTRING("drawArrays: overflow in first+count"));
|
| + // return NS_ERROR_INVALID_ARG;
|
| + return;
|
| + }
|
| +
|
| + // FIXME: validate against currently bound buffer.
|
| + // if (!ValidateBuffers(first+count))
|
| + // return NS_ERROR_INVALID_ARG;
|
| +
|
| + makeContextCurrent();
|
| + glDrawArrays(mode, first, count);
|
| +}
|
| +
|
| +void GraphicsContext3D::drawElements(unsigned long mode, unsigned long count, unsigned long type, long offset)
|
| +{
|
| + makeContextCurrent();
|
| + // FIXME: make this verification more efficient.
|
| + GLint binding = 0;
|
| + GLenum binding_target = GL_ELEMENT_ARRAY_BUFFER_BINDING;
|
| + glGetIntegerv(binding_target, &binding);
|
| + if (binding <= 0) {
|
| + // FIXME: raise exception.
|
| + // LogMessagef(("bufferData: no buffer bound"));
|
| + return;
|
| + }
|
| + glDrawElements(mode, count, type,
|
| + reinterpret_cast<void*>(static_cast<intptr_t>(offset)));
|
| +}
|
| +
|
| +void GraphicsContext3D::enable(unsigned long cap)
|
| +{
|
| + m_internal->enable(cap);
|
| +}
|
| +
|
| +void GraphicsContext3D::enableVertexAttribArray(unsigned long index)
|
| +{
|
| + m_internal->enableVertexAttribArray(index);
|
| +}
|
| +
|
| +GL_SAME_METHOD_0(Finish, finish)
|
| +
|
| +GL_SAME_METHOD_0(Flush, flush)
|
| +
|
| +GL_SAME_METHOD_4_X4(FramebufferRenderbuffer, framebufferRenderbuffer, unsigned long, unsigned long, unsigned long, CanvasRenderbuffer*)
|
| +
|
| +GL_SAME_METHOD_5_X4(FramebufferTexture2D, framebufferTexture2D, unsigned long, unsigned long, unsigned long, CanvasTexture*, long)
|
| +
|
| +GL_SAME_METHOD_1(FrontFace, frontFace, unsigned long)
|
| +
|
| +void GraphicsContext3D::generateMipmap(unsigned long target)
|
| +{
|
| + makeContextCurrent();
|
| + if (glGenerateMipmapEXT) {
|
| + glGenerateMipmapEXT(target);
|
| + }
|
| + // FIXME: provide alternative code path? This will be unpleasant
|
| + // to implement if glGenerateMipmapEXT is not available -- it will
|
| + // require a texture readback and re-upload.
|
| +}
|
| +
|
| +int GraphicsContext3D::getAttribLocation(CanvasProgram* program, const String& name)
|
| +{
|
| + if (!program)
|
| + return -1;
|
| +
|
| + makeContextCurrent();
|
| + return glGetAttribLocation(EXTRACT(program), name.utf8().data());
|
| +}
|
| +
|
| +bool GraphicsContext3D::getBoolean(unsigned long pname)
|
| +{
|
| + makeContextCurrent();
|
| + GLboolean val;
|
| + // FIXME: validate pname to ensure it returns only a single value.
|
| + glGetBooleanv(pname, &val);
|
| + return static_cast<bool>(val);
|
| +}
|
| +
|
| +PassRefPtr<CanvasUnsignedByteArray> GraphicsContext3D::getBooleanv(unsigned long pname)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return NULL;
|
| +}
|
| +
|
| +int GraphicsContext3D::getBufferParameteri(unsigned long target, unsigned long pname)
|
| +{
|
| + makeContextCurrent();
|
| + GLint data;
|
| + glGetBufferParameteriv(target, pname, &data);
|
| + return static_cast<int>(data);
|
| +}
|
| +
|
| +PassRefPtr<CanvasIntArray> GraphicsContext3D::getBufferParameteriv(unsigned long target, unsigned long pname)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return NULL;
|
| +}
|
| +
|
| +unsigned long GraphicsContext3D::getError()
|
| +{
|
| + makeContextCurrent();
|
| + return glGetError();
|
| +}
|
| +
|
| +float GraphicsContext3D::getFloat(unsigned long pname)
|
| +{
|
| + makeContextCurrent();
|
| + GLfloat val;
|
| + // FIXME: validate pname to ensure it returns only a single value.
|
| + glGetFloatv(pname, &val);
|
| + return static_cast<float>(val);
|
| +}
|
| +
|
| +PassRefPtr<CanvasFloatArray> GraphicsContext3D::getFloatv(unsigned long pname)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return NULL;
|
| +}
|
| +
|
| +int GraphicsContext3D::getFramebufferAttachmentParameteri(unsigned long target,
|
| + unsigned long attachment,
|
| + unsigned long pname)
|
| +{
|
| + makeContextCurrent();
|
| + GLint data;
|
| + glGetFramebufferAttachmentParameteriv(target, attachment, pname, &data);
|
| + return static_cast<int>(data);
|
| +}
|
| +
|
| +PassRefPtr<CanvasIntArray> GraphicsContext3D::getFramebufferAttachmentParameteriv(unsigned long target,
|
| + unsigned long attachment,
|
| + unsigned long pname)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return NULL;
|
| +}
|
| +
|
| +int GraphicsContext3D::getInteger(unsigned long pname)
|
| +{
|
| + makeContextCurrent();
|
| + GLint val;
|
| + // FIXME: validate pname to ensure it returns only a single value.
|
| + glGetIntegerv(pname, &val);
|
| + return static_cast<int>(val);
|
| +}
|
| +
|
| +PassRefPtr<CanvasIntArray> GraphicsContext3D::getIntegerv(unsigned long pname)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return NULL;
|
| +}
|
| +
|
| +int GraphicsContext3D::getProgrami(CanvasProgram* program,
|
| + unsigned long pname)
|
| +{
|
| + makeContextCurrent();
|
| + GLint param;
|
| + glGetProgramiv(EXTRACT(program), pname, ¶m);
|
| + return static_cast<int>(param);
|
| +}
|
| +
|
| +PassRefPtr<CanvasIntArray> GraphicsContext3D::getProgramiv(CanvasProgram* program,
|
| + unsigned long pname)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return NULL;
|
| +}
|
| +
|
| +String GraphicsContext3D::getProgramInfoLog(CanvasProgram* program)
|
| +{
|
| + makeContextCurrent();
|
| + GLuint programID = EXTRACT(program);
|
| + GLint logLength;
|
| + glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &logLength);
|
| + if (logLength == 0)
|
| + return String();
|
| + GLchar* log = NULL;
|
| + if (!tryFastMalloc(logLength * sizeof(GLchar)).getValue(log))
|
| + return String();
|
| + GLsizei returnedLogLength;
|
| + glGetProgramInfoLog(programID, logLength, &returnedLogLength, log);
|
| + ASSERT(logLength == returnedLogLength + 1);
|
| + String res = String::fromUTF8(log, returnedLogLength);
|
| + fastFree(log);
|
| + return res;
|
| +}
|
| +
|
| +int GraphicsContext3D::getRenderbufferParameteri(unsigned long target,
|
| + unsigned long pname)
|
| +{
|
| + makeContextCurrent();
|
| + GLint param;
|
| + glGetRenderbufferParameteriv(target, pname, ¶m);
|
| + return static_cast<int>(param);
|
| +}
|
| +
|
| +PassRefPtr<CanvasIntArray> GraphicsContext3D::getRenderbufferParameteriv(unsigned long target,
|
| + unsigned long pname)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return NULL;
|
| +}
|
| +
|
| +int GraphicsContext3D::getShaderi(CanvasShader* shader,
|
| + unsigned long pname)
|
| +{
|
| + makeContextCurrent();
|
| + GLint param;
|
| + glGetShaderiv(EXTRACT(shader), pname, ¶m);
|
| + return static_cast<int>(param);
|
| +}
|
| +
|
| +PassRefPtr<CanvasIntArray> GraphicsContext3D::getShaderiv(CanvasShader* shader,
|
| + unsigned long pname)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return NULL;
|
| +}
|
| +
|
| +String GraphicsContext3D::getShaderInfoLog(CanvasShader* shader)
|
| +{
|
| + makeContextCurrent();
|
| + GLuint shaderID = EXTRACT(shader);
|
| + GLint logLength;
|
| + glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &logLength);
|
| + if (logLength == 0)
|
| + return String();
|
| + GLchar* log = NULL;
|
| + if (!tryFastMalloc(logLength * sizeof(GLchar)).getValue(log))
|
| + return String();
|
| + GLsizei returnedLogLength;
|
| + glGetShaderInfoLog(shaderID, logLength, &returnedLogLength, log);
|
| + ASSERT(logLength == returnedLogLength + 1);
|
| + String res = String::fromUTF8(log, returnedLogLength);
|
| + fastFree(log);
|
| + return res;
|
| +}
|
| +
|
| +String GraphicsContext3D::getShaderSource(CanvasShader* shader)
|
| +{
|
| + makeContextCurrent();
|
| + GLuint shaderID = EXTRACT(shader);
|
| + GLint logLength;
|
| + glGetShaderiv(shaderID, GL_SHADER_SOURCE_LENGTH, &logLength);
|
| + if (logLength == 0)
|
| + return String();
|
| + GLchar* log = NULL;
|
| + if (!tryFastMalloc(logLength * sizeof(GLchar)).getValue(log))
|
| + return String();
|
| + GLsizei returnedLogLength;
|
| + glGetShaderSource(shaderID, logLength, &returnedLogLength, log);
|
| + ASSERT(logLength == returnedLogLength + 1);
|
| + String res = String::fromUTF8(log, returnedLogLength);
|
| + fastFree(log);
|
| + return res;
|
| +}
|
| +
|
| +String GraphicsContext3D::getString(unsigned long name)
|
| +{
|
| + makeContextCurrent();
|
| + return String::fromUTF8(reinterpret_cast<const char*>(glGetString(name)));
|
| +}
|
| +
|
| +float GraphicsContext3D::getTexParameterf(unsigned long target, unsigned long pname)
|
| +{
|
| + makeContextCurrent();
|
| + if (!m_internal->validateTextureTarget(target)) {
|
| + // FIXME: throw exception.
|
| + return 0;
|
| + }
|
| +
|
| + if (!m_internal->validateTextureParameter(pname)) {
|
| + // FIXME: throw exception.
|
| + return 0;
|
| + }
|
| +
|
| + GLfloat param;
|
| + glGetTexParameterfv(target, pname, ¶m);
|
| + return static_cast<float>(param);
|
| +}
|
| +
|
| +PassRefPtr<CanvasFloatArray> GraphicsContext3D::getTexParameterfv(unsigned long target, unsigned long pname)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return NULL;
|
| +}
|
| +
|
| +int GraphicsContext3D::getTexParameteri(unsigned long target, unsigned long pname)
|
| +{
|
| + makeContextCurrent();
|
| + if (!m_internal->validateTextureTarget(target)) {
|
| + // FIXME: throw exception.
|
| + return 0;
|
| + }
|
| +
|
| + if (!m_internal->validateTextureParameter(pname)) {
|
| + // FIXME: throw exception.
|
| + return 0;
|
| + }
|
| +
|
| + GLint param;
|
| + glGetTexParameteriv(target, pname, ¶m);
|
| + return static_cast<int>(param);
|
| +}
|
| +
|
| +PassRefPtr<CanvasIntArray> GraphicsContext3D::getTexParameteriv(unsigned long target, unsigned long pname)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return NULL;
|
| +}
|
| +
|
| +float GraphicsContext3D::getUniformf(CanvasProgram* program, long location)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return 0;
|
| +}
|
| +
|
| +PassRefPtr<CanvasFloatArray> GraphicsContext3D::getUniformfv(CanvasProgram* program, long location)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return NULL;
|
| +}
|
| +
|
| +int GraphicsContext3D::getUniformi(CanvasProgram* program, long location)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return 0;
|
| +}
|
| +
|
| +PassRefPtr<CanvasIntArray> GraphicsContext3D::getUniformiv(CanvasProgram* program, long location)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return NULL;
|
| +}
|
| +
|
| +long GraphicsContext3D::getUniformLocation(CanvasProgram* program, const String& name)
|
| +{
|
| + if (!program)
|
| + return -1;
|
| +
|
| + makeContextCurrent();
|
| + return glGetUniformLocation(EXTRACT(program), name.utf8().data());
|
| +}
|
| +
|
| +float GraphicsContext3D::getVertexAttribf(unsigned long index,
|
| + unsigned long pname)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return 0;
|
| +}
|
| +
|
| +PassRefPtr<CanvasFloatArray> GraphicsContext3D::getVertexAttribfv(unsigned long index,
|
| + unsigned long pname)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return NULL;
|
| +}
|
| +
|
| +int GraphicsContext3D::getVertexAttribi(unsigned long index,
|
| + unsigned long pname)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return NULL;
|
| +}
|
| +
|
| +PassRefPtr<CanvasIntArray> GraphicsContext3D::getVertexAttribiv(unsigned long index,
|
| + unsigned long pname)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return NULL;
|
| +}
|
| +
|
| +long GraphicsContext3D::getVertexAttribOffset(unsigned long index, unsigned long pname)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return 0;
|
| +}
|
| +
|
| +GL_SAME_METHOD_2(Hint, hint, unsigned long, unsigned long);
|
| +
|
| +bool GraphicsContext3D::isBuffer(CanvasBuffer* buffer)
|
| +{
|
| + makeContextCurrent();
|
| + return glIsBuffer(EXTRACT(buffer));
|
| +}
|
| +
|
| +bool GraphicsContext3D::isEnabled(unsigned long cap)
|
| +{
|
| + makeContextCurrent();
|
| + return glIsEnabled(cap);
|
| +}
|
| +
|
| +bool GraphicsContext3D::isFramebuffer(CanvasFramebuffer* framebuffer)
|
| +{
|
| + makeContextCurrent();
|
| + return glIsFramebuffer(EXTRACT(framebuffer));
|
| +}
|
| +
|
| +bool GraphicsContext3D::isProgram(CanvasProgram* program)
|
| +{
|
| + makeContextCurrent();
|
| + return glIsProgram(EXTRACT(program));
|
| +}
|
| +
|
| +bool GraphicsContext3D::isRenderbuffer(CanvasRenderbuffer* renderbuffer)
|
| +{
|
| + makeContextCurrent();
|
| + return glIsRenderbuffer(EXTRACT(renderbuffer));
|
| +}
|
| +
|
| +bool GraphicsContext3D::isShader(CanvasShader* shader)
|
| +{
|
| + makeContextCurrent();
|
| + return glIsShader(EXTRACT(shader));
|
| +}
|
| +
|
| +bool GraphicsContext3D::isTexture(CanvasTexture* texture)
|
| +{
|
| + makeContextCurrent();
|
| + return glIsTexture(EXTRACT(texture));
|
| +}
|
| +
|
| +GL_SAME_METHOD_1(LineWidth, lineWidth, double)
|
| +
|
| +GL_SAME_METHOD_1_X(LinkProgram, linkProgram, CanvasProgram*)
|
| +
|
| +void GraphicsContext3D::pixelStorei(unsigned long pname, long param)
|
| +{
|
| + if (pname != GL_PACK_ALIGNMENT &&
|
| + pname != GL_UNPACK_ALIGNMENT) {
|
| + // FIXME: force fake GL error to be produced and throw
|
| + // exception.
|
| + return;
|
| + }
|
| +
|
| + makeContextCurrent();
|
| + glPixelStorei(pname, param);
|
| +}
|
| +
|
| +GL_SAME_METHOD_2(PolygonOffset, polygonOffset, double, double)
|
| +
|
| +void GraphicsContext3D::releaseShaderCompiler()
|
| +{
|
| +}
|
| +
|
| +GL_SAME_METHOD_4(RenderbufferStorage, renderbufferStorage, unsigned long, unsigned long, unsigned long, unsigned long)
|
| +
|
| +GL_SAME_METHOD_2(SampleCoverage, sampleCoverage, double, bool)
|
| +
|
| +GL_SAME_METHOD_4(Scissor, scissor, long, long, unsigned long, unsigned long)
|
| +
|
| +void GraphicsContext3D::shaderSource(CanvasShader* shader, const String& source)
|
| +{
|
| + makeContextCurrent();
|
| + CString str = source.utf8();
|
| + const char* data = str.data();
|
| + GLint length = str.length();
|
| + glShaderSource(EXTRACT(shader), 1, &data, &length);
|
| +}
|
| +
|
| +GL_SAME_METHOD_3(StencilFunc, stencilFunc, unsigned long, long, unsigned long)
|
| +
|
| +GL_SAME_METHOD_4(StencilFuncSeparate, stencilFuncSeparate, unsigned long, unsigned long, long, unsigned long)
|
| +
|
| +GL_SAME_METHOD_1(StencilMask, stencilMask, unsigned long)
|
| +
|
| +GL_SAME_METHOD_2(StencilMaskSeparate, stencilMaskSeparate, unsigned long, unsigned long)
|
| +
|
| +GL_SAME_METHOD_3(StencilOp, stencilOp, unsigned long, unsigned long, unsigned long)
|
| +
|
| +GL_SAME_METHOD_4(StencilOpSeparate, stencilOpSeparate, unsigned long, unsigned long, unsigned long, unsigned long)
|
| +
|
| +int GraphicsContext3D::texImage2D(unsigned target,
|
| + unsigned level,
|
| + unsigned internalformat,
|
| + unsigned width,
|
| + unsigned height,
|
| + unsigned border,
|
| + unsigned format,
|
| + unsigned type,
|
| + CanvasArray* pixels)
|
| +{
|
| + // FIXME: must do validation similar to JOGL's to ensure that
|
| + // the incoming array is of the appropriate length.
|
| + glTexImage2D(target,
|
| + level,
|
| + internalformat,
|
| + width,
|
| + height,
|
| + border,
|
| + format,
|
| + type,
|
| + pixels->baseAddress());
|
| + return 0;
|
| +}
|
| +
|
| +int GraphicsContext3D::texImage2D(unsigned target,
|
| + unsigned level,
|
| + unsigned internalformat,
|
| + unsigned width,
|
| + unsigned height,
|
| + unsigned border,
|
| + unsigned format,
|
| + unsigned type,
|
| + ImageData* pixels)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return -1;
|
| +}
|
| +
|
| +// Remove premultiplied alpha from color channels.
|
| +// FIXME: this is lossy. Must retrieve original values from HTMLImageElement.
|
| +static void unmultiplyAlpha(unsigned char* rgbaData, int numPixels)
|
| +{
|
| + for (int j = 0; j < numPixels; j++) {
|
| + float b = rgbaData[4*j+0] / 255.0f;
|
| + float g = rgbaData[4*j+1] / 255.0f;
|
| + float r = rgbaData[4*j+2] / 255.0f;
|
| + float a = rgbaData[4*j+3] / 255.0f;
|
| + if (a > 0.0f) {
|
| + b /= a;
|
| + g /= a;
|
| + r /= a;
|
| + b = (b > 1.0f) ? 1.0f : b;
|
| + g = (g > 1.0f) ? 1.0f : g;
|
| + r = (r > 1.0f) ? 1.0f : r;
|
| + rgbaData[4*j+0] = (unsigned char) (b * 255.0f);
|
| + rgbaData[4*j+1] = (unsigned char) (g * 255.0f);
|
| + rgbaData[4*j+2] = (unsigned char) (r * 255.0f);
|
| + }
|
| + }
|
| +}
|
| +
|
| +int GraphicsContext3D::texImage2D(unsigned target, unsigned level, HTMLImageElement* image,
|
| + bool flipY, bool premultiplyAlpha)
|
| +{
|
| + CachedImage* cachedImage = image->cachedImage();
|
| + if (cachedImage == NULL) {
|
| + ASSERT_NOT_REACHED();
|
| + return -1;
|
| + }
|
| + Image* img = cachedImage->image();
|
| + NativeImageSkia* skiaImage = img->nativeImageForCurrentFrame();
|
| + if (skiaImage == NULL) {
|
| + ASSERT_NOT_REACHED();
|
| + return -1;
|
| + }
|
| + SkBitmap::Config skiaConfig = skiaImage->config();
|
| + // FIXME: must support more image configurations.
|
| + if (skiaConfig != SkBitmap::kARGB_8888_Config) {
|
| + ASSERT_NOT_REACHED();
|
| + return -1;
|
| + }
|
| + SkBitmap& skiaImageRef = *skiaImage;
|
| + SkAutoLockPixels lock(skiaImageRef);
|
| + int width = skiaImage->width();
|
| + int height = skiaImage->height();
|
| + if (flipY) {
|
| + // Need to flip images vertically. To avoid making a copy of
|
| + // the entire image, we perform a ton of glTexSubImage2D
|
| + // calls. FIXME: should rethink this strategy for efficiency.
|
| + glTexImage2D(target, level, GL_RGBA8,
|
| + width,
|
| + height,
|
| + 0,
|
| + GL_BGRA,
|
| + GL_UNSIGNED_BYTE,
|
| + NULL);
|
| + unsigned char* pixels =
|
| + reinterpret_cast<unsigned char*>(skiaImage->getPixels());
|
| + int rowBytes = skiaImage->rowBytes();
|
| +
|
| + unsigned char* row = NULL;
|
| + bool allocatedRow = false;
|
| + if (!premultiplyAlpha) {
|
| + row = new unsigned char[rowBytes];
|
| + allocatedRow = true;
|
| + }
|
| + for (int i = 0; i < height; i++) {
|
| + if (premultiplyAlpha)
|
| + row = pixels + (rowBytes * i);
|
| + else {
|
| + memcpy(row, pixels + (rowBytes * i), rowBytes);
|
| + unmultiplyAlpha(row, width);
|
| + }
|
| + glTexSubImage2D(target, level, 0, height - i - 1,
|
| + width, 1,
|
| + GL_BGRA,
|
| + GL_UNSIGNED_BYTE,
|
| + row);
|
| + }
|
| + if (allocatedRow)
|
| + delete[] row;
|
| + } else {
|
| + // The pixels of cube maps' faces are defined with a top-down
|
| + // scanline ordering, unlike GL_TEXTURE_2D, so when uploading
|
| + // these, the above vertical flip is the wrong thing to do.
|
| + if (premultiplyAlpha)
|
| + glTexImage2D(target, level, GL_RGBA8,
|
| + width,
|
| + height,
|
| + 0,
|
| + GL_BGRA,
|
| + GL_UNSIGNED_BYTE,
|
| + skiaImage->getPixels());
|
| + else {
|
| + glTexImage2D(target, level, GL_RGBA8,
|
| + width,
|
| + height,
|
| + 0,
|
| + GL_BGRA,
|
| + GL_UNSIGNED_BYTE,
|
| + NULL);
|
| + unsigned char* pixels =
|
| + reinterpret_cast<unsigned char*>(skiaImage->getPixels());
|
| + int rowBytes = skiaImage->rowBytes();
|
| + unsigned char* row = new unsigned char[rowBytes];
|
| + for (int i = 0; i < height; i++) {
|
| + memcpy(row, pixels + (rowBytes * i), rowBytes);
|
| + unmultiplyAlpha(row, width);
|
| + glTexSubImage2D(target, level, 0, i,
|
| + width, 1,
|
| + GL_BGRA,
|
| + GL_UNSIGNED_BYTE,
|
| + row);
|
| + }
|
| + delete[] row;
|
| + }
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +int GraphicsContext3D::texImage2D(unsigned target, unsigned level, HTMLCanvasElement* canvas,
|
| + bool flipY, bool premultiplyAlpha)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return -1;
|
| +}
|
| +
|
| +int GraphicsContext3D::texImage2D(unsigned target, unsigned level, HTMLVideoElement* video,
|
| + bool flipY, bool premultiplyAlpha)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return -1;
|
| +}
|
| +
|
| +GL_SAME_METHOD_3(TexParameterf, texParameterf, unsigned, unsigned, float);
|
| +
|
| +GL_SAME_METHOD_3(TexParameteri, texParameteri, unsigned, unsigned, int);
|
| +
|
| +int GraphicsContext3D::texSubImage2D(unsigned target,
|
| + unsigned level,
|
| + unsigned xoffset,
|
| + unsigned yoffset,
|
| + unsigned width,
|
| + unsigned height,
|
| + unsigned format,
|
| + unsigned type,
|
| + CanvasArray* pixels)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return -1;
|
| +}
|
| +
|
| +int GraphicsContext3D::texSubImage2D(unsigned target,
|
| + unsigned level,
|
| + unsigned xoffset,
|
| + unsigned yoffset,
|
| + unsigned width,
|
| + unsigned height,
|
| + unsigned format,
|
| + unsigned type,
|
| + ImageData* pixels)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return -1;
|
| +}
|
| +
|
| +int GraphicsContext3D::texSubImage2D(unsigned target,
|
| + unsigned level,
|
| + unsigned xoffset,
|
| + unsigned yoffset,
|
| + unsigned width,
|
| + unsigned height,
|
| + HTMLImageElement* image,
|
| + bool flipY,
|
| + bool premultiplyAlpha)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return -1;
|
| +}
|
| +
|
| +int GraphicsContext3D::texSubImage2D(unsigned target,
|
| + unsigned level,
|
| + unsigned xoffset,
|
| + unsigned yoffset,
|
| + unsigned width,
|
| + unsigned height,
|
| + HTMLCanvasElement* canvas,
|
| + bool flipY,
|
| + bool premultiplyAlpha)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return -1;
|
| +}
|
| +
|
| +int GraphicsContext3D::texSubImage2D(unsigned target,
|
| + unsigned level,
|
| + unsigned xoffset,
|
| + unsigned yoffset,
|
| + unsigned width,
|
| + unsigned height,
|
| + HTMLVideoElement* video,
|
| + bool flipY,
|
| + bool premultiplyAlpha)
|
| +{
|
| + // FIXME: implement.
|
| + notImplemented();
|
| + return -1;
|
| +}
|
| +
|
| +GL_SAME_METHOD_2(Uniform1f, uniform1f, long, float)
|
| +
|
| +void GraphicsContext3D::uniform1fv(long location, float* v, int size)
|
| +{
|
| + makeContextCurrent();
|
| + glUniform1fv(location, size, v);
|
| +}
|
| +
|
| +GL_SAME_METHOD_2(Uniform1i, uniform1i, long, int)
|
| +
|
| +void GraphicsContext3D::uniform1iv(long location, int* v, int size)
|
| +{
|
| + makeContextCurrent();
|
| + glUniform1iv(location, size, v);
|
| +}
|
| +
|
| +GL_SAME_METHOD_3(Uniform2f, uniform2f, long, float, float)
|
| +
|
| +void GraphicsContext3D::uniform2fv(long location, float* v, int size)
|
| +{
|
| + makeContextCurrent();
|
| + glUniform2fv(location, size, v);
|
| +}
|
| +
|
| +GL_SAME_METHOD_3(Uniform2i, uniform2i, long, int, int)
|
| +
|
| +void GraphicsContext3D::uniform2iv(long location, int* v, int size)
|
| +{
|
| + makeContextCurrent();
|
| + glUniform2iv(location, size, v);
|
| +}
|
| +
|
| +GL_SAME_METHOD_4(Uniform3f, uniform3f, long, float, float, float)
|
| +
|
| +void GraphicsContext3D::uniform3fv(long location, float* v, int size)
|
| +{
|
| + makeContextCurrent();
|
| + glUniform3fv(location, size, v);
|
| +}
|
| +
|
| +GL_SAME_METHOD_4(Uniform3i, uniform3i, long, int, int, int)
|
| +
|
| +void GraphicsContext3D::uniform3iv(long location, int* v, int size)
|
| +{
|
| + makeContextCurrent();
|
| + glUniform3iv(location, size, v);
|
| +}
|
| +
|
| +GL_SAME_METHOD_5(Uniform4f, uniform4f, long, float, float, float, float)
|
| +
|
| +void GraphicsContext3D::uniform4fv(long location, float* v, int size)
|
| +{
|
| + makeContextCurrent();
|
| + glUniform4fv(location, size, v);
|
| +}
|
| +
|
| +GL_SAME_METHOD_5(Uniform4i, uniform4i, long, int, int, int, int)
|
| +
|
| +void GraphicsContext3D::uniform4iv(long location, int* v, int size)
|
| +{
|
| + makeContextCurrent();
|
| + glUniform4iv(location, size, v);
|
| +}
|
| +
|
| +void GraphicsContext3D::uniformMatrix2fv(long location, bool transpose, float* value, int size)
|
| +{
|
| + makeContextCurrent();
|
| + glUniformMatrix2fv(location, size, transpose, value);
|
| +}
|
| +
|
| +void GraphicsContext3D::uniformMatrix3fv(long location, bool transpose, float* value, int size)
|
| +{
|
| + makeContextCurrent();
|
| + glUniformMatrix3fv(location, size, transpose, value);
|
| +}
|
| +
|
| +void GraphicsContext3D::uniformMatrix4fv(long location, bool transpose, float* value, int size)
|
| +{
|
| + makeContextCurrent();
|
| + glUniformMatrix4fv(location, size, transpose, value);
|
| +}
|
| +
|
| +void GraphicsContext3D::useProgram(CanvasProgram* program)
|
| +{
|
| + m_internal->useProgram(program);
|
| +}
|
| +
|
| +GL_SAME_METHOD_1_X(ValidateProgram, validateProgram, CanvasProgram*)
|
| +
|
| +GL_SAME_METHOD_2(VertexAttrib1f, vertexAttrib1f, unsigned long, float)
|
| +
|
| +void GraphicsContext3D::vertexAttrib1fv(unsigned long indx, float* values)
|
| +{
|
| + makeContextCurrent();
|
| + glVertexAttrib1fv(indx, values);
|
| +}
|
| +
|
| +GL_SAME_METHOD_3(VertexAttrib2f, vertexAttrib2f, unsigned long, float, float)
|
| +
|
| +void GraphicsContext3D::vertexAttrib2fv(unsigned long indx, float* values)
|
| +{
|
| + makeContextCurrent();
|
| + glVertexAttrib2fv(indx, values);
|
| +}
|
| +
|
| +GL_SAME_METHOD_4(VertexAttrib3f, vertexAttrib3f, unsigned long, float, float, float)
|
| +
|
| +void GraphicsContext3D::vertexAttrib3fv(unsigned long indx, float* values)
|
| +{
|
| + makeContextCurrent();
|
| + glVertexAttrib3fv(indx, values);
|
| +}
|
| +
|
| +GL_SAME_METHOD_5(VertexAttrib4f, vertexAttrib4f, unsigned long, float, float, float, float)
|
| +
|
| +void GraphicsContext3D::vertexAttrib4fv(unsigned long indx, float* values)
|
| +{
|
| + makeContextCurrent();
|
| + glVertexAttrib4fv(indx, values);
|
| +}
|
| +
|
| +void GraphicsContext3D::vertexAttribPointer(unsigned long indx, int size, int type, bool normalized,
|
| + unsigned long stride, unsigned long offset)
|
| +{
|
| + m_internal->vertexAttribPointer(indx, size, type, normalized, stride, offset);
|
| +}
|
| +
|
| +void GraphicsContext3D::viewport(long x, long y, unsigned long width, unsigned long height)
|
| +{
|
| + makeContextCurrent();
|
| + m_internal->viewportImpl(x, y, width, height);
|
| +}
|
| +
|
| +}
|
| +
|
| +#endif // ENABLE(3D_CANVAS)
|
|
|
| Property changes on: webkit\api\src\GraphicsContext3D.cpp
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|