Ion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
printer.cc
Go to the documentation of this file.
1 
18 #include "ion/gfxutils/printer.h"
19 
20 #include <algorithm>
21 #include <iomanip>
22 #include <set>
23 #include <sstream>
24 #include <string>
25 
26 #include "ion/base/array2.h"
27 #include "ion/base/enumhelper.h"
28 #include "ion/base/invalid.h"
29 #include "ion/base/logging.h"
30 #include "ion/base/serialize.h"
31 #include "ion/gfx/attribute.h"
32 #include "ion/gfx/attributearray.h"
33 #include "ion/gfx/cubemaptexture.h"
34 #include "ion/gfx/image.h"
35 #include "ion/gfx/sampler.h"
37 #include "ion/gfx/shaderprogram.h"
38 #include "ion/gfx/shape.h"
39 #include "ion/gfx/statetable.h"
40 #include "ion/gfx/texture.h"
41 #include "ion/gfx/uniform.h"
42 #include "ion/gfx/uniformblock.h"
43 #include "ion/math/matrix.h"
44 #include "ion/math/range.h"
45 #include "ion/math/vector.h"
46 #include "ion/math/vectorutils.h"
47 
48 namespace ion {
49 namespace gfxutils {
50 
51 namespace {
52 
53 using gfx::Attribute;
54 using gfx::AttributeArray;
56 using gfx::CubeMapTexture;
58 using gfx::BufferObject;
59 using gfx::BufferObjectElement;
61 using gfx::Image;
62 using gfx::ImagePtr;
63 using gfx::IndexBuffer;
65 using gfx::Node;
66 using gfx::NodePtr;
67 using gfx::Sampler;
68 using gfx::SamplerPtr;
69 using gfx::ShaderInputRegistry;
71 using gfx::ShaderProgram;
73 using gfx::Shape;
74 using gfx::ShapePtr;
75 using gfx::StateTable;
76 using gfx::StateTablePtr;
77 using gfx::Texture;
78 using gfx::TextureBase;
79 using gfx::TexturePtr;
80 using gfx::Uniform;
81 using gfx::UniformBlock;
83 
85 
90 
91 
92 struct Mask {
93  explicit Mask(uint32 value_in) : value(value_in) {}
94  const uint32 value;
95 };
96 
97 std::ostream& operator<<(std::ostream& out, const Mask& mask) {
98  return out << "0x" << std::hex << mask.value << std::dec;
99 }
100 
102 
107 
108 
109 struct Pointer {
110  explicit Pointer(const void* pointer_in) : pointer(pointer_in) {}
111  const void* pointer;
112 };
113 
114 std::ostream& operator<<(std::ostream& out, const Pointer& p) {
115  if (p.pointer)
116  out << p.pointer;
117  else
118  out << "NULL";
119  return out;
120 }
121 
123 
128 
129 
132 template <typename T> const std::string ValueToString(const T& value) {
133  return base::ValueToString(value);
134 }
135 template <int Dimension, typename T>
136 const std::string ValueToString(const math::VectorBase<Dimension, T>& vec) {
137  return base::ValueToString(
138  static_cast<const math::Vector<Dimension, T>&>(vec));
139 }
141 template <typename T> const std::string ValueToString(const T* value) {
142  return value ? base::ValueToString(value) : std::string("NULL");
143 }
144 
148 template<typename ValueType, typename ValuePrintType>
149 static void PrintBufferData(std::ostream& out, // NOLINT
150  const char* data, const size_t num_components) {
151  if (const ValueType* typed_data = reinterpret_cast<const ValueType*>(data)) {
152  if (num_components == 1) {
153  out << static_cast<ValuePrintType>(typed_data[0]);
154  } else {
155  out << "[";
156  for (size_t i = 0; i < num_components; ++i) {
157  out << static_cast<ValuePrintType>(typed_data[i]);
158  if (i < num_components - 1)
159  out << ", ";
160  }
161  out << "]";
162  }
163  } else {
164  out << "[NULL]";
165  }
166 }
167 
169 template<typename T>
170 static void PrintMatrixBufferData(std::ostream& out, // NOLINT
171  const char* data,
172  const size_t num_columns,
173  const size_t num_components) {
174  if (const T* typed_data = reinterpret_cast<const T*>(data)) {
175  out << "[";
176  for (size_t i = 0; i < num_components; ++i) {
177  for (size_t j = 0; j < num_columns; ++j) {
178  out << typed_data[i * num_columns + j];
179  if (j < num_columns - 1)
180  out << ", ";
181  }
182  if (i < num_components - 1)
183  out << " | ";
184  }
185  out << "]";
186  }
187 }
188 
189 static void PrintBufferDataByType(std::ostream& out, // NOLINT
190  BufferObject::ComponentType type,
191  const char* ptr, size_t count) {
192  switch (type) {
193  case BufferObject::kByte:
194  PrintBufferData<int8, int32>(out, ptr, count);
195  break;
196  case BufferObject::kUnsignedByte:
197  PrintBufferData<uint8, uint32>(out, ptr, count);
198  break;
199  case BufferObject::kShort:
200  PrintBufferData<int16, int32>(out, ptr, count);
201  break;
202  case BufferObject::kUnsignedShort:
203  PrintBufferData<uint16, uint32>(out, ptr, count);
204  break;
205  case BufferObject::kInt:
206  PrintBufferData<int32, int32>(out, ptr, count);
207  break;
208  case BufferObject::kUnsignedInt:
209  PrintBufferData<uint32, uint32>(out, ptr, count);
210  break;
211  case BufferObject::kFloat:
212  PrintBufferData<float, float>(out, ptr, count);
213  break;
214  case BufferObject::kFloatMatrixColumn2:
215  PrintMatrixBufferData<float>(out, ptr, 2U, count);
216  break;
217  case BufferObject::kFloatMatrixColumn3:
218  PrintMatrixBufferData<float>(out, ptr, 3U, count);
219  break;
220  case BufferObject::kFloatMatrixColumn4:
221  PrintMatrixBufferData<float>(out, ptr, 4U, count);
222  break;
223  case BufferObject::kInvalid:
224  default:
225 #if !defined(ION_COVERAGE) // COV_NF_START
226  DCHECK(false) << "Invalid buffer component type " << type;
227 #endif // COV_NF_END
228  break;
229  }
230 }
231 
234 static size_t GetBufferAttributeVertexCount(const AttributeArray& aa) {
235  size_t min_vertex_count = 0;
236  bool is_first = true;
237  const size_t attribute_count = aa.GetAttributeCount();
238  for (size_t i = 0; i < attribute_count; ++i) {
239  const Attribute& attribute = aa.GetAttribute(i);
240  if (attribute.IsValid() && attribute.Is<BufferObjectElement>() &&
241  aa.IsAttributeEnabled(i)) {
242  const size_t vertex_count =
243  attribute.GetValue<BufferObjectElement>().buffer_object->GetCount();
244  if (is_first) {
245  min_vertex_count = vertex_count;
246  is_first = false;
247  } else {
248  min_vertex_count = std::min(min_vertex_count, vertex_count);
249  }
250  }
251  }
252  return min_vertex_count;
253 }
254 
255 static const std::string GetBufferAttributeValue(const AttributeArray& aa,
256  size_t vertex_index) {
257  std::ostringstream s;
258  bool is_first = true;
259  const size_t attribute_count = aa.GetAttributeCount();
260  for (size_t i = 0; i < attribute_count; ++i) {
261  const Attribute& a = aa.GetAttribute(i);
262  if (a.IsValid() && a.Is<BufferObjectElement>() &&
263  aa.IsAttributeEnabled(i)) {
264  if (is_first) {
265  is_first = false;
266  } else {
267  s << ", ";
268  }
269 
271  const BufferObjectPtr& bo =
272  a.GetValue<BufferObjectElement>().buffer_object;
273  const size_t num_entries = bo->GetCount();
274  if (vertex_index < num_entries) {
277  const size_t stride = bo->GetStructSize();
278  const char* raw_data =
279  static_cast<const char*>(bo->GetData()->GetData());
280 
281  const size_t spec_index = a.GetValue<BufferObjectElement>().spec_index;
282  const BufferObject::Spec& spec = bo->GetSpec(spec_index);
284  const char* ptr =
285  raw_data ? &raw_data[stride * vertex_index + spec.byte_offset]
286  : NULL;
287  PrintBufferDataByType(s, spec.type, ptr, spec.component_count);
288  }
289  }
290  }
291  return s.str();
292 }
293 
295 
301 
302 
303 class Tree {
304  public:
307  class Table : public base::Array2<std::string> {
308  public:
309  Table(size_t num_columns, size_t num_rows, bool has_label_column)
310  : base::Array2<std::string>(num_columns, num_rows),
311  has_label_column_(has_label_column) {}
312 
313  bool HasLabelColumn() const { return has_label_column_; }
314 
315  private:
317  };
318 
321  struct StringField {
322  StringField(const std::string& name_in, const std::string& value_in)
323  : name(name_in), value(value_in) {}
324  std::string name;
325  std::string value;
326  };
327 
329  struct TableField {
330  TableField(const std::string& name_in, const Table& table_in)
331  : name(name_in), table(table_in) {}
332  std::string name;
333  Table table;
334  };
335 
338  struct ObjectField {
339  ObjectField(const std::string& name_in, size_t object_index_in)
340  : name(name_in), object_index(object_index_in) {}
341  std::string name;
342  size_t object_index; // Index of object in vector.
343  };
344 
347  struct Object {
348  Object(const void* pointer_in, const std::string& type_in,
349  const std::string& label_in, bool is_inside_field_in)
350  : pointer(pointer_in), type(type_in),
351  label(label_in), is_inside_field(is_inside_field_in) {}
352  const void* pointer;
353  std::string type;
354  std::string label;
356  std::vector<StringField> string_fields;
357  std::vector<TableField> table_fields;
358  std::vector<ObjectField> object_fields;
359  std::vector<size_t> child_object_indices;
360  };
361 
362  Tree() {
363  all_objects_.reserve(128);
364  root_objects_.reserve(16);
365  cur_objects_.reserve(16);
366  }
367 
368  size_t BeginObject(const void* pointer, const std::string& type,
369  const std::string& label, bool is_inside_field) {
370  const size_t index = all_objects_.size();
371  all_objects_.push_back(Object(pointer, type, label, is_inside_field));
372 
375  if (!is_inside_field) {
376  if (cur_objects_.empty()) {
377  root_objects_.push_back(index);
378  } else {
379  GetCurObject()->child_object_indices.push_back(index);
380  }
381  }
382 
383  cur_objects_.push_back(index);
384  return index;
385  }
386 
387  template <typename T>
388  size_t BeginLabeledObject(const T* pointer, const std::string& type) {
389  return BeginObject(pointer, type, pointer ? pointer->GetLabel() : "");
390  }
391 
392  void EndObject() {
393  DCHECK(!cur_objects_.empty());
394  cur_objects_.pop_back();
395  }
396 
399  template <typename T>
400  void AddField(const std::string& name, const T& value) {
401  AddStringField(name, ValueToString(value));
402  }
403 
406  template <typename E>
407  void AddEnumField(const std::string& name, E enumvalue) {
408  AddStringField(name, base::EnumHelper::GetString(enumvalue));
409  }
410 
411  void AddStringField(const std::string& name, const std::string& value) {
412  GetCurObject()->string_fields.push_back(StringField(name, value));
413  }
414 
415  void AddTableField(const std::string& name, const Table& table) {
416  GetCurObject()->table_fields.push_back(TableField(name, table));
417  }
418 
419  void AddObjectField(const std::string& name, size_t object_index) {
420  GetCurObject()->object_fields.push_back(ObjectField(name, object_index));
421  }
422 
423  const std::vector<size_t>& GetRootObjectIndices() const {
424  return root_objects_;
425  }
426 
427  const Object& GetObject(size_t index) const {
428  DCHECK_LT(index, all_objects_.size());
429  return all_objects_[index];
430  }
431 
432  private:
433  Object* GetCurObject() {
434  DCHECK(!cur_objects_.empty());
435  return &all_objects_[cur_objects_.back()];
436  }
437 
438  std::vector<Object> all_objects_; // All objects added to the Tree.
439  std::vector<size_t> root_objects_; // Indices of all root objects.
440  std::vector<size_t> cur_objects_; // Stack of indices of open objects.
441 };
442 
444 
450 
451 
452 class MultiField {
453  public:
454  MultiField() : is_first_(true) {}
455 
457  template <typename T>
458  MultiField& Add(const std::string& name, const T& value) {
459  return AddField(name, ValueToString(value));
460  }
461 
463  template <typename E>
464  MultiField& AddEnum(const std::string& name, E enumvalue) {
465  return AddField(name, base::EnumHelper::GetString(enumvalue));
466  }
467 
469  MultiField& AddString(const std::string& name, const std::string& value) {
470  return AddField(name, value);
471  }
472 
474  template <typename T>
475  MultiField& AddIf(bool cond, const std::string& name, const T& value) {
476  if (cond) {
477  Add(name, value);
478  }
479  return *this;
480  }
481 
483  const std::string Get() const { return out_.str(); }
484 
485  private:
486  MultiField& AddField(const std::string& name, const std::string& value) {
487  if (is_first_)
488  is_first_ = false;
489  else
490  out_ << ", ";
491  out_ << name << '=' << value;
492  return *this;
493  }
494 
495  std::ostringstream out_;
496  bool is_first_;
497 };
498 
500 
505 
506 
508 template <int Dimension, typename T>
509 static const Tree::Table BuildMatrixTable(const math::Matrix<Dimension, T>& m) {
510  Tree::Table table(Dimension, Dimension, false);
511  for (int row = 0; row < Dimension; ++row) {
512  for (int col = 0; col < Dimension; ++col) {
513  table.Set(col, row, ValueToString(m(row, col)));
514  }
515  }
516  return table;
517 }
518 
520 static const Tree::Table GetIndexBufferTable(
521  const IndexBuffer& ib, const BufferObject::Spec& spec) {
523  const size_t stride = ib.GetStructSize();
524  const char* raw_data = ib.GetData().Get() ?
525  static_cast<const char*>(ib.GetData()->GetData()) :
526  NULL;
527  const size_t index_count = ib.GetCount();
528 
530  static const size_t kNumColumns = 10U;
531  const size_t num_rows = (index_count + kNumColumns - 1) / kNumColumns;
532  Tree::Table table(1U + kNumColumns, num_rows, true);
533  size_t cur_index = 0;
534  for (size_t row = 0; row < num_rows; ++row) {
536  const size_t last = std::min(cur_index + kNumColumns - 1, index_count - 1);
537  table.Set(0, row,
538  base::ValueToString(cur_index) + " - " + ValueToString(last));
539 
541  std::ostringstream out;
542  for (size_t col = 0; col < kNumColumns; ++col) {
543  const char* ptr =
544  raw_data ? &raw_data[stride * cur_index + spec.byte_offset] : NULL;
545  PrintBufferDataByType(out, spec.type, ptr, spec.component_count);
546  table.Set(1U + col, row, out.str());
547  out.str("");
548  if (++cur_index >= index_count)
549  break;
550  }
551  }
552  return table;
553 }
554 
556 
561 
562 
563 class TreeBuilder {
564  public:
565  TreeBuilder(bool address_printing_enabled,
566  bool full_shape_printing_enabled)
567  : address_printing_enabled_(address_printing_enabled),
568  full_shape_printing_enabled_(full_shape_printing_enabled) {}
569  ~TreeBuilder() {}
570 
571  const Tree& BuildTree(const Node& node) {
572  AddNode(node);
573  return tree_;
574  }
575 
576  private:
578  class ScopedObjectBase {
579  public:
580  ScopedObjectBase(Tree* tree, const void* object, const std::string& type,
581  const std::string& label, bool is_inside_field)
582  : tree_(tree),
584  tree_->BeginObject(object, type, label, is_inside_field)) {}
585  ~ScopedObjectBase() { tree_->EndObject(); }
586  size_t GetIndex() const { return object_index_; }
587 
588  private:
589  Tree* tree_;
590  const size_t object_index_;
591  };
592 
594  template <typename T> class ScopedLabeledObject : public ScopedObjectBase {
595  public:
596  ScopedLabeledObject(Tree* tree, const T* object, const std::string& type,
597  bool is_inside_field)
598  : ScopedObjectBase(tree, object, type,
599  object ? object->GetLabel() : std::string(""),
600  is_inside_field) {}
601  };
602 
604  class ScopedObject : public ScopedObjectBase {
605  public:
606  ScopedObject(Tree* tree, const void* object, const std::string& type)
607  : ScopedObjectBase(tree, object, type, "", false) {}
608  };
609 
612  class ContainerObject : public ScopedObjectBase {
613  public:
615  explicit ContainerObject(Tree* tree)
616  : ScopedObjectBase(tree, NULL, "", "", true) {}
617  };
618 
622  void AddNode(const Node& node);
623  void AddStateTable(const StateTable& st);
624  void AddImageFields(const Image& image, const char* face);
625  size_t AddCubeMapTexture(const CubeMapTexture* texture);
626  size_t AddTexture(const Texture* texture);
627  void AddTextureBaseFields(const TextureBase* texture);
628  size_t AddSampler(const Sampler* sampler);
629  void AddShape(const Shape& shape);
630  void AddUniform(const Uniform& uniform);
631  void AddUniformBlock(const UniformBlock* block);
632  void AddUniformValueField(const Uniform& uniform);
633  void AddAttributeArray(const AttributeArray& va, bool add_contents);
634  void AddAttribute(const Attribute& attribute, bool is_enabled);
635  void AddNonbufferAttributeValueField(const Attribute& attribute);
636  void AddBufferAttributeValues(const AttributeArray& aa);
637 
638  Tree tree_;
641  std::set<const AttributeArray*> added_attribute_arrays_;
642 };
643 
644 void TreeBuilder::AddNode(const Node& node) {
645  ScopedLabeledObject<Node> obj(&tree_, &node, "Node", false);
646 
647  tree_.AddField("Enabled", node.IsEnabled());
648 
650  if (const ShaderProgram* program = node.GetShaderProgram().Get())
651  tree_.AddField("Shader ID", program->GetLabel());
652 
654  if (const StateTable* st = node.GetStateTable().Get())
655  AddStateTable(*st);
656 
658  const base::AllocVector<Uniform>& uniforms = node.GetUniforms();
659  for (size_t i = 0; i < uniforms.size(); ++i)
660  AddUniform(uniforms[i]);
661 
663  const base::AllocVector<UniformBlockPtr>& uniform_blocks =
664  node.GetUniformBlocks();
665  for (size_t i = 0; i < uniform_blocks.size(); ++i)
666  AddUniformBlock(uniform_blocks[i].Get());
667 
669  const base::AllocVector<ShapePtr>& shapes = node.GetShapes();
670  for (size_t i = 0; i < shapes.size(); ++i)
671  AddShape(*shapes[i]);
672 
674  const base::AllocVector<NodePtr>& children = node.GetChildren();
675  for (size_t i = 0; i < children.size(); ++i)
676  AddNode(*children[i]);
677 }
678 
679 void TreeBuilder::AddStateTable(const StateTable& st) {
680  ScopedObject obj(&tree_, &st, "StateTable");
681 
683  const int num_capabilities = StateTable::GetCapabilityCount();
684  for (int i = 0; i < num_capabilities; ++i) {
685  const StateTable::Capability cap = static_cast<StateTable::Capability>(i);
686  if (st.IsCapabilitySet(cap))
687  tree_.AddField(StateTable::GetEnumString(cap), st.IsEnabled(cap));
688  }
689 
691  if (st.IsValueSet(StateTable::kBlendColorValue))
692  tree_.AddField("Blend Color", st.GetBlendColor());
693  if (st.IsValueSet(StateTable::kBlendEquationsValue)) {
694  tree_.AddStringField(
695  "Blend Equations",
696  MultiField()
697  .AddEnum("RGB", st.GetRgbBlendEquation())
698  .AddEnum("Alpha", st.GetAlphaBlendEquation())
699  .Get());
700  }
701  if (st.IsValueSet(StateTable::kBlendFunctionsValue)) {
702  tree_.AddStringField(
703  "Blend Functions",
704  MultiField()
705  .AddEnum("RGB-src", st.GetRgbBlendFunctionSourceFactor())
706  .AddEnum("RGB-dest", st.GetRgbBlendFunctionDestinationFactor())
707  .AddEnum("Alpha-src", st.GetAlphaBlendFunctionSourceFactor())
708  .AddEnum("Alpha-dest", st.GetAlphaBlendFunctionDestinationFactor())
709  .Get());
710  }
711  if (st.IsValueSet(StateTable::kClearColorValue))
712  tree_.AddField("Clear Color", st.GetClearColor());
713  if (st.IsValueSet(StateTable::kColorWriteMasksValue)) {
714  tree_.AddStringField(
715  "Color Write Masks",
716  MultiField()
717  .Add("R", st.GetRedColorWriteMask())
718  .Add("G", st.GetGreenColorWriteMask())
719  .Add("B", st.GetBlueColorWriteMask())
720  .Add("A", st.GetAlphaColorWriteMask())
721  .Get());
722  }
723  if (st.IsValueSet(StateTable::kCullFaceModeValue))
724  tree_.AddEnumField("Cull Face Mode", st.GetCullFaceMode());
725  if (st.IsValueSet(StateTable::kFrontFaceModeValue))
726  tree_.AddEnumField("Front Face Mode", st.GetFrontFaceMode());
727  if (st.IsValueSet(StateTable::kClearDepthValue))
728  tree_.AddField("Clear Depth Value", st.GetClearDepthValue());
729  if (st.IsValueSet(StateTable::kDepthFunctionValue))
730  tree_.AddEnumField("Depth Function", st.GetDepthFunction());
731  if (st.IsValueSet(StateTable::kDepthRangeValue))
732  tree_.AddField("Depth Range", st.GetDepthRange());
733  if (st.IsValueSet(StateTable::kDepthWriteMaskValue))
734  tree_.AddField("Depth Write Mask", st.GetDepthWriteMask());
735  if (st.IsValueSet(StateTable::kDrawBufferValue))
736  tree_.AddEnumField("Draw Buffer", st.GetDrawBuffer());
737  if (st.IsValueSet(StateTable::kHintsValue))
738  tree_.AddEnumField("Generate Mipmap Hint",
739  st.GetHint(StateTable::kGenerateMipmapHint));
740  if (st.IsValueSet(StateTable::kLineWidthValue))
741  tree_.AddField("Line Width", st.GetLineWidth());
742  if (st.IsValueSet(StateTable::kPolygonOffsetValue)) {
743  tree_.AddStringField(
744  "Polygon Offset",
745  MultiField()
746  .Add("Factor", st.GetPolygonOffsetFactor())
747  .Add("Units", st.GetPolygonOffsetUnits())
748  .Get());
749  }
750  if (st.IsValueSet(StateTable::kSampleCoverageValue)) {
751  tree_.AddStringField(
752  "Sample Coverage",
753  MultiField()
754  .Add("Value", st.GetSampleCoverageValue())
755  .Add("Inverted", st.IsSampleCoverageInverted())
756  .Get());
757  }
758  if (st.IsValueSet(StateTable::kScissorBoxValue))
759  tree_.AddField("Scissor Box", st.GetScissorBox());
760  if (st.IsValueSet(StateTable::kStencilFunctionsValue)) {
761  tree_.AddStringField(
762  "Stencil Functions",
763  MultiField()
764  .AddEnum("FFunc", st.GetFrontStencilFunction())
765  .Add("FRef", st.GetFrontStencilReferenceValue())
766  .Add("FMask", Mask(st.GetFrontStencilMask()))
767  .AddEnum("BFunc", st.GetBackStencilFunction())
768  .Add("BRef", st.GetBackStencilReferenceValue())
769  .Add("BMask", Mask(st.GetBackStencilMask()))
770  .Get());
771  }
772  if (st.IsValueSet(StateTable::kStencilOperationsValue)) {
773  tree_.AddStringField(
774  "Stencil Operations",
775  MultiField()
776  .AddEnum("FFail", st.GetFrontStencilFailOperation())
777  .AddEnum("FDFail", st.GetFrontStencilDepthFailOperation())
778  .AddEnum("FPass", st.GetFrontStencilPassOperation())
779  .AddEnum("BFail", st.GetBackStencilFailOperation())
780  .AddEnum("BDFail", st.GetBackStencilDepthFailOperation())
781  .AddEnum("BPass", st.GetBackStencilPassOperation())
782  .Get());
783  }
784  if (st.IsValueSet(StateTable::kClearStencilValue))
785  tree_.AddField("Clear Stencil Value", st.GetClearStencilValue());
786  if (st.IsValueSet(StateTable::kStencilWriteMasksValue)) {
787  tree_.AddStringField(
788  "Stencil Write Masks",
789  MultiField()
790  .Add("F", Mask(st.GetFrontStencilWriteMask()))
791  .Add("B", Mask(st.GetBackStencilWriteMask()))
792  .Get());
793  }
794  if (st.IsValueSet(StateTable::kViewportValue))
795  tree_.AddField("Viewport", st.GetViewport());
796 }
797 
798 void TreeBuilder::AddImageFields(const Image& image, const char* face) {
799  tree_.AddStringField(
800  "Image",
801  MultiField()
802  .AddIf(address_printing_enabled_, "Address", &image)
803  .AddString("Face", face)
804  .AddString("Format", Image::GetFormatString(image.GetFormat()))
805  .Add("Width", image.GetWidth())
806  .Add("Height", image.GetHeight())
807  .Add("Depth", image.GetDepth())
808  .AddEnum("Type", image.GetType())
809  .AddEnum("Dimensions", image.GetDimensions())
810  .Get());
811 }
812 
813 size_t TreeBuilder::AddCubeMapTexture(const CubeMapTexture* texture) {
814  ScopedLabeledObject<CubeMapTexture> cmt(
815  &tree_, texture, "CubeMapTexture", true);
816  if (texture) {
817  for (int i = 0; i < 6; ++i) {
818  const CubeMapTexture::CubeFace face =
819  static_cast<CubeMapTexture::CubeFace>(i);
820  if (texture->HasImage(face, 0U)) {
821  const Image& image = *texture->GetImage(face, 0U);
822  AddImageFields(image, base::EnumHelper::GetString(face));
823  }
824  }
825  AddTextureBaseFields(texture);
826  }
827  return cmt.GetIndex();
828 }
829 
830 size_t TreeBuilder::AddTexture(const Texture* texture) {
831  ScopedLabeledObject<Texture> t(&tree_, texture, "Texture", true);
832  if (texture) {
833  if (texture->HasImage(0U)) {
834  const Image& image = *texture->GetImage(0U);
835  AddImageFields(image, "None");
836  }
837  AddTextureBaseFields(texture);
838  }
839  return t.GetIndex();
840 }
841 
842 void TreeBuilder::AddTextureBaseFields(const TextureBase* texture) {
843  tree_.AddField(
844  "Level range",
845  math::Range1i(texture->GetBaseLevel(), texture->GetMaxLevel()));
846  tree_.AddStringField(
847  "Multisampling",
848  MultiField()
849  .Add("Samples", texture->GetMultisampleSamples())
850  .Add("Fixed sample locations",
851  texture->IsMultisampleFixedSampleLocations())
852  .Get());
853  tree_.AddStringField(
854  "Swizzles",
855  MultiField()
856  .AddEnum("R", texture->GetSwizzleRed())
857  .AddEnum("G", texture->GetSwizzleGreen())
858  .AddEnum("B", texture->GetSwizzleBlue())
859  .AddEnum("A", texture->GetSwizzleAlpha())
860  .Get());
861  tree_.AddObjectField("Sampler", AddSampler(texture->GetSampler().Get()));
862 }
863 
864 size_t TreeBuilder::AddSampler(const Sampler* sampler) {
865  ScopedLabeledObject<Sampler> s(&tree_, sampler, "Sampler", true);
866  if (sampler) {
867  tree_.AddField("Autogenerating mipmaps",
868  sampler->IsAutogenerateMipmapsEnabled());
869  tree_.AddEnumField("Texture compare mode", sampler->GetCompareMode());
870  tree_.AddEnumField("Texture compare function",
871  sampler->GetCompareFunction());
872  tree_.AddEnumField("MinFilter mode", sampler->GetMinFilter());
873  tree_.AddEnumField("MagFilter mode", sampler->GetMagFilter());
874  tree_.AddField("Level-of-detail range",
875  math::Range1f(sampler->GetMinLod(), sampler->GetMaxLod()));
876  tree_.AddStringField(
877  "Wrap modes",
878  MultiField()
879  .AddEnum("R", sampler->GetWrapR())
880  .AddEnum("S", sampler->GetWrapS())
881  .AddEnum("T", sampler->GetWrapT())
882  .Get());
883  }
884  return s.GetIndex();
885 }
886 
887 void TreeBuilder::AddShape(const Shape& shape) {
888  ScopedLabeledObject<Shape> s(&tree_, &shape, "Shape", false);
889 
890  tree_.AddEnumField("Primitive Type", shape.GetPrimitiveType());
891 
892  if (const AttributeArray* aa = shape.GetAttributeArray().Get()) {
893  const bool was_added = added_attribute_arrays_.count(aa);
894  AddAttributeArray(*aa, !was_added);
895  if (!was_added)
896  added_attribute_arrays_.insert(aa);
897  }
898 
899  if (const size_t range_count = shape.GetVertexRangeCount()) {
900  tree_.AddField("# Vertex Ranges", range_count);
901  for (size_t i = 0; i < range_count; ++i) {
902  tree_.AddStringField(
903  std::string("Range ") + base::ValueToString(i),
904  MultiField()
905  .Add("Enabled", shape.IsVertexRangeEnabled(i))
906  .Add("Range", shape.GetVertexRange(i))
907  .Get());
908  }
909  }
910 
911  if (IndexBuffer* ib = shape.GetIndexBuffer().Get()) {
912  ScopedLabeledObject<IndexBuffer> si(&tree_, ib, "IndexBuffer", false);
915  DCHECK_EQ(ib->GetSpecCount(), 1U);
916  const BufferObject::Spec& spec = ib->GetSpec(0);
918  tree_.AddEnumField("Type", spec.type);
919  tree_.AddEnumField("Target", ib->GetTarget());
920  tree_.AddTableField("Indices", GetIndexBufferTable(*ib, spec));
921  }
922  }
923 }
924 
925 void TreeBuilder::AddUniform(const Uniform& uniform) {
926  DCHECK(uniform.IsValid());
927  ScopedObject u(&tree_, &uniform, "Uniform");
928 
929  const ShaderInputRegistry::Spec<Uniform>& spec =
930  *uniform.GetRegistry().GetSpec(uniform);
931  tree_.AddField("Name", spec.name);
932  tree_.AddStringField("Type", Uniform::GetValueTypeName(spec.value_type));
933  AddUniformValueField(uniform);
934 }
935 
936 void TreeBuilder::AddUniformBlock(const UniformBlock* block) {
937  ScopedLabeledObject<UniformBlock> u(&tree_, block, "UniformBlock", false);
938  if (block) {
939  const base::AllocVector<Uniform>& uniforms = block->GetUniforms();
940  tree_.AddField("Enabled", block->IsEnabled());
941  for (size_t i = 0; i < uniforms.size(); ++i)
942  AddUniform(uniforms[i]);
943  }
944 }
945 
946 void TreeBuilder::AddUniformValueField(const Uniform& uniform) {
947  DCHECK(uniform.IsValid());
948  const std::string& name("Value");
949  switch (uniform.GetType()) {
950  case gfx::kFloatUniform:
951  if (uniform.GetCount()) {
952  for (size_t i = 0; i < uniform.GetCount(); ++i)
953  tree_.AddField(name + " " + base::ValueToString(i),
954  uniform.GetValueAt<float>(i));
955  } else {
956  tree_.AddField(name, uniform.GetValue<float>());
957  }
958  break;
959  case gfx::kIntUniform:
960  if (uniform.GetCount()) {
961  for (size_t i = 0; i < uniform.GetCount(); ++i)
962  tree_.AddField(name + " " + base::ValueToString(i),
963  uniform.GetValueAt<int>(i));
964  } else {
965  tree_.AddField(name, uniform.GetValue<int>());
966  }
967  break;
969  if (uniform.GetCount()) {
970  for (size_t i = 0; i < uniform.GetCount(); ++i)
971  tree_.AddField(name + " " + base::ValueToString(i),
972  uniform.GetValueAt<uint32>(i));
973  } else {
974  tree_.AddField(name, uniform.GetValue<uint32>());
975  }
976  break;
978  if (uniform.GetCount()) {
979  for (size_t i = 0; i < uniform.GetCount(); ++i) {
980  tree_.AddObjectField(
981  name + " " + base::ValueToString(i),
982  AddCubeMapTexture(uniform.GetValueAt<CubeMapTexturePtr>(i)
983  .Get()));
984  }
985  } else {
986  tree_.AddObjectField(
987  name,
988  AddCubeMapTexture(uniform.GetValue<CubeMapTexturePtr>().Get()));
989  }
990  break;
992  if (uniform.GetCount()) {
993  for (size_t i = 0; i < uniform.GetCount(); ++i) {
994  tree_.AddObjectField(
995  name + " " + base::ValueToString(i),
996  AddTexture(uniform.GetValueAt<TexturePtr>(i).Get()));
997  }
998  } else {
999  tree_.AddObjectField(name,
1000  AddTexture(uniform.GetValue<TexturePtr>().Get()));
1001  }
1002  break;
1004  if (uniform.GetCount()) {
1005  for (size_t i = 0; i < uniform.GetCount(); ++i)
1006  tree_.AddField(name + " " + base::ValueToString(i),
1007  uniform.GetValueAt<math::VectorBase2f>(i));
1008  } else {
1009  tree_.AddField(name, uniform.GetValue<math::VectorBase2f>());
1010  }
1011  break;
1013  if (uniform.GetCount()) {
1014  for (size_t i = 0; i < uniform.GetCount(); ++i)
1015  tree_.AddField(name + " " + base::ValueToString(i),
1016  uniform.GetValueAt<math::VectorBase3f>(i));
1017  } else {
1018  tree_.AddField(name, uniform.GetValue<math::VectorBase3f>());
1019  }
1020  break;
1022  if (uniform.GetCount()) {
1023  for (size_t i = 0; i < uniform.GetCount(); ++i)
1024  tree_.AddField(name + " " + base::ValueToString(i),
1025  uniform.GetValueAt<math::VectorBase4f>(i));
1026  } else {
1027  tree_.AddField(name, uniform.GetValue<math::VectorBase4f>());
1028  }
1029  break;
1031  if (uniform.GetCount()) {
1032  for (size_t i = 0; i < uniform.GetCount(); ++i)
1033  tree_.AddField(name + " " + base::ValueToString(i),
1034  uniform.GetValueAt<math::VectorBase2i>(i));
1035  } else {
1036  tree_.AddField(name, uniform.GetValue<math::VectorBase2i>());
1037  }
1038  break;
1040  if (uniform.GetCount()) {
1041  for (size_t i = 0; i < uniform.GetCount(); ++i)
1042  tree_.AddField(name + " " + base::ValueToString(i),
1043  uniform.GetValueAt<math::VectorBase3i>(i));
1044  } else {
1045  tree_.AddField(name, uniform.GetValue<math::VectorBase3i>());
1046  }
1047  break;
1049  if (uniform.GetCount()) {
1050  for (size_t i = 0; i < uniform.GetCount(); ++i)
1051  tree_.AddField(name + " " + base::ValueToString(i),
1052  uniform.GetValueAt<math::VectorBase4i>(i));
1053  } else {
1054  tree_.AddField(name, uniform.GetValue<math::VectorBase4i>());
1055  }
1056  break;
1058  if (uniform.GetCount()) {
1059  for (size_t i = 0; i < uniform.GetCount(); ++i)
1060  tree_.AddField(name + " " + base::ValueToString(i),
1061  uniform.GetValueAt<math::VectorBase2ui>(i));
1062  } else {
1063  tree_.AddField(name, uniform.GetValue<math::VectorBase2ui>());
1064  }
1065  break;
1067  if (uniform.GetCount()) {
1068  for (size_t i = 0; i < uniform.GetCount(); ++i)
1069  tree_.AddField(name + " " + base::ValueToString(i),
1070  uniform.GetValueAt<math::VectorBase3ui>(i));
1071  } else {
1072  tree_.AddField(name, uniform.GetValue<math::VectorBase3ui>());
1073  }
1074  break;
1076  if (uniform.GetCount()) {
1077  for (size_t i = 0; i < uniform.GetCount(); ++i)
1078  tree_.AddField(name + " " + base::ValueToString(i),
1079  uniform.GetValueAt<math::VectorBase4ui>(i));
1080  } else {
1081  tree_.AddField(name, uniform.GetValue<math::VectorBase4ui>());
1082  }
1083  break;
1085  if (uniform.GetCount()) {
1086  for (size_t i = 0; i < uniform.GetCount(); ++i)
1087  tree_.AddTableField(
1088  name + " " + base::ValueToString(i),
1089  BuildMatrixTable(uniform.GetValueAt<math::Matrix2f>(i)));
1090  } else {
1091  tree_.AddTableField(
1092  name, BuildMatrixTable(uniform.GetValue<math::Matrix2f>()));
1093  }
1094  break;
1096  if (uniform.GetCount()) {
1097  for (size_t i = 0; i < uniform.GetCount(); ++i)
1098  tree_.AddTableField(
1099  name + " " + base::ValueToString(i),
1100  BuildMatrixTable(uniform.GetValueAt<math::Matrix3f>(i)));
1101  } else {
1102  tree_.AddTableField(
1103  name, BuildMatrixTable(uniform.GetValue<math::Matrix3f>()));
1104  }
1105  break;
1107  if (uniform.GetCount()) {
1108  for (size_t i = 0; i < uniform.GetCount(); ++i)
1109  tree_.AddTableField(
1110  name + " " + base::ValueToString(i),
1111  BuildMatrixTable(uniform.GetValueAt<math::Matrix4f>(i)));
1112  } else {
1113  tree_.AddTableField(
1114  name, BuildMatrixTable(uniform.GetValue<math::Matrix4f>()));
1115  }
1116  break;
1117 #if !defined(ION_COVERAGE) // COV_NF_START
1118  default:
1119  DCHECK(false) << "Invalid uniform type " << uniform.GetType();
1120  break;
1121 #endif // COV_NF_END
1122  }
1123 }
1124 
1125 void TreeBuilder::AddAttributeArray(const AttributeArray& aa,
1126  bool add_contents) {
1127  ScopedLabeledObject<AttributeArray> a(&tree_, &aa, "AttributeArray", false);
1128  const size_t attribute_count = aa.GetAttributeCount();
1129  if (add_contents && attribute_count) {
1131  for (size_t i = 0; i < attribute_count; ++i) {
1132  const Attribute& attribute = aa.GetAttribute(i);
1133  if (attribute.IsValid() && !attribute.Is<BufferObjectElement>())
1134  AddAttribute(attribute, aa.IsAttributeEnabled(i));
1135  }
1136 
1138  for (size_t i = 0; i < attribute_count; ++i) {
1139  const Attribute& attribute = aa.GetAttribute(i);
1140  if (attribute.IsValid() && attribute.Is<BufferObjectElement>())
1141  AddAttribute(attribute, aa.IsAttributeEnabled(i));
1142  }
1143 
1146  AddBufferAttributeValues(aa);
1147  }
1148 }
1149 
1150 void TreeBuilder::AddAttribute(const Attribute& attribute, bool is_enabled) {
1151  DCHECK(attribute.IsValid());
1152  const bool is_buffer_attribute = attribute.Is<BufferObjectElement>();
1153  const std::string type_name(is_buffer_attribute ? "(Buffer)" : "(Nonbuffer)");
1154 
1155  ScopedObject a(&tree_, &attribute, std::string("Attribute ") + type_name);
1156 
1157  const ShaderInputRegistry::Spec<Attribute>& spec =
1158  *attribute.GetRegistry().GetSpec(attribute);
1159  tree_.AddField("Name", spec.name);
1160  tree_.AddField("Enabled", is_enabled);
1161  if (is_buffer_attribute) {
1162  tree_.AddField("Normalized", attribute.IsFixedPointNormalized());
1163  if (is_enabled) {
1165  const BufferObjectPtr& vb =
1166  attribute.GetValue<BufferObjectElement>().buffer_object;
1167  const std::string& label = vb->GetLabel();
1168  if (!label.empty())
1169  tree_.AddField("Buffer", label);
1170  }
1172  } else {
1174  AddNonbufferAttributeValueField(attribute);
1175  }
1176 }
1177 
1178 void TreeBuilder::AddNonbufferAttributeValueField(const Attribute& attribute) {
1179  DCHECK(attribute.IsValid());
1180  const std::string& name("Value");
1181  switch (attribute.GetType()) {
1182  case gfx::kFloatAttribute:
1183  tree_.AddField(name, attribute.GetValue<float>());
1184  break;
1186  tree_.AddField(name, attribute.GetValue<math::VectorBase2f>());
1187  break;
1189  tree_.AddField(name, attribute.GetValue<math::VectorBase3f>());
1190  break;
1192  tree_.AddField(name, attribute.GetValue<math::VectorBase4f>());
1193  break;
1195  tree_.AddTableField(
1196  name, BuildMatrixTable(attribute.GetValue<math::Matrix2f>()));
1197  break;
1199  tree_.AddTableField(
1200  name, BuildMatrixTable(attribute.GetValue<math::Matrix3f>()));
1201  break;
1203  tree_.AddTableField(
1204  name, BuildMatrixTable(attribute.GetValue<math::Matrix4f>()));
1205  break;
1206  default:
1207 #if !defined(ION_COVERAGE) // COV_NF_START
1208  DCHECK(false) << "Invalid nonbuffer attribute type "
1209  << attribute.GetType();
1210 #endif // COV_NF_END
1211  break;
1212  }
1213 }
1214 
1215 void TreeBuilder::AddBufferAttributeValues(const AttributeArray& aa) {
1216  if (const size_t vertex_count = GetBufferAttributeVertexCount(aa)) {
1217  size_t object_index;
1218  {
1219  ContainerObject co(&tree_);
1220  for (size_t i = 0; i < vertex_count; ++i) {
1221  tree_.AddStringField(std::string("v ") + base::ValueToString(i),
1222  GetBufferAttributeValue(aa, i));
1223  }
1224  object_index = co.GetIndex();
1225  }
1226  tree_.AddObjectField("Buffer Values", object_index);
1227  }
1228 }
1229 
1231 
1236 
1237 
1238 class TextTreePrinter {
1239  public:
1240  TextTreePrinter(std::ostream& out, const Tree& tree, // NOLINT
1241  bool address_printing_enabled)
1242  : out_(out),
1243  tree_(tree),
1244  address_printing_enabled_(address_printing_enabled),
1245  indent_level_(0) {}
1246  void Print();
1247 
1248  private:
1249  void PrintObject(size_t object_index);
1250  void PrintObjectHeader(const Tree::Object& object);
1251  void PrintObjectField(const Tree::ObjectField& field);
1252  void PrintStringField(const Tree::StringField& field);
1253  void PrintTableField(const Tree::TableField& field);
1254  void PrintLabeledTable(const Tree::Table& table, size_t extra_indent);
1255  void PrintUnlabeledTable(const Tree::Table& table, size_t extra_indent);
1256 
1258  void Indent() { IndentExtra(0); }
1259 
1261  void IndentExtra(size_t extra) {
1262  const size_t num_spaces = 2 * indent_level_ + extra;
1263  for (size_t i = 0; i < num_spaces; ++i)
1264  out_ << ' ';
1265  }
1266 
1267  std::ostream& out_;
1268  const Tree& tree_;
1271 };
1272 
1273 void TextTreePrinter::Print() {
1274  const std::vector<size_t>& roots = tree_.GetRootObjectIndices();
1275  for (size_t i = 0; i < roots.size(); ++i)
1276  PrintObject(roots[i]);
1277 }
1278 
1279 void TextTreePrinter::PrintObject(size_t object_index) {
1280  const Tree::Object& object = tree_.GetObject(object_index);
1281 
1283  PrintObjectHeader(object);
1284  ++indent_level_;
1285 
1287  for (size_t i = 0; i < object.string_fields.size(); ++i)
1288  PrintStringField(object.string_fields[i]);
1289  for (size_t i = 0; i < object.table_fields.size(); ++i)
1290  PrintTableField(object.table_fields[i]);
1291  for (size_t i = 0; i < object.object_fields.size(); ++i)
1292  PrintObjectField(object.object_fields[i]);
1293 
1295  for (size_t i = 0; i < object.child_object_indices.size(); ++i)
1296  PrintObject(object.child_object_indices[i]);
1297 
1299  --indent_level_;
1300  Indent();
1301  out_ << "}\n";
1302 }
1303 
1304 void TextTreePrinter::PrintObjectHeader(const Tree::Object& object) {
1305  if (!object.is_inside_field)
1306  Indent();
1307 
1310  if (!object.type.empty()) {
1311  out_ << "ION " << object.type << ' ';
1312  if (!object.label.empty())
1313  out_ << "\"" << object.label << "\" ";
1315  out_ << '[' << Pointer(object.pointer) << "] ";
1316  }
1317  out_ << "{\n";
1318 }
1319 
1320 void TextTreePrinter::PrintObjectField(const Tree::ObjectField& field) {
1321  Indent();
1322  out_ << field.name << ": ";
1323  PrintObject(field.object_index);
1324 }
1325 
1326 void TextTreePrinter::PrintStringField(const Tree::StringField& field) {
1327  Indent();
1328  out_ << field.name << ": " << field.value << "\n";
1329 }
1330 
1331 void TextTreePrinter::PrintTableField(const Tree::TableField& field) {
1332  Indent();
1333  out_ << field.name << ": ";
1334  const size_t extra_indent = field.name.size() + 3U; // For ": [".
1335 
1336  const Tree::Table& table = field.table;
1337  out_ << '[';
1338  if (table.GetSize()) {
1339  if (table.HasLabelColumn())
1340  PrintLabeledTable(table, extra_indent);
1341  else
1342  PrintUnlabeledTable(table, extra_indent);
1343  }
1344  out_ << "]\n";
1345 }
1346 
1347 void TextTreePrinter::PrintLabeledTable(const Tree::Table& table,
1348  size_t extra_indent) {
1349  const size_t num_rows = table.GetHeight();
1350  const size_t num_columns = table.GetWidth();
1351  for (size_t row = 0; row < num_rows; ++row) {
1352  if (row > 0) {
1353  out_ << ",\n";
1354  IndentExtra(extra_indent);
1355  }
1356  for (size_t col = 0; col < num_columns; ++col) {
1357  const std::string& cell = table.Get(col, row);
1358  if (col == 0) { // Label column.
1359  out_ << cell << ": ";
1360  } else if (!cell.empty()) {
1361  if (col > 1)
1362  out_ << ", ";
1363  out_ << cell;
1364  }
1365  }
1366  }
1367 }
1368 
1369 void TextTreePrinter::PrintUnlabeledTable(const Tree::Table& table,
1370  size_t extra_indent) {
1371  const size_t num_rows = table.GetHeight();
1372  const size_t num_columns = table.GetWidth();
1373  for (size_t row = 0; row < num_rows; ++row) {
1374  if (row == 0) {
1375  out_ << '[';
1376  } else {
1377  out_ << '\n';
1378  IndentExtra(extra_indent);
1379  out_ << '[';
1380  }
1381  for (size_t col = 0; col < num_columns; ++col) {
1382  if (col > 0)
1383  out_ << ", ";
1384  out_ << table.Get(col, row);
1385  }
1386  out_ << ']';
1387  }
1388 }
1389 
1391 
1396 
1397 
1398 class HtmlTreePrinter {
1399  public:
1400  HtmlTreePrinter(std::ostream& out, const Tree& tree, // NOLINT
1401  bool address_printing_enabled)
1402  : out_(out),
1403  tree_(tree),
1404  address_printing_enabled_(address_printing_enabled) {}
1405  void Print();
1406 
1408  static void ResetObjectCounter() { object_counter_ = 0; }
1409 
1410  private:
1411  void PrintObject(size_t object_index);
1412  void PrintObjectHeader(const Tree::Object& object);
1413  void PrintFieldHeader();
1414  void PrintFieldFooter();
1415  void PrintFieldStart(const std::string& name);
1416  void PrintFieldEnd();
1417  void PrintObjectField(const Tree::ObjectField& field);
1418  void PrintStringField(const Tree::StringField& field);
1419  void PrintTableField(const Tree::TableField& field);
1420 
1421  std::ostream& out_;
1422  const Tree& tree_;
1426  static size_t object_counter_;
1427 };
1428 
1429 size_t HtmlTreePrinter::object_counter_ = 0;
1430 
1431 void HtmlTreePrinter::Print() {
1432  const std::vector<size_t>& roots = tree_.GetRootObjectIndices();
1433  for (size_t i = 0; i < roots.size(); ++i)
1434  PrintObject(roots[i]);
1435 }
1436 
1437 void HtmlTreePrinter::PrintObject(size_t object_index) {
1438  const Tree::Object& object = tree_.GetObject(object_index);
1439 
1441  PrintObjectHeader(object);
1442 
1444  const bool has_fields = (!object.string_fields.empty() ||
1445  !object.table_fields.empty() ||
1446  !object.object_fields.empty());
1447  if (has_fields)
1448  PrintFieldHeader();
1449 
1450  for (size_t i = 0; i < object.string_fields.size(); ++i)
1451  PrintStringField(object.string_fields[i]);
1452  for (size_t i = 0; i < object.table_fields.size(); ++i)
1453  PrintTableField(object.table_fields[i]);
1454  for (size_t i = 0; i < object.object_fields.size(); ++i)
1455  PrintObjectField(object.object_fields[i]);
1456 
1457  if (has_fields)
1458  PrintFieldFooter();
1459 
1461  for (size_t i = 0; i < object.child_object_indices.size(); ++i)
1462  PrintObject(object.child_object_indices[i]);
1463 
1465  out_ << "</ul></li>\n";
1466 }
1467 
1468 void HtmlTreePrinter::PrintObjectHeader(const Tree::Object& object) {
1470  out_ << "<li><input type =\"checkbox\" checked=\"checked\" id=\"list-"
1471  << object_counter_ << "\"/><label for=\"list-" << object_counter_
1472  << "\">";
1473 
1475  if (!object.type.empty()) {
1476  out_ << "ION " << object.type;
1477  if (!object.label.empty())
1478  out_ << " \"" << object.label << '\"';
1480  out_ << " [" << Pointer(object.pointer) << ']';
1481  }
1482  out_ << "</label><ul>\n";
1483 
1484  ++object_counter_;
1485 }
1486 
1487 void HtmlTreePrinter::PrintFieldHeader() {
1488  out_ << "<table class=\"nodes_field_table\">\n";
1489 }
1490 
1491 void HtmlTreePrinter::PrintFieldFooter() {
1492  out_ << "</table>\n";
1493 }
1494 
1495 void HtmlTreePrinter::PrintFieldStart(const std::string& name) {
1496  out_ << "<tr><td class=\"name\">" << name << "</td><td class=\"value\">";
1497 }
1498 
1499 void HtmlTreePrinter::PrintFieldEnd() {
1500  out_ << "</td></tr>\n";
1501 }
1502 
1503 void HtmlTreePrinter::PrintObjectField(const Tree::ObjectField& field) {
1504  PrintFieldStart(field.name);
1505  PrintObject(field.object_index);
1506  PrintFieldEnd();
1507 }
1508 
1509 void HtmlTreePrinter::PrintStringField(const Tree::StringField& field) {
1510  PrintFieldStart(field.name);
1511  out_ << field.value;
1512  PrintFieldEnd();
1513 }
1514 
1515 void HtmlTreePrinter::PrintTableField(const Tree::TableField& field) {
1516  PrintFieldStart(field.name);
1517  const Tree::Table& table = field.table;
1518  if (table.GetSize()) {
1519  out_ << "<table class=\"nodes_field_value_table\">\n";
1520  const size_t num_rows = table.GetHeight();
1521  const size_t num_columns = table.GetWidth();
1522  for (size_t row = 0; row < num_rows; ++row) {
1523  out_ << "<tr>\n";
1524  for (size_t col = 0; col < num_columns; ++col) {
1525  const std::string& cell = table.Get(col, row);
1526  if (table.HasLabelColumn() && col == 0)
1527  out_ << "<td><span class=\"table_label\">" << cell << "</span></td>";
1528  else
1529  out_ << "<td>" << cell << "</td>\n";
1530  }
1531  out_ << "</tr>\n";
1532  }
1533  out_ << "</table>\n";
1534  }
1535  PrintFieldEnd();
1536 }
1537 
1538 } // anonymous namespace
1539 
1541 
1546 
1547 
1549  : format_(kText),
1552 }
1553 
1555  HtmlTreePrinter::ResetObjectCounter();
1556 }
1557 
1558 void Printer::PrintScene(const NodePtr& node, std::ostream& out) { // NOLINT
1559  if (node.Get()) {
1560  TreeBuilder tb(address_printing_enabled_, full_shape_printing_enabled_);
1561  const Tree tree = tb.BuildTree(*node);
1562 
1563  if (format_ == kText) {
1564  TextTreePrinter(out, tree, address_printing_enabled_).Print();
1565  } else {
1566  HtmlTreePrinter(out, tree, address_printing_enabled_).Print();
1567  }
1568  }
1569 }
1570 
1571 } // namespace gfxutils
1572 } // 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
Matrix< 4, float > Matrix4f
Definition: matrix.h:371
base::ReferentPtr< Node >::Type NodePtr
Definition: node.h:33
base::ReferentPtr< Image >::Type ImagePtr
Definition: image.h:29
Printer()
Printer class functions.
Definition: printer.cc:1548
std::string type
Definition: printer.cc:353
base::ReferentPtr< Shape >::Type ShapePtr
Convenience typedef for shared pointer to a Shape.
Definition: shape.h:167
Range< 1, int32 > Range1i
Definition: range.h:363
#define DCHECK(expr)
Definition: logging.h:331
bool full_shape_printing_enabled_
Definition: printer.cc:640
std::vector< size_t > cur_objects_
Definition: printer.cc:440
Matrix< 3, float > Matrix3f
Definition: matrix.h:369
base::ReferentPtr< CubeMapTexture >::Type CubeMapTexturePtr
Convenience typedef for shared pointer to a CubeMapTexture.
void PrintScene(const gfx::NodePtr &node, std::ostream &out)
Prints the scene graph rooted by the given node.
Definition: printer.cc:1558
Table table
Definition: printer.cc:333
std::ostream & operator<<(std::ostream &os, const DateTime &dtime)
Definition: datetime.cc:361
size_t vertex_count
const size_t object_index_
Definition: printer.cc:590
Scalar types.
Definition: uniform.h:39
base::ReferentPtr< StateTable >::Type StateTablePtr
Convenience typedef for shared pointer to a StateTable.
Definition: statetable.h:705
std::string label
Definition: printer.cc:354
std::vector< size_t > root_objects_
Definition: printer.cc:439
std::vector< size_t > child_object_indices
Definition: printer.cc:359
base::ReferentPtr< Sampler >::Type SamplerPtr
Convenience typedef for shared pointer to a Sampler.
std::vector< StringField > string_fields
Definition: printer.cc:356
base::ReferentPtr< IndexBuffer >::Type IndexBufferPtr
Definition: indexbuffer.h:38
std::ostringstream out_
Definition: printer.cc:495
std::string ValueToString(const T &val)
ValueToString.
Definition: serialize.h:209
const void * pointer
Definition: printer.cc:111
const uint32 value
Definition: printer.cc:94
static const char * GetString(EnumType e)
Returns a string corresponding to an enum.
Definition: enumhelper.h:59
std::string name
Definition: printer.cc:324
size_t object_index
Definition: printer.cc:342
bool is_first_
Definition: printer.cc:496
const Grid & image
The original monochrome image data, as doubles (0 - 1).
Definition: sdfutils.cc:90
base::ReferentPtr< ShaderProgram >::Type ShaderProgramPtr
Copyright 2016 Google Inc.
std::vector< ObjectField > object_fields
Definition: printer.cc:358
Matrix types.
Definition: uniform.h:59
Matrix< 2, float > Matrix2f
Dimension- and type-specific typedefs.
Definition: matrix.h:367
#define DCHECK_EQ(val1, val2)
Definition: logging.h:332
TexturePtr texture
The Texture to add sub-image data to.
Definition: fontimage.cc:107
base::ReferentPtr< AttributeArray >::Type AttributeArrayPtr
Convenience typedef for shared pointer to a AttributeArray.
base::ReferentPtr< UniformBlock >::Type UniformBlockPtr
Convenience typedef for shared pointer to a UniformBlock.
Definition: uniformblock.h:58
std::set< const AttributeArray * > added_attribute_arrays_
Definition: printer.cc:641
size_t indent_level_
Definition: printer.cc:1270
Scalar types.
Definition: attribute.h:35
std::vector< TableField > table_fields
Definition: printer.cc:357
base::ReferentPtr< ShaderInputRegistry >::Type ShaderInputRegistryPtr
Convenience typedef for shared pointer to a ShaderInputRegistry.
Tree * tree_
Definition: printer.cc:589
base::ReferentPtr< BufferObject >::Type BufferObjectPtr
Convenience typedef for shared pointer to a BufferObject.
Definition: bufferobject.h:31
bool has_label_column_
Definition: printer.cc:316
std::vector< Object > all_objects_
Definition: printer.cc:438
bool address_printing_enabled_
Definition: printer.cc:639
bool is_inside_field
Definition: printer.cc:355
base::ReferentPtr< Texture >::Type TexturePtr
Convenience typedef for shared pointer to a Texture.
Definition: texture.h:333
#define DCHECK_LT(val1, val2)
Definition: logging.h:335
Range< 1, float > Range1f
Definition: range.h:365