Ion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
shapeutils.cc
Go to the documentation of this file.
1 
19 
20 #include <algorithm>
21 
22 #include "base/integral_types.h"
24 #include "ion/base/datacontainer.h"
25 #include "ion/base/invalid.h"
26 #include "ion/base/logging.h"
29 #include "ion/gfx/attributearray.h"
32 #include "ion/math/angle.h"
33 #include "ion/math/matrixutils.h"
34 #include "ion/math/range.h"
35 #include "ion/math/vectorutils.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"
42 
43 namespace ion {
44 namespace gfxutils {
45 
46 using math::Anglef;
47 using math::Matrix3f;
48 using math::Point2f;
49 using math::Point3f;
50 using math::Range3f;
51 using math::Vector3f;
52 
53 namespace {
54 
56 
62 
63 
65 struct VertexP {
66  VertexP() : position(Point3f::Zero()) {}
67  Point3f position;
68 };
69 
71 struct VertexPT {
72  VertexPT() : position(Point3f::Zero()), texture_coords(Point2f::Zero()) {}
73  Point3f position;
74  Point2f texture_coords;
75 };
76 
78 struct VertexPN {
79  VertexPN() : position(Point3f::Zero()), normal(Vector3f::Zero()) {}
80  Point3f position;
81  Vector3f normal;
82 };
83 
85 struct VertexPTN {
86  VertexPTN() :
87  position(Point3f::Zero()),
88  texture_coords(Point2f::Zero()),
89  normal(Vector3f::Zero()) {}
90  Point3f position;
91  Point2f texture_coords;
92  Vector3f normal;
93 };
94 
96 
103 
104 
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";
110 #endif // COV_NF_END
111 }
112 
114 template <>
115 void CompactVertices<VertexP>(size_t count, const VertexPTN vertices_in[],
116  VertexP vertices_out[]) {
117  for (size_t i = 0; i < count; ++i)
118  vertices_out[i].position = vertices_in[i].position;
119 }
120 
122 template <>
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;
128  }
129 }
130 
132 template <>
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;
138  }
139 }
140 
142 
148 
149 
150 template <typename VertexType>
151 static void BindVertices(const gfx::AttributeArrayPtr& attribute_array,
152  const gfx::BufferObjectPtr& buffer_object) {
153 #if !defined(ION_COVERAGE) // COV_NF_START
154  DCHECK(false) << "Unspecialized BindVertices called";
155 #endif // COV_NF_END
156 }
157 
159 template <>
160 void BindVertices<VertexP>(const gfx::AttributeArrayPtr& attribute_array,
161  const gfx::BufferObjectPtr& buffer_object) {
162  VertexP v;
163  BufferToAttributeBinder<VertexP>(v)
164  .Bind(v.position, "aVertex")
166  attribute_array, buffer_object);
167 }
168 
170 template <>
171 void BindVertices<VertexPT>(const gfx::AttributeArrayPtr& attribute_array,
172  const gfx::BufferObjectPtr& buffer_object) {
173  VertexPT v;
174  BufferToAttributeBinder<VertexPT>(v)
175  .Bind(v.position, "aVertex")
176  .Bind(v.texture_coords, "aTexCoords")
178  attribute_array, buffer_object);
179 }
180 
182 template <>
183 void BindVertices<VertexPN>(const gfx::AttributeArrayPtr& attribute_array,
184  const gfx::BufferObjectPtr& buffer_object) {
185  VertexPN v;
186  BufferToAttributeBinder<VertexPN>(v)
187  .Bind(v.position, "aVertex")
188  .Bind(v.normal, "aNormal")
190  attribute_array, buffer_object);
191 }
192 
194 template <>
195 void BindVertices<VertexPTN>(const gfx::AttributeArrayPtr& attribute_array,
196  const gfx::BufferObjectPtr& buffer_object) {
197  VertexPTN v;
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);
204 }
205 
207 
212 
213 
216 static const base::AllocatorPtr& GetShortTermAllocator(
217  const base::AllocatorPtr& allocator) {
218  return allocator.Get() ?
221 }
222 
224 static const Vector3f SwizzleVector3f(const Vector3f& v,
225  const char swizzle[3]) {
226  Vector3f swizzled;
227  math::Swizzle(v, swizzle, &swizzled);
228  return swizzled;
229 }
230 
234 template <typename VertexType>
235 const base::DataContainerPtr CompactVerticesIntoDataContainer(
236  const base::AllocatorPtr& allocator, size_t count, bool is_wipeable,
237  const VertexPTN vertices[]) {
239  base::ScopedAllocation<VertexType> sa(allocator, count);
240 
242  CompactVertices<VertexType>(count, vertices, sa.Get());
243 
246  return sa.TransferToDataContainer(is_wipeable);
247 }
248 
251 static bool IsWipeable(const ShapeSpec& spec) {
252  return spec.usage_mode == gfx::BufferObject::kStaticDraw;
253 }
254 
257 static bool HasTextureCoordinates(const ShapeSpec& spec) {
258  return spec.vertex_type == ShapeSpec::kPositionTexCoords ||
259  spec.vertex_type == ShapeSpec::kPositionTexCoordsNormal;
260 }
261 
263 static bool HasNormals(const ShapeSpec& spec) {
264  return spec.vertex_type == ShapeSpec::kPositionNormal ||
265  spec.vertex_type == ShapeSpec::kPositionTexCoordsNormal;
266 }
267 
271 static const gfx::AttributeArrayPtr BuildAttributeArray(
272  const ShapeSpec& spec, const gfx::BufferObjectPtr& buffer_object) {
273  gfx::AttributeArrayPtr attribute_array(
274  new(spec.allocator) gfx::AttributeArray);
275  switch (spec.vertex_type) {
277  BindVertices<VertexP>(attribute_array, buffer_object);
278  break;
280  BindVertices<VertexPT>(attribute_array, buffer_object);
281  break;
283  BindVertices<VertexPN>(attribute_array, buffer_object);
284  break;
286  default:
287  BindVertices<VertexPTN>(attribute_array, buffer_object);
288  break;
289  }
290  return attribute_array;
291 }
292 
297 static const gfx::BufferObjectPtr BuildBufferObject(
298  const ShapeSpec& spec, size_t vertex_count, const VertexPTN vertices[]) {
299  gfx::BufferObjectPtr buffer_object(new(spec.allocator) gfx::BufferObject);
300  const bool is_wipeable = IsWipeable(spec);
301  base::DataContainerPtr container;
302  size_t vertex_size;
304  switch (spec.vertex_type) {
306  container = CompactVerticesIntoDataContainer<VertexP>(
307  spec.allocator, vertex_count, is_wipeable, vertices);
308  vertex_size = sizeof(VertexP);
309  break;
311  container = CompactVerticesIntoDataContainer<VertexPT>(
312  spec.allocator, vertex_count, is_wipeable, vertices);
313  vertex_size = sizeof(VertexPT);
314  break;
316  container = CompactVerticesIntoDataContainer<VertexPN>(
317  spec.allocator, vertex_count, is_wipeable, vertices);
318  vertex_size = sizeof(VertexPN);
319  break;
321  default:
323  container = base::DataContainer::CreateAndCopy<VertexPTN>(
324  vertices, vertex_count, is_wipeable, spec.allocator);
325  vertex_size = sizeof(vertices[0]);
326  break;
327  }
328  buffer_object->SetData(container, vertex_size, vertex_count, spec.usage_mode);
329  return buffer_object;
330 }
331 
334 static const gfx::IndexBufferPtr BuildIndexBuffer(
335  const ShapeSpec& spec, size_t num_indices, const uint16 indices[]) {
336  gfx::IndexBufferPtr index_buffer(new(spec.allocator) gfx::IndexBuffer);
337  base::DataContainerPtr container =
338  base::DataContainer::CreateAndCopy<uint16>(
339  indices, num_indices, IsWipeable(spec), spec.allocator);
340 
341  index_buffer->AddSpec(gfx::BufferObject::kUnsignedShort, 1, 0);
342  index_buffer->SetData(container, sizeof(indices[0]), num_indices,
343  spec.usage_mode);
344 
345  return index_buffer;
346 }
347 
351 template <typename T>
352 static const base::DataContainerPtr TriIndicesToLineIndices(
353  const base::DataContainerPtr& tri_data, size_t tri_index_count,
354  size_t line_index_count, const base::AllocatorPtr& allocator) {
355  const T* tri_indices = tri_data->GetData<T>();
356 
358  base::AllocVector<T> line_indices(GetShortTermAllocator(allocator),
359  line_index_count, static_cast<T>(0));
360 
362  const size_t num_tris = tri_index_count / 3;
363  size_t tri_index = 0;
364  size_t line_index = 0;
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];
372  tri_index += 3U;
373  line_index += 6U;
374  }
375  DCHECK_EQ(tri_index, tri_index_count);
376  DCHECK_EQ(line_index, line_index_count);
377 
378  base::DataContainerPtr line_data = base::DataContainer::CreateAndCopy<T>(
379  &line_indices[0], line_index_count, tri_data->IsWipeable(),
380  allocator);
381 
382  return line_data;
383 }
384 
386 
391 
392 
396 static const char* GetPlanarShapeSwizzle(
397  PlanarShapeSpec::PlaneNormal plane_normal) {
398  switch (plane_normal) {
401  return "zyx";
404  return "xzy";
407  default:
408  return "xyz";
409  }
410 }
411 
416 static const Vector3f GetPlanarShapeSigns(
417  PlanarShapeSpec::PlaneNormal plane_normal) {
418  switch (plane_normal) {
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);
430  default:
431  return Vector3f(-1.f, 1.f, -1.f);
432  }
433 }
434 
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;
447  math::Swizzle(Point3f(-half_w, -half_h, 0.f), swizzle, &vertices[0].position);
448  math::Swizzle(Point3f(half_w, -half_h, 0.f), swizzle, &vertices[1].position);
449  math::Swizzle(Point3f(half_w, half_h, 0.f), swizzle, &vertices[2].position);
450  math::Swizzle(Point3f(-half_w, half_h, 0.f), swizzle, &vertices[3].position);
451 
453  const Vector3f translation = spec.translation - Point3f::Zero();
454  for (int i = 0; i < 4; ++i)
455  vertices[i].position =
456  spec.rotation * (vertices[i].position * spec.scale) + translation;
457 
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);
464  }
465 
467  if (HasNormals(spec)) {
468  Vector3f normal;
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;
472  }
473 }
474 
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);
483  Vector3f normal;
484  if (has_normals) {
485  math::Swizzle(Vector3f(0.f, 0.f, signs[2]), swizzle, &normal);
486  }
487 
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,
491  &vertices[i].position);
492  vertices[i].position =
493  spec.rotation * (vertices[i].position * spec.scale) + translation;
494  if (has_textures) {
497  vertices[i].texture_coords.Set((points[i][0] + 1.0f) * 0.5f,
498  (points[i][1] + 1.0f) * 0.5f);
499  }
500  if (has_normals) {
501  vertices[i].normal = spec.rotation * normal;
502  }
503  }
504 }
505 
509 static void GetPartialCirclePoints(size_t sector_count,
510  const math::Anglef& angle_start,
511  const math::Anglef& angle_end,
512  Point2f points[]) {
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));
519  }
520 }
521 
525 static void GetCirclePoints(size_t sector_count, Point2f points[]) {
526  GetPartialCirclePoints(sector_count,
527  math::Anglef(),
528  math::Anglef::FromDegrees(360.f),
529  points);
530 }
531 
533 
538 
539 
541 static void LoadExternalShapeData(ExternalShapeSpec::Format format,
542  std::istream& in, // NOLINT
543  Mesh* mesh) {
544  switch (format) {
546  Import_3DS(in, mesh);
547  break;
549  Import_DAE(in, mesh);
550  break;
552  Import_LWO(in, mesh);
553  break;
555  Import_OBJ(in, mesh);
556  break;
558  Import_OFF(in, mesh);
559  break;
560  default:
561  break;
562  }
563 }
564 
567 static gfx::BufferObjectPtr BuildExternalBufferObject(
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) {
576  Vector3 bmin, bmax;
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();
581  }
582  for (size_t i = 0; i < vertex_count; ++i) {
583  const Point3f point(mesh.mVertices[i].x, mesh.mVertices[i].y,
584  mesh.mVertices[i].z);
585  vertices[i].position = spec.rotation * ((point - center) * spec.scale) +
586  spec.translation;
587  if (mesh.HasNormals())
588  vertices[i].normal =
589  spec.rotation *
590  Vector3f(mesh.mNormals[i].x, mesh.mNormals[i].y, mesh.mNormals[i].z);
591  if (mesh.HasTexCoords())
592  vertices[i]
593  .texture_coords.Set(mesh.mTexCoords[i].u, mesh.mTexCoords[i].v);
594  }
595 
596  return BuildBufferObject(spec, vertex_count, vertices.data());
597 }
598 
600 static gfx::IndexBufferPtr BuildExternalIndexBuffer(
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.";
611  return gfx::IndexBufferPtr();
612  }
613  indices[i] = static_cast<uint16>(mesh.mIndices[i]);
614  }
615  return BuildIndexBuffer(spec, index_count, indices.data());
616  }
617  case ExternalShapeSpec::IndexSize::k32Bit: {
618  gfx::IndexBufferPtr index_buffer(new (spec.allocator) gfx::IndexBuffer);
620  mesh.mIndices.data(), mesh.mIndices.size(), IsWipeable(spec),
621  spec.allocator);
622  index_buffer->AddSpec(gfx::BufferObject::kUnsignedInt, 1, 0);
623  index_buffer->SetData(container, sizeof(mesh.mIndices[0]),
624  mesh.mIndices.size(), spec.usage_mode);
625  return index_buffer;
626  }
627  default:
628  DCHECK(false) << "Unknown vertex size.";
629  return gfx::IndexBufferPtr();
630  }
631 }
632 
634 
639 
640 
642 static gfx::BufferObjectPtr BuildRectangleBufferObject(
643  const RectangleSpec& spec) {
644  VertexPTN vertices[4];
645  GetRectangleVertices(spec, spec.size[0], spec.size[1],
646  GetPlanarShapeSwizzle(spec.plane_normal),
647  GetPlanarShapeSigns(spec.plane_normal),
648  vertices);
649  return BuildBufferObject(spec, 4U, vertices);
650 }
651 
653 static const gfx::IndexBufferPtr BuildRectangleIndexBuffer(
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);
658 }
659 
661 
666 
667 
670 static gfx::BufferObjectPtr BuildRegularPolygonBufferObject(
671  const RegularPolygonSpec& spec) {
674  const int kNumVertices = spec.sides + 2;
675  const base::AllocatorPtr& allocator = GetShortTermAllocator(spec.allocator);
676 
679  base::AllocVector<Point2f> points(allocator, kNumVertices, Point2f::Zero());
680  GetCirclePoints(static_cast<size_t>(spec.sides), &points[1]);
681 
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());
687 }
688 
690 
695 
696 
698 static void GetBoxFaceVertices(const BoxSpec& spec,
699  PlanarShapeSpec::PlaneNormal plane_normal,
700  VertexPTN vertices[]) {
703  const char* swizzle = GetPlanarShapeSwizzle(plane_normal);
704  const Vector3f signs = GetPlanarShapeSigns(plane_normal);
705  const Vector3f swizzled_size = SwizzleVector3f(spec.size, swizzle);
706 
708  GetRectangleVertices(spec, swizzled_size[0], swizzled_size[1],
709  swizzle, signs, vertices);
710 
712  const Vector3f translation = spec.rotation * SwizzleVector3f(
713  Vector3f(0.f, 0.f, 0.5f * signs[2] * swizzled_size[2] * spec.scale),
714  swizzle);
717  for (int i = 0; i < 4; ++i)
718  vertices[i].position = vertices[i].position + translation;
719 }
720 
722 static gfx::BufferObjectPtr BuildBoxBufferObject(const BoxSpec& spec) {
723  static const size_t kNumVertices = 6 * 4;
724  VertexPTN verts[kNumVertices];
725  GetBoxFaceVertices(spec, RectangleSpec::kPositiveZ, &verts[0]); // Front.
726  GetBoxFaceVertices(spec, RectangleSpec::kNegativeZ, &verts[4]); // Back.
727  GetBoxFaceVertices(spec, RectangleSpec::kPositiveX, &verts[8]); // Right.
728  GetBoxFaceVertices(spec, RectangleSpec::kNegativeX, &verts[12]); // Left.
729  GetBoxFaceVertices(spec, RectangleSpec::kPositiveY, &verts[16]); // Top.
730  GetBoxFaceVertices(spec, RectangleSpec::kNegativeY, &verts[20]); // Bottom.
731  return BuildBufferObject(spec, kNumVertices, verts);
732 }
733 
735 static gfx::IndexBufferPtr BuildBoxIndexBuffer(const BoxSpec& spec) {
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);
747  }
748  return BuildIndexBuffer(spec, kNumIndices, indices);
749 }
750 
752 
757 
758 
760 struct EllipsoidData {
761  size_t band_count; // Number of latitudinal bands.
762  size_t sector_count; // Number of longitudinal sectors.
763  size_t vertices_per_ring; // Number of vertices in a latitudinal ring.
764  size_t vertex_count; // Total number of vertices.
765 };
766 
767 static const EllipsoidData GetEllipsoidData(const EllipsoidSpec& spec) {
768  EllipsoidData data;
769 
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);
773 
775  data.vertices_per_ring = data.sector_count + 1;
776 
779  data.vertex_count = (data.band_count + 1U) * data.vertices_per_ring;
780 
781  return data;
782 }
783 
785 static gfx::BufferObjectPtr BuildEllipsoidBufferObject(
786  const EllipsoidSpec& spec) {
788  const base::AllocatorPtr& allocator = GetShortTermAllocator(spec.allocator);
789 
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,
794  VertexPTN());
795 
797  base::AllocVector<Point2f> ring_points(allocator, data.vertices_per_ring,
798  Point2f::Zero());
799  GetPartialCirclePoints(data.sector_count,
800  spec.longitude_start,
801  spec.longitude_end,
802  &ring_points[0]);
803 
807  const Vector3f scale = 0.5f * spec.size;
808  const Vector3f inv_scale = 1.0f / scale;
809 
817  const Anglef delta_angle = (spec.latitude_end - spec.latitude_start)
818  / static_cast<float>(data.band_count);
819  size_t cur_vertex = 0;
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());
825  Point3f pos;
826  for (size_t s = 0; s <= data.sector_count; ++s) {
827  VertexPTN& v = vertices[cur_vertex];
828 
831  const Point2f& ring_pt = ring_points[s];
832  const Vector3f sphere_pt_vec(ring_radius * -ring_pt[1],
833  sphere_y,
834  ring_radius * -ring_pt[0]);
835  v.position = spec.rotation * ((scale * sphere_pt_vec) * spec.scale) +
836  spec.translation;
837 
839  if (has_tex_coords) {
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);
845  }
846 
850  if (has_normals)
851  v.normal = spec.rotation * math::Normalized(inv_scale * sphere_pt_vec);
852 
853  ++cur_vertex;
854  }
855  }
856  DCHECK_EQ(cur_vertex, data.vertex_count);
857 
858  return BuildBufferObject(spec, vertices.size(), &vertices[0]);
859 }
860 
862 static gfx::IndexBufferPtr BuildEllipsoidIndexBuffer(
863  const EllipsoidSpec& spec) {
864  const EllipsoidData data = GetEllipsoidData(spec);
865 
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));
871 
872  size_t cur_index = 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);
885  cur_index += 6U;
886  }
887  }
888  DCHECK_EQ(cur_index, index_count);
889 
890  return BuildIndexBuffer(spec, index_count, &indices[0]);
891 }
892 
894 
899 
900 
902 struct CylinderData {
903  bool add_top_cap; // Whether to add the top cap.
904  bool add_bottom_cap; // Whether to add the bottom cap.
905  size_t num_caps; // Number of caps that are included.
906  size_t shaft_band_count; // Number of bands in the shaft.
907  size_t cap_band_count; // Number of bands in the cap.
908  size_t sector_count; // Number of longitudinal sectors.
909  size_t vertices_per_ring; // Number of vertices in a latitudinal ring.
910  size_t shaft_vertex_count; // Total number of vertices in the shaft.
911  size_t cap_vertex_count; // Total number of vertices in each cap.
912  size_t vertex_count; // Total number of vertices.
913 };
914 
915 static const CylinderData GetCylinderData(const CylinderSpec& spec) {
916  CylinderData data;
917 
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;
920 
921  data.num_caps = (data.add_top_cap ? 1 : 0) + (data.add_bottom_cap ? 1 : 0);
922 
924  data.shaft_band_count = std::max(static_cast<size_t>(1),
925  spec.shaft_band_count);
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);
928 
930  data.vertices_per_ring = data.sector_count + 1;
931 
932  data.shaft_vertex_count =
933  (data.shaft_band_count + 1) * data.vertices_per_ring;
934 
936  data.cap_vertex_count = 1U + data.cap_band_count * data.vertices_per_ring;
937 
939  data.vertex_count =
940  data.shaft_vertex_count + data.num_caps * data.cap_vertex_count;
941 
942  return data;
943 }
944 
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,
956  -ring_pt[0]));
957  }
958  } else {
963  float base_radius;
964  float apex_y;
965  if (top_radius < bottom_radius) {
966  base_radius = bottom_radius;
967  apex_y = height + (top_radius * height) / (bottom_radius - top_radius);
968  } else {
969  base_radius = top_radius;
970  apex_y = -(height + (bottom_radius * height) /
971  (top_radius - bottom_radius));
972  }
973 
981  const float base_radius_squared = math::Square(base_radius);
982  const float ny = base_radius_squared / apex_y;
983 
986  const float inv_length = 1.f / math::Sqrt(base_radius_squared + ny * ny);
987 
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]);
992  }
993  }
994 }
995 
997 static size_t AddCylinderCapVertices(const CylinderSpec& spec,
998  const Point2f ring_points[], bool is_top,
999  VertexPTN* vertices) {
1000  const Vector3f normal =
1001  spec.rotation * (is_top ? Vector3f::AxisY() : -Vector3f::AxisY());
1002  const Vector3f scale =
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;
1009 
1010  size_t cur_vertex = 0;
1011 
1013  VertexPTN& center_v = vertices[0];
1014  center_v.position =
1015  spec.rotation * ((scale * Vector3f(0.f, y, 0.f)) * spec.scale) +
1016  spec.translation;
1017  if (has_tex_coords)
1018  center_v.texture_coords.Set(.5f, .5f);
1019  ++cur_vertex;
1020 
1022  float radius = 0.f;
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) {
1027  radius += delta_radius;
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];
1031 
1034  const Vector3f pt_vec(radius * -ring_pt[1], y, -radius * ring_pt[0]);
1035  v.position =
1036  spec.rotation * ((scale * pt_vec) * spec.scale) + spec.translation;
1037 
1040  if (has_tex_coords)
1041  v.texture_coords.Set(.5f + s_scale * pt_vec[0],
1042  .5f + t_scale * pt_vec[2]);
1043 
1044  ++cur_vertex;
1045  }
1046  }
1047 
1049  if (has_normals) {
1050  for (size_t i = 0; i < cur_vertex; ++i)
1051  vertices[i].normal = normal;
1052  }
1053 
1054  return cur_vertex;
1055 }
1056 
1059 static size_t AddCylinderCapIndices(
1060  const CylinderData& data, size_t start_index, bool invert_orientation,
1061  uint16 indices[]) {
1063  const uint16 center_index = static_cast<uint16>(start_index);
1064  size_t cur_index = 0;
1065 
1067  const int i0 = invert_orientation ? 1 : 0;
1068  const int i1 = 1 - i0;
1069 
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);
1076  cur_index += 3U;
1077  }
1078 
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);
1093  cur_index += 6U;
1094  }
1095  first_band_vertex = static_cast<uint16>(first_band_vertex + ring_offset);
1096  }
1097  return cur_index;
1098 }
1099 
1101 static gfx::BufferObjectPtr BuildCylinderBufferObject(
1102  const CylinderSpec& spec) {
1104  const base::AllocatorPtr& allocator = GetShortTermAllocator(spec.allocator);
1105 
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,
1110  VertexPTN());
1111 
1113  base::AllocVector<Point2f> ring_points(allocator, data.vertices_per_ring,
1114  Point2f::Zero());
1115  GetCirclePoints(data.sector_count, &ring_points[0]);
1116 
1118  base::AllocVector<Vector3f> shaft_normals(allocator, data.vertices_per_ring,
1119  Vector3f::Zero());
1120  GetCylinderShaftNormals(data.vertices_per_ring, &ring_points[0],
1121  spec.top_radius, spec.bottom_radius, spec.height,
1122  &shaft_normals[0]);
1123 
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);
1128  float ring_y = .5f;
1129  float ring_radius = spec.top_radius;
1130  size_t cur_vertex = 0;
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) +
1142  spec.translation;
1144  if (has_tex_coords)
1145  v.texture_coords.Set(static_cast<float>(s) /
1146  static_cast<float>(data.sector_count), ring_t);
1148  if (has_normals)
1149  v.normal = spec.rotation * shaft_normals[s];
1150 
1151  ++cur_vertex;
1152  }
1153  ring_y -= delta_y;
1154  ring_radius -= delta_radius;
1155  }
1156 
1158  if (data.add_top_cap)
1159  cur_vertex += AddCylinderCapVertices(spec, &ring_points[0], true,
1160  &vertices[cur_vertex]);
1161  if (data.add_bottom_cap)
1162  cur_vertex += AddCylinderCapVertices(spec, &ring_points[0], false,
1163  &vertices[cur_vertex]);
1164 
1165  DCHECK_EQ(cur_vertex, data.vertex_count);
1166 
1167  return BuildBufferObject(spec, vertices.size(), &vertices[0]);
1168 }
1169 
1171 static gfx::IndexBufferPtr BuildCylinderIndexBuffer(
1172  const CylinderSpec& spec) {
1173  const CylinderData data = GetCylinderData(spec);
1174 
1177  const size_t shaft_index_count =
1178  6U * data.shaft_band_count * data.sector_count;
1181  const size_t cap_index_count =
1182  3U * data.sector_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));
1188 
1189  size_t cur_index = 0;
1190 
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);
1204  cur_index += 6U;
1205  }
1206  }
1207 
1209  size_t first_cap_vertex = data.shaft_vertex_count;
1210  if (data.add_top_cap) {
1211  cur_index += AddCylinderCapIndices(data, first_cap_vertex, false,
1212  &indices[cur_index]);
1213  first_cap_vertex += data.cap_vertex_count;
1214  }
1215 
1216  if (data.add_bottom_cap) {
1217  cur_index += AddCylinderCapIndices(data, first_cap_vertex, true,
1218  &indices[cur_index]);
1219  first_cap_vertex += data.cap_vertex_count;
1220  }
1221  DCHECK_EQ(cur_index, index_count);
1222 
1223  return BuildIndexBuffer(spec, index_count, &indices[0]);
1224 }
1225 
1226 } // anonymous namespace
1227 
1229 
1234 
1235 
1237  const gfx::IndexBufferPtr& tri_index_buffer) {
1238  gfx::IndexBufferPtr line_index_buffer;
1239 
1240  if (tri_index_buffer.Get()) {
1242  const size_t tri_index_count = tri_index_buffer->GetCount();
1243  const base::DataContainerPtr& tri_data = tri_index_buffer->GetData();
1244  if (tri_index_count % 3U == 0U && tri_data.Get() && tri_data->GetData()) {
1245  const base::AllocatorPtr& al = tri_index_buffer->GetAllocator();
1246  const size_t line_index_count = 2U * tri_index_count;
1247 
1249  const gfx::BufferObject::Spec& spec = tri_index_buffer->GetSpec(0);
1251  DCHECK_EQ(spec.byte_offset, 0U);
1252  base::DataContainerPtr line_data;
1254  line_data = TriIndicesToLineIndices<uint8>(
1255  tri_data, tri_index_count, line_index_count, al);
1256  else if (spec.type == gfx::BufferObject::kUnsignedShort)
1257  line_data = TriIndicesToLineIndices<uint16>(
1258  tri_data, tri_index_count, line_index_count, al);
1259 
1260  if (line_data.Get()) {
1261  line_index_buffer = new(al) gfx::IndexBuffer;
1262  line_index_buffer->AddSpec(spec.type, 1, 0);
1263  line_index_buffer->SetData(line_data, tri_index_buffer->GetStructSize(),
1264  line_index_count,
1265  tri_index_buffer->GetUsageMode());
1266  }
1267  }
1268  }
1269  return line_index_buffer;
1270 }
1271 
1273  std::istream& in) { // NOLINT
1274  Mesh mesh;
1275  LoadExternalShapeData(spec.format, in, &mesh);
1276 
1278  if (mesh.mIndices.empty() || mesh.mVertices.empty())
1279  return gfx::ShapePtr();
1280 
1281  gfx::BufferObjectPtr buffer_object = BuildExternalBufferObject(spec, mesh);
1282  gfx::ShapePtr shape(new(spec.allocator) gfx::Shape);
1283  shape->SetLabel("External geometry");
1284  shape->SetPrimitiveType(gfx::Shape::kTriangles);
1285  shape->SetAttributeArray(BuildAttributeArray(spec, buffer_object));
1286  shape->SetIndexBuffer(BuildExternalIndexBuffer(spec, mesh));
1287  return shape;
1288 }
1289 
1291  gfx::ShapePtr shape(new(spec.allocator) gfx::Shape);
1292  shape->SetLabel("Rectangle");
1293  shape->SetPrimitiveType(gfx::Shape::kTriangles);
1294  shape->SetAttributeArray(
1295  BuildAttributeArray(spec, BuildRectangleBufferObject(spec)));
1296  shape->SetIndexBuffer(BuildRectangleIndexBuffer(spec));
1297  return shape;
1298 }
1299 
1301  DCHECK_LE(3, spec.sides) << "Polygons must have at least 3 sides";
1302  gfx::ShapePtr shape(new (spec.allocator) gfx::Shape);
1303  shape->SetLabel("Polygon");
1304  shape->SetPrimitiveType(gfx::Shape::kTriangleFan);
1305  shape->SetAttributeArray(
1306  BuildAttributeArray(spec, BuildRegularPolygonBufferObject(spec)));
1307  return shape;
1308 }
1309 
1311  gfx::ShapePtr shape(new(spec.allocator) gfx::Shape);
1312  shape->SetLabel("Box");
1313  shape->SetPrimitiveType(gfx::Shape::kTriangles);
1314  shape->SetAttributeArray(
1315  BuildAttributeArray(spec, BuildBoxBufferObject(spec)));
1316  shape->SetIndexBuffer(BuildBoxIndexBuffer(spec));
1317  return shape;
1318 }
1319 
1321  gfx::ShapePtr shape(new(spec.allocator) gfx::Shape);
1322  shape->SetLabel("Ellipsoid");
1323  shape->SetPrimitiveType(gfx::Shape::kTriangles);
1324  shape->SetAttributeArray(
1325  BuildAttributeArray(spec, BuildEllipsoidBufferObject(spec)));
1326  shape->SetIndexBuffer(BuildEllipsoidIndexBuffer(spec));
1327  return shape;
1328 }
1329 
1331  gfx::ShapePtr shape(new(spec.allocator) gfx::Shape);
1332  shape->SetLabel("Cylinder");
1333  shape->SetPrimitiveType(gfx::Shape::kTriangles);
1334  shape->SetAttributeArray(
1335  BuildAttributeArray(spec, BuildCylinderBufferObject(spec)));
1336  shape->SetIndexBuffer(BuildCylinderIndexBuffer(spec));
1337  return shape;
1338 }
1339 
1340 } // namespace gfxutils
1341 } // namespace ion
bool IsInvalidReference(const T &value)
IsInvalidReference() returns true if a passed const reference of type T has an address of InvalidRefe...
Definition: invalid.h:41
kShortTerm is used for objects that are very transient in nature, such as scratch memory used to comp...
Definition: allocator.h:36
ComponentType type
The type of each component.
Definition: bufferobject.h:164
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)...
Definition: vectorutils.h:262
Angle< float > Anglef
Type-specific typedefs.
Definition: angle.h:156
Vector3f normal
Definition: shapeutils.cc:81
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.
Definition: indexbuffer.h:28
#define DCHECK(expr)
Definition: logging.h:331
size_t vertices_per_ring
Definition: shapeutils.cc:763
#define LOG(severity)
Logs the streamed message unconditionally with a severity of severity.
Definition: logging.h:216
Point2f texture_coords
Definition: shapeutils.cc:74
size_t byte_offset
The offset of the element defined by this Spec in the data type.
Definition: bufferobject.h:162
size_t sector_count
Definition: shapeutils.cc:762
Matrix< 3, float > Matrix3f
Definition: matrix.h:369
virtual const AllocatorPtr & GetAllocatorForLifetime(AllocationLifetime lifetime) const
Returns the correct Allocator to use to allocate memory with a specific lifetime. ...
Definition: allocator.cc:27
External geometry formats.
Definition: shapeutils.h:92
const gfx::ShapePtr BuildEllipsoidShape(const EllipsoidSpec &spec)
Builds and returns a Shape representing an axis-aligned ellipsoid.
Definition: shapeutils.cc:1320
T Sqrt(const T &val)
Returns the square root of a value.
Definition: utils.h:59
SharedPtr< Allocator > AllocatorPtr
Definition: allocator.h:51
size_t shaft_vertex_count
Definition: shapeutils.cc:910
size_t cap_band_count
Definition: shapeutils.cc:907
base::ReferentPtr< IndexBuffer >::Type IndexBufferPtr
Definition: indexbuffer.h:38
T * Get() const
Returns a raw pointer to the instance, which may be NULL.
Definition: sharedptr.h:89
Point3f position
Definition: shapeutils.cc:67
const gfx::ShapePtr BuildCylinderShape(const CylinderSpec &spec)
Builds and returns a Shape representing an axis-aligned cylinder.
Definition: shapeutils.cc:1330
Vector2d translation
Definition: coretextfont.mm:62
const gfx::IndexBufferPtr BuildWireframeIndexBuffer(const gfx::IndexBufferPtr &tri_index_buffer)
Public functions.
Definition: shapeutils.cc:1236
Range< 3, float > Range3f
Definition: range.h:381
const gfx::ShapePtr LoadExternalShape(const ExternalShapeSpec &spec, std::istream &in)
Loads a Shape with the specified format from the passed stream.
Definition: shapeutils.cc:1272
size_t num_caps
Definition: shapeutils.cc:905
A Shape object represents a shape (vertices + indices) to draw.
Definition: shape.h:32
size_t vertex_count
Definition: shapeutils.cc:764
const gfx::ShapePtr BuildRegularPolygonShape(const RegularPolygonSpec &spec)
Builds and returns a Shape representing a flat regular polygon.
Definition: shapeutils.cc:1300
Format
The set of external geometry file formats that can be read with LoadExternalShape().
Definition: shapeutils.h:95
const Vector< Dimension, T > Normalized(const Vector< Dimension, T > &v)
Returns a unit-length version of a Vector.
Definition: vectorutils.h:104
const gfx::ShapePtr BuildBoxShape(const BoxSpec &spec)
Builds and returns a Shape representing an axis-aligned box.
Definition: shapeutils.cc:1310
bool add_top_cap
Definition: shapeutils.cc:903
size_t band_count
Definition: shapeutils.cc:761
Copyright 2016 Google Inc.
bool add_bottom_cap
Definition: shapeutils.cc:904
int width
#define DCHECK_EQ(val1, val2)
Definition: logging.h:332
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...
Definition: shapeutils.h:144
#define DCHECK_LE(val1, val2)
Definition: logging.h:334
size_t shaft_band_count
Definition: shapeutils.cc:906
size_t cap_vertex_count
Definition: shapeutils.cc:911
const T Square(const T &val)
Squares a value.
Definition: utils.h:48
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
Definition: datacontainer.h:38
base::ReferentPtr< BufferObject >::Type BufferObjectPtr
Convenience typedef for shared pointer to a BufferObject.
Definition: bufferobject.h:31
base::AllocatorPtr allocator
Definition: shapeutils.h:55
Vector2d scale
Definition: coretextfont.mm:63
A SharedPtr is a smart shared pointer to an instance of some class that implements reference counting...
Definition: sharedptr.h:60
const gfx::ShapePtr BuildRectangleShape(const RectangleSpec &spec)
Builds and returns a Shape representing a rectangle in one of the principal Cartesian planes...
Definition: shapeutils.cc:1290
static const AllocatorPtr & GetDefaultAllocatorForLifetime(AllocationLifetime lifetime)