Ion: gfxutils/shapeutils.cc Source File
22 #include "base/integral_types.h"
36 #include "third_party/openctm/files/tools/3ds.h"
37 #include "third_party/openctm/files/tools/dae.h"
38 #include "third_party/openctm/files/tools/lwo.h"
39 #include "third_party/openctm/files/tools/mesh.h"
40 #include "third_party/openctm/files/tools/obj.h"
41 #include "third_party/openctm/files/tools/off.h"
66 VertexP() : position(Point3f::Zero()) {}
79 VertexPN() : position(Point3f::Zero()), normal(Vector3f::Zero()) {}
89 normal(Vector3f::Zero()) {}
105 template <typename VertexType>
106 static void CompactVertices(size_t count, const VertexPTN vertices_in[],
107 VertexType vertices_out[]) {
108 #if !defined(ION_COVERAGE) // COV_NF_START
109 DCHECK(false) << "Unspecialized CompactVertices called";
115 void CompactVertices<VertexP>(size_t count, const VertexPTN vertices_in[],
117 for (size_t i = 0; i < count; ++i)
123 void CompactVertices<VertexPT>(size_t count, const VertexPTN vertices_in[],
124 VertexPT vertices_out[]) {
125 for (size_t i = 0; i < count; ++i) {
126 vertices_out[i].position = vertices_in[i].position;
127 vertices_out[i].texture_coords = vertices_in[i].texture_coords;
133 void CompactVertices<VertexPN>(size_t count, const VertexPTN vertices_in[],
134 VertexPN vertices_out[]) {
135 for (size_t i = 0; i < count; ++i) {
136 vertices_out[i].position = vertices_in[i].position;
137 vertices_out[i].normal = vertices_in[i].normal;
150 template <typename VertexType>
153 #if !defined(ION_COVERAGE) // COV_NF_START
154 DCHECK(false) << "Unspecialized BindVertices called";
163 BufferToAttributeBinder<VertexP>(v)
164 .Bind(v.position, "aVertex")
166 attribute_array, buffer_object);
174 BufferToAttributeBinder<VertexPT>(v)
175 .Bind(v.position, "aVertex")
176 .Bind(v.texture_coords, "aTexCoords")
178 attribute_array, buffer_object);
186 BufferToAttributeBinder<VertexPN>(v)
187 .Bind(v.position, "aVertex")
188 .Bind(v.normal, "aNormal")
190 attribute_array, buffer_object);
198 BufferToAttributeBinder<VertexPTN>(v)
199 .Bind(v.position, "aVertex")
200 .Bind(v.texture_coords, "aTexCoords")
201 .Bind(v.normal, "aNormal")
203 attribute_array, buffer_object);
218 return allocator.Get() ?
224 static const Vector3f SwizzleVector3f(const Vector3f& v,
234 template <typename VertexType>
237 const VertexPTN vertices[]) {
239 base::ScopedAllocation<VertexType> sa(allocator, count);
242 CompactVertices<VertexType>(count, vertices, sa.Get());
246 return sa.TransferToDataContainer(is_wipeable);
251 static bool IsWipeable(const ShapeSpec& spec) {
257 static bool HasTextureCoordinates(const ShapeSpec& spec) {
263 static bool HasNormals(const ShapeSpec& spec) {
274 new(spec.allocator) gfx::AttributeArray);
275 switch (spec.vertex_type) {
277 BindVertices<VertexP>(attribute_array, buffer_object);
280 BindVertices<VertexPT>(attribute_array, buffer_object);
283 BindVertices<VertexPN>(attribute_array, buffer_object);
287 BindVertices<VertexPTN>(attribute_array, buffer_object);
298 const ShapeSpec& spec, size_t vertex_count, const VertexPTN vertices[]) {
300 const bool is_wipeable = IsWipeable(spec);
304 switch (spec.vertex_type) {
306 container = CompactVerticesIntoDataContainer<VertexP>(
307 spec.allocator, vertex_count, is_wipeable, vertices);
308 vertex_size = sizeof(VertexP);
311 container = CompactVerticesIntoDataContainer<VertexPT>(
312 spec.allocator, vertex_count, is_wipeable, vertices);
313 vertex_size = sizeof(VertexPT);
316 container = CompactVerticesIntoDataContainer<VertexPN>(
317 spec.allocator, vertex_count, is_wipeable, vertices);
318 vertex_size = sizeof(VertexPN);
323 container = base::DataContainer::CreateAndCopy<VertexPTN>(
324 vertices, vertex_count, is_wipeable, spec.allocator);
325 vertex_size = sizeof(vertices[0]);
328 buffer_object->SetData(container, vertex_size, vertex_count, spec.usage_mode);
335 const ShapeSpec& spec, size_t num_indices, const uint16 indices[]) {
338 base::DataContainer::CreateAndCopy<uint16>(
339 indices, num_indices, IsWipeable(spec), spec.allocator);
342 index_buffer->SetData(container, sizeof(indices[0]), num_indices,
355 const T* tri_indices = tri_data->GetData<T>();
358 base::AllocVector<T> line_indices(GetShortTermAllocator(allocator),
359 line_index_count, static_cast<T>(0));
362 const size_t num_tris = tri_index_count / 3;
365 for (size_t i = 0; i < num_tris; ++i) {
366 line_indices[line_index + 0] = tri_indices[tri_index + 0];
367 line_indices[line_index + 1] = tri_indices[tri_index + 1];
368 line_indices[line_index + 2] = tri_indices[tri_index + 1];
369 line_indices[line_index + 3] = tri_indices[tri_index + 2];
370 line_indices[line_index + 4] = tri_indices[tri_index + 2];
371 line_indices[line_index + 5] = tri_indices[tri_index + 0];
375 DCHECK_EQ(tri_index, tri_index_count);
376 DCHECK_EQ(line_index, line_index_count);
379 &line_indices[0], line_index_count, tri_data->IsWipeable(),
396 static const char* GetPlanarShapeSwizzle(
416 static const Vector3f GetPlanarShapeSigns(
420 return Vector3f(-1.f, 1.f, 1.f);
422 return Vector3f(1.f, 1.f, -1.f);
424 return Vector3f(1.f, -1.f, 1.f);
426 return Vector3f(1.f, 1.f, -1.f);
428 return Vector3f(1.f, 1.f, 1.f);
431 return Vector3f(-1.f, 1.f, -1.f);
441 static void GetRectangleVertices(
442 const ShapeSpec& spec, float width, float height,
443 const char* swizzle, const Vector3f& signs, VertexPTN vertices[]) {
445 const float half_w = signs[0] * 0.5f * width;
446 const float half_h = signs[1] * 0.5f * height;
453 const Vector3f translation = spec.translation - Point3f::Zero();
454 for (int i = 0; i < 4; ++i)
456 spec.rotation * (vertices[i].position * spec.scale) + translation;
459 if (HasTextureCoordinates(spec)) {
460 vertices[0].texture_coords.Set(0.f, 0.f);
461 vertices[1].texture_coords.Set(1.f, 0.f);
462 vertices[2].texture_coords.Set(1.f, 1.f);
463 vertices[3].texture_coords.Set(0.f, 1.f);
469 math::Swizzle(Vector3f(0.f, 0.f, signs[2]), swizzle, &normal);
470 for (int i = 0; i < 4; ++i)
471 vertices[i].normal = spec.rotation * normal;
477 static void GetRegularPolygonVertices(
478 const ShapeSpec& spec, const base::AllocVector<Point2f>& points,
479 const char* swizzle, const Vector3f& signs, VertexPTN vertices[]) {
480 const Vector3f translation = spec.translation - Point3f::Zero();
481 const bool has_textures = HasTextureCoordinates(spec);
482 const bool has_normals = HasNormals(spec);
485 math::Swizzle(Vector3f(0.f, 0.f, signs[2]), swizzle, &normal);
488 const size_t num_vertices = points.size();
489 for (size_t i = 0; i < num_vertices; i++) {
490 math::Swizzle(Point3f(points[i][0], points[i][1], 0.0f), swizzle,
493 spec.rotation * (vertices[i].position * spec.scale) + translation;
497 vertices[i].texture_coords.Set((points[i][0] + 1.0f) * 0.5f,
498 (points[i][1] + 1.0f) * 0.5f);
501 vertices[i].normal = spec.rotation * normal;
509 static void GetPartialCirclePoints(size_t sector_count,
513 const Anglef sector_angle =
514 (angle_end - angle_start) / static_cast<float>(sector_count);
515 for (size_t i = 0; i < sector_count + 1; ++i) {
516 const Anglef angle = angle_start + sector_angle * static_cast<float>(i);
517 const float radians = angle.Radians();
518 points[i].Set(cosf(radians), sinf(radians));
525 static void GetCirclePoints(size_t sector_count, Point2f points[]) {
526 GetPartialCirclePoints(sector_count,
528 math::Anglef::FromDegrees(360.f),
568 const ExternalShapeSpec& spec, const Mesh& mesh) {
570 const size_t vertex_count = mesh.mVertices.size();
571 base::AllocVector<VertexPTN> vertices(GetShortTermAllocator(spec.allocator),
572 vertex_count, VertexPTN());
574 Vector3f center = Vector3f::Zero();
575 if (spec.center_at_origin) {
577 mesh.BoundingBox(bmin, bmax);
578 const Point3f mesh_min = Point3f(bmin.x, bmin.y, bmin.z);
579 const Point3f mesh_max = Point3f(bmax.x, bmax.y, bmax.z);
580 center = Range3f(mesh_min, mesh_max).GetCenter() - Point3f::Zero();
583 const Point3f point(mesh.mVertices[i].x, mesh.mVertices[i].y,
585 vertices[i].position = spec.rotation * ((point - center) * spec.scale) +
590 Vector3f(mesh.mNormals[i].x, mesh.mNormals[i].y, mesh.mNormals[i].z);
593 .texture_coords.Set(mesh.mTexCoords[i].u, mesh.mTexCoords[i].v);
596 return BuildBufferObject(spec, vertex_count, vertices.data());
601 const ExternalShapeSpec& spec, const Mesh& mesh) {
602 switch (spec.index_size) {
603 case ExternalShapeSpec::IndexSize::k16Bit: {
604 const size_t index_count = mesh.mIndices.size();
605 base::AllocVector<uint16> indices(GetShortTermAllocator(spec.allocator),
606 index_count, static_cast<uint16>(0));
607 for (size_t i = 0; i < index_count; ++i) {
608 if (mesh.mIndices[i] >= (1 << 16)) {
609 LOG(ERROR) << "Vertex index " << mesh.mIndices[i]
610 << " is too large to store as uint16.";
613 indices[i] = static_cast<uint16>(mesh.mIndices[i]);
615 return BuildIndexBuffer(spec, index_count, indices.data());
617 case ExternalShapeSpec::IndexSize::k32Bit: {
620 mesh.mIndices.data(), mesh.mIndices.size(), IsWipeable(spec),
623 index_buffer->SetData(container, sizeof(mesh.mIndices[0]),
624 mesh.mIndices.size(), spec.usage_mode);
628 DCHECK(false) << "Unknown vertex size.";
643 const RectangleSpec& spec) {
645 GetRectangleVertices(spec, spec.size[0], spec.size[1],
646 GetPlanarShapeSwizzle(spec.plane_normal),
647 GetPlanarShapeSigns(spec.plane_normal),
649 return BuildBufferObject(spec, 4U, vertices);
654 const RectangleSpec& spec) {
655 static const int kNumIndices = 6;
656 static const uint16 kIndices[kNumIndices] = { 0, 1, 2, 0, 2, 3 };
657 return BuildIndexBuffer(spec, kNumIndices, kIndices);
671 const RegularPolygonSpec& spec) {
674 const int kNumVertices = spec.sides + 2;
675 const base::AllocatorPtr& allocator = GetShortTermAllocator(spec.allocator);
679 base::AllocVector<Point2f> points(allocator, kNumVertices, Point2f::Zero());
680 GetCirclePoints(static_cast<size_t>(spec.sides), &points[1]);
682 base::AllocVector<VertexPTN> vertices(allocator, kNumVertices, VertexPTN());
683 GetRegularPolygonVertices(
684 spec, points, GetPlanarShapeSwizzle(spec.plane_normal),
685 GetPlanarShapeSigns(spec.plane_normal), vertices.data());
686 return BuildBufferObject(spec, kNumVertices, vertices.data());
698 static void GetBoxFaceVertices(const BoxSpec& spec,
703 const char* swizzle = GetPlanarShapeSwizzle(plane_normal);
704 const Vector3f signs = GetPlanarShapeSigns(plane_normal);
705 const Vector3f swizzled_size = SwizzleVector3f(spec.size, swizzle);
708 GetRectangleVertices(spec, swizzled_size[0], swizzled_size[1],
709 swizzle, signs, vertices);
712 const Vector3f translation = spec.rotation * SwizzleVector3f(
713 Vector3f(0.f, 0.f, 0.5f * signs[2] * swizzled_size[2] * spec.scale),
717 for (int i = 0; i < 4; ++i)
723 static const size_t kNumVertices = 6 * 4;
724 VertexPTN verts[kNumVertices];
731 return BuildBufferObject(spec, kNumVertices, verts);
737 static const size_t kNumFaces = 6;
738 static const size_t kNumIndices = kNumFaces * 6;
739 uint16 indices[kNumIndices];
740 for (uint16 i = 0; i < kNumFaces; ++i) {
741 indices[6 * i + 0] = static_cast<uint16>(4 * i + 0);
742 indices[6 * i + 1] = static_cast<uint16>(4 * i + 1);
743 indices[6 * i + 2] = static_cast<uint16>(4 * i + 2);
744 indices[6 * i + 3] = static_cast<uint16>(4 * i + 0);
745 indices[6 * i + 4] = static_cast<uint16>(4 * i + 2);
746 indices[6 * i + 5] = static_cast<uint16>(4 * i + 3);
748 return BuildIndexBuffer(spec, kNumIndices, indices);
761 size_t band_count;
767 static const EllipsoidData GetEllipsoidData(const EllipsoidSpec& spec) {
771 data.band_count = std::max(static_cast<size_t>(2), spec.band_count);
772 data.sector_count = std::max(static_cast<size_t>(3), spec.sector_count);
775 data.vertices_per_ring = data.sector_count + 1;
779 data.vertex_count = (data.band_count + 1U) * data.vertices_per_ring;
786 const EllipsoidSpec& spec) {
788 const base::AllocatorPtr& allocator = GetShortTermAllocator(spec.allocator);
790 const EllipsoidData data = GetEllipsoidData(spec);
791 const bool has_tex_coords = HasTextureCoordinates(spec);
792 const bool has_normals = HasNormals(spec);
793 base::AllocVector<VertexPTN> vertices(allocator, data.vertex_count,
797 base::AllocVector<Point2f> ring_points(allocator, data.vertices_per_ring,
799 GetPartialCirclePoints(data.sector_count,
807 const Vector3f scale = 0.5f * spec.size;
808 const Vector3f inv_scale = 1.0f / scale;
817 const Anglef delta_angle = (spec.latitude_end - spec.latitude_start)
818 / static_cast<float>(data.band_count);
820 for (size_t ring = 0; ring <= data.band_count; ++ring) {
821 const Anglef latitude_angle = spec.latitude_end -
822 delta_angle * static_cast<float>(ring);
823 const float ring_radius = cosf(latitude_angle.Radians());
824 const float sphere_y = sinf(latitude_angle.Radians());
826 for (size_t s = 0; s <= data.sector_count; ++s) {
827 VertexPTN& v = vertices[cur_vertex];
831 const Point2f& ring_pt = ring_points[s];
832 const Vector3f sphere_pt_vec(ring_radius * -ring_pt[1],
834 ring_radius * -ring_pt[0]);
835 v.position = spec.rotation * ((scale * sphere_pt_vec) * spec.scale) +
840 const float ts = static_cast<float>(s) /
841 static_cast<float>(data.sector_count);
842 const float tt = static_cast<float>(data.band_count - ring) /
843 static_cast<float>(data.band_count);
844 v.texture_coords.Set(ts, tt);
851 v.normal = spec.rotation * math::Normalized(inv_scale * sphere_pt_vec);
856 DCHECK_EQ(cur_vertex, data.vertex_count);
858 return BuildBufferObject(spec, vertices.size(), &vertices[0]);
863 const EllipsoidSpec& spec) {
864 const EllipsoidData data = GetEllipsoidData(spec);
868 const size_t index_count = 6U * data.band_count * data.sector_count;
869 base::AllocVector<uint16> indices(GetShortTermAllocator(spec.allocator),
870 index_count, static_cast<uint16>(0));
873 const uint16 ring_offset = static_cast<uint16>(data.vertices_per_ring);
874 for (uint16 band = 0; band < data.band_count; ++band) {
875 const uint16 first_band_vertex = static_cast<uint16>(band * ring_offset);
876 for (uint16 s = 0; s < data.sector_count; ++s) {
877 const uint16 v = static_cast<uint16>(first_band_vertex + s);
878 indices[cur_index + 0] = v;
879 indices[cur_index + 1] = static_cast<uint16>(v + ring_offset);
880 indices[cur_index + 2] = static_cast<uint16>(v + 1U);
881 indices[cur_index + 3] = static_cast<uint16>(v + 1U);
882 indices[cur_index + 4] = static_cast<uint16>(v + ring_offset);
883 indices[cur_index + 5] = static_cast<uint16>(v + ring_offset + 1U);
884 DCHECK_LE(indices[cur_index + 5U], data.vertex_count);
888 DCHECK_EQ(cur_index, index_count);
890 return BuildIndexBuffer(spec, index_count, &indices[0]);
908 size_t sector_count;
909 size_t vertices_per_ring;
912 size_t vertex_count;
915 static const CylinderData GetCylinderData(const CylinderSpec& spec) {
918 data.add_top_cap = spec.has_top_cap && spec.top_radius != 0.f;
919 data.add_bottom_cap = spec.has_bottom_cap && spec.bottom_radius != 0.f;
921 data.num_caps = (data.add_top_cap ? 1 : 0) + (data.add_bottom_cap ? 1 : 0);
924 data.shaft_band_count = std::max(static_cast<size_t>(1),
926 data.cap_band_count = std::max(static_cast<size_t>(1), spec.cap_band_count);
927 data.sector_count = std::max(static_cast<size_t>(3), spec.sector_count);
930 data.vertices_per_ring = data.sector_count + 1;
933 (data.shaft_band_count + 1) * data.vertices_per_ring;
936 data.cap_vertex_count = 1U + data.cap_band_count * data.vertices_per_ring;
940 data.shaft_vertex_count + data.num_caps * data.cap_vertex_count;
948 static void GetCylinderShaftNormals(
949 size_t count, const Point2f ring_points[], float top_radius,
950 float bottom_radius, float height, Vector3f shaft_normals[]) {
951 if (top_radius == bottom_radius) {
953 for (size_t i = 0; i < count; ++i) {
954 const Point2f& ring_pt = ring_points[i];
955 shaft_normals[i] = math::Normalized(Vector3f(-ring_pt[1], 0.f,
965 if (top_radius < bottom_radius) {
966 base_radius = bottom_radius;
967 apex_y = height + (top_radius * height) / (bottom_radius - top_radius);
970 apex_y = -(height + (bottom_radius * height) /
971 (top_radius - bottom_radius));
981 const float base_radius_squared = math::Square(base_radius);
982 const float ny = base_radius_squared / apex_y;
986 const float inv_length = 1.f / math::Sqrt(base_radius_squared + ny * ny);
988 for (size_t i = 0; i < count; ++i) {
989 const Point2f& ring_pt = ring_points[i];
990 shaft_normals[i] = inv_length * Vector3f(base_radius * -ring_pt[1], ny,
991 base_radius * -ring_pt[0]);
997 static size_t AddCylinderCapVertices(const CylinderSpec& spec,
998 const Point2f ring_points[], bool is_top,
1001 spec.rotation * (is_top ? Vector3f::AxisY() : -Vector3f::AxisY());
1003 is_top ? Vector3f(spec.top_radius, spec.height, spec.top_radius)
1004 : Vector3f(spec.bottom_radius, spec.height, spec.bottom_radius);
1005 const bool has_tex_coords = HasTextureCoordinates(spec);
1006 const bool has_normals = HasNormals(spec);
1007 const CylinderData data = GetCylinderData(spec);
1008 const float y = is_top ? .5f : -.5f;
1013 VertexPTN& center_v = vertices[0];
1015 spec.rotation * ((scale * Vector3f(0.f, y, 0.f)) * spec.scale) +
1018 center_v.texture_coords.Set(.5f, .5f);
1023 const float delta_radius = 1.f / static_cast<float>(data.cap_band_count);
1024 const float s_scale = .5f;
1025 const float t_scale = is_top ? -.5f : .5f;
1026 for (size_t ring = 0; ring < data.cap_band_count; ++ring) {
1028 for (size_t s = 0; s <= data.sector_count; ++s) {
1029 VertexPTN& v = vertices[cur_vertex];
1030 const Point2f& ring_pt = ring_points[s];
1034 const Vector3f pt_vec(radius * -ring_pt[1], y, -radius * ring_pt[0]);
1036 spec.rotation * ((scale * pt_vec) * spec.scale) + spec.translation;
1041 v.texture_coords.Set(.5f + s_scale * pt_vec[0],
1042 .5f + t_scale * pt_vec[2]);
1050 for (size_t i = 0; i < cur_vertex; ++i)
1051 vertices[i].normal = normal;
1059 static size_t AddCylinderCapIndices(
1060 const CylinderData& data, size_t start_index, bool invert_orientation,
1063 const uint16 center_index = static_cast<uint16>(start_index);
1067 const int i0 = invert_orientation ? 1 : 0;
1071 for (uint16 s = 0; s < data.sector_count; ++s) {
1072 const uint16 v = static_cast<uint16>(center_index + 1U + s);
1073 indices[cur_index + 0] = center_index;
1074 indices[cur_index + 1 + i0] = v;
1075 indices[cur_index + 1 + i1] = static_cast<uint16>(v + 1U);
1080 const uint16 ring_offset = static_cast<uint16>(data.vertices_per_ring);
1081 uint16 first_band_vertex = static_cast<uint16>(center_index + 1U);
1082 for (uint16 band = 1; band < data.cap_band_count; ++band) {
1083 for (uint16 s = 0; s < data.sector_count; ++s) {
1084 const uint16 v = static_cast<uint16>(first_band_vertex + s);
1085 indices[cur_index + 0] = v;
1086 indices[cur_index + 1 + i0] = static_cast<uint16>(v + ring_offset);
1087 indices[cur_index + 1 + i1] = static_cast<uint16>(v + 1U);
1088 indices[cur_index + 3] = static_cast<uint16>(v + 1U);
1089 indices[cur_index + 4 + i0] = static_cast<uint16>(v + ring_offset);
1090 indices[cur_index + 4 + i1] = static_cast<uint16>(v + ring_offset + 1U);
1091 DCHECK_LE(indices[cur_index + 4], data.vertex_count);
1092 DCHECK_LE(indices[cur_index + 5], data.vertex_count);
1095 first_band_vertex = static_cast<uint16>(first_band_vertex + ring_offset);
1102 const CylinderSpec& spec) {
1104 const base::AllocatorPtr& allocator = GetShortTermAllocator(spec.allocator);
1106 const CylinderData data = GetCylinderData(spec);
1107 const bool has_tex_coords = HasTextureCoordinates(spec);
1108 const bool has_normals = HasNormals(spec);
1109 base::AllocVector<VertexPTN> vertices(allocator, data.vertex_count,
1113 base::AllocVector<Point2f> ring_points(allocator, data.vertices_per_ring,
1115 GetCirclePoints(data.sector_count, &ring_points[0]);
1118 base::AllocVector<Vector3f> shaft_normals(allocator, data.vertices_per_ring,
1120 GetCylinderShaftNormals(data.vertices_per_ring, &ring_points[0],
1121 spec.top_radius, spec.bottom_radius, spec.height,
1125 const float delta_y = 1.f / static_cast<float>(data.shaft_band_count);
1126 const float delta_radius = (spec.top_radius - spec.bottom_radius) /
1127 static_cast<float>(data.shaft_band_count);
1129 float ring_radius = spec.top_radius;
1131 for (size_t ring = 0; ring <= data.shaft_band_count; ++ring) {
1132 const float ring_t = ring_y + .5f;
1134 const Vector3f scale(ring_radius, spec.height, ring_radius);
1135 for (size_t s = 0; s <= data.sector_count; ++s) {
1136 VertexPTN& v = vertices[cur_vertex];
1137 const Point2f& ring_pt = ring_points[s];
1140 const Vector3f shaft_pt_vec(-ring_pt[1], ring_y, -ring_pt[0]);
1141 v.position = spec.rotation * ((scale * shaft_pt_vec) * spec.scale) +
1145 v.texture_coords.Set(static_cast<float>(s) /
1146 static_cast<float>(data.sector_count), ring_t);
1149 v.normal = spec.rotation * shaft_normals[s];
1154 ring_radius -= delta_radius;
1159 cur_vertex += AddCylinderCapVertices(spec, &ring_points[0], true,
1162 cur_vertex += AddCylinderCapVertices(spec, &ring_points[0], false,
1165 DCHECK_EQ(cur_vertex, data.vertex_count);
1167 return BuildBufferObject(spec, vertices.size(), &vertices[0]);
1172 const CylinderSpec& spec) {
1173 const CylinderData data = GetCylinderData(spec);
1177 const size_t shaft_index_count =
1178 6U * data.shaft_band_count * data.sector_count;
1181 const size_t cap_index_count =
1183 6U * data.sector_count * (data.cap_band_count - 1U);
1184 const size_t index_count =
1185 shaft_index_count + data.num_caps * cap_index_count;
1186 base::AllocVector<uint16> indices(GetShortTermAllocator(spec.allocator),
1187 index_count, static_cast<uint16>(0));
1192 const uint16 ring_offset = static_cast<uint16>(data.vertices_per_ring);
1193 for (uint16 band = 0; band < data.shaft_band_count; ++band) {
1194 const uint16 first_band_vertex = static_cast<uint16>(band * ring_offset);
1195 for (uint16 s = 0; s < data.sector_count; ++s) {
1196 const uint16 v = static_cast<uint16>(first_band_vertex + s);
1197 indices[cur_index + 0] = v;
1198 indices[cur_index + 1] = static_cast<uint16>(v + ring_offset);
1199 indices[cur_index + 2] = static_cast<uint16>(v + 1U);
1200 indices[cur_index + 3] = static_cast<uint16>(v + 1U);
1201 indices[cur_index + 4] = static_cast<uint16>(v + ring_offset);
1202 indices[cur_index + 5] = static_cast<uint16>(v + ring_offset + 1U);
1203 DCHECK_LE(indices[cur_index + 5U], data.vertex_count);
1209 size_t first_cap_vertex = data.shaft_vertex_count;
1211 cur_index += AddCylinderCapIndices(data, first_cap_vertex, false,
1213 first_cap_vertex += data.cap_vertex_count;
1216 if (data.add_bottom_cap) {
1217 cur_index += AddCylinderCapIndices(data, first_cap_vertex, true,
1219 first_cap_vertex += data.cap_vertex_count;
1221 DCHECK_EQ(cur_index, index_count);
1223 return BuildIndexBuffer(spec, index_count, &indices[0]);
1240 if (tri_index_buffer.Get()) {
1242 const size_t tri_index_count = tri_index_buffer->GetCount();
1244 if (tri_index_count % 3U == 0U && tri_data.Get() && tri_data->GetData()) {
1246 const size_t line_index_count = 2U * tri_index_count;
1254 line_data = TriIndicesToLineIndices<uint8>(
1255 tri_data, tri_index_count, line_index_count, al);
1257 line_data = TriIndicesToLineIndices<uint16>(
1258 tri_data, tri_index_count, line_index_count, al);
1260 if (line_data.Get()) {
1262 line_index_buffer->AddSpec(spec.type, 1, 0);
1263 line_index_buffer->SetData(line_data, tri_index_buffer->GetStructSize(),
1265 tri_index_buffer->GetUsageMode());
1269 return line_index_buffer;
1275 LoadExternalShapeData(spec.format, in, &mesh);
1278 if (mesh.mIndices.empty() || mesh.mVertices.empty())
1283 shape->SetLabel("External geometry");
1285 shape->SetAttributeArray(BuildAttributeArray(spec, buffer_object));
1286 shape->SetIndexBuffer(BuildExternalIndexBuffer(spec, mesh));
1292 shape->SetLabel("Rectangle");
1294 shape->SetAttributeArray(
1295 BuildAttributeArray(spec, BuildRectangleBufferObject(spec)));
1296 shape->SetIndexBuffer(BuildRectangleIndexBuffer(spec));
1301 DCHECK_LE(3, spec.sides) << "Polygons must have at least 3 sides";
1303 shape->SetLabel("Polygon");
1305 shape->SetAttributeArray(
1306 BuildAttributeArray(spec, BuildRegularPolygonBufferObject(spec)));
1314 shape->SetAttributeArray(
1315 BuildAttributeArray(spec, BuildBoxBufferObject(spec)));
1316 shape->SetIndexBuffer(BuildBoxIndexBuffer(spec));
1322 shape->SetLabel("Ellipsoid");
1324 shape->SetAttributeArray(
1325 BuildAttributeArray(spec, BuildEllipsoidBufferObject(spec)));
1326 shape->SetIndexBuffer(BuildEllipsoidIndexBuffer(spec));
1332 shape->SetLabel("Cylinder");
1334 shape->SetAttributeArray(
1335 BuildAttributeArray(spec, BuildCylinderBufferObject(spec)));
1336 shape->SetIndexBuffer(BuildCylinderIndexBuffer(spec));
bool IsInvalidReference(const T &value)
IsInvalidReference() returns true if a passed const reference of type T has an address of InvalidRefe...
kShortTerm is used for objects that are very transient in nature, such as scratch memory used to comp...
ComponentType type
The type of each component.
bool Swizzle(const VectorBase< InDimension, T > &input, const char *swizzle_string, VectorBase< OutDimension, T > *output)
Computes the result of swizzling a Vector or Point (or anything else derived from VectorBase)...
Angle< float > Anglef
Type-specific typedefs.
static const ShaderInputRegistryPtr & GetGlobalRegistry()
Returns the ShaderInputRegistry instance representing all supported global uniforms and attributes...
An IndexBuffer is a type of BufferObject that contains the element indices of an array, e.g., a vertex index array.
#define LOG(severity)
Logs the streamed message unconditionally with a severity of severity.
size_t byte_offset
The offset of the element defined by this Spec in the data type.
Matrix< 3, float > Matrix3f
virtual const AllocatorPtr & GetAllocatorForLifetime(AllocationLifetime lifetime) const
Returns the correct Allocator to use to allocate memory with a specific lifetime. ...
External geometry formats.
const gfx::ShapePtr BuildEllipsoidShape(const EllipsoidSpec &spec)
Builds and returns a Shape representing an axis-aligned ellipsoid.
T Sqrt(const T &val)
Returns the square root of a value.
SharedPtr< Allocator > AllocatorPtr
size_t shaft_vertex_count
base::ReferentPtr< IndexBuffer >::Type IndexBufferPtr
const gfx::ShapePtr BuildCylinderShape(const CylinderSpec &spec)
Builds and returns a Shape representing an axis-aligned cylinder.
const gfx::IndexBufferPtr BuildWireframeIndexBuffer(const gfx::IndexBufferPtr &tri_index_buffer)
Public functions.
Range< 3, float > Range3f
const gfx::ShapePtr LoadExternalShape(const ExternalShapeSpec &spec, std::istream &in)
Loads a Shape with the specified format from the passed stream.
A Shape object represents a shape (vertices + indices) to draw.
const gfx::ShapePtr BuildRegularPolygonShape(const RegularPolygonSpec &spec)
Builds and returns a Shape representing a flat regular polygon.
Format
The set of external geometry file formats that can be read with LoadExternalShape().
const Vector< Dimension, T > Normalized(const Vector< Dimension, T > &v)
Returns a unit-length version of a Vector.
const gfx::ShapePtr BuildBoxShape(const BoxSpec &spec)
Builds and returns a Shape representing an axis-aligned box.
Copyright 2016 Google Inc.
#define DCHECK_EQ(val1, val2)
base::ReferentPtr< AttributeArray >::Type AttributeArrayPtr
Convenience typedef for shared pointer to a AttributeArray.
PlaneNormal
This enum specifies the principal Cartesian plane containing the rectangle by its directed normal...
#define DCHECK_LE(val1, val2)
const T Square(const T &val)
Squares a value.
static DataContainerPtr CreateAndCopy(const T *data, size_t count, bool is_wipeable, const AllocatorPtr &container_and_data_allocator)
See class comment for documentation.
base::ReferentPtr< DataContainer >::Type DataContainerPtr
base::ReferentPtr< BufferObject >::Type BufferObjectPtr
Convenience typedef for shared pointer to a BufferObject.
base::AllocatorPtr allocator
const gfx::ShapePtr BuildRectangleShape(const RectangleSpec &spec)
Builds and returns a Shape representing a rectangle in one of the principal Cartesian planes...
static const AllocatorPtr & GetDefaultAllocatorForLifetime(AllocationLifetime lifetime)