objcompress.cc 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  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. if (argc != 3) {
  25. fprintf(stderr, "Usage: %s in.obj out.utf8\n\n"
  26. "\tCompress in.obj to out.utf8 and writes JS to STDOUT.\n\n",
  27. argv[0]);
  28. return -1;
  29. }
  30. FILE* fp = fopen(argv[1], "r");
  31. WavefrontObjFile obj(fp);
  32. fclose(fp);
  33. printf("MODELS[\'%s\'] = {\n", StripLeadingDir(argv[1]));
  34. puts(" materials: {");
  35. const MaterialList& materials = obj.materials();
  36. for (size_t i = 0; i < materials.size(); ++i) {
  37. materials[i].DumpJson();
  38. }
  39. puts(" },");
  40. const MaterialBatches& batches = obj.material_batches();
  41. // Pass 1: compute bounds.
  42. webgl_loader::Bounds bounds;
  43. bounds.Clear();
  44. for (MaterialBatches::const_iterator iter = batches.begin();
  45. iter != batches.end(); ++iter) {
  46. const DrawBatch& draw_batch = iter->second;
  47. bounds.Enclose(draw_batch.draw_mesh().attribs);
  48. }
  49. webgl_loader::BoundsParams bounds_params =
  50. webgl_loader::BoundsParams::FromBounds(bounds);
  51. printf(" decodeParams: ");
  52. bounds_params.DumpJson();
  53. puts(" urls: {");
  54. std::vector<char> utf8;
  55. webgl_loader::VectorSink sink(&utf8);
  56. // Pass 2: quantize, optimize, compress, report.
  57. for (MaterialBatches::const_iterator iter = batches.begin();
  58. iter != batches.end(); ++iter) {
  59. size_t offset = 0;
  60. utf8.clear();
  61. const DrawMesh& draw_mesh = iter->second.draw_mesh();
  62. if (draw_mesh.indices.empty()) continue;
  63. QuantizedAttribList quantized_attribs;
  64. webgl_loader::AttribsToQuantizedAttribs(draw_mesh.attribs, bounds_params,
  65. &quantized_attribs);
  66. VertexOptimizer vertex_optimizer(quantized_attribs);
  67. const std::vector<GroupStart>& group_starts = iter->second.group_starts();
  68. WebGLMeshList webgl_meshes;
  69. std::vector<size_t> group_lengths;
  70. for (size_t i = 1; i < group_starts.size(); ++i) {
  71. const size_t here = group_starts[i-1].offset;
  72. const size_t length = group_starts[i].offset - here;
  73. group_lengths.push_back(length);
  74. vertex_optimizer.AddTriangles(&draw_mesh.indices[here], length,
  75. &webgl_meshes);
  76. }
  77. const size_t here = group_starts.back().offset;
  78. const size_t length = draw_mesh.indices.size() - here;
  79. const bool divisible_by_3 = length % 3 == 0;
  80. CHECK(divisible_by_3);
  81. group_lengths.push_back(length);
  82. vertex_optimizer.AddTriangles(&draw_mesh.indices[here], length,
  83. &webgl_meshes);
  84. std::vector<std::string> material;
  85. std::vector<size_t> attrib_start, attrib_length, index_start, index_length;
  86. for (size_t i = 0; i < webgl_meshes.size(); ++i) {
  87. const size_t num_attribs = webgl_meshes[i].attribs.size();
  88. const size_t num_indices = webgl_meshes[i].indices.size();
  89. const bool kBadSizes = num_attribs % 8 || num_indices % 3;
  90. CHECK(!kBadSizes);
  91. webgl_loader::CompressQuantizedAttribsToUtf8(webgl_meshes[i].attribs,
  92. &sink);
  93. webgl_loader::CompressIndicesToUtf8(webgl_meshes[i].indices, &sink);
  94. material.push_back(iter->first);
  95. attrib_start.push_back(offset);
  96. attrib_length.push_back(num_attribs / 8);
  97. index_start.push_back(offset + num_attribs);
  98. index_length.push_back(num_indices / 3);
  99. offset += num_attribs + num_indices;
  100. }
  101. const uint32 hash = SimpleHash(&utf8[0], utf8.size());
  102. char buf[9] = { '\0' };
  103. ToHex(hash, buf);
  104. // TODO: this needs to handle paths.
  105. std::string out_fn = std::string(buf) + "." + argv[2];
  106. FILE* out_fp = fopen(out_fn.c_str(), "wb");
  107. printf(" \'%s\': [\n", out_fn.c_str());
  108. size_t group_index = 0;
  109. for (size_t i = 0; i < webgl_meshes.size(); ++i) {
  110. printf(" { material: \'%s\',\n"
  111. " attribRange: [" PRIuS ", " PRIuS "],\n"
  112. " indexRange: [" PRIuS ", " PRIuS "],\n"
  113. " bboxes: " PRIuS ",\n"
  114. " names: [",
  115. material[i].c_str(),
  116. attrib_start[i], attrib_length[i],
  117. index_start[i], index_length[i],
  118. offset);
  119. std::vector<size_t> buffered_lengths;
  120. size_t group_start = 0;
  121. while (group_index < group_lengths.size()) {
  122. printf("\'%s\', ",
  123. obj.LineToGroup(group_starts[group_index].group_line).c_str());
  124. const size_t group_length = group_lengths[group_index];
  125. const size_t next_start = group_start + group_length;
  126. const size_t webgl_index_length = webgl_meshes[i].indices.size();
  127. // TODO: bbox info is better placed at the head of the file,
  128. // perhaps transposed. Also, when a group gets split between
  129. // batches, the bbox gets stored twice.
  130. webgl_loader::CompressAABBToUtf8(group_starts[group_index].bounds,
  131. bounds_params, &sink);
  132. offset += 6;
  133. if (next_start < webgl_index_length) {
  134. buffered_lengths.push_back(group_length);
  135. group_start = next_start;
  136. ++group_index;
  137. } else {
  138. const size_t fits = webgl_index_length - group_start;
  139. buffered_lengths.push_back(fits);
  140. group_start = 0;
  141. group_lengths[group_index] -= fits;
  142. break;
  143. }
  144. }
  145. printf("],\n lengths: [");
  146. for (size_t k = 0; k < buffered_lengths.size(); ++k) {
  147. printf(PRIuS ", ", buffered_lengths[k]);
  148. }
  149. puts("],\n },");
  150. }
  151. fwrite(&utf8[0], 1, utf8.size(), out_fp);
  152. fclose(out_fp);
  153. puts(" ],");
  154. }
  155. puts(" }\n};");
  156. return 0;
  157. }