blob: 01a90cf420931a20496f46d1c004217cf6d21a5f [file] [log] [blame]
#include "include/private/dvr/eds_mesh.h"
#include <log/log.h>
#include <math.h>
#include <private/dvr/types.h>
namespace {
using android::dvr::EdsVertex;
using android::dvr::EyeType;
using android::dvr::DistortionFunction;
using android::dvr::vec2;
// Computes the vertices for a distortion mesh with resolution |resolution| and
// distortion provided by |hmd| and stores them in |vertices|.
static void ComputeDistortionMeshVertices(
EdsVertex* vertices, int resolution,
const DistortionFunction& distortion_function, EyeType eye) {
for (int row = 0; row < resolution; row++) {
for (int col = 0; col < resolution; col++) {
const float x_norm =
static_cast<float>(col) / (static_cast<float>(resolution - 1U));
const float y_norm =
static_cast<float>(row) / (static_cast<float>(resolution - 1U));
const vec2 xy_norm(x_norm, y_norm);
const size_t index = col * resolution + row;
// Evaluate distortion function to get the new coordinates for each color
// channel. The distortion function returns the new coordinates relative
// to a full viewport with 0 <= x <= 1 for each eye.
vec2 coords[3];
distortion_function(eye, xy_norm, &vertices[index].position, coords);
// Store distortion mapping in texture coordinates.
vertices[index].red_viewport_coords = coords[0];
vertices[index].green_viewport_coords = coords[1];
vertices[index].blue_viewport_coords = coords[2];
}
}
}
// Computes the triangle strip indices for a distortion mesh with resolution
// |resolution| and stores them in |indices|.
static void ComputeDistortionMeshIndices(uint16_t* indices, int resolution) {
// The following strip method has been used in the Cardboard SDK
// (java/com/google/vrtoolkit/cardboard/DistortionRenderer.java) and has
// originally been described at:
//
// http://dan.lecocq.us/wordpress/2009/12/25/triangle-strip-for-grids-a-construction/
//
// For a grid with 4 rows and 4 columns of vertices, the strip would
// look like:
// ↻
// 0 - 4 - 8 - 12
// ↓ ↗ ↓ ↗ ↓ ↗ ↓
// 1 - 5 - 9 - 13
// ↓ ↖ ↓ ↖ ↓ ↖ ↓
// 2 - 6 - 10 - 14
// ↓ ↗ ↓ ↗ ↓ ↗ ↓
// 3 - 7 - 11 - 15
// ↺
//
// Note the little circular arrows next to 7 and 8 that indicate
// repeating that vertex once so as to produce degenerate triangles.
//
// To facilitate scanline racing, the vertex order is left to right.
int16_t index_offset = 0;
int16_t vertex_offset = 0;
for (int row = 0; row < resolution - 1; ++row) {
if (row > 0) {
indices[index_offset] = indices[index_offset - 1];
++index_offset;
}
for (int col = 0; col < resolution; ++col) {
if (col > 0) {
if (row % 2 == 0) {
// Move right on even rows.
++vertex_offset;
} else {
--vertex_offset;
}
}
// A cast to uint16_t is safe here as |vertex_offset| will not drop below
// zero in this loop. As col is initially equal to zero |vertex_offset| is
// always incremented before being decremented, is initialized to zero and
// is only incremented outside of the loop.
indices[index_offset++] = static_cast<uint16_t>(vertex_offset);
indices[index_offset++] = static_cast<uint16_t>(
vertex_offset + static_cast<int16_t>(resolution));
}
vertex_offset =
static_cast<int16_t>(static_cast<int>(resolution) + vertex_offset);
}
}
} // anonymous namespace
namespace android {
namespace dvr {
// Builds a distortion mesh of resolution |resolution| using the distortion
// provided by |hmd| for |eye|.
EdsMesh BuildDistortionMesh(EyeType eye, int resolution,
const DistortionFunction& distortion_function) {
LOG_ALWAYS_FATAL_IF(resolution <= 2);
// Number of indices produced by the strip method
// (see comment in ComputeDistortionMeshIndices):
//
// 1 vertex per triangle
// 2 triangles per quad, (rows - 1) * (cols - 1) quads
// 2 vertices at the start of each row for the first triangle
// 1 extra vertex per row (except first and last) for a
// degenerate triangle
//
const uint16_t index_count =
static_cast<uint16_t>(resolution * (2 * resolution - 1U) - 2U);
const uint16_t vertex_count = static_cast<uint16_t>(resolution * resolution);
EdsMesh mesh;
mesh.vertices.resize(vertex_count);
mesh.indices.resize(index_count);
// Populate vertex and index buffer.
ComputeDistortionMeshVertices(&mesh.vertices[0], resolution,
distortion_function, eye);
ComputeDistortionMeshIndices(&mesh.indices[0], resolution);
return mesh;
}
} // namespace dvr
} // namespace android