vrshoot

view libs/assimp/TerragenLoader.cpp @ 0:b2f14e535253

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 01 Feb 2014 19:58:19 +0200
parents
children
line source
1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
6 Copyright (c) 2006-2012, assimp team
8 All rights reserved.
10 Redistribution and use of this software in source and binary forms,
11 with or without modification, are permitted provided that the following
12 conditions are met:
14 * Redistributions of source code must retain the above
15 copyright notice, this list of conditions and the
16 following disclaimer.
18 * Redistributions in binary form must reproduce the above
19 copyright notice, this list of conditions and the
20 following disclaimer in the documentation and/or other
21 materials provided with the distribution.
23 * Neither the name of the assimp team, nor the names of its
24 contributors may be used to endorse or promote products
25 derived from this software without specific prior
26 written permission of the assimp team.
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 ---------------------------------------------------------------------------
40 */
42 /** @file Implementation of the Terragen importer class */
44 #include "AssimpPCH.h"
46 #ifndef ASSIMP_BUILD_NO_TERRAGEN_IMPORTER
47 #include "TerragenLoader.h"
49 using namespace Assimp;
51 static const aiImporterDesc desc = {
52 "Terragen Heightmap Importer",
53 "",
54 "",
55 "http://www.planetside.co.uk/",
56 aiImporterFlags_SupportBinaryFlavour,
57 0,
58 0,
59 0,
60 0,
61 "ter"
62 };
64 // ------------------------------------------------------------------------------------------------
65 // Constructor to be privately used by Importer
66 TerragenImporter::TerragenImporter()
67 : configComputeUVs (false)
68 {}
70 // ------------------------------------------------------------------------------------------------
71 // Destructor, private as well
72 TerragenImporter::~TerragenImporter()
73 {}
75 // ------------------------------------------------------------------------------------------------
76 // Returns whether the class can handle the format of the given file.
77 bool TerragenImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
78 {
79 // check file extension
80 std::string extension = GetExtension(pFile);
82 if( extension == "ter")
83 return true;
85 if( !extension.length() || checkSig) {
86 /* If CanRead() is called in order to check whether we
87 * support a specific file extension in general pIOHandler
88 * might be NULL and it's our duty to return true here.
89 */
90 if (!pIOHandler)return true;
91 const char* tokens[] = {"terragen"};
92 return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
93 }
94 return false;
95 }
97 // ------------------------------------------------------------------------------------------------
98 // Build a string of all file extensions supported
99 const aiImporterDesc* TerragenImporter::GetInfo () const
100 {
101 return &desc;
102 }
104 // ------------------------------------------------------------------------------------------------
105 // Setup import properties
106 void TerragenImporter::SetupProperties(const Importer* pImp)
107 {
108 // AI_CONFIG_IMPORT_TER_MAKE_UVS
109 configComputeUVs = ( 0 != pImp->GetPropertyInteger(AI_CONFIG_IMPORT_TER_MAKE_UVS,0) );
110 }
112 // ------------------------------------------------------------------------------------------------
113 // Imports the given file into the given scene structure.
114 void TerragenImporter::InternReadFile( const std::string& pFile,
115 aiScene* pScene, IOSystem* pIOHandler)
116 {
117 IOStream* file = pIOHandler->Open( pFile, "rb");
119 // Check whether we can read from the file
120 if( file == NULL)
121 throw DeadlyImportError( "Failed to open TERRAGEN TERRAIN file " + pFile + ".");
123 // Construct a stream reader to read all data in the correct endianess
124 StreamReaderLE reader(file);
125 if(reader.GetRemainingSize() < 16)
126 throw DeadlyImportError( "TER: file is too small" );
128 // Check for the existence of the two magic strings 'TERRAGEN' and 'TERRAIN '
129 if (::strncmp((const char*)reader.GetPtr(),AI_TERR_BASE_STRING,8))
130 throw DeadlyImportError( "TER: Magic string \'TERRAGEN\' not found" );
132 if (::strncmp((const char*)reader.GetPtr()+8,AI_TERR_TERRAIN_STRING,8))
133 throw DeadlyImportError( "TER: Magic string \'TERRAIN\' not found" );
135 unsigned int x = 0,y = 0,mode = 0;
136 float rad = 6370.f;
137 (void)rad;
140 aiNode* root = pScene->mRootNode = new aiNode();
141 root->mName.Set("<TERRAGEN.TERRAIN>");
143 // Default scaling is 30
144 root->mTransformation.a1 = root->mTransformation.b2 = root->mTransformation.c3 = 30.f;
146 // Now read all chunks until we're finished or an EOF marker is encountered
147 reader.IncPtr(16);
148 while (reader.GetRemainingSize() >= 4)
149 {
150 const char* head = (const char*)reader.GetPtr();
151 reader.IncPtr(4);
153 // EOF, break in every case
154 if (!::strncmp(head,AI_TERR_EOF_STRING,4))
155 break;
157 // Number of x-data points
158 if (!::strncmp(head,AI_TERR_CHUNK_XPTS,4))
159 {
160 x = (uint16_t)reader.GetI2();
161 }
162 // Number of y-data points
163 else if (!::strncmp(head,AI_TERR_CHUNK_YPTS,4))
164 {
165 y = (uint16_t)reader.GetI2();
166 }
167 // Squared terrains width-1.
168 else if (!::strncmp(head,AI_TERR_CHUNK_SIZE,4))
169 {
170 x = y = (uint16_t)reader.GetI2()+1;
171 }
172 // terrain scaling
173 else if (!::strncmp(head,AI_TERR_CHUNK_SCAL,4))
174 {
175 root->mTransformation.a1 = reader.GetF4();
176 root->mTransformation.b2 = reader.GetF4();
177 root->mTransformation.c3 = reader.GetF4();
178 }
179 // mapping == 1: earth radius
180 else if (!::strncmp(head,AI_TERR_CHUNK_CRAD,4))
181 {
182 rad = reader.GetF4();
183 }
184 // mapping mode
185 else if (!::strncmp(head,AI_TERR_CHUNK_CRVM,4))
186 {
187 mode = reader.GetI1();
188 if (0 != mode)
189 DefaultLogger::get()->error("TER: Unsupported mapping mode, a flat terrain is returned");
190 }
191 // actual terrain data
192 else if (!::strncmp(head,AI_TERR_CHUNK_ALTW,4))
193 {
194 float hscale = (float)reader.GetI2() / 65536;
195 float bheight = (float)reader.GetI2();
197 if (!hscale)hscale = 1;
199 // Ensure we have enough data
200 if (reader.GetRemainingSize() < x*y*2)
201 throw DeadlyImportError("TER: ALTW chunk is too small");
203 if (x <= 1 || y <= 1)
204 throw DeadlyImportError("TER: Invalid terrain size");
206 // Allocate the output mesh
207 pScene->mMeshes = new aiMesh*[pScene->mNumMeshes = 1];
208 aiMesh* m = pScene->mMeshes[0] = new aiMesh();
210 // We return quads
211 aiFace* f = m->mFaces = new aiFace[m->mNumFaces = (x-1)*(y-1)];
212 aiVector3D* pv = m->mVertices = new aiVector3D[m->mNumVertices = m->mNumFaces*4];
214 aiVector3D *uv( NULL );
215 float step_y( 0.0f ), step_x( 0.0f );
216 if (configComputeUVs) {
217 uv = m->mTextureCoords[0] = new aiVector3D[m->mNumVertices];
218 step_y = 1.f/y;
219 step_x = 1.f/x;
220 }
221 const int16_t* data = (const int16_t*)reader.GetPtr();
223 for (unsigned int yy = 0, t = 0; yy < y-1;++yy) {
224 for (unsigned int xx = 0; xx < x-1;++xx,++f) {
226 // make verts
227 const float fy = (float)yy, fx = (float)xx;
228 register unsigned tmp,tmp2;
229 *pv++ = aiVector3D(fx,fy, (float)data[(tmp2=x*yy) + xx] * hscale + bheight);
230 *pv++ = aiVector3D(fx,fy+1, (float)data[(tmp=x*(yy+1)) + xx] * hscale + bheight);
231 *pv++ = aiVector3D(fx+1,fy+1,(float)data[tmp + xx+1] * hscale + bheight);
232 *pv++ = aiVector3D(fx+1,fy, (float)data[tmp2 + xx+1] * hscale + bheight);
234 // also make texture coordinates, if necessary
235 if (configComputeUVs) {
236 *uv++ = aiVector3D( step_x*xx, step_y*yy, 0.f );
237 *uv++ = aiVector3D( step_x*xx, step_y*(yy+1), 0.f );
238 *uv++ = aiVector3D( step_x*(xx+1), step_y*(yy+1), 0.f );
239 *uv++ = aiVector3D( step_x*(xx+1), step_y*yy, 0.f );
240 }
242 // make indices
243 f->mIndices = new unsigned int[f->mNumIndices = 4];
244 for (unsigned int i = 0; i < 4;++i)
245 f->mIndices[i] = t++;
246 }
247 }
249 // Add the mesh to the root node
250 root->mMeshes = new unsigned int[root->mNumMeshes = 1];
251 root->mMeshes[0] = 0;
252 }
254 // Get to the next chunk (4 byte aligned)
255 unsigned dtt;
256 if ((dtt = reader.GetCurrentPos() & 0x3))
257 reader.IncPtr(4-dtt);
258 }
260 // Check whether we have a mesh now
261 if (pScene->mNumMeshes != 1)
262 throw DeadlyImportError("TER: Unable to load terrain");
264 // Set the AI_SCENE_FLAGS_TERRAIN bit
265 pScene->mFlags |= AI_SCENE_FLAGS_TERRAIN;
266 }
268 #endif // !! ASSIMP_BUILD_NO_TERRAGEN_IMPORTER