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