summaryrefslogtreecommitdiff
path: root/libs/assimp/contrib/draco/src/draco/mesh/mesh_stripifier.h
diff options
context:
space:
mode:
Diffstat (limited to 'libs/assimp/contrib/draco/src/draco/mesh/mesh_stripifier.h')
-rw-r--r--libs/assimp/contrib/draco/src/draco/mesh/mesh_stripifier.h260
1 files changed, 260 insertions, 0 deletions
diff --git a/libs/assimp/contrib/draco/src/draco/mesh/mesh_stripifier.h b/libs/assimp/contrib/draco/src/draco/mesh/mesh_stripifier.h
new file mode 100644
index 0000000..262e3c7
--- /dev/null
+++ b/libs/assimp/contrib/draco/src/draco/mesh/mesh_stripifier.h
@@ -0,0 +1,260 @@
+// Copyright 2017 The Draco Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#ifndef DRACO_MESH_MESH_STRIPIFIER_H_
+#define DRACO_MESH_MESH_STRIPIFIER_H_
+
+#include "draco/mesh/mesh_misc_functions.h"
+
+namespace draco {
+
+// Class that generates triangle strips from a provided draco::Mesh data
+// structure. The strips represent a more memory efficient storage of triangle
+// connectivity that can be used directly on the GPU (see
+// https://en.wikipedia.org/wiki/Triangle_strip ). In general, a mesh needs to
+// be represented by several triangle strips and it has been proven that finding
+// the optimal set of triangle strips is an NP-complete problem. The algorithm
+// implemented by this class finds this set of triangle strips based on a greedy
+// heuristic that always selects the longest available strip that covers the
+// next unprocessed face. The longest strip is found by analyzing all strips
+// that can cover the given face (three strips corresponding to three
+// directions).
+class MeshStripifier {
+ public:
+ MeshStripifier()
+ : mesh_(nullptr),
+ num_strips_(0),
+ num_encoded_faces_(0),
+ last_encoded_point_(kInvalidPointIndex) {}
+
+ // Generate triangle strips for a given mesh and output them to the output
+ // iterator |out_it|. In most cases |out_it| stores the values in a buffer
+ // that can be used directly on the GPU. Note that the algorithm can generate
+ // multiple strips to represent the whole mesh. In such cases multiple strips
+ // are separated using a so called primitive restart index that is specified
+ // by the |primitive_restart_index| (usually defined as the maximum allowed
+ // value for the given type).
+ // https://www.khronos.org/opengl/wiki/Vertex_Rendering#Primitive_Restart
+ template <typename OutputIteratorT, typename IndexTypeT>
+ bool GenerateTriangleStripsWithPrimitiveRestart(
+ const Mesh &mesh, IndexTypeT primitive_restart_index,
+ OutputIteratorT out_it);
+
+ // The same as above but disjoint triangle strips are separated by degenerate
+ // triangles instead of the primitive restart index. Degenerate triangles are
+ // zero area triangles that are automatically discarded by the GPU. Using
+ // degenerate triangles usually results in a slightly longer output indices
+ // array compared to the similar triangle strips that use primitive restart
+ // index. The advantage of this method is that it is supported by all hardware
+ // and all relevant APIs (including WebGL 1.0).
+ template <typename OutputIteratorT>
+ bool GenerateTriangleStripsWithDegenerateTriangles(const Mesh &mesh,
+ OutputIteratorT out_it);
+
+ // Returns the number of strips generated by the last call of the
+ // GenerateTriangleStrips() method.
+ int num_strips() const { return num_strips_; }
+
+ private:
+ bool Prepare(const Mesh &mesh) {
+ mesh_ = &mesh;
+ num_strips_ = 0;
+ num_encoded_faces_ = 0;
+ // TODO(ostava): We may be able to avoid computing the corner table if we
+ // already have it stored somewhere.
+ corner_table_ = CreateCornerTableFromPositionAttribute(mesh_);
+ if (corner_table_ == nullptr) {
+ return false;
+ }
+
+ // Mark all faces as unvisited.
+ is_face_visited_.assign(mesh.num_faces(), false);
+ return true;
+ }
+
+ // Returns local id of the longest strip that can be created from the given
+ // face |fi|.
+ int FindLongestStripFromFace(FaceIndex fi) {
+ // There are three possible strip directions that can contain the provided
+ // input face. We try all of them and select the direction that result in
+ // the longest strip.
+ const CornerIndex first_ci = corner_table_->FirstCorner(fi);
+ int longest_strip_id = -1;
+ int longest_strip_length = 0;
+ for (int i = 0; i < 3; ++i) {
+ GenerateStripsFromCorner(i, first_ci + i);
+ if (strip_faces_[i].size() > longest_strip_length) {
+ longest_strip_length = static_cast<int>(strip_faces_[i].size());
+ longest_strip_id = i;
+ }
+ }
+ return longest_strip_id;
+ }
+
+ // Generates strip from the data stored in |strip_faces_| and
+ // |strip_start_start_corners_| and stores it to |out_it|.
+ template <typename OutputIteratorT>
+ void StoreStrip(int local_strip_id, OutputIteratorT out_it) {
+ ++num_strips_;
+
+ const int num_strip_faces = strip_faces_[local_strip_id].size();
+ CornerIndex ci = strip_start_corners_[local_strip_id];
+ for (int i = 0; i < num_strip_faces; ++i) {
+ const FaceIndex fi = corner_table_->Face(ci);
+ is_face_visited_[fi] = true;
+ ++num_encoded_faces_;
+
+ if (i == 0) {
+ // Add the start face (three indices).
+ *out_it++ = CornerToPointIndex(ci).value();
+ *out_it++ = CornerToPointIndex(corner_table_->Next(ci)).value();
+ last_encoded_point_ = CornerToPointIndex(corner_table_->Previous(ci));
+ *out_it++ = last_encoded_point_.value();
+ } else {
+ // Store the point on the newly reached corner.
+ last_encoded_point_ = CornerToPointIndex(ci);
+ *out_it++ = last_encoded_point_.value();
+
+ // Go to the correct source corner to proceed to the next face.
+ if (i & 1) {
+ ci = corner_table_->Previous(ci);
+ } else {
+ ci = corner_table_->Next(ci);
+ }
+ }
+ ci = corner_table_->Opposite(ci);
+ }
+ }
+
+ PointIndex CornerToPointIndex(CornerIndex ci) const {
+ return mesh_->CornerToPointId(ci);
+ }
+
+ // Returns the opposite corner in case the opposite triangle does not lie
+ // across an attribute seam. Otherwise return kInvalidCornerIndex.
+ CornerIndex GetOppositeCorner(CornerIndex ci) const {
+ const CornerIndex oci = corner_table_->Opposite(ci);
+ if (oci < 0) {
+ return kInvalidCornerIndex;
+ }
+ // Ensure the point ids are same on both sides of the shared edge between
+ // the triangles.
+ if (CornerToPointIndex(corner_table_->Next(ci)) !=
+ CornerToPointIndex(corner_table_->Previous(oci))) {
+ return kInvalidCornerIndex;
+ }
+ if (CornerToPointIndex(corner_table_->Previous(ci)) !=
+ CornerToPointIndex(corner_table_->Next(oci))) {
+ return kInvalidCornerIndex;
+ }
+ return oci;
+ }
+
+ void GenerateStripsFromCorner(int local_strip_id, CornerIndex ci);
+
+ const Mesh *mesh_;
+ std::unique_ptr<CornerTable> corner_table_;
+
+ // Store strip faces for each of three possible directions from a given face.
+ std::vector<FaceIndex> strip_faces_[3];
+ // Start corner for each direction of the strip containing the processed face.
+ CornerIndex strip_start_corners_[3];
+ IndexTypeVector<FaceIndex, bool> is_face_visited_;
+ // The number of strips generated by this method.
+ int num_strips_;
+ // The number of encoded triangles.
+ int num_encoded_faces_;
+ // Last encoded point.
+ PointIndex last_encoded_point_;
+};
+
+template <typename OutputIteratorT, typename IndexTypeT>
+bool MeshStripifier::GenerateTriangleStripsWithPrimitiveRestart(
+ const Mesh &mesh, IndexTypeT primitive_restart_index,
+ OutputIteratorT out_it) {
+ if (!Prepare(mesh)) {
+ return false;
+ }
+
+ // Go over all faces and generate strips from the first unvisited one.
+ for (FaceIndex fi(0); fi < mesh.num_faces(); ++fi) {
+ if (is_face_visited_[fi]) {
+ continue;
+ }
+
+ const int longest_strip_id = FindLongestStripFromFace(fi);
+
+ // Separate triangle strips with the primitive restart index.
+ if (num_strips_ > 0) {
+ *out_it++ = primitive_restart_index;
+ }
+
+ StoreStrip(longest_strip_id, out_it);
+ }
+
+ return true;
+}
+
+template <typename OutputIteratorT>
+bool MeshStripifier::GenerateTriangleStripsWithDegenerateTriangles(
+ const Mesh &mesh, OutputIteratorT out_it) {
+ if (!Prepare(mesh)) {
+ return false;
+ }
+
+ // Go over all faces and generate strips from the first unvisited one.
+ for (FaceIndex fi(0); fi < mesh.num_faces(); ++fi) {
+ if (is_face_visited_[fi]) {
+ continue;
+ }
+
+ const int longest_strip_id = FindLongestStripFromFace(fi);
+
+ // Separate triangle strips by degenerate triangles. There will be either
+ // three or four degenerate triangles inserted based on the number of
+ // triangles that are already encoded in the output strip (three degenerate
+ // triangles for even number of existing triangles, four degenerate
+ // triangles for odd number of triangles).
+ if (num_strips_ > 0) {
+ // Duplicate last encoded index (first degenerate face).
+ *out_it++ = last_encoded_point_.value();
+
+ // Connect it to the start point of the new triangle strip (second
+ // degenerate face).
+ const CornerIndex new_start_corner =
+ strip_start_corners_[longest_strip_id];
+ const PointIndex new_start_point = CornerToPointIndex(new_start_corner);
+ *out_it++ = new_start_point.value();
+ num_encoded_faces_ += 2;
+ // If we have previously encoded number of faces we need to duplicate the
+ // point one more time to preserve the correct orientation of the next
+ // strip.
+ if (num_encoded_faces_ & 1) {
+ *out_it++ = new_start_point.value();
+ num_encoded_faces_ += 1;
+ }
+ // The last degenerate face will be added implicitly in the StoreStrip()
+ // function below as the first point index is going to be encoded there
+ // again.
+ }
+
+ StoreStrip(longest_strip_id, out_it);
+ }
+
+ return true;
+}
+
+} // namespace draco
+
+#endif // DRACO_MESH_MESH_STRIPIFIER_H_