1
2 //
3 // This source file is part of appleseed.
4 // Visit https://appleseedhq.net/ for additional information and resources.
5 //
6 // This software is released under the MIT license.
7 //
8 // Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited
9 // Copyright (c) 2014-2018 Francois Beaune, The appleseedhq Organization
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining a copy
12 // of this software and associated documentation files (the "Software"), to deal
13 // in the Software without restriction, including without limitation the rights
14 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 // copies of the Software, and to permit persons to whom the Software is
16 // furnished to do so, subject to the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 // THE SOFTWARE.
28 //
29
30 // Interface header.
31 #include "binarymeshfilereader.h"
32
33 // appleseed.foundation headers.
34 #include "foundation/core/exceptions/exceptionioerror.h"
35 #include "foundation/math/vector.h"
36 #include "foundation/mesh/imeshbuilder.h"
37 #include "foundation/platform/types.h"
38 #include "foundation/utility/bufferedfile.h"
39 #include "foundation/utility/memory.h"
40
41 // Standard headers.
42 #include <cstring>
43 #include <memory>
44
45 using namespace std;
46
47 namespace foundation
48 {
49
50 //
51 // BinaryMeshFileReader class implementation.
52 //
53
BinaryMeshFileReader(const string & filename)54 BinaryMeshFileReader::BinaryMeshFileReader(const string& filename)
55 : m_filename(filename)
56 {
57 }
58
read(IMeshBuilder & builder)59 void BinaryMeshFileReader::read(IMeshBuilder& builder)
60 {
61 BufferedFile file(
62 m_filename.c_str(),
63 BufferedFile::BinaryType,
64 BufferedFile::ReadMode);
65
66 if (!file.is_open())
67 throw ExceptionIOError();
68
69 read_and_check_signature(file);
70
71 uint16 version;
72 checked_read(file, version);
73
74 switch (version)
75 {
76 // Uncompressed, double-precision geometry.
77 case 1:
78 {
79 PassthroughReaderAdapter reader(file);
80 read_meshes<double>(reader, builder);
81 }
82 break;
83
84 // LZO-compressed, double-precision geometry.
85 case 2:
86 throw ExceptionIOError(
87 "binarymesh format version 2 is no longer supported; "
88 "please use the convertmeshfile tool that ships with appleseed 1.1.0 alpha-21 or earlier");
89
90 // LZ4-compressed, double-precision geometry.
91 case 3:
92 {
93 LZ4CompressedReaderAdapter reader(file);
94 read_meshes<double>(reader, builder);
95 }
96 break;
97
98 // LZ4-compressed, single-precision geometry.
99 case 4:
100 {
101 LZ4CompressedReaderAdapter reader(file);
102 read_meshes<float>(reader, builder);
103 }
104 break;
105
106 // Unknown format.
107 default:
108 throw ExceptionIOError("unknown binarymesh format version");
109 }
110 }
111
read_and_check_signature(BufferedFile & file)112 void BinaryMeshFileReader::read_and_check_signature(BufferedFile& file)
113 {
114 static const char ExpectedSig[10] = { 'B', 'I', 'N', 'A', 'R', 'Y', 'M', 'E', 'S', 'H' };
115
116 char signature[sizeof(ExpectedSig)];
117 checked_read(file, signature, sizeof(signature));
118
119 if (memcmp(signature, ExpectedSig, sizeof(ExpectedSig)))
120 throw ExceptionIOError("invalid binarymesh format signature");
121 }
122
read_string(ReaderAdapter & reader)123 string BinaryMeshFileReader::read_string(ReaderAdapter& reader)
124 {
125 uint16 length;
126 checked_read(reader, length);
127
128 string s;
129 s.resize(length);
130 checked_read(reader, &s[0], length);
131
132 return s;
133 }
134
135 template <typename T>
read_meshes(ReaderAdapter & reader,IMeshBuilder & builder)136 void BinaryMeshFileReader::read_meshes(ReaderAdapter& reader, IMeshBuilder& builder)
137 {
138 try
139 {
140 while (true)
141 {
142 // Read the name of the next mesh.
143 string mesh_name;
144 try
145 {
146 mesh_name = read_string(reader);
147 }
148 catch (const ExceptionEOF&)
149 {
150 // Expected EOF.
151 break;
152 }
153
154 builder.begin_mesh(mesh_name.c_str());
155 read_vertices<T>(reader, builder);
156 read_vertex_normals<T>(reader, builder);
157 read_texture_coordinates<T>(reader, builder);
158 read_material_slots(reader, builder);
159 read_faces(reader, builder);
160
161 builder.end_mesh();
162 }
163 }
164 catch (const ExceptionEOF&)
165 {
166 // Unexpected EOF.
167 throw ExceptionIOError();
168 }
169 }
170
171 template <typename T>
read_vertices(ReaderAdapter & reader,IMeshBuilder & builder)172 void BinaryMeshFileReader::read_vertices(ReaderAdapter& reader, IMeshBuilder& builder)
173 {
174 uint32 count;
175 checked_read(reader, count);
176
177 for (uint32 i = 0; i < count; ++i)
178 {
179 Vector<T, 3> v;
180 checked_read(reader, v);
181 builder.push_vertex(Vector3d(v));
182 }
183 }
184
185 template <typename T>
read_vertex_normals(ReaderAdapter & reader,IMeshBuilder & builder)186 void BinaryMeshFileReader::read_vertex_normals(ReaderAdapter& reader, IMeshBuilder& builder)
187 {
188 uint32 count;
189 checked_read(reader, count);
190
191 for (uint32 i = 0; i < count; ++i)
192 {
193 Vector<T, 3> v;
194 checked_read(reader, v);
195 builder.push_vertex_normal(Vector3d(v));
196 }
197 }
198
199 template <typename T>
read_texture_coordinates(ReaderAdapter & reader,IMeshBuilder & builder)200 void BinaryMeshFileReader::read_texture_coordinates(ReaderAdapter& reader, IMeshBuilder& builder)
201 {
202 uint32 count;
203 checked_read(reader, count);
204
205 for (uint32 i = 0; i < count; ++i)
206 {
207 Vector<T, 2> v;
208 checked_read(reader, v);
209 builder.push_tex_coords(Vector2d(v));
210 }
211 }
212
read_material_slots(ReaderAdapter & reader,IMeshBuilder & builder)213 void BinaryMeshFileReader::read_material_slots(ReaderAdapter& reader, IMeshBuilder& builder)
214 {
215 uint16 count;
216 checked_read(reader, count);
217
218 for (uint16 i = 0; i < count; ++i)
219 {
220 const string material_slot = read_string(reader);
221 builder.push_material_slot(material_slot.c_str());
222 }
223 }
224
read_faces(ReaderAdapter & reader,IMeshBuilder & builder)225 void BinaryMeshFileReader::read_faces(ReaderAdapter& reader, IMeshBuilder& builder)
226 {
227 uint32 count;
228 checked_read(reader, count);
229
230 for (uint32 i = 0; i < count; ++i)
231 read_face(reader, builder);
232 }
233
read_face(ReaderAdapter & reader,IMeshBuilder & builder)234 void BinaryMeshFileReader::read_face(ReaderAdapter& reader, IMeshBuilder& builder)
235 {
236 uint16 count;
237 checked_read(reader, count);
238
239 ensure_minimum_size(m_vertices, count);
240 ensure_minimum_size(m_vertex_normals, count);
241 ensure_minimum_size(m_tex_coords, count);
242
243 for (uint16 i = 0; i < count; ++i)
244 {
245 uint32 face_vertex;
246 checked_read(reader, face_vertex);
247 m_vertices[i] = face_vertex;
248
249 uint32 face_vertex_normal;
250 checked_read(reader, face_vertex_normal);
251 m_vertex_normals[i] = face_vertex_normal;
252
253 uint32 face_tex_coords;
254 checked_read(reader, face_tex_coords);
255 m_tex_coords[i] = face_tex_coords;
256 }
257
258 uint16 material;
259 checked_read(reader, material);
260
261 builder.begin_face(count);
262 builder.set_face_vertices(&m_vertices[0]);
263 builder.set_face_vertex_normals(&m_vertex_normals[0]);
264 builder.set_face_vertex_tex_coords(&m_tex_coords[0]);
265 builder.set_face_material(material);
266 builder.end_face();
267 }
268
269 } // namespace foundation
270