1/*
2 * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above
9 *    copyright notice, this list of conditions and the following
10 *    disclaimer.
11 * 2. Redistributions in binary form must reproduce the above
12 *    copyright notice, this list of conditions and the following
13 *    disclaimer in the documentation and/or other materials
14 *    provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
25 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
26 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include "config.h"
31
32#if ENABLE(CSS_SHADERS) && USE(3D_GRAPHICS)
33#include "CustomFilterMeshGenerator.h"
34
35namespace WebCore {
36
37#ifndef NDEBUG
38// Use "call 'WebCore::s_dumpCustomFilterMeshBuffers' = 1" in GDB to activate printing of the mesh buffers.
39static bool s_dumpCustomFilterMeshBuffers = false;
40#endif
41
42CustomFilterMeshGenerator::CustomFilterMeshGenerator(unsigned columns, unsigned rows, const FloatRect& meshBox, CustomFilterMeshType meshType)
43    : m_meshType(meshType)
44    , m_points(columns + 1, rows + 1)
45    , m_tiles(columns, rows)
46    , m_tileSizeInPixels(meshBox.width() / m_tiles.width(), meshBox.height() / m_tiles.height())
47    , m_tileSizeInDeviceSpace(1.0f / m_tiles.width(), 1.0f / m_tiles.height())
48    , m_meshBox(meshBox)
49{
50    // Build the two buffers needed to draw triangles:
51    // * m_vertices has a number of float attributes that will be passed to the vertex shader
52    // for each computed vertex. This number is calculated in floatsPerVertex() based on the meshType.
53    // * m_indices is a buffer that will have 3 indices per triangle. Each index will point inside
54    // the m_vertices buffer.
55    m_vertices.reserveCapacity(verticesCount() * floatsPerVertex());
56    m_indices.reserveCapacity(indicesCount());
57
58    // Based on the meshType there can be two types of meshes.
59    // * attached: each triangle uses vertices from the neighbor triangles. This is useful to save some GPU memory
60    // when there's no need to explode the tiles.
61    // * detached: each triangle has its own vertices. This means each triangle can be moved independently and a vec3
62    // attribute is passed, so that each vertex can be uniquely identified.
63    if (m_meshType == MeshTypeAttached)
64        generateAttachedMesh();
65    else
66        generateDetachedMesh();
67
68#ifndef NDEBUG
69    if (s_dumpCustomFilterMeshBuffers)
70        dumpBuffers();
71#endif
72}
73
74void CustomFilterMeshGenerator::addAttachedMeshIndex(int quadX, int quadY, int triangleX, int triangleY, int triangle)
75{
76    UNUSED_PARAM(triangle);
77    m_indices.append((quadY + triangleY) * m_points.width() + (quadX + triangleX));
78}
79
80void CustomFilterMeshGenerator::generateAttachedMesh()
81{
82    for (int j = 0; j < m_points.height(); ++j) {
83        for (int i = 0; i < m_points.width(); ++i)
84            addAttachedMeshVertexAttributes(i, j);
85    }
86
87    for (int j = 0; j < m_tiles.height(); ++j) {
88        for (int i = 0; i < m_tiles.width(); ++i)
89            addTile<&CustomFilterMeshGenerator::addAttachedMeshIndex>(i, j);
90    }
91}
92
93void CustomFilterMeshGenerator::addDetachedMeshVertexAndIndex(int quadX, int quadY, int triangleX, int triangleY, int triangle)
94{
95    addDetachedMeshVertexAttributes(quadX, quadY, triangleX, triangleY, triangle);
96    m_indices.append(m_indices.size());
97}
98
99void CustomFilterMeshGenerator::generateDetachedMesh()
100{
101    for (int j = 0; j < m_tiles.height(); ++j) {
102        for (int i = 0; i < m_tiles.width(); ++i)
103            addTile<&CustomFilterMeshGenerator::addDetachedMeshVertexAndIndex>(i, j);
104    }
105}
106
107void CustomFilterMeshGenerator::addPositionAttribute(int quadX, int quadY)
108{
109    // vec4 a_position
110    m_vertices.append(m_tileSizeInPixels.width() * quadX - 0.5f + m_meshBox.x());
111    m_vertices.append(m_tileSizeInPixels.height() * quadY - 0.5f + m_meshBox.y());
112    m_vertices.append(0.0f); // z
113    m_vertices.append(1.0f);
114}
115
116void CustomFilterMeshGenerator::addTexCoordAttribute(int quadX, int quadY)
117{
118    // vec2 a_texCoord
119    m_vertices.append(m_tileSizeInPixels.width() * quadX + m_meshBox.x());
120    m_vertices.append(m_tileSizeInPixels.height() * quadY + m_meshBox.y());
121}
122
123void CustomFilterMeshGenerator::addMeshCoordAttribute(int quadX, int quadY)
124{
125    // vec2 a_meshCoord
126    m_vertices.append(m_tileSizeInDeviceSpace.width() * quadX);
127    m_vertices.append(m_tileSizeInDeviceSpace.height() * quadY);
128}
129
130void CustomFilterMeshGenerator::addTriangleCoordAttribute(int quadX, int quadY, int triangle)
131{
132    // vec3 a_triangleCoord
133    m_vertices.append(quadX);
134    m_vertices.append(quadY);
135    m_vertices.append(triangle);
136}
137
138void CustomFilterMeshGenerator::addAttachedMeshVertexAttributes(int quadX, int quadY)
139{
140    addPositionAttribute(quadX, quadY);
141    addTexCoordAttribute(quadX, quadY);
142    addMeshCoordAttribute(quadX, quadY);
143}
144
145void CustomFilterMeshGenerator::addDetachedMeshVertexAttributes(int quadX, int quadY, int triangleX, int triangleY, int triangle)
146{
147    addAttachedMeshVertexAttributes(quadX + triangleX, quadY + triangleY);
148    addTriangleCoordAttribute(quadX, quadY, triangle);
149}
150
151#ifndef NDEBUG
152void CustomFilterMeshGenerator::dumpBuffers() const
153{
154    printf("Mesh buffers: Points.width(): %d, Points.height(): %d meshBox: %f, %f, %f, %f, type: %s\n",
155        m_points.width(), m_points.height(), m_meshBox.x(), m_meshBox.y(), m_meshBox.width(), m_meshBox.height(),
156        (m_meshType == MeshTypeAttached) ? "Attached" : "Detached");
157    printf("---Vertex:\n\t");
158    for (unsigned i = 0; i < m_vertices.size(); ++i) {
159        printf("%f ", m_vertices.at(i));
160        if (!((i + 1) % floatsPerVertex()))
161            printf("\n\t");
162    }
163    printf("\n---Indices: ");
164    for (unsigned i = 0; i < m_indices.size(); ++i)
165        printf("%d ", m_indices.at(i));
166    printf("\n");
167}
168#endif
169
170} // namespace WebCore
171
172#endif // ENABLE(CSS_SHADERS) && USE(3D_GRAPHICS)
173
174