1 | /* |
2 | --------------------------------------------------------------------------- |
3 | Open Asset Import Library (assimp) |
4 | --------------------------------------------------------------------------- |
5 | |
6 | Copyright (c) 2006-2017, assimp team |
7 | |
8 | |
9 | All rights reserved. |
10 | |
11 | Redistribution and use of this software in source and binary forms, |
12 | with or without modification, are permitted provided that the following |
13 | conditions are met: |
14 | |
15 | * Redistributions of source code must retain the above |
16 | copyright notice, this list of conditions and the |
17 | following disclaimer. |
18 | |
19 | * Redistributions in binary form must reproduce the above |
20 | copyright notice, this list of conditions and the |
21 | following disclaimer in the documentation and/or other |
22 | materials provided with the distribution. |
23 | |
24 | * Neither the name of the assimp team, nor the names of its |
25 | contributors may be used to endorse or promote products |
26 | derived from this software without specific prior |
27 | written permission of the assimp team. |
28 | |
29 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
30 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
31 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
32 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
33 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
34 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
35 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
36 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
37 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
38 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
39 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
40 | --------------------------------------------------------------------------- |
41 | */ |
42 | |
43 | /** @file RawLoader.cpp |
44 | * @brief Implementation of the RAW importer class |
45 | */ |
46 | |
47 | |
48 | #ifndef ASSIMP_BUILD_NO_RAW_IMPORTER |
49 | |
50 | // internal headers |
51 | #include "RawLoader.h" |
52 | #include "ParsingUtils.h" |
53 | #include "fast_atof.h" |
54 | #include <memory> |
55 | #include <assimp/IOSystem.hpp> |
56 | #include <assimp/DefaultLogger.hpp> |
57 | #include <assimp/scene.h> |
58 | #include <assimp/importerdesc.h> |
59 | |
60 | using namespace Assimp; |
61 | |
62 | static const aiImporterDesc desc = { |
63 | "Raw Importer" , |
64 | "" , |
65 | "" , |
66 | "" , |
67 | aiImporterFlags_SupportTextFlavour, |
68 | 0, |
69 | 0, |
70 | 0, |
71 | 0, |
72 | "raw" |
73 | }; |
74 | |
75 | // ------------------------------------------------------------------------------------------------ |
76 | // Constructor to be privately used by Importer |
77 | RAWImporter::RAWImporter() |
78 | {} |
79 | |
80 | // ------------------------------------------------------------------------------------------------ |
81 | // Destructor, private as well |
82 | RAWImporter::~RAWImporter() |
83 | {} |
84 | |
85 | // ------------------------------------------------------------------------------------------------ |
86 | // Returns whether the class can handle the format of the given file. |
87 | bool RAWImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const |
88 | { |
89 | return SimpleExtensionCheck(pFile,"raw" ); |
90 | } |
91 | |
92 | // ------------------------------------------------------------------------------------------------ |
93 | const aiImporterDesc* RAWImporter::GetInfo () const |
94 | { |
95 | return &desc; |
96 | } |
97 | |
98 | // ------------------------------------------------------------------------------------------------ |
99 | // Imports the given file into the given scene structure. |
100 | void RAWImporter::InternReadFile( const std::string& pFile, |
101 | aiScene* pScene, IOSystem* pIOHandler) |
102 | { |
103 | std::unique_ptr<IOStream> file( pIOHandler->Open( pFile, "rb" )); |
104 | |
105 | // Check whether we can read from the file |
106 | if( file.get() == NULL) { |
107 | throw DeadlyImportError( "Failed to open RAW file " + pFile + "." ); |
108 | } |
109 | |
110 | // allocate storage and copy the contents of the file to a memory buffer |
111 | // (terminate it with zero) |
112 | std::vector<char> mBuffer2; |
113 | TextFileToBuffer(file.get(),mBuffer2); |
114 | const char* buffer = &mBuffer2[0]; |
115 | |
116 | // list of groups loaded from the file |
117 | std::vector< GroupInformation > outGroups(1,GroupInformation("<default>" )); |
118 | std::vector< GroupInformation >::iterator curGroup = outGroups.begin(); |
119 | |
120 | // now read all lines |
121 | char line[4096]; |
122 | while (GetNextLine(buffer,line)) |
123 | { |
124 | // if the line starts with a non-numeric identifier, it marks |
125 | // the beginning of a new group |
126 | const char* sz = line;SkipSpaces(&sz); |
127 | if (IsLineEnd(*sz))continue; |
128 | if (!IsNumeric(*sz)) |
129 | { |
130 | const char* sz2 = sz; |
131 | while (!IsSpaceOrNewLine(*sz2))++sz2; |
132 | const unsigned int length = (unsigned int)(sz2-sz); |
133 | |
134 | // find an existing group with this name |
135 | for (std::vector< GroupInformation >::iterator it = outGroups.begin(), end = outGroups.end(); |
136 | it != end;++it) |
137 | { |
138 | if (length == (*it).name.length() && !::strcmp(sz,(*it).name.c_str())) |
139 | { |
140 | curGroup = it;sz2 = NULL; |
141 | break; |
142 | } |
143 | } |
144 | if (sz2) |
145 | { |
146 | outGroups.push_back(GroupInformation(std::string(sz,length))); |
147 | curGroup = outGroups.end()-1; |
148 | } |
149 | } |
150 | else |
151 | { |
152 | // there can be maximally 12 floats plus an extra texture file name |
153 | float data[12]; |
154 | unsigned int num; |
155 | for (num = 0; num < 12;++num) |
156 | { |
157 | if(!SkipSpaces(&sz) || !IsNumeric(*sz))break; |
158 | sz = fast_atoreal_move<float>(sz,data[num]); |
159 | } |
160 | if (num != 12 && num != 9) |
161 | { |
162 | DefaultLogger::get()->error("A line may have either 9 or 12 floats and an optional texture" ); |
163 | continue; |
164 | } |
165 | |
166 | MeshInformation* output = NULL; |
167 | |
168 | const char* sz2 = sz; |
169 | unsigned int length; |
170 | if (!IsLineEnd(*sz)) |
171 | { |
172 | while (!IsSpaceOrNewLine(*sz2))++sz2; |
173 | length = (unsigned int)(sz2-sz); |
174 | } |
175 | else if (9 == num) |
176 | { |
177 | sz = "%default%" ; |
178 | length = 9; |
179 | } |
180 | else |
181 | { |
182 | sz = "" ; |
183 | length = 0; |
184 | } |
185 | |
186 | // search in the list of meshes whether we have one with this texture |
187 | for (auto &mesh : (*curGroup).meshes) |
188 | { |
189 | if (length == mesh.name.length() && (length ? !::strcmp(sz, mesh.name.c_str()) : true)) |
190 | { |
191 | output = &mesh; |
192 | break; |
193 | } |
194 | } |
195 | // if we don't have the mesh, create it |
196 | if (!output) |
197 | { |
198 | (*curGroup).meshes.push_back(MeshInformation(std::string(sz,length))); |
199 | output = &((*curGroup).meshes.back()); |
200 | } |
201 | if (12 == num) |
202 | { |
203 | aiColor4D v(data[0],data[1],data[2],1.0f); |
204 | output->colors.push_back(v); |
205 | output->colors.push_back(v); |
206 | output->colors.push_back(v); |
207 | |
208 | output->vertices.push_back(aiVector3D(data[3],data[4],data[5])); |
209 | output->vertices.push_back(aiVector3D(data[6],data[7],data[8])); |
210 | output->vertices.push_back(aiVector3D(data[9],data[10],data[11])); |
211 | } |
212 | else |
213 | { |
214 | output->vertices.push_back(aiVector3D(data[0],data[1],data[2])); |
215 | output->vertices.push_back(aiVector3D(data[3],data[4],data[5])); |
216 | output->vertices.push_back(aiVector3D(data[6],data[7],data[8])); |
217 | } |
218 | } |
219 | } |
220 | |
221 | pScene->mRootNode = new aiNode(); |
222 | pScene->mRootNode->mName.Set("<RawRoot>" ); |
223 | |
224 | // count the number of valid groups |
225 | // (meshes can't be empty) |
226 | for (auto & outGroup : outGroups) |
227 | { |
228 | if (!outGroup.meshes.empty()) |
229 | { |
230 | ++pScene->mRootNode->mNumChildren; |
231 | pScene->mNumMeshes += (unsigned int) outGroup.meshes.size(); |
232 | } |
233 | } |
234 | |
235 | if (!pScene->mNumMeshes) |
236 | { |
237 | throw DeadlyImportError("RAW: No meshes loaded. The file seems to be corrupt or empty." ); |
238 | } |
239 | |
240 | pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; |
241 | aiNode** cc; |
242 | if (1 == pScene->mRootNode->mNumChildren) |
243 | { |
244 | cc = &pScene->mRootNode; |
245 | pScene->mRootNode->mNumChildren = 0; |
246 | } |
247 | else cc = pScene->mRootNode->mChildren = new aiNode*[pScene->mRootNode->mNumChildren]; |
248 | |
249 | pScene->mNumMaterials = pScene->mNumMeshes; |
250 | aiMaterial** mats = pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]; |
251 | |
252 | unsigned int meshIdx = 0; |
253 | for (auto & outGroup : outGroups) |
254 | { |
255 | if (outGroup.meshes.empty())continue; |
256 | |
257 | aiNode* node; |
258 | if (pScene->mRootNode->mNumChildren) |
259 | { |
260 | node = *cc = new aiNode(); |
261 | node->mParent = pScene->mRootNode; |
262 | } |
263 | else node = *cc; |
264 | node->mName.Set(outGroup.name); |
265 | |
266 | // add all meshes |
267 | node->mNumMeshes = (unsigned int) outGroup.meshes.size(); |
268 | unsigned int* pi = node->mMeshes = new unsigned int[ node->mNumMeshes ]; |
269 | for (std::vector< MeshInformation >::iterator it2 = outGroup.meshes.begin(), |
270 | end2 = outGroup.meshes.end(); it2 != end2; ++it2) |
271 | { |
272 | ai_assert(!(*it2).vertices.empty()); |
273 | |
274 | // allocate the mesh |
275 | *pi++ = meshIdx; |
276 | aiMesh* mesh = pScene->mMeshes[meshIdx] = new aiMesh(); |
277 | mesh->mMaterialIndex = meshIdx++; |
278 | |
279 | mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; |
280 | |
281 | // allocate storage for the vertex components and copy them |
282 | mesh->mNumVertices = (unsigned int)(*it2).vertices.size(); |
283 | mesh->mVertices = new aiVector3D[ mesh->mNumVertices ]; |
284 | ::memcpy(mesh->mVertices,&(*it2).vertices[0],sizeof(aiVector3D)*mesh->mNumVertices); |
285 | |
286 | if ((*it2).colors.size()) |
287 | { |
288 | ai_assert((*it2).colors.size() == mesh->mNumVertices); |
289 | |
290 | mesh->mColors[0] = new aiColor4D[ mesh->mNumVertices ]; |
291 | ::memcpy(mesh->mColors[0],&(*it2).colors[0],sizeof(aiColor4D)*mesh->mNumVertices); |
292 | } |
293 | |
294 | // generate triangles |
295 | ai_assert(0 == mesh->mNumVertices % 3); |
296 | aiFace* fc = mesh->mFaces = new aiFace[ mesh->mNumFaces = mesh->mNumVertices/3 ]; |
297 | aiFace* const fcEnd = fc + mesh->mNumFaces; |
298 | unsigned int n = 0; |
299 | while (fc != fcEnd) |
300 | { |
301 | aiFace& f = *fc++; |
302 | f.mIndices = new unsigned int[f.mNumIndices = 3]; |
303 | for (unsigned int m = 0; m < 3;++m) |
304 | f.mIndices[m] = n++; |
305 | } |
306 | |
307 | // generate a material for the mesh |
308 | aiMaterial* mat = new aiMaterial(); |
309 | |
310 | aiColor4D clr(1.0f,1.0f,1.0f,1.0f); |
311 | if ("%default%" == (*it2).name) // a gray default material |
312 | { |
313 | clr.r = clr.g = clr.b = 0.6f; |
314 | } |
315 | else if ((*it2).name.length() > 0) // a texture |
316 | { |
317 | aiString s; |
318 | s.Set((*it2).name); |
319 | mat->AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0)); |
320 | } |
321 | mat->AddProperty<aiColor4D>(&clr,1,AI_MATKEY_COLOR_DIFFUSE); |
322 | *mats++ = mat; |
323 | } |
324 | } |
325 | } |
326 | |
327 | #endif // !! ASSIMP_BUILD_NO_RAW_IMPORTER |
328 | |