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