obj2utf8x.cc 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. #if 0 // A cute trick to making this .cc self-building from shell.
  2. g++ $0 -O2 -Wall -Werror -o `basename $0 .cc`;
  3. exit;
  4. #endif
  5. // Copyright 2011 Google Inc. All Rights Reserved.
  6. //
  7. // Licensed under the Apache License, Version 2.0 (the "License"); you
  8. // may not use this file except in compliance with the License. You
  9. // may obtain a copy of the License at
  10. //
  11. // http://www.apache.org/licenses/LICENSE-2.0
  12. //
  13. // Unless required by applicable law or agreed to in writing, software
  14. // distributed under the License is distributed on an "AS IS" BASIS,
  15. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
  16. // implied. See the License for the specific language governing
  17. // permissions and limitations under the License.
  18. #include "bounds.h"
  19. #include "compress.h"
  20. #include "mesh.h"
  21. #include "optimize.h"
  22. #include "stream.h"
  23. int main(int argc, const char* argv[]) {
  24. FILE* json_out = stdout;
  25. if (argc != 3 && argc != 4) {
  26. fprintf(stderr, "Usage: %s in.obj out.utf8\n\n"
  27. "\tCompress in.obj to out.utf8 and writes JS to STDOUT.\n\n",
  28. argv[0]);
  29. return -1;
  30. } else if (argc == 4) {
  31. json_out = fopen(argv[3], "w");
  32. CHECK(json_out != NULL);
  33. }
  34. FILE* fp = fopen(argv[1], "r");
  35. WavefrontObjFile obj(fp);
  36. fclose(fp);
  37. fputs("{\n \"materials\": {\n", json_out);
  38. const MaterialList& materials = obj.materials();
  39. for (size_t i = 0; i < materials.size(); ++i) {
  40. materials[i].DumpJson(json_out);
  41. const bool last = i == materials.size() - 1;
  42. fputs(",\n" + last, json_out);
  43. }
  44. fputs(" },\n", json_out);
  45. const MaterialBatches& batches = obj.material_batches();
  46. // Pass 1: compute bounds.
  47. webgl_loader::Bounds bounds;
  48. bounds.Clear();
  49. for (MaterialBatches::const_iterator iter = batches.begin();
  50. iter != batches.end(); ++iter) {
  51. const DrawBatch& draw_batch = iter->second;
  52. bounds.Enclose(draw_batch.draw_mesh().attribs);
  53. }
  54. webgl_loader::BoundsParams bounds_params =
  55. webgl_loader::BoundsParams::FromBounds(bounds);
  56. fputs(" \"decodeParams\": ", json_out);
  57. bounds_params.DumpJson(json_out);
  58. fputs(",\n \"urls\": {\n", json_out);
  59. // Pass 2: quantize, optimize, compress, report.
  60. FILE* utf8_out_fp = fopen(argv[2], "wb");
  61. CHECK(utf8_out_fp != NULL);
  62. fprintf(json_out, " \"%s\": [\n", argv[2]);
  63. webgl_loader::FileSink utf8_sink(utf8_out_fp);
  64. size_t offset = 0;
  65. MaterialBatches::const_iterator iter = batches.begin();
  66. while (iter != batches.end()) {
  67. const DrawMesh& draw_mesh = iter->second.draw_mesh();
  68. if (draw_mesh.indices.empty()) {
  69. ++iter;
  70. continue;
  71. }
  72. QuantizedAttribList quantized_attribs;
  73. webgl_loader::AttribsToQuantizedAttribs(draw_mesh.attribs, bounds_params,
  74. &quantized_attribs);
  75. VertexOptimizer vertex_optimizer(quantized_attribs);
  76. const std::vector<GroupStart>& group_starts = iter->second.group_starts();
  77. WebGLMeshList webgl_meshes;
  78. std::vector<size_t> group_lengths;
  79. for (size_t i = 1; i < group_starts.size(); ++i) {
  80. const size_t here = group_starts[i-1].offset;
  81. const size_t length = group_starts[i].offset - here;
  82. group_lengths.push_back(length);
  83. vertex_optimizer.AddTriangles(&draw_mesh.indices[here], length,
  84. &webgl_meshes);
  85. }
  86. const size_t here = group_starts.back().offset;
  87. const size_t length = draw_mesh.indices.size() - here;
  88. CHECK(length % 3 == 0);
  89. group_lengths.push_back(length);
  90. vertex_optimizer.AddTriangles(&draw_mesh.indices[here], length,
  91. &webgl_meshes);
  92. std::vector<std::string> material;
  93. // TODO: is this buffering still necessary?
  94. std::vector<size_t> attrib_start, attrib_length,
  95. code_start, code_length, num_tris;
  96. for (size_t i = 0; i < webgl_meshes.size(); ++i) {
  97. const size_t num_attribs = webgl_meshes[i].attribs.size();
  98. const size_t num_indices = webgl_meshes[i].indices.size();
  99. CHECK(num_attribs % 8 == 0);
  100. CHECK(num_indices % 3 == 0);
  101. webgl_loader::EdgeCachingCompressor compressor(webgl_meshes[i].attribs,
  102. webgl_meshes[i].indices);
  103. compressor.Compress(&utf8_sink);
  104. material.push_back(iter->first);
  105. attrib_start.push_back(offset);
  106. attrib_length.push_back(num_attribs / 8);
  107. code_start.push_back(offset + num_attribs);
  108. code_length.push_back(compressor.codes().size());
  109. num_tris.push_back(num_indices / 3);
  110. offset += num_attribs + compressor.codes().size();
  111. }
  112. for (size_t i = 0; i < webgl_meshes.size(); ++i) {
  113. fprintf(json_out,
  114. " { \"material\": \"%s\",\n"
  115. " \"attribRange\": [" PRIuS ", " PRIuS "],\n"
  116. " \"codeRange\": [" PRIuS ", " PRIuS ", " PRIuS "]\n"
  117. " }",
  118. material[i].c_str(),
  119. attrib_start[i], attrib_length[i],
  120. code_start[i], code_length[i], num_tris[i]);
  121. if (i != webgl_meshes.size() - 1) {
  122. fputs(",\n", json_out);
  123. }
  124. }
  125. const bool last = (++iter == batches.end());
  126. fputs(",\n" + last, json_out);
  127. }
  128. fputs(" ]\n", json_out);
  129. fputs(" }\n}", json_out);
  130. return 0;
  131. }