blob: 83783bd70558a79b0fd3c4fc5a0fd96c35b8ca6b [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_UI_LIB_ESCHER_MESH_TESSELLATION_H_
#define SRC_UI_LIB_ESCHER_MESH_TESSELLATION_H_
#include <vector>
#include "src/ui/lib/escher/forward_declarations.h"
#include "src/ui/lib/escher/geometry/types.h"
#include "src/ui/lib/escher/mesh/indexed_triangle_mesh.h"
namespace escher {
// Tessellate a circle. The coarsest circle (i.e. subdivisions == 0) is a
// square; increasing the number of subdivisions doubles the number of vertices.
MeshPtr NewCircleMesh(MeshBuilderFactory* factory, BatchGpuUploader* gpu_uploader,
const MeshSpec& spec, int subdivisions, vec2 center, float radius,
float offset_magnitude = 0.f);
// Tessellate a circle and return it as an IndexedTriangleMesh suitable for
// further processing on the CPU.
IndexedTriangleMesh2d<vec2> NewCircleIndexedTriangleMesh(const MeshSpec& spec,
uint32_t subdivisions, vec2 center,
float radius);
// Tessellate a rectangle with multiple vertices along the top and bottom edges.
// Increasing subdivisions by 1 doubles the number of vertices. If the spec
// has kPositionOffset, the top offset points up and the bottom points down.
MeshPtr NewRectangleMesh(MeshBuilderFactory* factory, BatchGpuUploader* gpu_uploader,
const MeshSpec& spec, int subdivisions, vec2 extent,
vec2 top_left = vec2(0.f, 0.f), float top_offset_magnitude = 0.f,
float bottom_offset_magnitude = 0.f);
// Tessellate a ring whose area is bounded by an inner and an outer circle.
// Increasing subdivisions by 1 doubles the number of vertices. If the spec
// has kPositionOffset, the outer offset points outward (away from the center of
// the ring) and the inner offset points inward (toward the center of the ring).
MeshPtr NewRingMesh(MeshBuilderFactory* factory, BatchGpuUploader* gpu_uploader,
const MeshSpec& spec, int subdivisions, vec2 center, float outer_radius,
float inner_radius, float outer_offset_magnitude = 0.f,
float inner_offset_magnitude = 0.f);
// Tessellate a full-screen mesh. The returned mesh has only position and UV
// coordinates.
MeshPtr NewFullScreenMesh(MeshBuilderFactory* factory, BatchGpuUploader* gpu_uploader);
// Tessellate a sphere with the specified center and radius. If subdivisions ==
// 0, the result is a regular octahedron. Increasing the number of subdivisions
// by 1 subdivides each triangle into 3 by adding a vertex at the triangle
// midpoint, and moving it outward to match the desired radius.
//
// If UV-coordinates are to be generated, the surface is parameterized as
// follows. Looking at the un-subdivided octahedron from the right (i.e. in the
// direction of the negative X-axis), the 4 visible faces are mapped to the
// rotated square with corners (0, .5), (.5, 0), (1, .5), (.5, 1), and the
// vertex at (radius, 0, 0) is mapped to the center of the texture: (.5, .5).
// The unmapped 4 corners of the texture are "folded over" to map to the 4
// hidden faces of the octahedron. During subdivision, the UV coordinates are
// linearly interpolated for each new vertex.
//
// TODO(fxbug.dev/7329): the approach described above is wrong: the newly-inserted
// vertices are correct positions, but the all of the initial octahedron edges
// are left untouched. The proper approach is to double the number of vertices
// at each subdivision level (and quadruple the triangle count) by splitting
// each edge at the mid-point. However, doing this with an indexed mesh (i.e.
// without inserting two vertices for every edge, one at each half-edge) is
// non-trivial, especially without a traversal-friendly mesh representation such
// as Rossignac's "corner table".
MeshPtr NewSphereMesh(MeshBuilderFactory* factory, BatchGpuUploader* gpu_uploader,
const MeshSpec& spec, int subdivisions, vec3 center, float radius);
// This returns a cube shaped mesh, with it's min-bounds point at the origin.
// To get boxes of different dimensions, this mesh can just be scaled in a
// non-uniform manner in the (x,y,z) directions with its transformation matrix.
IndexedTriangleMesh3d<vec2> NewCubeIndexedTriangleMesh(const MeshSpec& spec);
// Tessellate a basic rectangle on the XY plane with no depth. The origin refers
// to the top-left hand corner of rectangle, and the extent is the width and height.
// UV coordinates are also provided directly by the caller.
IndexedTriangleMesh2d<vec2> NewFlatRectangleMesh(vec2 origin, vec2 extent,
vec2 top_left_uv = vec2(0, 0),
vec2 bottom_right_uv = vec2(1, 1));
// The following functions are used for convenience during unit testing.
IndexedTriangleMesh2d<vec2> GetStandardTestMesh2d();
IndexedTriangleMesh3d<vec2> GetStandardTestMesh3d();
} // namespace escher
#endif // SRC_UI_LIB_ESCHER_MESH_TESSELLATION_H_