1/*
2---------------------------------------------------------------------------
3Open Asset Import Library (assimp)
4---------------------------------------------------------------------------
5
6Copyright (c) 2006-2017, assimp team
7
8
9All rights reserved.
10
11Redistribution and use of this software in source and binary forms,
12with or without modification, are permitted provided that the following
13conditions 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
29THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39OF 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
60using namespace Assimp;
61
62static 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
77RAWImporter::RAWImporter()
78{}
79
80// ------------------------------------------------------------------------------------------------
81// Destructor, private as well
82RAWImporter::~RAWImporter()
83{}
84
85// ------------------------------------------------------------------------------------------------
86// Returns whether the class can handle the format of the given file.
87bool RAWImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const
88{
89 return SimpleExtensionCheck(pFile,"raw");
90}
91
92// ------------------------------------------------------------------------------------------------
93const aiImporterDesc* RAWImporter::GetInfo () const
94{
95 return &desc;
96}
97
98// ------------------------------------------------------------------------------------------------
99// Imports the given file into the given scene structure.
100void 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