CustomFilterMesh.cpp [plain text]
#include "config.h"
#if ENABLE(CSS_SHADERS) && ENABLE(WEBGL)
#include "CustomFilterMesh.h"
#include "GraphicsContext3D.h"
namespace WebCore {
#ifndef NDEBUG
static bool s_dumpCustomFilterMeshBuffers = false;
#endif
class MeshGenerator {
public:
MeshGenerator(unsigned columns, unsigned rows, const FloatRect& meshBox, CustomFilterOperation::MeshType meshType)
: m_meshType(meshType)
, m_points(columns + 1, rows + 1)
, m_tiles(columns, rows)
, m_tileSizeInPixels(meshBox.width() / m_tiles.width(), meshBox.height() / m_tiles.height())
, m_tileSizeInDeviceSpace(1.0f / m_tiles.width(), 1.0f / m_tiles.height())
, m_meshBox(meshBox)
{
m_vertices.reserveCapacity(verticesCount() * floatsPerVertex());
m_indices.reserveCapacity(indicesCount());
if (m_meshType == CustomFilterOperation::ATTACHED)
generateAttachedMesh();
else
generateDetachedMesh();
#ifndef NDEBUG
if (s_dumpCustomFilterMeshBuffers)
dumpBuffers();
#endif
}
const Vector<float>& vertices() const { return m_vertices; }
const Vector<uint16_t>& indices() const { return m_indices; }
const IntSize& points() const { return m_points; }
unsigned pointsCount() const { return m_points.width() * m_points.height(); }
const IntSize& tiles() const { return m_tiles; }
unsigned tilesCount() const { return m_tiles.width() * m_tiles.height(); }
unsigned indicesCount() const
{
const unsigned trianglesPerTile = 2;
const unsigned indicesPerTriangle = 3;
return tilesCount() * trianglesPerTile * indicesPerTriangle;
}
unsigned floatsPerVertex() const
{
static const unsigned AttachedMeshVertexSize = 4 + 2 + 2;
static const unsigned DetachedMeshVertexSize = AttachedMeshVertexSize +
3;
return m_meshType == CustomFilterOperation::ATTACHED ? AttachedMeshVertexSize : DetachedMeshVertexSize;
}
unsigned verticesCount() const
{
return m_meshType == CustomFilterOperation::ATTACHED ? pointsCount() : indicesCount();
}
private:
typedef void (MeshGenerator::*AddTriangleVertexFunction)(int quadX, int quadY, int triangleX, int triangleY, int triangle);
template <AddTriangleVertexFunction addTriangleVertex>
void addTile(int quadX, int quadY)
{
((*this).*(addTriangleVertex))(quadX, quadY, 0, 0, 1);
((*this).*(addTriangleVertex))(quadX, quadY, 1, 0, 2);
((*this).*(addTriangleVertex))(quadX, quadY, 1, 1, 3);
((*this).*(addTriangleVertex))(quadX, quadY, 0, 0, 4);
((*this).*(addTriangleVertex))(quadX, quadY, 1, 1, 5);
((*this).*(addTriangleVertex))(quadX, quadY, 0, 1, 6);
}
void addAttachedMeshIndex(int quadX, int quadY, int triangleX, int triangleY, int triangle)
{
UNUSED_PARAM(triangle);
m_indices.append((quadY + triangleY) * m_points.width() + (quadX + triangleX));
}
void generateAttachedMesh()
{
for (int j = 0; j < m_points.height(); ++j) {
for (int i = 0; i < m_points.width(); ++i)
addAttachedMeshVertexAttributes(i, j);
}
for (int j = 0; j < m_tiles.height(); ++j) {
for (int i = 0; i < m_tiles.width(); ++i)
addTile<&MeshGenerator::addAttachedMeshIndex>(i, j);
}
}
void addDetachedMeshVertexAndIndex(int quadX, int quadY, int triangleX, int triangleY, int triangle)
{
addDetachedMeshVertexAttributes(quadX, quadY, triangleX, triangleY, triangle);
m_indices.append(m_indices.size());
}
void generateDetachedMesh()
{
for (int j = 0; j < m_tiles.height(); ++j) {
for (int i = 0; i < m_tiles.width(); ++i)
addTile<&MeshGenerator::addDetachedMeshVertexAndIndex>(i, j);
}
}
void addPositionAttribute(int quadX, int quadY)
{
m_vertices.append(m_tileSizeInPixels.width() * quadX - 0.5f + m_meshBox.x());
m_vertices.append(m_tileSizeInPixels.height() * quadY - 0.5f + m_meshBox.y());
m_vertices.append(0.0f); m_vertices.append(1.0f);
}
void addTexCoordAttribute(int quadX, int quadY)
{
m_vertices.append(m_tileSizeInPixels.width() * quadX + m_meshBox.x());
m_vertices.append(m_tileSizeInPixels.height() * quadY + m_meshBox.y());
}
void addMeshCoordAttribute(int quadX, int quadY)
{
m_vertices.append(m_tileSizeInDeviceSpace.width() * quadX);
m_vertices.append(m_tileSizeInDeviceSpace.height() * quadY);
}
void addTriangleCoordAttribute(int quadX, int quadY, int triangle)
{
m_vertices.append(quadX);
m_vertices.append(quadY);
m_vertices.append(triangle);
}
void addAttachedMeshVertexAttributes(int quadX, int quadY)
{
addPositionAttribute(quadX, quadY);
addTexCoordAttribute(quadX, quadY);
addMeshCoordAttribute(quadX, quadY);
}
void addDetachedMeshVertexAttributes(int quadX, int quadY, int triangleX, int triangleY, int triangle)
{
addAttachedMeshVertexAttributes(quadX + triangleX, quadY + triangleY);
addTriangleCoordAttribute(quadX, quadY, triangle);
}
#ifndef NDEBUG
void dumpBuffers() const
{
printf("Mesh buffers: Points.width(): %d, Points.height(): %d meshBox: %f, %f, %f, %f, type: %s\n",
m_points.width(), m_points.height(), m_meshBox.x(), m_meshBox.y(), m_meshBox.width(), m_meshBox.height(),
(m_meshType == CustomFilterOperation::ATTACHED) ? "Attached" : "Detached");
printf("---Vertex:\n\t");
for (unsigned i = 0; i < m_vertices.size(); ++i) {
printf("%f ", m_vertices.at(i));
if (!((i + 1) % floatsPerVertex()))
printf("\n\t");
}
printf("\n---Indices: ");
for (unsigned i = 0; i < m_indices.size(); ++i)
printf("%d ", m_indices.at(i));
printf("\n");
}
#endif
private:
Vector<float> m_vertices;
Vector<uint16_t> m_indices;
CustomFilterOperation::MeshType m_meshType;
IntSize m_points;
IntSize m_tiles;
FloatSize m_tileSizeInPixels;
FloatSize m_tileSizeInDeviceSpace;
FloatRect m_meshBox;
};
CustomFilterMesh::CustomFilterMesh(GraphicsContext3D* context, unsigned columns, unsigned rows,
const FloatRect& meshBox, CustomFilterOperation::MeshType meshType)
: m_context(context)
, m_verticesBufferObject(0)
, m_elementsBufferObject(0)
, m_meshBox(meshBox)
, m_meshType(meshType)
{
MeshGenerator generator(columns, rows, meshBox, meshType);
m_indicesCount = generator.indicesCount();
m_bytesPerVertex = generator.floatsPerVertex() * sizeof(float);
m_verticesBufferObject = m_context->createBuffer();
m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_verticesBufferObject);
m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, generator.vertices().size() * sizeof(float), generator.vertices().data(), GraphicsContext3D::STATIC_DRAW);
m_elementsBufferObject = m_context->createBuffer();
m_context->bindBuffer(GraphicsContext3D::ELEMENT_ARRAY_BUFFER, m_elementsBufferObject);
m_context->bufferData(GraphicsContext3D::ELEMENT_ARRAY_BUFFER, generator.indices().size() * sizeof(uint16_t), generator.indices().data(), GraphicsContext3D::STATIC_DRAW);
}
CustomFilterMesh::~CustomFilterMesh()
{
m_context->deleteBuffer(m_verticesBufferObject);
m_context->deleteBuffer(m_elementsBufferObject);
}
}
#endif // ENABLE(CSS_SHADERS) && ENABLE(WEBGL)