diff options
author | David Walter Seikel | 2014-01-13 19:47:58 +1000 |
---|---|---|
committer | David Walter Seikel | 2014-01-13 19:47:58 +1000 |
commit | f9158592e1478b2013afc7041d9ed041cf2d2f4a (patch) | |
tree | b16e389d7988700e21b4c9741044cefa536dcbae /libraries/irrlicht-1.8/source/Irrlicht/CQ3LevelMesh.cpp | |
parent | Libraries readme updated with change markers and more of the Irrlicht changes. (diff) | |
download | SledjHamr-f9158592e1478b2013afc7041d9ed041cf2d2f4a.zip SledjHamr-f9158592e1478b2013afc7041d9ed041cf2d2f4a.tar.gz SledjHamr-f9158592e1478b2013afc7041d9ed041cf2d2f4a.tar.bz2 SledjHamr-f9158592e1478b2013afc7041d9ed041cf2d2f4a.tar.xz |
Update Irrlicht to 1.8.1. Include actual change markers this time. lol
Diffstat (limited to 'libraries/irrlicht-1.8/source/Irrlicht/CQ3LevelMesh.cpp')
-rw-r--r-- | libraries/irrlicht-1.8/source/Irrlicht/CQ3LevelMesh.cpp | 2082 |
1 files changed, 0 insertions, 2082 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CQ3LevelMesh.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CQ3LevelMesh.cpp deleted file mode 100644 index 00b0fa1..0000000 --- a/libraries/irrlicht-1.8/source/Irrlicht/CQ3LevelMesh.cpp +++ /dev/null | |||
@@ -1,2082 +0,0 @@ | |||
1 | // Copyright (C) 2002-2012 Nikolaus Gebhardt | ||
2 | // This file is part of the "Irrlicht Engine". | ||
3 | // For conditions of distribution and use, see copyright notice in irrlicht.h | ||
4 | |||
5 | #include "IrrCompileConfig.h" | ||
6 | #ifdef _IRR_COMPILE_WITH_BSP_LOADER_ | ||
7 | |||
8 | #include "CQ3LevelMesh.h" | ||
9 | #include "ISceneManager.h" | ||
10 | #include "os.h" | ||
11 | #include "SMeshBufferLightMap.h" | ||
12 | #include "irrString.h" | ||
13 | #include "ILightSceneNode.h" | ||
14 | #include "IQ3Shader.h" | ||
15 | #include "IFileList.h" | ||
16 | |||
17 | //#define TJUNCTION_SOLVER_ROUND | ||
18 | //#define TJUNCTION_SOLVER_0125 | ||
19 | |||
20 | namespace irr | ||
21 | { | ||
22 | namespace scene | ||
23 | { | ||
24 | |||
25 | using namespace quake3; | ||
26 | |||
27 | //! constructor | ||
28 | CQ3LevelMesh::CQ3LevelMesh(io::IFileSystem* fs, scene::ISceneManager* smgr, | ||
29 | const Q3LevelLoadParameter &loadParam) | ||
30 | : LoadParam(loadParam), Textures(0), NumTextures(0), LightMaps(0), NumLightMaps(0), | ||
31 | Vertices(0), NumVertices(0), Faces(0), NumFaces(0), Models(0), NumModels(0), | ||
32 | Planes(0), NumPlanes(0), Nodes(0), NumNodes(0), Leafs(0), NumLeafs(0), | ||
33 | LeafFaces(0), NumLeafFaces(0), MeshVerts(0), NumMeshVerts(0), | ||
34 | Brushes(0), NumBrushes(0), BrushEntities(0), FileSystem(fs), | ||
35 | SceneManager(smgr), FramesPerSecond(25.f) | ||
36 | { | ||
37 | #ifdef _DEBUG | ||
38 | IReferenceCounted::setDebugName("CQ3LevelMesh"); | ||
39 | #endif | ||
40 | |||
41 | for ( s32 i = 0; i!= E_Q3_MESH_SIZE; ++i ) | ||
42 | { | ||
43 | Mesh[i] = 0; | ||
44 | } | ||
45 | |||
46 | Driver = smgr ? smgr->getVideoDriver() : 0; | ||
47 | if (Driver) | ||
48 | Driver->grab(); | ||
49 | |||
50 | if (FileSystem) | ||
51 | FileSystem->grab(); | ||
52 | |||
53 | // load default shaders | ||
54 | InitShader(); | ||
55 | } | ||
56 | |||
57 | |||
58 | //! destructor | ||
59 | CQ3LevelMesh::~CQ3LevelMesh() | ||
60 | { | ||
61 | cleanLoader (); | ||
62 | |||
63 | if (Driver) | ||
64 | Driver->drop(); | ||
65 | |||
66 | if (FileSystem) | ||
67 | FileSystem->drop(); | ||
68 | |||
69 | s32 i; | ||
70 | |||
71 | for ( i = 0; i!= E_Q3_MESH_SIZE; ++i ) | ||
72 | { | ||
73 | if ( Mesh[i] ) | ||
74 | { | ||
75 | Mesh[i]->drop(); | ||
76 | Mesh[i] = 0; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | for ( i = 1; i < NumModels; i++ ) | ||
81 | { | ||
82 | BrushEntities[i]->drop(); | ||
83 | } | ||
84 | delete [] BrushEntities; BrushEntities = 0; | ||
85 | |||
86 | ReleaseShader(); | ||
87 | ReleaseEntity(); | ||
88 | } | ||
89 | |||
90 | |||
91 | //! loads a level from a .bsp-File. Also tries to load all needed textures. Returns true if successful. | ||
92 | bool CQ3LevelMesh::loadFile(io::IReadFile* file) | ||
93 | { | ||
94 | if (!file) | ||
95 | return false; | ||
96 | |||
97 | LevelName = file->getFileName(); | ||
98 | |||
99 | file->read(&header, sizeof(tBSPHeader)); | ||
100 | |||
101 | #ifdef __BIG_ENDIAN__ | ||
102 | header.strID = os::Byteswap::byteswap(header.strID); | ||
103 | header.version = os::Byteswap::byteswap(header.version); | ||
104 | #endif | ||
105 | |||
106 | if ( (header.strID != 0x50534249 || // IBSP | ||
107 | ( header.version != 0x2e // quake3 | ||
108 | && header.version != 0x2f // rtcw | ||
109 | ) | ||
110 | ) | ||
111 | && | ||
112 | ( header.strID != 0x50534252 || header.version != 1 ) // RBSP, starwars jedi, sof | ||
113 | ) | ||
114 | { | ||
115 | os::Printer::log("Could not load .bsp file, unknown header.", file->getFileName(), ELL_ERROR); | ||
116 | return false; | ||
117 | } | ||
118 | |||
119 | #if 0 | ||
120 | if ( header.strID == 0x50534252 ) // RBSP Raven | ||
121 | { | ||
122 | LoadParam.swapHeader = 1; | ||
123 | } | ||
124 | #endif | ||
125 | |||
126 | // now read lumps | ||
127 | file->read(&Lumps[0], sizeof(tBSPLump)*kMaxLumps); | ||
128 | |||
129 | s32 i; | ||
130 | if ( LoadParam.swapHeader ) | ||
131 | { | ||
132 | for ( i=0; i< kMaxLumps;++i) | ||
133 | { | ||
134 | Lumps[i].offset = os::Byteswap::byteswap(Lumps[i].offset); | ||
135 | Lumps[i].length = os::Byteswap::byteswap(Lumps[i].length); | ||
136 | } | ||
137 | } | ||
138 | |||
139 | ReleaseEntity(); | ||
140 | |||
141 | // load everything | ||
142 | loadEntities(&Lumps[kEntities], file); // load the entities | ||
143 | loadTextures(&Lumps[kShaders], file); // Load the textures | ||
144 | loadLightmaps(&Lumps[kLightmaps], file); // Load the lightmaps | ||
145 | loadVerts(&Lumps[kVertices], file); // Load the vertices | ||
146 | loadFaces(&Lumps[kFaces], file); // Load the faces | ||
147 | loadPlanes(&Lumps[kPlanes], file); // Load the Planes of the BSP | ||
148 | loadNodes(&Lumps[kNodes], file); // load the Nodes of the BSP | ||
149 | loadLeafs(&Lumps[kLeafs], file); // load the Leafs of the BSP | ||
150 | loadLeafFaces(&Lumps[kLeafFaces], file); // load the Faces of the Leafs of the BSP | ||
151 | loadVisData(&Lumps[kVisData], file); // load the visibility data of the clusters | ||
152 | loadModels(&Lumps[kModels], file); // load the models | ||
153 | loadMeshVerts(&Lumps[kMeshVerts], file); // load the mesh vertices | ||
154 | loadBrushes(&Lumps[kBrushes], file); // load the brushes of the BSP | ||
155 | loadBrushSides(&Lumps[kBrushSides], file); // load the brushsides of the BSP | ||
156 | loadLeafBrushes(&Lumps[kLeafBrushes], file); // load the brushes of the leaf | ||
157 | loadFogs(&Lumps[kFogs], file ); // load the fogs | ||
158 | |||
159 | loadTextures(); | ||
160 | constructMesh(); | ||
161 | solveTJunction(); | ||
162 | |||
163 | cleanMeshes(); | ||
164 | calcBoundingBoxes(); | ||
165 | cleanLoader(); | ||
166 | |||
167 | return true; | ||
168 | } | ||
169 | |||
170 | /*! | ||
171 | */ | ||
172 | void CQ3LevelMesh::cleanLoader () | ||
173 | { | ||
174 | delete [] Textures; Textures = 0; | ||
175 | delete [] LightMaps; LightMaps = 0; | ||
176 | delete [] Vertices; Vertices = 0; | ||
177 | delete [] Faces; Faces = 0; | ||
178 | delete [] Models; Models = 0; | ||
179 | delete [] Planes; Planes = 0; | ||
180 | delete [] Nodes; Nodes = 0; | ||
181 | delete [] Leafs; Leafs = 0; | ||
182 | delete [] LeafFaces; LeafFaces = 0; | ||
183 | delete [] MeshVerts; MeshVerts = 0; | ||
184 | delete [] Brushes; Brushes = 0; | ||
185 | |||
186 | Lightmap.clear(); | ||
187 | Tex.clear(); | ||
188 | } | ||
189 | |||
190 | //! returns the amount of frames in milliseconds. If the amount is 1, it is a static (=non animated) mesh. | ||
191 | u32 CQ3LevelMesh::getFrameCount() const | ||
192 | { | ||
193 | return 1; | ||
194 | } | ||
195 | |||
196 | |||
197 | //! returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail. Note, that some Meshes will ignore the detail level. | ||
198 | IMesh* CQ3LevelMesh::getMesh(s32 frameInMs, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop) | ||
199 | { | ||
200 | return Mesh[frameInMs]; | ||
201 | } | ||
202 | |||
203 | |||
204 | void CQ3LevelMesh::loadTextures(tBSPLump* l, io::IReadFile* file) | ||
205 | { | ||
206 | NumTextures = l->length / sizeof(tBSPTexture); | ||
207 | if ( !NumTextures ) | ||
208 | return; | ||
209 | Textures = new tBSPTexture[NumTextures]; | ||
210 | |||
211 | file->seek(l->offset); | ||
212 | file->read(Textures, l->length); | ||
213 | |||
214 | if ( LoadParam.swapHeader ) | ||
215 | { | ||
216 | for (s32 i=0;i<NumTextures;++i) | ||
217 | { | ||
218 | Textures[i].flags = os::Byteswap::byteswap(Textures[i].flags); | ||
219 | Textures[i].contents = os::Byteswap::byteswap(Textures[i].contents); | ||
220 | //os::Printer::log("Loaded texture", Textures[i].strName, ELL_INFORMATION); | ||
221 | } | ||
222 | } | ||
223 | } | ||
224 | |||
225 | |||
226 | void CQ3LevelMesh::loadLightmaps(tBSPLump* l, io::IReadFile* file) | ||
227 | { | ||
228 | NumLightMaps = l->length / sizeof(tBSPLightmap); | ||
229 | if ( !NumLightMaps ) | ||
230 | return; | ||
231 | LightMaps = new tBSPLightmap[NumLightMaps]; | ||
232 | |||
233 | file->seek(l->offset); | ||
234 | file->read(LightMaps, l->length); | ||
235 | } | ||
236 | |||
237 | /*! | ||
238 | */ | ||
239 | void CQ3LevelMesh::loadVerts(tBSPLump* l, io::IReadFile* file) | ||
240 | { | ||
241 | NumVertices = l->length / sizeof(tBSPVertex); | ||
242 | if ( !NumVertices ) | ||
243 | return; | ||
244 | Vertices = new tBSPVertex[NumVertices]; | ||
245 | |||
246 | file->seek(l->offset); | ||
247 | file->read(Vertices, l->length); | ||
248 | |||
249 | if ( LoadParam.swapHeader ) | ||
250 | for (s32 i=0;i<NumVertices;i++) | ||
251 | { | ||
252 | Vertices[i].vPosition[0] = os::Byteswap::byteswap(Vertices[i].vPosition[0]); | ||
253 | Vertices[i].vPosition[1] = os::Byteswap::byteswap(Vertices[i].vPosition[1]); | ||
254 | Vertices[i].vPosition[2] = os::Byteswap::byteswap(Vertices[i].vPosition[2]); | ||
255 | Vertices[i].vTextureCoord[0] = os::Byteswap::byteswap(Vertices[i].vTextureCoord[0]); | ||
256 | Vertices[i].vTextureCoord[1] = os::Byteswap::byteswap(Vertices[i].vTextureCoord[1]); | ||
257 | Vertices[i].vLightmapCoord[0] = os::Byteswap::byteswap(Vertices[i].vLightmapCoord[0]); | ||
258 | Vertices[i].vLightmapCoord[1] = os::Byteswap::byteswap(Vertices[i].vLightmapCoord[1]); | ||
259 | Vertices[i].vNormal[0] = os::Byteswap::byteswap(Vertices[i].vNormal[0]); | ||
260 | Vertices[i].vNormal[1] = os::Byteswap::byteswap(Vertices[i].vNormal[1]); | ||
261 | Vertices[i].vNormal[2] = os::Byteswap::byteswap(Vertices[i].vNormal[2]); | ||
262 | } | ||
263 | } | ||
264 | |||
265 | |||
266 | /*! | ||
267 | */ | ||
268 | void CQ3LevelMesh::loadFaces(tBSPLump* l, io::IReadFile* file) | ||
269 | { | ||
270 | NumFaces = l->length / sizeof(tBSPFace); | ||
271 | if (!NumFaces) | ||
272 | return; | ||
273 | Faces = new tBSPFace[NumFaces]; | ||
274 | |||
275 | file->seek(l->offset); | ||
276 | file->read(Faces, l->length); | ||
277 | |||
278 | if ( LoadParam.swapHeader ) | ||
279 | { | ||
280 | for ( s32 i=0;i<NumFaces;i++) | ||
281 | { | ||
282 | Faces[i].textureID = os::Byteswap::byteswap(Faces[i].textureID); | ||
283 | Faces[i].fogNum = os::Byteswap::byteswap(Faces[i].fogNum); | ||
284 | Faces[i].type = os::Byteswap::byteswap(Faces[i].type); | ||
285 | Faces[i].vertexIndex = os::Byteswap::byteswap(Faces[i].vertexIndex); | ||
286 | Faces[i].numOfVerts = os::Byteswap::byteswap(Faces[i].numOfVerts); | ||
287 | Faces[i].meshVertIndex = os::Byteswap::byteswap(Faces[i].meshVertIndex); | ||
288 | Faces[i].numMeshVerts = os::Byteswap::byteswap(Faces[i].numMeshVerts); | ||
289 | Faces[i].lightmapID = os::Byteswap::byteswap(Faces[i].lightmapID); | ||
290 | Faces[i].lMapCorner[0] = os::Byteswap::byteswap(Faces[i].lMapCorner[0]); | ||
291 | Faces[i].lMapCorner[1] = os::Byteswap::byteswap(Faces[i].lMapCorner[1]); | ||
292 | Faces[i].lMapSize[0] = os::Byteswap::byteswap(Faces[i].lMapSize[0]); | ||
293 | Faces[i].lMapSize[1] = os::Byteswap::byteswap(Faces[i].lMapSize[1]); | ||
294 | Faces[i].lMapPos[0] = os::Byteswap::byteswap(Faces[i].lMapPos[0]); | ||
295 | Faces[i].lMapPos[1] = os::Byteswap::byteswap(Faces[i].lMapPos[1]); | ||
296 | Faces[i].lMapPos[2] = os::Byteswap::byteswap(Faces[i].lMapPos[2]); | ||
297 | Faces[i].lMapBitsets[0][0] = os::Byteswap::byteswap(Faces[i].lMapBitsets[0][0]); | ||
298 | Faces[i].lMapBitsets[0][1] = os::Byteswap::byteswap(Faces[i].lMapBitsets[0][1]); | ||
299 | Faces[i].lMapBitsets[0][2] = os::Byteswap::byteswap(Faces[i].lMapBitsets[0][2]); | ||
300 | Faces[i].lMapBitsets[1][0] = os::Byteswap::byteswap(Faces[i].lMapBitsets[1][0]); | ||
301 | Faces[i].lMapBitsets[1][1] = os::Byteswap::byteswap(Faces[i].lMapBitsets[1][1]); | ||
302 | Faces[i].lMapBitsets[1][2] = os::Byteswap::byteswap(Faces[i].lMapBitsets[1][2]); | ||
303 | Faces[i].vNormal[0] = os::Byteswap::byteswap(Faces[i].vNormal[0]); | ||
304 | Faces[i].vNormal[1] = os::Byteswap::byteswap(Faces[i].vNormal[1]); | ||
305 | Faces[i].vNormal[2] = os::Byteswap::byteswap(Faces[i].vNormal[2]); | ||
306 | Faces[i].size[0] = os::Byteswap::byteswap(Faces[i].size[0]); | ||
307 | Faces[i].size[1] = os::Byteswap::byteswap(Faces[i].size[1]); | ||
308 | } | ||
309 | } | ||
310 | } | ||
311 | |||
312 | |||
313 | /*! | ||
314 | */ | ||
315 | void CQ3LevelMesh::loadPlanes(tBSPLump* l, io::IReadFile* file) | ||
316 | { | ||
317 | // ignore | ||
318 | } | ||
319 | |||
320 | |||
321 | /*! | ||
322 | */ | ||
323 | void CQ3LevelMesh::loadNodes(tBSPLump* l, io::IReadFile* file) | ||
324 | { | ||
325 | // ignore | ||
326 | } | ||
327 | |||
328 | |||
329 | /*! | ||
330 | */ | ||
331 | void CQ3LevelMesh::loadLeafs(tBSPLump* l, io::IReadFile* file) | ||
332 | { | ||
333 | // ignore | ||
334 | } | ||
335 | |||
336 | |||
337 | /*! | ||
338 | */ | ||
339 | void CQ3LevelMesh::loadLeafFaces(tBSPLump* l, io::IReadFile* file) | ||
340 | { | ||
341 | // ignore | ||
342 | } | ||
343 | |||
344 | |||
345 | /*! | ||
346 | */ | ||
347 | void CQ3LevelMesh::loadVisData(tBSPLump* l, io::IReadFile* file) | ||
348 | { | ||
349 | // ignore | ||
350 | } | ||
351 | |||
352 | |||
353 | /*! | ||
354 | */ | ||
355 | void CQ3LevelMesh::loadEntities(tBSPLump* l, io::IReadFile* file) | ||
356 | { | ||
357 | core::array<u8> entity; | ||
358 | entity.set_used( l->length + 2 ); | ||
359 | entity[l->length + 1 ] = 0; | ||
360 | |||
361 | file->seek(l->offset); | ||
362 | file->read( entity.pointer(), l->length); | ||
363 | |||
364 | parser_parse( entity.pointer(), l->length, &CQ3LevelMesh::scriptcallback_entity ); | ||
365 | } | ||
366 | |||
367 | |||
368 | /*! | ||
369 | load fog brushes | ||
370 | */ | ||
371 | void CQ3LevelMesh::loadFogs(tBSPLump* l, io::IReadFile* file) | ||
372 | { | ||
373 | u32 files = l->length / sizeof(tBSPFog); | ||
374 | |||
375 | file->seek( l->offset ); | ||
376 | tBSPFog fog; | ||
377 | const IShader *shader; | ||
378 | STexShader t; | ||
379 | for ( u32 i = 0; i!= files; ++i ) | ||
380 | { | ||
381 | file->read( &fog, sizeof( fog ) ); | ||
382 | |||
383 | shader = getShader( fog.shader ); | ||
384 | t.Texture = 0; | ||
385 | t.ShaderID = shader ? shader->ID : -1; | ||
386 | |||
387 | FogMap.push_back ( t ); | ||
388 | } | ||
389 | } | ||
390 | |||
391 | |||
392 | /*! | ||
393 | load models named in bsp | ||
394 | */ | ||
395 | void CQ3LevelMesh::loadModels(tBSPLump* l, io::IReadFile* file) | ||
396 | { | ||
397 | NumModels = l->length / sizeof(tBSPModel); | ||
398 | Models = new tBSPModel[NumModels]; | ||
399 | |||
400 | file->seek( l->offset ); | ||
401 | file->read(Models, l->length); | ||
402 | |||
403 | if ( LoadParam.swapHeader ) | ||
404 | { | ||
405 | for ( s32 i = 0; i < NumModels; i++) | ||
406 | { | ||
407 | Models[i].min[0] = os::Byteswap::byteswap(Models[i].min[0]); | ||
408 | Models[i].min[1] = os::Byteswap::byteswap(Models[i].min[1]); | ||
409 | Models[i].min[2] = os::Byteswap::byteswap(Models[i].min[2]); | ||
410 | Models[i].max[0] = os::Byteswap::byteswap(Models[i].max[0]); | ||
411 | Models[i].max[1] = os::Byteswap::byteswap(Models[i].max[1]); | ||
412 | Models[i].max[2] = os::Byteswap::byteswap(Models[i].max[2]); | ||
413 | |||
414 | Models[i].faceIndex = os::Byteswap::byteswap(Models[i].faceIndex); | ||
415 | Models[i].numOfFaces = os::Byteswap::byteswap(Models[i].numOfFaces); | ||
416 | Models[i].brushIndex = os::Byteswap::byteswap(Models[i].brushIndex); | ||
417 | Models[i].numOfBrushes = os::Byteswap::byteswap(Models[i].numOfBrushes); | ||
418 | } | ||
419 | } | ||
420 | |||
421 | BrushEntities = new SMesh*[NumModels]; | ||
422 | } | ||
423 | |||
424 | /*! | ||
425 | */ | ||
426 | void CQ3LevelMesh::loadMeshVerts(tBSPLump* l, io::IReadFile* file) | ||
427 | { | ||
428 | NumMeshVerts = l->length / sizeof(s32); | ||
429 | if (!NumMeshVerts) | ||
430 | return; | ||
431 | MeshVerts = new s32[NumMeshVerts]; | ||
432 | |||
433 | file->seek(l->offset); | ||
434 | file->read(MeshVerts, l->length); | ||
435 | |||
436 | if ( LoadParam.swapHeader ) | ||
437 | { | ||
438 | for (int i=0;i<NumMeshVerts;i++) | ||
439 | MeshVerts[i] = os::Byteswap::byteswap(MeshVerts[i]); | ||
440 | } | ||
441 | } | ||
442 | |||
443 | /*! | ||
444 | */ | ||
445 | void CQ3LevelMesh::loadBrushes(tBSPLump* l, io::IReadFile* file) | ||
446 | { | ||
447 | // ignore | ||
448 | } | ||
449 | |||
450 | /*! | ||
451 | */ | ||
452 | void CQ3LevelMesh::loadBrushSides(tBSPLump* l, io::IReadFile* file) | ||
453 | { | ||
454 | // ignore | ||
455 | } | ||
456 | |||
457 | /*! | ||
458 | */ | ||
459 | void CQ3LevelMesh::loadLeafBrushes(tBSPLump* l, io::IReadFile* file) | ||
460 | { | ||
461 | // ignore | ||
462 | } | ||
463 | |||
464 | /*! | ||
465 | */ | ||
466 | inline bool isQ3WhiteSpace( const u8 symbol ) | ||
467 | { | ||
468 | return symbol == ' ' || symbol == '\t' || symbol == '\r'; | ||
469 | } | ||
470 | |||
471 | /*! | ||
472 | */ | ||
473 | inline bool isQ3ValidName( const u8 symbol ) | ||
474 | { | ||
475 | return (symbol >= 'a' && symbol <= 'z' ) || | ||
476 | (symbol >= 'A' && symbol <= 'Z' ) || | ||
477 | (symbol >= '0' && symbol <= '9' ) || | ||
478 | (symbol == '/' || symbol == '_' || symbol == '.' ); | ||
479 | } | ||
480 | |||
481 | /*! | ||
482 | */ | ||
483 | void CQ3LevelMesh::parser_nextToken() | ||
484 | { | ||
485 | u8 symbol; | ||
486 | |||
487 | Parser.token = ""; | ||
488 | Parser.tokenresult = Q3_TOKEN_UNRESOLVED; | ||
489 | |||
490 | // skip white space | ||
491 | do | ||
492 | { | ||
493 | if ( Parser.index >= Parser.sourcesize ) | ||
494 | { | ||
495 | Parser.tokenresult = Q3_TOKEN_EOF; | ||
496 | return; | ||
497 | } | ||
498 | |||
499 | symbol = Parser.source [ Parser.index ]; | ||
500 | Parser.index += 1; | ||
501 | } while ( isQ3WhiteSpace( symbol ) ); | ||
502 | |||
503 | // first symbol, one symbol | ||
504 | switch ( symbol ) | ||
505 | { | ||
506 | case 0: | ||
507 | Parser.tokenresult = Q3_TOKEN_EOF; | ||
508 | return; | ||
509 | |||
510 | case '/': | ||
511 | // comment or divide | ||
512 | if ( Parser.index >= Parser.sourcesize ) | ||
513 | { | ||
514 | Parser.tokenresult = Q3_TOKEN_EOF; | ||
515 | return; | ||
516 | } | ||
517 | symbol = Parser.source [ Parser.index ]; | ||
518 | Parser.index += 1; | ||
519 | if ( isQ3WhiteSpace( symbol ) ) | ||
520 | { | ||
521 | Parser.tokenresult = Q3_TOKEN_MATH_DIVIDE; | ||
522 | return; | ||
523 | } | ||
524 | else | ||
525 | if ( symbol == '*' ) | ||
526 | { | ||
527 | // C-style comment in quake? | ||
528 | } | ||
529 | else | ||
530 | if ( symbol == '/' ) | ||
531 | { | ||
532 | // skip to eol | ||
533 | do | ||
534 | { | ||
535 | if ( Parser.index >= Parser.sourcesize ) | ||
536 | { | ||
537 | Parser.tokenresult = Q3_TOKEN_EOF; | ||
538 | return; | ||
539 | } | ||
540 | symbol = Parser.source [ Parser.index ]; | ||
541 | Parser.index += 1; | ||
542 | } while ( symbol != '\n' ); | ||
543 | Parser.tokenresult = Q3_TOKEN_COMMENT; | ||
544 | return; | ||
545 | } | ||
546 | // take /[name] as valid token..?!?!?. mhmm, maybe | ||
547 | break; | ||
548 | |||
549 | case '\n': | ||
550 | Parser.tokenresult = Q3_TOKEN_EOL; | ||
551 | return; | ||
552 | case '{': | ||
553 | Parser.tokenresult = Q3_TOKEN_START_LIST; | ||
554 | return; | ||
555 | case '}': | ||
556 | Parser.tokenresult = Q3_TOKEN_END_LIST; | ||
557 | return; | ||
558 | |||
559 | case '"': | ||
560 | // string literal | ||
561 | do | ||
562 | { | ||
563 | if ( Parser.index >= Parser.sourcesize ) | ||
564 | { | ||
565 | Parser.tokenresult = Q3_TOKEN_EOF; | ||
566 | return; | ||
567 | } | ||
568 | symbol = Parser.source [ Parser.index ]; | ||
569 | Parser.index += 1; | ||
570 | if ( symbol != '"' ) | ||
571 | Parser.token.append( symbol ); | ||
572 | } while ( symbol != '"' ); | ||
573 | Parser.tokenresult = Q3_TOKEN_ENTITY; | ||
574 | return; | ||
575 | } | ||
576 | |||
577 | // user identity | ||
578 | Parser.token.append( symbol ); | ||
579 | |||
580 | // continue till whitespace | ||
581 | bool validName = true; | ||
582 | do | ||
583 | { | ||
584 | if ( Parser.index >= Parser.sourcesize ) | ||
585 | { | ||
586 | Parser.tokenresult = Q3_TOKEN_EOF; | ||
587 | return; | ||
588 | } | ||
589 | symbol = Parser.source [ Parser.index ]; | ||
590 | |||
591 | validName = isQ3ValidName( symbol ); | ||
592 | if ( validName ) | ||
593 | { | ||
594 | Parser.token.append( symbol ); | ||
595 | Parser.index += 1; | ||
596 | } | ||
597 | } while ( validName ); | ||
598 | |||
599 | Parser.tokenresult = Q3_TOKEN_TOKEN; | ||
600 | return; | ||
601 | } | ||
602 | |||
603 | |||
604 | /* | ||
605 | parse entity & shader | ||
606 | calls callback on content in {} | ||
607 | */ | ||
608 | void CQ3LevelMesh::parser_parse( const void * data, const u32 size, CQ3LevelMesh::tParserCallback callback ) | ||
609 | { | ||
610 | Parser.source = static_cast<const c8*>(data); | ||
611 | Parser.sourcesize = size; | ||
612 | Parser.index = 0; | ||
613 | |||
614 | SVarGroupList *groupList; | ||
615 | |||
616 | s32 active; | ||
617 | s32 last; | ||
618 | |||
619 | SVariable entity ( "" ); | ||
620 | |||
621 | groupList = new SVarGroupList(); | ||
622 | |||
623 | groupList->VariableGroup.push_back( SVarGroup() ); | ||
624 | active = last = 0; | ||
625 | |||
626 | do | ||
627 | { | ||
628 | parser_nextToken(); | ||
629 | |||
630 | switch ( Parser.tokenresult ) | ||
631 | { | ||
632 | case Q3_TOKEN_START_LIST: | ||
633 | { | ||
634 | //stack = core::min_( stack + 1, 7 ); | ||
635 | |||
636 | groupList->VariableGroup.push_back( SVarGroup() ); | ||
637 | last = active; | ||
638 | active = groupList->VariableGroup.size() - 1; | ||
639 | entity.clear(); | ||
640 | } break; | ||
641 | |||
642 | // a unregisterd variable is finished | ||
643 | case Q3_TOKEN_EOL: | ||
644 | { | ||
645 | if ( entity.isValid() ) | ||
646 | { | ||
647 | groupList->VariableGroup[active].Variable.push_back( entity ); | ||
648 | entity.clear(); | ||
649 | } | ||
650 | } break; | ||
651 | |||
652 | case Q3_TOKEN_TOKEN: | ||
653 | case Q3_TOKEN_ENTITY: | ||
654 | { | ||
655 | Parser.token.make_lower(); | ||
656 | |||
657 | // store content based on line-delemiter | ||
658 | if ( 0 == entity.isValid() ) | ||
659 | { | ||
660 | entity.name = Parser.token; | ||
661 | entity.content = ""; | ||
662 | |||
663 | } | ||
664 | else | ||
665 | { | ||
666 | if ( entity.content.size() ) | ||
667 | { | ||
668 | entity.content += " "; | ||
669 | } | ||
670 | entity.content += Parser.token; | ||
671 | } | ||
672 | } break; | ||
673 | |||
674 | case Q3_TOKEN_END_LIST: | ||
675 | { | ||
676 | //stack = core::max_( stack - 1, 0 ); | ||
677 | |||
678 | // close tag for first | ||
679 | if ( active == 1 ) | ||
680 | { | ||
681 | (this->*callback)( groupList, Q3_TOKEN_END_LIST ); | ||
682 | |||
683 | // new group | ||
684 | groupList->drop(); | ||
685 | groupList = new SVarGroupList(); | ||
686 | groupList->VariableGroup.push_back( SVarGroup() ); | ||
687 | last = 0; | ||
688 | } | ||
689 | |||
690 | active = last; | ||
691 | entity.clear(); | ||
692 | |||
693 | } break; | ||
694 | |||
695 | default: | ||
696 | break; | ||
697 | } | ||
698 | |||
699 | } while ( Parser.tokenresult != Q3_TOKEN_EOF ); | ||
700 | |||
701 | (this->*callback)( groupList, Q3_TOKEN_EOF ); | ||
702 | |||
703 | groupList->drop(); | ||
704 | } | ||
705 | |||
706 | |||
707 | /* | ||
708 | this loader applies only textures for stage 1 & 2 | ||
709 | */ | ||
710 | s32 CQ3LevelMesh::setShaderFogMaterial( video::SMaterial &material, const tBSPFace * face ) const | ||
711 | { | ||
712 | material.MaterialType = video::EMT_SOLID; | ||
713 | material.Wireframe = false; | ||
714 | material.Lighting = false; | ||
715 | material.BackfaceCulling = false; | ||
716 | material.setTexture(0, 0); | ||
717 | material.setTexture(1, 0); | ||
718 | material.setTexture(2, 0); | ||
719 | material.setTexture(3, 0); | ||
720 | material.ZBuffer = video::ECFN_LESSEQUAL; | ||
721 | material.ZWriteEnable = false; | ||
722 | material.MaterialTypeParam = 0.f; | ||
723 | |||
724 | s32 shaderState = -1; | ||
725 | |||
726 | if ( (u32) face->fogNum < FogMap.size() ) | ||
727 | { | ||
728 | material.setTexture(0, FogMap [ face->fogNum ].Texture); | ||
729 | shaderState = FogMap [ face->fogNum ].ShaderID; | ||
730 | } | ||
731 | |||
732 | return shaderState; | ||
733 | |||
734 | } | ||
735 | /* | ||
736 | this loader applies only textures for stage 1 & 2 | ||
737 | */ | ||
738 | s32 CQ3LevelMesh::setShaderMaterial( video::SMaterial &material, const tBSPFace * face ) const | ||
739 | { | ||
740 | material.MaterialType = video::EMT_SOLID; | ||
741 | material.Wireframe = false; | ||
742 | material.Lighting = false; | ||
743 | material.BackfaceCulling = true; | ||
744 | material.setTexture(0, 0); | ||
745 | material.setTexture(1, 0); | ||
746 | material.setTexture(2, 0); | ||
747 | material.setTexture(3, 0); | ||
748 | material.ZBuffer = video::ECFN_LESSEQUAL; | ||
749 | material.ZWriteEnable = true; | ||
750 | material.MaterialTypeParam = 0.f; | ||
751 | |||
752 | s32 shaderState = -1; | ||
753 | |||
754 | if ( face->textureID >= 0 && face->textureID < (s32)Tex.size() ) | ||
755 | { | ||
756 | material.setTexture(0, Tex [ face->textureID ].Texture); | ||
757 | shaderState = Tex [ face->textureID ].ShaderID; | ||
758 | } | ||
759 | |||
760 | if ( face->lightmapID >= 0 && face->lightmapID < (s32)Lightmap.size() ) | ||
761 | { | ||
762 | material.setTexture(1, Lightmap [ face->lightmapID ]); | ||
763 | material.MaterialType = LoadParam.defaultLightMapMaterial; | ||
764 | } | ||
765 | |||
766 | // store shader ID | ||
767 | material.MaterialTypeParam2 = (f32) shaderState; | ||
768 | |||
769 | const IShader *shader = getShader(shaderState); | ||
770 | if ( 0 == shader ) | ||
771 | return shaderState; | ||
772 | |||
773 | return shaderState; | ||
774 | |||
775 | #if 0 | ||
776 | const SVarGroup *group; | ||
777 | |||
778 | |||
779 | // generic | ||
780 | group = shader->getGroup( 1 ); | ||
781 | if ( group ) | ||
782 | { | ||
783 | material.BackfaceCulling = getCullingFunction( group->get( "cull" ) ); | ||
784 | |||
785 | if ( group->isDefined( "surfaceparm", "nolightmap" ) ) | ||
786 | { | ||
787 | material.MaterialType = video::EMT_SOLID; | ||
788 | material.setTexture(1, 0); | ||
789 | } | ||
790 | |||
791 | } | ||
792 | |||
793 | // try to get the best of the 8 texture stages.. | ||
794 | |||
795 | // texture 1, texture 2 | ||
796 | u32 startPos; | ||
797 | for ( s32 g = 2; g <= 3; ++g ) | ||
798 | { | ||
799 | group = shader->getGroup( g ); | ||
800 | if ( 0 == group ) | ||
801 | continue; | ||
802 | |||
803 | startPos = 0; | ||
804 | |||
805 | if ( group->isDefined( "depthwrite" ) ) | ||
806 | { | ||
807 | material.ZWriteEnable = true; | ||
808 | } | ||
809 | |||
810 | SBlendFunc blendfunc ( LoadParam.defaultModulate ); | ||
811 | getBlendFunc( group->get( "blendfunc" ), blendfunc ); | ||
812 | getBlendFunc( group->get( "alphafunc" ), blendfunc ); | ||
813 | |||
814 | if ( 0 == LoadParam.alpharef && | ||
815 | ( blendfunc.type == video::EMT_TRANSPARENT_ALPHA_CHANNEL || | ||
816 | blendfunc.type == video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF | ||
817 | ) | ||
818 | ) | ||
819 | { | ||
820 | blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL; | ||
821 | blendfunc.param0 = 0.f; | ||
822 | } | ||
823 | |||
824 | material.MaterialType = blendfunc.type; | ||
825 | material.MaterialTypeParam = blendfunc.param0; | ||
826 | |||
827 | // try if we can match better | ||
828 | shaderState |= (material.MaterialType == video::EMT_SOLID ) ? 0x00020000 : 0; | ||
829 | } | ||
830 | |||
831 | //material.BackfaceCulling = false; | ||
832 | |||
833 | if ( shader->VarGroup->VariableGroup.size() <= 4 ) | ||
834 | { | ||
835 | shaderState |= 0x00010000; | ||
836 | } | ||
837 | |||
838 | material.MaterialTypeParam2 = (f32) shaderState; | ||
839 | return shaderState; | ||
840 | #endif | ||
841 | } | ||
842 | |||
843 | /*! | ||
844 | Internal function to build a mesh. | ||
845 | */ | ||
846 | scene::SMesh** CQ3LevelMesh::buildMesh(s32 num) | ||
847 | { | ||
848 | scene::SMesh** newmesh = new SMesh *[quake3::E_Q3_MESH_SIZE]; | ||
849 | |||
850 | s32 i, j, k,s; | ||
851 | |||
852 | for (i = 0; i < E_Q3_MESH_SIZE; i++) | ||
853 | { | ||
854 | newmesh[i] = new SMesh(); | ||
855 | } | ||
856 | |||
857 | s32 *index; | ||
858 | |||
859 | video::S3DVertex2TCoords temp[3]; | ||
860 | video::SMaterial material; | ||
861 | video::SMaterial material2; | ||
862 | |||
863 | SToBuffer item [ E_Q3_MESH_SIZE ]; | ||
864 | u32 itemSize; | ||
865 | |||
866 | for (i = Models[num].faceIndex; i < Models[num].numOfFaces + Models[num].faceIndex; ++i) | ||
867 | { | ||
868 | const tBSPFace * face = Faces + i; | ||
869 | |||
870 | s32 shaderState = setShaderMaterial( material, face ); | ||
871 | itemSize = 0; | ||
872 | |||
873 | const IShader *shader = getShader(shaderState); | ||
874 | |||
875 | if ( face->fogNum >= 0 ) | ||
876 | { | ||
877 | setShaderFogMaterial ( material2, face ); | ||
878 | item[itemSize].index = E_Q3_MESH_FOG; | ||
879 | item[itemSize].takeVertexColor = 1; | ||
880 | itemSize += 1; | ||
881 | } | ||
882 | |||
883 | switch( face->type ) | ||
884 | { | ||
885 | case 1: // normal polygons | ||
886 | case 2: // patches | ||
887 | case 3: // meshes | ||
888 | if ( 0 == shader ) | ||
889 | { | ||
890 | if ( LoadParam.cleanUnResolvedMeshes || material.getTexture(0) ) | ||
891 | { | ||
892 | item[itemSize].takeVertexColor = 1; | ||
893 | item[itemSize].index = E_Q3_MESH_GEOMETRY; | ||
894 | itemSize += 1; | ||
895 | } | ||
896 | else | ||
897 | { | ||
898 | item[itemSize].takeVertexColor = 1; | ||
899 | item[itemSize].index = E_Q3_MESH_UNRESOLVED; | ||
900 | itemSize += 1; | ||
901 | } | ||
902 | } | ||
903 | else | ||
904 | { | ||
905 | item[itemSize].takeVertexColor = 1; | ||
906 | item[itemSize].index = E_Q3_MESH_ITEMS; | ||
907 | itemSize += 1; | ||
908 | } | ||
909 | break; | ||
910 | |||
911 | case 4: // billboards | ||
912 | //item[itemSize].takeVertexColor = 1; | ||
913 | //item[itemSize].index = E_Q3_MESH_ITEMS; | ||
914 | //itemSize += 1; | ||
915 | break; | ||
916 | |||
917 | } | ||
918 | |||
919 | for ( u32 g = 0; g != itemSize; ++g ) | ||
920 | { | ||
921 | scene::SMeshBufferLightMap* buffer = 0; | ||
922 | |||
923 | if ( item[g].index == E_Q3_MESH_GEOMETRY ) | ||
924 | { | ||
925 | if ( 0 == item[g].takeVertexColor ) | ||
926 | { | ||
927 | item[g].takeVertexColor = material.getTexture(0) == 0 || material.getTexture(1) == 0; | ||
928 | } | ||
929 | |||
930 | if (Faces[i].lightmapID < -1 || Faces[i].lightmapID > NumLightMaps-1) | ||
931 | { | ||
932 | Faces[i].lightmapID = -1; | ||
933 | } | ||
934 | |||
935 | #if 0 | ||
936 | // there are lightmapsids and textureid with -1 | ||
937 | const s32 tmp_index = ((Faces[i].lightmapID+1) * (NumTextures+1)) + (Faces[i].textureID+1); | ||
938 | buffer = (SMeshBufferLightMap*) newmesh[E_Q3_MESH_GEOMETRY]->getMeshBuffer(tmp_index); | ||
939 | buffer->setHardwareMappingHint ( EHM_STATIC ); | ||
940 | buffer->getMaterial() = material; | ||
941 | #endif | ||
942 | } | ||
943 | |||
944 | // Construct a unique mesh for each shader or combine meshbuffers for same shader | ||
945 | if ( 0 == buffer ) | ||
946 | { | ||
947 | |||
948 | if ( LoadParam.mergeShaderBuffer == 1 ) | ||
949 | { | ||
950 | // combine | ||
951 | buffer = (SMeshBufferLightMap*) newmesh[ item[g].index ]->getMeshBuffer( | ||
952 | item[g].index != E_Q3_MESH_FOG ? material : material2 ); | ||
953 | } | ||
954 | |||
955 | // create a seperate mesh buffer | ||
956 | if ( 0 == buffer ) | ||
957 | { | ||
958 | buffer = new scene::SMeshBufferLightMap(); | ||
959 | newmesh[ item[g].index ]->addMeshBuffer( buffer ); | ||
960 | buffer->drop(); | ||
961 | buffer->getMaterial() = item[g].index != E_Q3_MESH_FOG ? material : material2; | ||
962 | if ( item[g].index == E_Q3_MESH_GEOMETRY ) | ||
963 | buffer->setHardwareMappingHint ( EHM_STATIC ); | ||
964 | } | ||
965 | } | ||
966 | |||
967 | |||
968 | switch(Faces[i].type) | ||
969 | { | ||
970 | case 4: // billboards | ||
971 | break; | ||
972 | case 2: // patches | ||
973 | createCurvedSurface_bezier( buffer, i, | ||
974 | LoadParam.patchTesselation, | ||
975 | item[g].takeVertexColor | ||
976 | ); | ||
977 | break; | ||
978 | |||
979 | case 1: // normal polygons | ||
980 | case 3: // mesh vertices | ||
981 | index = MeshVerts + face->meshVertIndex; | ||
982 | k = buffer->getVertexCount(); | ||
983 | |||
984 | // reallocate better if many small meshes are used | ||
985 | s = buffer->getIndexCount()+face->numMeshVerts; | ||
986 | if ( buffer->Indices.allocated_size () < (u32) s ) | ||
987 | { | ||
988 | if ( buffer->Indices.allocated_size () > 0 && | ||
989 | face->numMeshVerts < 20 && NumFaces > 1000 | ||
990 | ) | ||
991 | { | ||
992 | s = buffer->getIndexCount() + (NumFaces >> 3 * face->numMeshVerts ); | ||
993 | } | ||
994 | buffer->Indices.reallocate( s); | ||
995 | } | ||
996 | |||
997 | for ( j = 0; j < face->numMeshVerts; ++j ) | ||
998 | { | ||
999 | buffer->Indices.push_back( k + index [j] ); | ||
1000 | } | ||
1001 | |||
1002 | s = k+face->numOfVerts; | ||
1003 | if ( buffer->Vertices.allocated_size () < (u32) s ) | ||
1004 | { | ||
1005 | if ( buffer->Indices.allocated_size () > 0 && | ||
1006 | face->numOfVerts < 20 && NumFaces > 1000 | ||
1007 | ) | ||
1008 | { | ||
1009 | s = buffer->getIndexCount() + (NumFaces >> 3 * face->numOfVerts ); | ||
1010 | } | ||
1011 | buffer->Vertices.reallocate( s); | ||
1012 | } | ||
1013 | for ( j = 0; j != face->numOfVerts; ++j ) | ||
1014 | { | ||
1015 | copy( &temp[0], &Vertices[ j + face->vertexIndex ], item[g].takeVertexColor ); | ||
1016 | buffer->Vertices.push_back( temp[0] ); | ||
1017 | } | ||
1018 | break; | ||
1019 | |||
1020 | } // end switch | ||
1021 | } | ||
1022 | } | ||
1023 | |||
1024 | return newmesh; | ||
1025 | } | ||
1026 | |||
1027 | /*! | ||
1028 | */ | ||
1029 | void CQ3LevelMesh::solveTJunction() | ||
1030 | { | ||
1031 | } | ||
1032 | |||
1033 | /*! | ||
1034 | constructs a mesh from the quake 3 level file. | ||
1035 | */ | ||
1036 | void CQ3LevelMesh::constructMesh() | ||
1037 | { | ||
1038 | if ( LoadParam.verbose > 0 ) | ||
1039 | { | ||
1040 | LoadParam.startTime = os::Timer::getRealTime(); | ||
1041 | |||
1042 | if ( LoadParam.verbose > 1 ) | ||
1043 | { | ||
1044 | snprintf( buf, sizeof ( buf ), | ||
1045 | "quake3::constructMesh start to create %d faces, %d vertices,%d mesh vertices", | ||
1046 | NumFaces, | ||
1047 | NumVertices, | ||
1048 | NumMeshVerts | ||
1049 | ); | ||
1050 | os::Printer::log(buf, ELL_INFORMATION); | ||
1051 | } | ||
1052 | |||
1053 | } | ||
1054 | |||
1055 | s32 i, j; | ||
1056 | |||
1057 | // First the main level | ||
1058 | SMesh **tmp = buildMesh(0); | ||
1059 | |||
1060 | for (i = 0; i < E_Q3_MESH_SIZE; i++) | ||
1061 | { | ||
1062 | Mesh[i] = tmp[i]; | ||
1063 | } | ||
1064 | delete [] tmp; | ||
1065 | |||
1066 | // Then the brush entities | ||
1067 | |||
1068 | for (i = 1; i < NumModels; i++) | ||
1069 | { | ||
1070 | tmp = buildMesh(i); | ||
1071 | BrushEntities[i] = tmp[0]; | ||
1072 | |||
1073 | // We only care about the main geometry here | ||
1074 | for (j = 1; j < E_Q3_MESH_SIZE; j++) | ||
1075 | { | ||
1076 | tmp[j]->drop(); | ||
1077 | } | ||
1078 | delete [] tmp; | ||
1079 | } | ||
1080 | |||
1081 | if ( LoadParam.verbose > 0 ) | ||
1082 | { | ||
1083 | LoadParam.endTime = os::Timer::getRealTime(); | ||
1084 | |||
1085 | snprintf( buf, sizeof ( buf ), | ||
1086 | "quake3::constructMesh needed %04d ms to create %d faces, %d vertices,%d mesh vertices", | ||
1087 | LoadParam.endTime - LoadParam.startTime, | ||
1088 | NumFaces, | ||
1089 | NumVertices, | ||
1090 | NumMeshVerts | ||
1091 | ); | ||
1092 | os::Printer::log(buf, ELL_INFORMATION); | ||
1093 | } | ||
1094 | |||
1095 | } | ||
1096 | |||
1097 | |||
1098 | void CQ3LevelMesh::S3DVertex2TCoords_64::copy( video::S3DVertex2TCoords &dest ) const | ||
1099 | { | ||
1100 | #if defined (TJUNCTION_SOLVER_ROUND) | ||
1101 | dest.Pos.X = core::round_( (f32) Pos.X ); | ||
1102 | dest.Pos.Y = core::round_( (f32) Pos.Y ); | ||
1103 | dest.Pos.Z = core::round_( (f32) Pos.Z ); | ||
1104 | #elif defined (TJUNCTION_SOLVER_0125) | ||
1105 | dest.Pos.X = (f32) ( floor ( Pos.X * 8.f + 0.5 ) * 0.125 ); | ||
1106 | dest.Pos.Y = (f32) ( floor ( Pos.Y * 8.f + 0.5 ) * 0.125 ); | ||
1107 | dest.Pos.Z = (f32) ( floor ( Pos.Z * 8.f + 0.5 ) * 0.125 ); | ||
1108 | #else | ||
1109 | dest.Pos.X = (f32) Pos.X; | ||
1110 | dest.Pos.Y = (f32) Pos.Y; | ||
1111 | dest.Pos.Z = (f32) Pos.Z; | ||
1112 | #endif | ||
1113 | |||
1114 | dest.Normal.X = (f32) Normal.X; | ||
1115 | dest.Normal.Y = (f32) Normal.Y; | ||
1116 | dest.Normal.Z = (f32) Normal.Z; | ||
1117 | dest.Normal.normalize(); | ||
1118 | |||
1119 | dest.Color = Color.toSColor(); | ||
1120 | |||
1121 | dest.TCoords.X = (f32) TCoords.X; | ||
1122 | dest.TCoords.Y = (f32) TCoords.Y; | ||
1123 | |||
1124 | dest.TCoords2.X = (f32) TCoords2.X; | ||
1125 | dest.TCoords2.Y = (f32) TCoords2.Y; | ||
1126 | } | ||
1127 | |||
1128 | |||
1129 | void CQ3LevelMesh::copy( S3DVertex2TCoords_64 * dest, const tBSPVertex * source, s32 vertexcolor ) const | ||
1130 | { | ||
1131 | #if defined (TJUNCTION_SOLVER_ROUND) | ||
1132 | dest->Pos.X = core::round_( source->vPosition[0] ); | ||
1133 | dest->Pos.Y = core::round_( source->vPosition[2] ); | ||
1134 | dest->Pos.Z = core::round_( source->vPosition[1] ); | ||
1135 | #elif defined (TJUNCTION_SOLVER_0125) | ||
1136 | dest->Pos.X = (f32) ( floor ( source->vPosition[0] * 8.f + 0.5 ) * 0.125 ); | ||
1137 | dest->Pos.Y = (f32) ( floor ( source->vPosition[2] * 8.f + 0.5 ) * 0.125 ); | ||
1138 | dest->Pos.Z = (f32) ( floor ( source->vPosition[1] * 8.f + 0.5 ) * 0.125 ); | ||
1139 | #else | ||
1140 | dest->Pos.X = source->vPosition[0]; | ||
1141 | dest->Pos.Y = source->vPosition[2]; | ||
1142 | dest->Pos.Z = source->vPosition[1]; | ||
1143 | #endif | ||
1144 | |||
1145 | dest->Normal.X = source->vNormal[0]; | ||
1146 | dest->Normal.Y = source->vNormal[2]; | ||
1147 | dest->Normal.Z = source->vNormal[1]; | ||
1148 | dest->Normal.normalize(); | ||
1149 | |||
1150 | dest->TCoords.X = source->vTextureCoord[0]; | ||
1151 | dest->TCoords.Y = source->vTextureCoord[1]; | ||
1152 | dest->TCoords2.X = source->vLightmapCoord[0]; | ||
1153 | dest->TCoords2.Y = source->vLightmapCoord[1]; | ||
1154 | |||
1155 | if ( vertexcolor ) | ||
1156 | { | ||
1157 | //u32 a = core::s32_min( source->color[3] * LoadParam.defaultModulate, 255 ); | ||
1158 | u32 a = source->color[3]; | ||
1159 | u32 r = core::s32_min( source->color[0] * LoadParam.defaultModulate, 255 ); | ||
1160 | u32 g = core::s32_min( source->color[1] * LoadParam.defaultModulate, 255 ); | ||
1161 | u32 b = core::s32_min( source->color[2] * LoadParam.defaultModulate, 255 ); | ||
1162 | |||
1163 | dest->Color.set(a * 1.f/255.f, r * 1.f/255.f, | ||
1164 | g * 1.f/255.f, b * 1.f/255.f); | ||
1165 | } | ||
1166 | else | ||
1167 | { | ||
1168 | dest->Color.set( 1.f, 1.f, 1.f, 1.f ); | ||
1169 | } | ||
1170 | } | ||
1171 | |||
1172 | |||
1173 | inline void CQ3LevelMesh::copy( video::S3DVertex2TCoords * dest, const tBSPVertex * source, s32 vertexcolor ) const | ||
1174 | { | ||
1175 | #if defined (TJUNCTION_SOLVER_ROUND) | ||
1176 | dest->Pos.X = core::round_( source->vPosition[0] ); | ||
1177 | dest->Pos.Y = core::round_( source->vPosition[2] ); | ||
1178 | dest->Pos.Z = core::round_( source->vPosition[1] ); | ||
1179 | #elif defined (TJUNCTION_SOLVER_0125) | ||
1180 | dest->Pos.X = (f32) ( floor ( source->vPosition[0] * 8.f + 0.5 ) * 0.125 ); | ||
1181 | dest->Pos.Y = (f32) ( floor ( source->vPosition[2] * 8.f + 0.5 ) * 0.125 ); | ||
1182 | dest->Pos.Z = (f32) ( floor ( source->vPosition[1] * 8.f + 0.5 ) * 0.125 ); | ||
1183 | #else | ||
1184 | dest->Pos.X = source->vPosition[0]; | ||
1185 | dest->Pos.Y = source->vPosition[2]; | ||
1186 | dest->Pos.Z = source->vPosition[1]; | ||
1187 | #endif | ||
1188 | |||
1189 | dest->Normal.X = source->vNormal[0]; | ||
1190 | dest->Normal.Y = source->vNormal[2]; | ||
1191 | dest->Normal.Z = source->vNormal[1]; | ||
1192 | dest->Normal.normalize(); | ||
1193 | |||
1194 | dest->TCoords.X = source->vTextureCoord[0]; | ||
1195 | dest->TCoords.Y = source->vTextureCoord[1]; | ||
1196 | dest->TCoords2.X = source->vLightmapCoord[0]; | ||
1197 | dest->TCoords2.Y = source->vLightmapCoord[1]; | ||
1198 | |||
1199 | if ( vertexcolor ) | ||
1200 | { | ||
1201 | //u32 a = core::s32_min( source->color[3] * LoadParam.defaultModulate, 255 ); | ||
1202 | u32 a = source->color[3]; | ||
1203 | u32 r = core::s32_min( source->color[0] * LoadParam.defaultModulate, 255 ); | ||
1204 | u32 g = core::s32_min( source->color[1] * LoadParam.defaultModulate, 255 ); | ||
1205 | u32 b = core::s32_min( source->color[2] * LoadParam.defaultModulate, 255 ); | ||
1206 | |||
1207 | dest->Color.set(a << 24 | r << 16 | g << 8 | b); | ||
1208 | } | ||
1209 | else | ||
1210 | { | ||
1211 | dest->Color.set(0xFFFFFFFF); | ||
1212 | } | ||
1213 | } | ||
1214 | |||
1215 | |||
1216 | void CQ3LevelMesh::SBezier::tesselate( s32 level ) | ||
1217 | { | ||
1218 | //Calculate how many vertices across/down there are | ||
1219 | s32 j, k; | ||
1220 | |||
1221 | column[0].set_used( level + 1 ); | ||
1222 | column[1].set_used( level + 1 ); | ||
1223 | column[2].set_used( level + 1 ); | ||
1224 | |||
1225 | const f64 w = 0.0 + (1.0 / (f64) level ); | ||
1226 | |||
1227 | //Tesselate along the columns | ||
1228 | for( j = 0; j <= level; ++j) | ||
1229 | { | ||
1230 | const f64 f = w * (f64) j; | ||
1231 | |||
1232 | column[0][j] = control[0].getInterpolated_quadratic(control[3], control[6], f ); | ||
1233 | column[1][j] = control[1].getInterpolated_quadratic(control[4], control[7], f ); | ||
1234 | column[2][j] = control[2].getInterpolated_quadratic(control[5], control[8], f ); | ||
1235 | } | ||
1236 | |||
1237 | const u32 idx = Patch->Vertices.size(); | ||
1238 | Patch->Vertices.reallocate(idx+level*level); | ||
1239 | //Tesselate across the rows to get final vertices | ||
1240 | video::S3DVertex2TCoords v; | ||
1241 | S3DVertex2TCoords_64 f; | ||
1242 | for( j = 0; j <= level; ++j) | ||
1243 | { | ||
1244 | for( k = 0; k <= level; ++k) | ||
1245 | { | ||
1246 | f = column[0][j].getInterpolated_quadratic(column[1][j], column[2][j], w * (f64) k); | ||
1247 | f.copy( v ); | ||
1248 | Patch->Vertices.push_back( v ); | ||
1249 | } | ||
1250 | } | ||
1251 | |||
1252 | Patch->Indices.reallocate(Patch->Indices.size()+6*level*level); | ||
1253 | // connect | ||
1254 | for( j = 0; j < level; ++j) | ||
1255 | { | ||
1256 | for( k = 0; k < level; ++k) | ||
1257 | { | ||
1258 | const s32 inx = idx + ( k * ( level + 1 ) ) + j; | ||
1259 | |||
1260 | Patch->Indices.push_back( inx + 0 ); | ||
1261 | Patch->Indices.push_back( inx + (level + 1 ) + 0 ); | ||
1262 | Patch->Indices.push_back( inx + (level + 1 ) + 1 ); | ||
1263 | |||
1264 | Patch->Indices.push_back( inx + 0 ); | ||
1265 | Patch->Indices.push_back( inx + (level + 1 ) + 1 ); | ||
1266 | Patch->Indices.push_back( inx + 1 ); | ||
1267 | } | ||
1268 | } | ||
1269 | } | ||
1270 | |||
1271 | |||
1272 | /*! | ||
1273 | no subdivision | ||
1274 | */ | ||
1275 | void CQ3LevelMesh::createCurvedSurface_nosubdivision(SMeshBufferLightMap* meshBuffer, | ||
1276 | s32 faceIndex, | ||
1277 | s32 patchTesselation, | ||
1278 | s32 storevertexcolor) | ||
1279 | { | ||
1280 | tBSPFace * face = &Faces[faceIndex]; | ||
1281 | u32 j,k,m; | ||
1282 | |||
1283 | // number of control points across & up | ||
1284 | const u32 controlWidth = face->size[0]; | ||
1285 | const u32 controlHeight = face->size[1]; | ||
1286 | if ( 0 == controlWidth || 0 == controlHeight ) | ||
1287 | return; | ||
1288 | |||
1289 | video::S3DVertex2TCoords v; | ||
1290 | |||
1291 | m = meshBuffer->Vertices.size(); | ||
1292 | meshBuffer->Vertices.reallocate(m+controlHeight * controlWidth); | ||
1293 | for ( j = 0; j!= controlHeight * controlWidth; ++j ) | ||
1294 | { | ||
1295 | copy( &v, &Vertices [ face->vertexIndex + j ], storevertexcolor ); | ||
1296 | meshBuffer->Vertices.push_back( v ); | ||
1297 | } | ||
1298 | |||
1299 | meshBuffer->Indices.reallocate(meshBuffer->Indices.size()+6*(controlHeight-1) * (controlWidth-1)); | ||
1300 | for ( j = 0; j!= controlHeight - 1; ++j ) | ||
1301 | { | ||
1302 | for ( k = 0; k!= controlWidth - 1; ++k ) | ||
1303 | { | ||
1304 | meshBuffer->Indices.push_back( m + k + 0 ); | ||
1305 | meshBuffer->Indices.push_back( m + k + controlWidth + 0 ); | ||
1306 | meshBuffer->Indices.push_back( m + k + controlWidth + 1 ); | ||
1307 | |||
1308 | meshBuffer->Indices.push_back( m + k + 0 ); | ||
1309 | meshBuffer->Indices.push_back( m + k + controlWidth + 1 ); | ||
1310 | meshBuffer->Indices.push_back( m + k + 1 ); | ||
1311 | } | ||
1312 | m += controlWidth; | ||
1313 | } | ||
1314 | } | ||
1315 | |||
1316 | |||
1317 | /*! | ||
1318 | */ | ||
1319 | void CQ3LevelMesh::createCurvedSurface_bezier(SMeshBufferLightMap* meshBuffer, | ||
1320 | s32 faceIndex, | ||
1321 | s32 patchTesselation, | ||
1322 | s32 storevertexcolor) | ||
1323 | { | ||
1324 | |||
1325 | tBSPFace * face = &Faces[faceIndex]; | ||
1326 | u32 j,k; | ||
1327 | |||
1328 | // number of control points across & up | ||
1329 | const u32 controlWidth = face->size[0]; | ||
1330 | const u32 controlHeight = face->size[1]; | ||
1331 | |||
1332 | if ( 0 == controlWidth || 0 == controlHeight ) | ||
1333 | return; | ||
1334 | |||
1335 | // number of biquadratic patches | ||
1336 | const u32 biquadWidth = (controlWidth - 1)/2; | ||
1337 | const u32 biquadHeight = (controlHeight -1)/2; | ||
1338 | |||
1339 | if ( LoadParam.verbose > 1 ) | ||
1340 | { | ||
1341 | LoadParam.startTime = os::Timer::getRealTime(); | ||
1342 | } | ||
1343 | |||
1344 | // Create space for a temporary array of the patch's control points | ||
1345 | core::array<S3DVertex2TCoords_64> controlPoint; | ||
1346 | controlPoint.set_used( controlWidth * controlHeight ); | ||
1347 | |||
1348 | for( j = 0; j < controlPoint.size(); ++j) | ||
1349 | { | ||
1350 | copy( &controlPoint[j], &Vertices [ face->vertexIndex + j ], storevertexcolor ); | ||
1351 | } | ||
1352 | |||
1353 | // create a temporary patch | ||
1354 | Bezier.Patch = new scene::SMeshBufferLightMap(); | ||
1355 | |||
1356 | //Loop through the biquadratic patches | ||
1357 | for( j = 0; j < biquadHeight; ++j) | ||
1358 | { | ||
1359 | for( k = 0; k < biquadWidth; ++k) | ||
1360 | { | ||
1361 | // set up this patch | ||
1362 | const s32 inx = j*controlWidth*2 + k*2; | ||
1363 | |||
1364 | // setup bezier control points for this patch | ||
1365 | Bezier.control[0] = controlPoint[ inx + 0]; | ||
1366 | Bezier.control[1] = controlPoint[ inx + 1]; | ||
1367 | Bezier.control[2] = controlPoint[ inx + 2]; | ||
1368 | Bezier.control[3] = controlPoint[ inx + controlWidth + 0 ]; | ||
1369 | Bezier.control[4] = controlPoint[ inx + controlWidth + 1 ]; | ||
1370 | Bezier.control[5] = controlPoint[ inx + controlWidth + 2 ]; | ||
1371 | Bezier.control[6] = controlPoint[ inx + controlWidth * 2 + 0]; | ||
1372 | Bezier.control[7] = controlPoint[ inx + controlWidth * 2 + 1]; | ||
1373 | Bezier.control[8] = controlPoint[ inx + controlWidth * 2 + 2]; | ||
1374 | |||
1375 | Bezier.tesselate( patchTesselation ); | ||
1376 | } | ||
1377 | } | ||
1378 | |||
1379 | // stitch together with existing geometry | ||
1380 | // TODO: only border needs to be checked | ||
1381 | const u32 bsize = Bezier.Patch->getVertexCount(); | ||
1382 | const u32 msize = meshBuffer->getVertexCount(); | ||
1383 | /* | ||
1384 | for ( j = 0; j!= bsize; ++j ) | ||
1385 | { | ||
1386 | const core::vector3df &v = Bezier.Patch->Vertices[j].Pos; | ||
1387 | |||
1388 | for ( k = 0; k!= msize; ++k ) | ||
1389 | { | ||
1390 | const core::vector3df &m = meshBuffer->Vertices[k].Pos; | ||
1391 | |||
1392 | if ( !v.equals( m, tolerance ) ) | ||
1393 | continue; | ||
1394 | |||
1395 | meshBuffer->Vertices[k].Pos = v; | ||
1396 | //Bezier.Patch->Vertices[j].Pos = m; | ||
1397 | } | ||
1398 | } | ||
1399 | */ | ||
1400 | |||
1401 | // add Patch to meshbuffer | ||
1402 | meshBuffer->Vertices.reallocate(msize+bsize); | ||
1403 | for ( j = 0; j!= bsize; ++j ) | ||
1404 | { | ||
1405 | meshBuffer->Vertices.push_back( Bezier.Patch->Vertices[j] ); | ||
1406 | } | ||
1407 | |||
1408 | // add indices to meshbuffer | ||
1409 | meshBuffer->Indices.reallocate(meshBuffer->getIndexCount()+Bezier.Patch->getIndexCount()); | ||
1410 | for ( j = 0; j!= Bezier.Patch->getIndexCount(); ++j ) | ||
1411 | { | ||
1412 | meshBuffer->Indices.push_back( msize + Bezier.Patch->Indices[j] ); | ||
1413 | } | ||
1414 | |||
1415 | delete Bezier.Patch; | ||
1416 | |||
1417 | if ( LoadParam.verbose > 1 ) | ||
1418 | { | ||
1419 | LoadParam.endTime = os::Timer::getRealTime(); | ||
1420 | |||
1421 | snprintf( buf, sizeof ( buf ), | ||
1422 | "quake3::createCurvedSurface_bezier needed %04d ms to create bezier patch.(%dx%d)", | ||
1423 | LoadParam.endTime - LoadParam.startTime, | ||
1424 | biquadWidth, | ||
1425 | biquadHeight | ||
1426 | ); | ||
1427 | os::Printer::log(buf, ELL_INFORMATION); | ||
1428 | } | ||
1429 | |||
1430 | } | ||
1431 | |||
1432 | |||
1433 | |||
1434 | /*! | ||
1435 | Loads entities from file | ||
1436 | */ | ||
1437 | void CQ3LevelMesh::getConfiguration( io::IReadFile* file ) | ||
1438 | { | ||
1439 | tBSPLump l; | ||
1440 | l.offset = file->getPos(); | ||
1441 | l.length = file->getSize (); | ||
1442 | |||
1443 | core::array<u8> entity; | ||
1444 | entity.set_used( l.length + 2 ); | ||
1445 | entity[l.length + 1 ] = 0; | ||
1446 | |||
1447 | file->seek(l.offset); | ||
1448 | file->read( entity.pointer(), l.length); | ||
1449 | |||
1450 | parser_parse( entity.pointer(), l.length, &CQ3LevelMesh::scriptcallback_config ); | ||
1451 | |||
1452 | if ( Entity.size () ) | ||
1453 | Entity.getLast().name = file->getFileName(); | ||
1454 | } | ||
1455 | |||
1456 | |||
1457 | //! get's an interface to the entities | ||
1458 | tQ3EntityList & CQ3LevelMesh::getEntityList() | ||
1459 | { | ||
1460 | // Entity.sort(); | ||
1461 | return Entity; | ||
1462 | } | ||
1463 | |||
1464 | //! returns the requested brush entity | ||
1465 | IMesh* CQ3LevelMesh::getBrushEntityMesh(s32 num) const | ||
1466 | { | ||
1467 | if (num < 1 || num >= NumModels) | ||
1468 | return 0; | ||
1469 | |||
1470 | return BrushEntities[num]; | ||
1471 | } | ||
1472 | |||
1473 | //! returns the requested brush entity | ||
1474 | IMesh* CQ3LevelMesh::getBrushEntityMesh(quake3::IEntity &ent) const | ||
1475 | { | ||
1476 | // This is a helper function to parse the entity, | ||
1477 | // so you don't have to. | ||
1478 | |||
1479 | s32 num; | ||
1480 | |||
1481 | const quake3::SVarGroup* group = ent.getGroup(1); | ||
1482 | const core::stringc& modnum = group->get("model"); | ||
1483 | |||
1484 | if (!group->isDefined("model")) | ||
1485 | return 0; | ||
1486 | |||
1487 | const char *temp = modnum.c_str() + 1; // We skip the first character. | ||
1488 | num = core::strtol10(temp); | ||
1489 | |||
1490 | return getBrushEntityMesh(num); | ||
1491 | } | ||
1492 | |||
1493 | |||
1494 | /*! | ||
1495 | */ | ||
1496 | const IShader * CQ3LevelMesh::getShader(u32 index) const | ||
1497 | { | ||
1498 | index &= 0xFFFF; | ||
1499 | |||
1500 | if ( index < Shader.size() ) | ||
1501 | { | ||
1502 | return &Shader[index]; | ||
1503 | } | ||
1504 | |||
1505 | return 0; | ||
1506 | } | ||
1507 | |||
1508 | |||
1509 | /*! | ||
1510 | loads the shader definition | ||
1511 | */ | ||
1512 | const IShader* CQ3LevelMesh::getShader( const c8 * filename, bool fileNameIsValid ) | ||
1513 | { | ||
1514 | core::stringc searchName ( filename ); | ||
1515 | |||
1516 | IShader search; | ||
1517 | search.name = searchName; | ||
1518 | search.name.replace( '\\', '/' ); | ||
1519 | search.name.make_lower(); | ||
1520 | |||
1521 | |||
1522 | core::stringc message; | ||
1523 | s32 index; | ||
1524 | |||
1525 | //! is Shader already in cache? | ||
1526 | index = Shader.linear_search( search ); | ||
1527 | if ( index >= 0 ) | ||
1528 | { | ||
1529 | if ( LoadParam.verbose > 1 ) | ||
1530 | { | ||
1531 | message = searchName + " found " + Shader[index].name; | ||
1532 | os::Printer::log("quake3:getShader", message.c_str(), ELL_INFORMATION); | ||
1533 | } | ||
1534 | |||
1535 | return &Shader[index]; | ||
1536 | } | ||
1537 | |||
1538 | io::path loadFile; | ||
1539 | |||
1540 | if ( !fileNameIsValid ) | ||
1541 | { | ||
1542 | // extract the shader name from the last path component in filename | ||
1543 | // "scripts/[name].shader" | ||
1544 | core::stringc cut( search.name ); | ||
1545 | |||
1546 | s32 end = cut.findLast( '/' ); | ||
1547 | s32 start = cut.findLast( '/', end - 1 ); | ||
1548 | |||
1549 | loadFile = LoadParam.scriptDir; | ||
1550 | loadFile.append( cut.subString( start, end - start ) ); | ||
1551 | loadFile.append( ".shader" ); | ||
1552 | } | ||
1553 | else | ||
1554 | { | ||
1555 | loadFile = search.name; | ||
1556 | } | ||
1557 | |||
1558 | // already loaded the file ? | ||
1559 | index = ShaderFile.binary_search( loadFile ); | ||
1560 | if ( index >= 0 ) | ||
1561 | return 0; | ||
1562 | |||
1563 | // add file to loaded files | ||
1564 | ShaderFile.push_back( loadFile ); | ||
1565 | |||
1566 | if ( !FileSystem->existFile( loadFile.c_str() ) ) | ||
1567 | { | ||
1568 | if ( LoadParam.verbose > 1 ) | ||
1569 | { | ||
1570 | message = loadFile + " for " + searchName + " failed "; | ||
1571 | os::Printer::log("quake3:getShader", message.c_str(), ELL_INFORMATION); | ||
1572 | } | ||
1573 | return 0; | ||
1574 | } | ||
1575 | |||
1576 | if ( LoadParam.verbose ) | ||
1577 | { | ||
1578 | message = loadFile + " for " + searchName; | ||
1579 | os::Printer::log("quake3:getShader Load shader", message.c_str(), ELL_INFORMATION); | ||
1580 | } | ||
1581 | |||
1582 | |||
1583 | io::IReadFile *file = FileSystem->createAndOpenFile( loadFile.c_str() ); | ||
1584 | if ( file ) | ||
1585 | { | ||
1586 | getShader ( file ); | ||
1587 | file->drop (); | ||
1588 | } | ||
1589 | |||
1590 | |||
1591 | // search again | ||
1592 | index = Shader.linear_search( search ); | ||
1593 | return index >= 0 ? &Shader[index] : 0; | ||
1594 | } | ||
1595 | |||
1596 | /*! | ||
1597 | loads the shader definition | ||
1598 | */ | ||
1599 | void CQ3LevelMesh::getShader( io::IReadFile* file ) | ||
1600 | { | ||
1601 | if ( 0 == file ) | ||
1602 | return; | ||
1603 | |||
1604 | // load script | ||
1605 | core::array<u8> script; | ||
1606 | const long len = file->getSize(); | ||
1607 | |||
1608 | script.set_used( len + 2 ); | ||
1609 | |||
1610 | file->seek( 0 ); | ||
1611 | file->read( script.pointer(), len ); | ||
1612 | script[ len + 1 ] = 0; | ||
1613 | |||
1614 | // start a parser instance | ||
1615 | parser_parse( script.pointer(), len, &CQ3LevelMesh::scriptcallback_shader ); | ||
1616 | } | ||
1617 | |||
1618 | |||
1619 | //! adding default shaders | ||
1620 | void CQ3LevelMesh::InitShader() | ||
1621 | { | ||
1622 | ReleaseShader(); | ||
1623 | |||
1624 | IShader element; | ||
1625 | |||
1626 | SVarGroup group; | ||
1627 | SVariable variable ( "noshader" ); | ||
1628 | |||
1629 | group.Variable.push_back( variable ); | ||
1630 | |||
1631 | element.VarGroup = new SVarGroupList(); | ||
1632 | element.VarGroup->VariableGroup.push_back( group ); | ||
1633 | element.VarGroup->VariableGroup.push_back( SVarGroup() ); | ||
1634 | element.name = element.VarGroup->VariableGroup[0].Variable[0].name; | ||
1635 | element.ID = Shader.size(); | ||
1636 | Shader.push_back( element ); | ||
1637 | |||
1638 | if ( LoadParam.loadAllShaders ) | ||
1639 | { | ||
1640 | io::EFileSystemType current = FileSystem->setFileListSystem ( io::FILESYSTEM_VIRTUAL ); | ||
1641 | io::path save = FileSystem->getWorkingDirectory(); | ||
1642 | |||
1643 | io::path newDir; | ||
1644 | newDir = "/"; | ||
1645 | newDir += LoadParam.scriptDir; | ||
1646 | newDir += "/"; | ||
1647 | FileSystem->changeWorkingDirectoryTo ( newDir.c_str() ); | ||
1648 | |||
1649 | core::stringc s; | ||
1650 | io::IFileList *fileList = FileSystem->createFileList (); | ||
1651 | for (u32 i=0; i< fileList->getFileCount(); ++i) | ||
1652 | { | ||
1653 | s = fileList->getFullFileName(i); | ||
1654 | if ( s.find ( ".shader" ) >= 0 ) | ||
1655 | { | ||
1656 | if ( 0 == LoadParam.loadSkyShader && s.find ( "sky.shader" ) >= 0 ) | ||
1657 | { | ||
1658 | } | ||
1659 | else | ||
1660 | { | ||
1661 | getShader ( s.c_str () ); | ||
1662 | } | ||
1663 | } | ||
1664 | } | ||
1665 | fileList->drop (); | ||
1666 | |||
1667 | FileSystem->changeWorkingDirectoryTo ( save ); | ||
1668 | FileSystem->setFileListSystem ( current ); | ||
1669 | } | ||
1670 | } | ||
1671 | |||
1672 | |||
1673 | //! script callback for shaders | ||
1674 | //! i'm having troubles with the reference counting, during callback.. resorting.. | ||
1675 | void CQ3LevelMesh::ReleaseShader() | ||
1676 | { | ||
1677 | for ( u32 i = 0; i!= Shader.size(); ++i ) | ||
1678 | { | ||
1679 | Shader[i].VarGroup->drop(); | ||
1680 | } | ||
1681 | Shader.clear(); | ||
1682 | ShaderFile.clear(); | ||
1683 | } | ||
1684 | |||
1685 | |||
1686 | /*! | ||
1687 | */ | ||
1688 | void CQ3LevelMesh::ReleaseEntity() | ||
1689 | { | ||
1690 | for ( u32 i = 0; i!= Entity.size(); ++i ) | ||
1691 | { | ||
1692 | Entity[i].VarGroup->drop(); | ||
1693 | } | ||
1694 | Entity.clear(); | ||
1695 | } | ||
1696 | |||
1697 | |||
1698 | // config in simple (quake3) and advanced style | ||
1699 | void CQ3LevelMesh::scriptcallback_config( SVarGroupList *& grouplist, eToken token ) | ||
1700 | { | ||
1701 | IShader element; | ||
1702 | |||
1703 | if ( token == Q3_TOKEN_END_LIST ) | ||
1704 | { | ||
1705 | if ( 0 == grouplist->VariableGroup[0].Variable.size() ) | ||
1706 | return; | ||
1707 | |||
1708 | element.name = grouplist->VariableGroup[0].Variable[0].name; | ||
1709 | } | ||
1710 | else | ||
1711 | { | ||
1712 | if ( grouplist->VariableGroup.size() != 2 ) | ||
1713 | return; | ||
1714 | |||
1715 | element.name = "configuration"; | ||
1716 | } | ||
1717 | |||
1718 | grouplist->grab(); | ||
1719 | element.VarGroup = grouplist; | ||
1720 | element.ID = Entity.size(); | ||
1721 | Entity.push_back( element ); | ||
1722 | } | ||
1723 | |||
1724 | |||
1725 | // entity only has only one valid level.. and no assoziative name.. | ||
1726 | void CQ3LevelMesh::scriptcallback_entity( SVarGroupList *& grouplist, eToken token ) | ||
1727 | { | ||
1728 | if ( token != Q3_TOKEN_END_LIST || grouplist->VariableGroup.size() != 2 ) | ||
1729 | return; | ||
1730 | |||
1731 | grouplist->grab(); | ||
1732 | |||
1733 | IEntity element; | ||
1734 | element.VarGroup = grouplist; | ||
1735 | element.ID = Entity.size(); | ||
1736 | element.name = grouplist->VariableGroup[1].get( "classname" ); | ||
1737 | |||
1738 | |||
1739 | Entity.push_back( element ); | ||
1740 | } | ||
1741 | |||
1742 | |||
1743 | //!. script callback for shaders | ||
1744 | void CQ3LevelMesh::scriptcallback_shader( SVarGroupList *& grouplist,eToken token ) | ||
1745 | { | ||
1746 | if ( token != Q3_TOKEN_END_LIST || grouplist->VariableGroup[0].Variable.size()==0) | ||
1747 | return; | ||
1748 | |||
1749 | |||
1750 | IShader element; | ||
1751 | |||
1752 | grouplist->grab(); | ||
1753 | element.VarGroup = grouplist; | ||
1754 | element.name = element.VarGroup->VariableGroup[0].Variable[0].name; | ||
1755 | element.ID = Shader.size(); | ||
1756 | /* | ||
1757 | core::stringc s; | ||
1758 | dumpShader ( s, &element ); | ||
1759 | printf ( s.c_str () ); | ||
1760 | */ | ||
1761 | Shader.push_back( element ); | ||
1762 | } | ||
1763 | |||
1764 | |||
1765 | /*! | ||
1766 | delete all buffers without geometry in it. | ||
1767 | */ | ||
1768 | void CQ3LevelMesh::cleanMeshes() | ||
1769 | { | ||
1770 | if ( 0 == LoadParam.cleanUnResolvedMeshes ) | ||
1771 | return; | ||
1772 | |||
1773 | s32 i; | ||
1774 | |||
1775 | // First the main level | ||
1776 | for (i = 0; i < E_Q3_MESH_SIZE; i++) | ||
1777 | { | ||
1778 | bool texture0important = ( i == 0 ); | ||
1779 | |||
1780 | cleanMesh(Mesh[i], texture0important); | ||
1781 | } | ||
1782 | |||
1783 | // Then the brush entities | ||
1784 | for (i = 1; i < NumModels; i++) | ||
1785 | { | ||
1786 | cleanMesh(BrushEntities[i], true); | ||
1787 | } | ||
1788 | } | ||
1789 | |||
1790 | void CQ3LevelMesh::cleanMesh(SMesh *m, const bool texture0important) | ||
1791 | { | ||
1792 | // delete all buffers without geometry in it. | ||
1793 | u32 run = 0; | ||
1794 | u32 remove = 0; | ||
1795 | |||
1796 | IMeshBuffer *b; | ||
1797 | |||
1798 | run = 0; | ||
1799 | remove = 0; | ||
1800 | |||
1801 | if ( LoadParam.verbose > 0 ) | ||
1802 | { | ||
1803 | LoadParam.startTime = os::Timer::getRealTime(); | ||
1804 | if ( LoadParam.verbose > 1 ) | ||
1805 | { | ||
1806 | snprintf( buf, sizeof ( buf ), | ||
1807 | "quake3::cleanMeshes start for %d meshes", | ||
1808 | m->MeshBuffers.size() | ||
1809 | ); | ||
1810 | os::Printer::log(buf, ELL_INFORMATION); | ||
1811 | } | ||
1812 | } | ||
1813 | |||
1814 | u32 i = 0; | ||
1815 | s32 blockstart = -1; | ||
1816 | s32 blockcount = 0; | ||
1817 | |||
1818 | while( i < m->MeshBuffers.size()) | ||
1819 | { | ||
1820 | run += 1; | ||
1821 | |||
1822 | b = m->MeshBuffers[i]; | ||
1823 | |||
1824 | if ( b->getVertexCount() == 0 || b->getIndexCount() == 0 || | ||
1825 | ( texture0important && b->getMaterial().getTexture(0) == 0 ) | ||
1826 | ) | ||
1827 | { | ||
1828 | if ( blockstart < 0 ) | ||
1829 | { | ||
1830 | blockstart = i; | ||
1831 | blockcount = 0; | ||
1832 | } | ||
1833 | blockcount += 1; | ||
1834 | i += 1; | ||
1835 | |||
1836 | // delete Meshbuffer | ||
1837 | i -= 1; | ||
1838 | remove += 1; | ||
1839 | b->drop(); | ||
1840 | m->MeshBuffers.erase(i); | ||
1841 | } | ||
1842 | else | ||
1843 | { | ||
1844 | // clean blockwise | ||
1845 | if ( blockstart >= 0 ) | ||
1846 | { | ||
1847 | if ( LoadParam.verbose > 1 ) | ||
1848 | { | ||
1849 | snprintf( buf, sizeof ( buf ), | ||
1850 | "quake3::cleanMeshes cleaning mesh %d %d size", | ||
1851 | blockstart, | ||
1852 | blockcount | ||
1853 | ); | ||
1854 | os::Printer::log(buf, ELL_INFORMATION); | ||
1855 | } | ||
1856 | blockstart = -1; | ||
1857 | } | ||
1858 | i += 1; | ||
1859 | } | ||
1860 | } | ||
1861 | |||
1862 | if ( LoadParam.verbose > 0 ) | ||
1863 | { | ||
1864 | LoadParam.endTime = os::Timer::getRealTime(); | ||
1865 | snprintf( buf, sizeof ( buf ), | ||
1866 | "quake3::cleanMeshes needed %04d ms to clean %d of %d meshes", | ||
1867 | LoadParam.endTime - LoadParam.startTime, | ||
1868 | remove, | ||
1869 | run | ||
1870 | ); | ||
1871 | os::Printer::log(buf, ELL_INFORMATION); | ||
1872 | } | ||
1873 | } | ||
1874 | |||
1875 | |||
1876 | // recalculate bounding boxes | ||
1877 | void CQ3LevelMesh::calcBoundingBoxes() | ||
1878 | { | ||
1879 | if ( LoadParam.verbose > 0 ) | ||
1880 | { | ||
1881 | LoadParam.startTime = os::Timer::getRealTime(); | ||
1882 | |||
1883 | if ( LoadParam.verbose > 1 ) | ||
1884 | { | ||
1885 | snprintf( buf, sizeof ( buf ), | ||
1886 | "quake3::calcBoundingBoxes start create %d textures and %d lightmaps", | ||
1887 | NumTextures, | ||
1888 | NumLightMaps | ||
1889 | ); | ||
1890 | os::Printer::log(buf, ELL_INFORMATION); | ||
1891 | } | ||
1892 | } | ||
1893 | |||
1894 | s32 g; | ||
1895 | |||
1896 | // create bounding box | ||
1897 | for ( g = 0; g != E_Q3_MESH_SIZE; ++g ) | ||
1898 | { | ||
1899 | for ( u32 j=0; j < Mesh[g]->MeshBuffers.size(); ++j) | ||
1900 | { | ||
1901 | ((SMeshBufferLightMap*)Mesh[g]->MeshBuffers[j])->recalculateBoundingBox(); | ||
1902 | } | ||
1903 | |||
1904 | Mesh[g]->recalculateBoundingBox(); | ||
1905 | // Mesh[0] is the main bbox | ||
1906 | if (g!=0) | ||
1907 | Mesh[0]->BoundingBox.addInternalBox(Mesh[g]->getBoundingBox()); | ||
1908 | } | ||
1909 | |||
1910 | for (g = 1; g < NumModels; g++) | ||
1911 | { | ||
1912 | for ( u32 j=0; j < BrushEntities[g]->MeshBuffers.size(); ++j) | ||
1913 | { | ||
1914 | ((SMeshBufferLightMap*)BrushEntities[g]->MeshBuffers[j])-> | ||
1915 | recalculateBoundingBox(); | ||
1916 | } | ||
1917 | |||
1918 | BrushEntities[g]->recalculateBoundingBox(); | ||
1919 | } | ||
1920 | |||
1921 | if ( LoadParam.verbose > 0 ) | ||
1922 | { | ||
1923 | LoadParam.endTime = os::Timer::getRealTime(); | ||
1924 | |||
1925 | snprintf( buf, sizeof ( buf ), | ||
1926 | "quake3::calcBoundingBoxes needed %04d ms to create %d textures and %d lightmaps", | ||
1927 | LoadParam.endTime - LoadParam.startTime, | ||
1928 | NumTextures, | ||
1929 | NumLightMaps | ||
1930 | ); | ||
1931 | os::Printer::log( buf, ELL_INFORMATION); | ||
1932 | } | ||
1933 | } | ||
1934 | |||
1935 | |||
1936 | //! loads the textures | ||
1937 | void CQ3LevelMesh::loadTextures() | ||
1938 | { | ||
1939 | if (!Driver) | ||
1940 | return; | ||
1941 | |||
1942 | if ( LoadParam.verbose > 0 ) | ||
1943 | { | ||
1944 | LoadParam.startTime = os::Timer::getRealTime(); | ||
1945 | |||
1946 | if ( LoadParam.verbose > 1 ) | ||
1947 | { | ||
1948 | snprintf( buf, sizeof ( buf ), | ||
1949 | "quake3::loadTextures start create %d textures and %d lightmaps", | ||
1950 | NumTextures, | ||
1951 | NumLightMaps | ||
1952 | ); | ||
1953 | os::Printer::log( buf, ELL_INFORMATION); | ||
1954 | } | ||
1955 | } | ||
1956 | |||
1957 | c8 lightmapname[255]; | ||
1958 | s32 t; | ||
1959 | |||
1960 | // load lightmaps. | ||
1961 | Lightmap.set_used(NumLightMaps); | ||
1962 | |||
1963 | /* | ||
1964 | bool oldMipMapState = Driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS); | ||
1965 | Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); | ||
1966 | */ | ||
1967 | core::dimension2d<u32> lmapsize(128,128); | ||
1968 | |||
1969 | video::IImage* lmapImg; | ||
1970 | for ( t = 0; t < NumLightMaps ; ++t) | ||
1971 | { | ||
1972 | sprintf(lightmapname, "%s.lightmap.%d", LevelName.c_str(), t); | ||
1973 | |||
1974 | // lightmap is a CTexture::R8G8B8 format | ||
1975 | lmapImg = Driver->createImageFromData( | ||
1976 | video::ECF_R8G8B8, lmapsize, | ||
1977 | LightMaps[t].imageBits, false, true ); | ||
1978 | |||
1979 | Lightmap[t] = Driver->addTexture( lightmapname, lmapImg ); | ||
1980 | lmapImg->drop(); | ||
1981 | } | ||
1982 | |||
1983 | // Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, oldMipMapState); | ||
1984 | |||
1985 | // load textures | ||
1986 | Tex.set_used( NumTextures ); | ||
1987 | |||
1988 | const IShader* shader; | ||
1989 | |||
1990 | core::stringc list; | ||
1991 | io::path check; | ||
1992 | tTexArray textureArray; | ||
1993 | |||
1994 | // pre-load shaders | ||
1995 | for ( t=0; t< NumTextures; ++t) | ||
1996 | { | ||
1997 | shader = getShader(Textures[t].strName, false); | ||
1998 | } | ||
1999 | |||
2000 | for ( t=0; t< NumTextures; ++t) | ||
2001 | { | ||
2002 | Tex[t].ShaderID = -1; | ||
2003 | Tex[t].Texture = 0; | ||
2004 | |||
2005 | list = ""; | ||
2006 | |||
2007 | // get a shader ( if one exists ) | ||
2008 | shader = getShader( Textures[t].strName, false); | ||
2009 | if ( shader ) | ||
2010 | { | ||
2011 | Tex[t].ShaderID = shader->ID; | ||
2012 | |||
2013 | // if texture name == stage1 Texture map | ||
2014 | const SVarGroup * group; | ||
2015 | |||
2016 | group = shader->getGroup( 2 ); | ||
2017 | if ( group ) | ||
2018 | { | ||
2019 | if ( core::cutFilenameExtension( check, group->get( "map" ) ) == Textures[t].strName ) | ||
2020 | { | ||
2021 | list += check; | ||
2022 | } | ||
2023 | else | ||
2024 | if ( check == "$lightmap" ) | ||
2025 | { | ||
2026 | // we check if lightmap is in stage 1 and texture in stage 2 | ||
2027 | group = shader->getGroup( 3 ); | ||
2028 | if ( group ) | ||
2029 | list += group->get( "map" ); | ||
2030 | } | ||
2031 | } | ||
2032 | } | ||
2033 | else | ||
2034 | { | ||
2035 | // no shader, take it | ||
2036 | list += Textures[t].strName; | ||
2037 | } | ||
2038 | |||
2039 | u32 pos = 0; | ||
2040 | getTextures( textureArray, list, pos, FileSystem, Driver ); | ||
2041 | |||
2042 | Tex[t].Texture = textureArray[0]; | ||
2043 | } | ||
2044 | |||
2045 | if ( LoadParam.verbose > 0 ) | ||
2046 | { | ||
2047 | LoadParam.endTime = os::Timer::getRealTime(); | ||
2048 | |||
2049 | snprintf( buf, sizeof ( buf ), | ||
2050 | "quake3::loadTextures needed %04d ms to create %d textures and %d lightmaps", | ||
2051 | LoadParam.endTime - LoadParam.startTime, | ||
2052 | NumTextures, | ||
2053 | NumLightMaps | ||
2054 | ); | ||
2055 | os::Printer::log( buf, ELL_INFORMATION); | ||
2056 | } | ||
2057 | } | ||
2058 | |||
2059 | |||
2060 | //! Returns an axis aligned bounding box of the mesh. | ||
2061 | const core::aabbox3d<f32>& CQ3LevelMesh::getBoundingBox() const | ||
2062 | { | ||
2063 | return Mesh[0]->getBoundingBox(); | ||
2064 | } | ||
2065 | |||
2066 | |||
2067 | void CQ3LevelMesh::setBoundingBox(const core::aabbox3df& box) | ||
2068 | { | ||
2069 | Mesh[0]->setBoundingBox(box); | ||
2070 | } | ||
2071 | |||
2072 | |||
2073 | //! Returns the type of the animated mesh. | ||
2074 | E_ANIMATED_MESH_TYPE CQ3LevelMesh::getMeshType() const | ||
2075 | { | ||
2076 | return scene::EAMT_BSP; | ||
2077 | } | ||
2078 | |||
2079 | } // end namespace scene | ||
2080 | } // end namespace irr | ||
2081 | |||
2082 | #endif // _IRR_COMPILE_WITH_BSP_LOADER_ | ||