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
CQ3LevelMesh(io::IFileSystem * fs,scene::ISceneManager * smgr,const Q3LevelLoadParameter & loadParam)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
~CQ3LevelMesh()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.
loadFile(io::IReadFile * file)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 */
cleanLoader()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.
getFrameCount() const191 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.
getMesh(s32 frameInMs,s32 detailLevel,s32 startFrameLoop,s32 endFrameLoop)198 IMesh* CQ3LevelMesh::getMesh(s32 frameInMs, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop)
199 {
200 	return Mesh[frameInMs];
201 }
202 
203 
loadTextures(tBSPLump * l,io::IReadFile * file)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 
loadLightmaps(tBSPLump * l,io::IReadFile * file)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 */
loadVerts(tBSPLump * l,io::IReadFile * file)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 */
loadFaces(tBSPLump * l,io::IReadFile * file)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 */
loadPlanes(tBSPLump * l,io::IReadFile * file)315 void CQ3LevelMesh::loadPlanes(tBSPLump* l, io::IReadFile* file)
316 {
317 	// ignore
318 }
319 
320 
321 /*!
322 */
loadNodes(tBSPLump * l,io::IReadFile * file)323 void CQ3LevelMesh::loadNodes(tBSPLump* l, io::IReadFile* file)
324 {
325 	// ignore
326 }
327 
328 
329 /*!
330 */
loadLeafs(tBSPLump * l,io::IReadFile * file)331 void CQ3LevelMesh::loadLeafs(tBSPLump* l, io::IReadFile* file)
332 {
333 	// ignore
334 }
335 
336 
337 /*!
338 */
loadLeafFaces(tBSPLump * l,io::IReadFile * file)339 void CQ3LevelMesh::loadLeafFaces(tBSPLump* l, io::IReadFile* file)
340 {
341 	// ignore
342 }
343 
344 
345 /*!
346 */
loadVisData(tBSPLump * l,io::IReadFile * file)347 void CQ3LevelMesh::loadVisData(tBSPLump* l, io::IReadFile* file)
348 {
349 	// ignore
350 }
351 
352 
353 /*!
354 */
loadEntities(tBSPLump * l,io::IReadFile * file)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 */
loadFogs(tBSPLump * l,io::IReadFile * file)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 */
loadModels(tBSPLump * l,io::IReadFile * file)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 */
loadMeshVerts(tBSPLump * l,io::IReadFile * file)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 */
loadBrushes(tBSPLump * l,io::IReadFile * file)445 void CQ3LevelMesh::loadBrushes(tBSPLump* l, io::IReadFile* file)
446 {
447 	// ignore
448 }
449 
450 /*!
451 */
loadBrushSides(tBSPLump * l,io::IReadFile * file)452 void CQ3LevelMesh::loadBrushSides(tBSPLump* l, io::IReadFile* file)
453 {
454 	// ignore
455 }
456 
457 /*!
458 */
loadLeafBrushes(tBSPLump * l,io::IReadFile * file)459 void CQ3LevelMesh::loadLeafBrushes(tBSPLump* l, io::IReadFile* file)
460 {
461 	// ignore
462 }
463 
464 /*!
465 */
isQ3WhiteSpace(const u8 symbol)466 inline bool isQ3WhiteSpace( const u8 symbol )
467 {
468 	return symbol == ' ' || symbol == '\t' || symbol == '\r';
469 }
470 
471 /*!
472 */
isQ3ValidName(const u8 symbol)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 */
parser_nextToken()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 */
parser_parse(const void * data,const u32 size,CQ3LevelMesh::tParserCallback callback)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 */
setShaderFogMaterial(video::SMaterial & material,const tBSPFace * face) const710 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 */
setShaderMaterial(video::SMaterial & material,const tBSPFace * face) const738 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 */
buildMesh(s32 num)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 */
solveTJunction()1029 void CQ3LevelMesh::solveTJunction()
1030 {
1031 }
1032 
1033 /*!
1034 	constructs a mesh from the quake 3 level file.
1035 */
constructMesh()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 
copy(video::S3DVertex2TCoords & dest) const1098 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 
copy(S3DVertex2TCoords_64 * dest,const tBSPVertex * source,s32 vertexcolor) const1129 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 
copy(video::S3DVertex2TCoords * dest,const tBSPVertex * source,s32 vertexcolor) const1173 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 
tesselate(s32 level)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 */
createCurvedSurface_nosubdivision(SMeshBufferLightMap * meshBuffer,s32 faceIndex,s32 patchTesselation,s32 storevertexcolor)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 */
createCurvedSurface_bezier(SMeshBufferLightMap * meshBuffer,s32 faceIndex,s32 patchTesselation,s32 storevertexcolor)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 */
getConfiguration(io::IReadFile * file)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
getEntityList()1458 tQ3EntityList & CQ3LevelMesh::getEntityList()
1459 {
1460 //	Entity.sort();
1461 	return Entity;
1462 }
1463 
1464 //! returns the requested brush entity
getBrushEntityMesh(s32 num) const1465 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
getBrushEntityMesh(quake3::IEntity & ent) const1474 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 */
getShader(u32 index) const1496 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 */
getShader(const c8 * filename,bool fileNameIsValid)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 */
getShader(io::IReadFile * file)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
InitShader()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..
ReleaseShader()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 */
ReleaseEntity()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
scriptcallback_config(SVarGroupList * & grouplist,eToken token)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..
scriptcallback_entity(SVarGroupList * & grouplist,eToken token)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
scriptcallback_shader(SVarGroupList * & grouplist,eToken token)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 */
cleanMeshes()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 
cleanMesh(SMesh * m,const bool texture0important)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
calcBoundingBoxes()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
loadTextures()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.
getBoundingBox() const2061 const core::aabbox3d<f32>& CQ3LevelMesh::getBoundingBox() const
2062 {
2063 	return Mesh[0]->getBoundingBox();
2064 }
2065 
2066 
setBoundingBox(const core::aabbox3df & box)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.
getMeshType() const2074 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_
2083