Ion: gfxutils/shapeutils.cc Source File

1 

19 

20 #include <algorithm>

21 

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"

42 

43 namespace ion {

44 namespace gfxutils {

45 

48 using math::Point2f;

49 using math::Point3f;

51 using math::Vector3f;

52 

53 namespace {

54 

56 

62 

63 

65 struct VertexP {

66  VertexP() : position(Point3f::Zero()) {}

68 };

69 

71 struct VertexPT {

75 };

76 

78 struct VertexPN {

79  VertexPN() : position(Point3f::Zero()), normal(Vector3f::Zero()) {}

82 };

83 

85 struct VertexPTN {

86  VertexPTN() :

89  normal(Vector3f::Zero()) {}

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)

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>

153 #if !defined(ION_COVERAGE) // COV_NF_START

154  DCHECK(false) << "Unspecialized BindVertices called";

155 #endif // COV_NF_END

156 }

157 

159 template <>

162  VertexP v;

163  BufferToAttributeBinder<VertexP>(v)

164  .Bind(v.position, "aVertex")

166  attribute_array, buffer_object);

167 }

168 

170 template <>

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 <>

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 <>

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 

218  return allocator.Get() ?

221 }

222 

224 static const Vector3f SwizzleVector3f(const Vector3f& v,

225  const char swizzle[3]) {

226  Vector3f swizzled;

228  return swizzled;

229 }

230 

234 template <typename VertexType>

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) {

253 }

254 

257 static bool HasTextureCoordinates(const ShapeSpec& spec) {

260 }

261 

263 static bool HasNormals(const ShapeSpec& spec) {

266 }

267 

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 

298  const ShapeSpec& spec, size_t vertex_count, const VertexPTN vertices[]) {

300  const bool is_wipeable = IsWipeable(spec);

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 

335  const ShapeSpec& spec, size_t num_indices, const uint16 indices[]) {

338  base::DataContainer::CreateAndCopy<uint16>(

339  indices, num_indices, IsWipeable(spec), spec.allocator);

340 

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>

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 

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(

398  switch (plane_normal) {

401  return "zyx";

404  return "xzy";

407  default:

408  return "xyz";

409  }

410 }

411 

416 static const Vector3f GetPlanarShapeSigns(

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;

451 

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;

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)) {

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);

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,

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,

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,

528  math::Anglef::FromDegrees(360.f),

529  points);

530 }

531 

533 

538 

539 

542  std::istream& in,

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 

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  }

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 

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.";

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: {

620  mesh.mIndices.data(), mesh.mIndices.size(), IsWipeable(spec),

621  spec.allocator);

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.";

630  }

631 }

632 

634 

639 

640 

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 

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 

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,

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)

719 }

720 

723  static const size_t kNumVertices = 6 * 4;

724  VertexPTN verts[kNumVertices];

731  return BuildBufferObject(spec, kNumVertices, verts);

732 }

733 

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;

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 

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 

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 {

905  size_t num_caps;

908  size_t sector_count;

909  size_t vertices_per_ring;

912  size_t vertex_count;

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 

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 

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 }

1227 

1229 

1234 

1235 

1239 

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;

1247 

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);

1259 

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(),

1264  line_index_count,

1265  tri_index_buffer->GetUsageMode());

1266  }

1267  }

1268  }

1269  return line_index_buffer;

1270 }

1271 

1273  std::istream& in) {

1274  Mesh mesh;

1275  LoadExternalShapeData(spec.format, in, &mesh);

1276 

1278  if (mesh.mIndices.empty() || mesh.mVertices.empty())

1280 

1283  shape->SetLabel("External geometry");

1285  shape->SetAttributeArray(BuildAttributeArray(spec, buffer_object));

1286  shape->SetIndexBuffer(BuildExternalIndexBuffer(spec, mesh));

1287  return shape;

1288 }

1289 

1292  shape->SetLabel("Rectangle");

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";

1303  shape->SetLabel("Polygon");

1305  shape->SetAttributeArray(

1306  BuildAttributeArray(spec, BuildRegularPolygonBufferObject(spec)));

1307  return shape;

1308 }

1309 

1312  shape->SetLabel("Box");

1314  shape->SetAttributeArray(

1315  BuildAttributeArray(spec, BuildBoxBufferObject(spec)));

1316  shape->SetIndexBuffer(BuildBoxIndexBuffer(spec));

1317  return shape;

1318 }

1319 

1322  shape->SetLabel("Ellipsoid");

1324  shape->SetAttributeArray(

1325  BuildAttributeArray(spec, BuildEllipsoidBufferObject(spec)));

1326  shape->SetIndexBuffer(BuildEllipsoidIndexBuffer(spec));

1327  return shape;

1328 }

1329 

1332  shape->SetLabel("Cylinder");

1334  shape->SetAttributeArray(

1335  BuildAttributeArray(spec, BuildCylinderBufferObject(spec)));

1336  shape->SetIndexBuffer(BuildCylinderIndexBuffer(spec));

1337  return shape;

1338 }

1339 

1340 }

1341 }

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)