1 /* bzflag
2 * Copyright (c) 1993-2021 Tim Riker
3 *
4 * This package is free software; you can redistribute it and/or
5 * modify it under the terms of the license found in the file
6 * named COPYING that should have accompanied this file.
7 *
8 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
9 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
10 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11 */
12
13 // interface header
14 #include "SceneBuilder.h"
15
16 // local implemenation headers
17 #include "ZSceneDatabase.h"
18 #include "BSPSceneDatabase.h"
19 #include "World.h"
20
21 // scene node implemenation headers
22 #include "MeshPolySceneNode.h"
23 #include "TankSceneNode.h"
24 #include "BoxSceneNodeGenerator.h"
25 #include "WallSceneNodeGenerator.h"
26 #include "MeshSceneNodeGenerator.h"
27 #include "BaseSceneNodeGenerator.h"
28 #include "PyramidSceneNodeGenerator.h"
29 #include "ObstacleSceneNodeGenerator.h"
30 #include "TeleporterSceneNodeGenerator.h"
31 #include "EighthDimShellNode.h"
32 #include "EighthDBoxSceneNode.h"
33 #include "EighthDPyrSceneNode.h"
34 #include "EighthDBaseSceneNode.h"
35
36 // common implementation headers
37 #include "StateDatabase.h"
38 #include "SceneRenderer.h"
39 #include "BZDBCache.h"
40 #include "TextureManager.h"
41 #include "ObstacleList.h"
42 #include "ObstacleMgr.h"
43
44
45 // uncomment for cheaper eighth dimension scene nodes
46 //#define SHELL_INSIDE_NODES
47
48
49 //
50 // SceneDatabaseBuilder
51 //
52
53 static const GLfloat black[3] = { 0.0f, 0.0f, 0.0f };
54
55 const GLfloat SceneDatabaseBuilder::wallColors[4][4] =
56 {
57 { 0.5f, 0.5f, 0.5f, 1.0f },
58 { 0.4f, 0.4f, 0.4f, 1.0f },
59 { 0.5f, 0.5f, 0.5f, 1.0f },
60 { 0.6f, 0.6f, 0.6f, 1.0f }
61 };
62 const GLfloat SceneDatabaseBuilder::wallModulateColors[4][4] =
63 {
64 { 0.5f, 0.5f, 0.5f, 1.0f },
65 { 0.4f, 0.4f, 0.4f, 1.0f },
66 { 0.5f, 0.5f, 0.5f, 1.0f },
67 { 0.6f, 0.6f, 0.6f, 1.0f }
68 };
69 const GLfloat SceneDatabaseBuilder::wallLightedColors[1][4] =
70 {
71 { 0.5f, 0.5f, 0.5f, 1.0f }
72 };
73 const GLfloat SceneDatabaseBuilder::wallLightedModulateColors[1][4] =
74 {
75 { 0.5f, 0.5f, 0.5f, 1.0f }
76 };
77
78 const GLfloat SceneDatabaseBuilder::boxColors[6][4] =
79 {
80 { 0.75f, 0.25f, 0.25f, 1.0f },
81 { 0.63f, 0.25f, 0.25f, 1.0f },
82 { 0.75f, 0.25f, 0.25f, 1.0f },
83 { 0.75f, 0.375f, 0.375f, 1.0f },
84 { 0.875f, 0.5f, 0.5f, 1.0f },
85 { 0.275f, 0.2f, 0.2f, 1.0f }
86 };
87 const GLfloat SceneDatabaseBuilder::boxModulateColors[6][4] =
88 {
89 { 0.75f, 0.75f, 0.75f, 1.0f },
90 { 0.63f, 0.63f, 0.63f, 1.0f },
91 { 0.75f, 0.75f, 0.75f, 1.0f },
92 { 0.69f, 0.69f, 0.69f, 1.0f },
93 { 0.875f, 0.875f, 0.875f, 1.0f },
94 { 0.375f, 0.375f, 0.375f, 1.0f }
95 };
96 const GLfloat SceneDatabaseBuilder::boxLightedColors[6][4] =
97 {
98 { 0.75f, 0.25f, 0.25f, 1.0f },
99 { 0.75f, 0.25f, 0.25f, 1.0f },
100 { 0.75f, 0.25f, 0.25f, 1.0f },
101 { 0.75f, 0.25f, 0.25f, 1.0f },
102 { 0.875f, 0.5f, 0.5f, 1.0f },
103 { 0.875f, 0.5f, 0.5f, 1.0f }
104 };
105 const GLfloat SceneDatabaseBuilder::boxLightedModulateColors[6][4] =
106 {
107 { 0.75f, 0.75f, 0.75f, 1.0f },
108 { 0.75f, 0.75f, 0.75f, 1.0f },
109 { 0.75f, 0.75f, 0.75f, 1.0f },
110 { 0.75f, 0.75f, 0.75f, 1.0f },
111 { 0.875f, 0.875f, 0.875f, 1.0f },
112 { 0.875f, 0.875f, 0.875f, 1.0f }
113 };
114
115 const GLfloat SceneDatabaseBuilder::pyramidColors[5][4] =
116 {
117 { 0.25f, 0.25f, 0.63f, 1.0f },
118 { 0.13f, 0.13f, 0.51f, 1.0f },
119 { 0.25f, 0.25f, 0.63f, 1.0f },
120 { 0.375f, 0.375f, 0.75f, 1.0f },
121 { 0.175f, 0.175f, 0.35f, 1.0f }
122 };
123
124 const GLfloat SceneDatabaseBuilder::pyramidModulateColors[5][4] =
125 {
126 { 0.25f, 0.25f, 0.63f, 1.0f },
127 { 0.13f, 0.13f, 0.51f, 1.0f },
128 { 0.25f, 0.25f, 0.63f, 1.0f },
129 { 0.375f, 0.375f, 0.75f, 1.0f },
130 { 0.175f, 0.175f, 0.35f, 1.0f }
131 };
132 const GLfloat SceneDatabaseBuilder::pyramidLightedColors[5][4] =
133 {
134 { 0.25f, 0.25f, 0.63f, 1.0f },
135 { 0.25f, 0.25f, 0.63f, 1.0f },
136 { 0.25f, 0.25f, 0.63f, 1.0f },
137 { 0.25f, 0.25f, 0.63f, 1.0f },
138 { 0.25f, 0.25f, 0.63f, 1.0f }
139 };
140 const GLfloat SceneDatabaseBuilder::pyramidLightedModulateColors[5][4] =
141 {
142 { 0.25f, 0.25f, 0.63f, 1.0f },
143 { 0.25f, 0.25f, 0.63f, 1.0f },
144 { 0.25f, 0.25f, 0.63f, 1.0f },
145 { 0.25f, 0.25f, 0.63f, 1.0f },
146 { 0.25f, 0.25f, 0.63f, 1.0f }
147 };
148
149 const GLfloat SceneDatabaseBuilder::teleporterColors[3][4] =
150 {
151 { 1.0f, 0.875f, 0.0f, 1.0f },
152 { 0.9f, 0.8f, 0.0f, 1.0f },
153 { 0.0f, 0.0f, 0.0f, 0.5f }
154 };
155 const GLfloat SceneDatabaseBuilder::teleporterModulateColors[3][4] =
156 {
157 { 1.0f, 1.0f, 1.0f, 1.0f },
158 { 0.9f, 0.9f, 0.9f, 1.0f },
159 { 0.0f, 0.0f, 0.0f, 0.5f }
160 };
161 const GLfloat SceneDatabaseBuilder::teleporterLightedColors[3][4] =
162 {
163 { 1.0f, 0.875f, 0.0f, 1.0f },
164 { 1.0f, 0.875f, 0.0f, 1.0f },
165 { 0.0f, 0.0f, 0.0f, 0.5f }
166 };
167 const GLfloat SceneDatabaseBuilder::teleporterLightedModulateColors[3][4] =
168 {
169 { 1.0f, 1.0f, 1.0f, 1.0f },
170 { 1.0f, 1.0f, 1.0f, 1.0f },
171 { 0.0f, 0.0f, 0.0f, 0.5f }
172 };
173
174
SceneDatabaseBuilder(const SceneRenderer * _renderer)175 SceneDatabaseBuilder::SceneDatabaseBuilder(const SceneRenderer* _renderer) :
176 renderer(_renderer),
177 wallMaterial(black, black, 0.0f), wallLOD(),
178 boxMaterial(black, black, 0.0f), boxLOD(),
179 pyramidMaterial(black, black, 0.0f), pyramidLOD(),
180 baseLOD(),
181 teleporterMaterial(black, black, 0.0f),
182 teleporterLOD()
183 {
184 // FIXME -- should get texture heights from resources
185
186 TextureManager &tm = TextureManager::instance();
187
188
189 // make styles -- first the outer wall
190 int wallTexture = tm.getTextureID( "wall" );
191 wallTexWidth = wallTexHeight = 10.0f;
192 if (wallTexture>=0)
193 wallTexWidth = tm.GetAspectRatio(wallTexture) * wallTexHeight;
194
195
196 // make box styles
197 int boxTexture = tm.getTextureID( "boxwall" );
198 boxTexWidth = boxTexHeight = 0.2f * BZDB.eval(StateDatabase::BZDB_BOXHEIGHT);
199 if (boxTexture>=0)
200 boxTexWidth = tm.GetAspectRatio(boxTexture) * boxTexHeight;
201
202
203 // lower maximum tank lod if lowdetail is true
204 if (renderer->useQuality() == 0)
205 TankSceneNode::setMaxLOD(2);
206 }
207
208
~SceneDatabaseBuilder()209 SceneDatabaseBuilder::~SceneDatabaseBuilder()
210 {
211 // do nothing
212 }
213
214
make(const World * world)215 SceneDatabase* SceneDatabaseBuilder::make(const World* world)
216 {
217 // set LOD flags
218 const bool doLODs = BZDBCache::lighting && BZDBCache::zbuffer;
219 wallLOD = baseLOD = boxLOD = pyramidLOD = teleporterLOD = doLODs;
220
221 // pick type of database
222 SceneDatabase* db;
223 if (BZDBCache::zbuffer)
224 db = new ZSceneDatabase;
225 else
226 db = new BSPSceneDatabase;
227 // FIXME -- when making BSP tree, try several shuffles for best tree
228
229 if (!world)
230 return db;
231
232 // free any prior inside nodes
233 world->freeInsideNodes();
234
235
236 // add nodes to database
237 unsigned int i;
238
239 const ObstacleList& walls = OBSTACLEMGR.getWalls();
240 for (i = 0; i < walls.size(); i++)
241 addWall(db, *((WallObstacle*) walls[i]));
242
243 const ObstacleList& boxes = OBSTACLEMGR.getBoxes();
244 for (i = 0; i < boxes.size(); i++)
245 addBox (db, *((BoxBuilding*) boxes[i]));
246
247 const ObstacleList& bases = OBSTACLEMGR.getBases();
248 for (i = 0; i < bases.size(); i++)
249 addBase (db, *((BaseBuilding*) bases[i]));
250
251 const ObstacleList& pyramids = OBSTACLEMGR.getPyrs();
252 for (i = 0; i < pyramids.size(); i++)
253 addPyramid (db, *((PyramidBuilding*) pyramids[i]));
254
255 const ObstacleList& teles = OBSTACLEMGR.getTeles();
256 for (i = 0; i < teles.size(); i++)
257 addTeleporter (db, *((Teleporter*) teles[i]), world);
258
259 const ObstacleList& meshes = OBSTACLEMGR.getMeshes();
260 for (i = 0; i < meshes.size(); i++)
261 addMesh (db, (MeshObstacle*) meshes[i]);
262
263 // add the water level node
264 addWaterLevel(db, world);
265
266 db->finalizeStatics();
267
268 return db;
269 }
270
271
addWaterLevel(SceneDatabase * db,const World * world)272 void SceneDatabaseBuilder::addWaterLevel(SceneDatabase* db,
273 const World* world)
274 {
275 float plane[4] = { 0.0f, 0.0f, 1.0f, 0.0f };
276 const float level = world->getWaterLevel();
277 plane[3] = -level;
278
279 // don't draw it if it isn't active
280 if (level < 0.0f)
281 return;
282
283 // setup the vertex and texture coordinates
284 float size = BZDBCache::worldSize;
285 GLfloat3Array v(4);
286 GLfloat3Array n(0);
287 GLfloat2Array t(4);
288 v[0][0] = v[0][1] = v[1][1] = v[3][0] = -size/2.0f;
289 v[1][0] = v[2][0] = v[2][1] = v[3][1] = +size/2.0f;
290 v[0][2] = v[1][2] = v[2][2] = v[3][2] = level;
291 t[0][0] = t[0][1] = t[1][1] = t[3][0] = 0.0f;
292 t[1][0] = t[2][0] = t[2][1] = t[3][1] = 2.0f;
293
294 // get the material
295 const BzMaterial* mat = world->getWaterMaterial();
296 const bool noRadar = mat->getNoRadar();
297 const bool noShadow = mat->getNoShadow();
298
299 MeshPolySceneNode* node =
300 new MeshPolySceneNode(plane, noRadar, noShadow, v, n, t);
301
302 // setup the material
303 MeshSceneNodeGenerator::setupNodeMaterial(node, mat);
304
305 db->addStaticNode(node, false);
306
307 return;
308 }
309
310
addWall(SceneDatabase * db,const WallObstacle & o)311 void SceneDatabaseBuilder::addWall(SceneDatabase* db, const WallObstacle& o)
312 {
313 if (o.getHeight() <= 0.0f)
314 return;
315
316 int part = 0;
317 WallSceneNode* node;
318 ObstacleSceneNodeGenerator* nodeGen = new WallSceneNodeGenerator (&o);
319
320 TextureManager &tm = TextureManager::instance();
321 int wallTexture = -1;
322
323 bool useColorTexture = false;
324
325 // try object, standard, then default
326 if (o.userTextures[0].size())
327 wallTexture = tm.getTextureID(o.userTextures[0].c_str(),false);
328 if (wallTexture < 0)
329 wallTexture = tm.getTextureID( "wall" );
330 else
331 useColorTexture = wallTexture >= 0;
332
333 while ((node = nodeGen->getNextNode(o.getBreadth() / wallTexWidth,
334 o.getHeight() / wallTexHeight, wallLOD)))
335 {
336 node->setColor(wallColors[part]);
337 node->setModulateColor(wallModulateColors[part]);
338 node->setLightedColor(wallLightedColors[0]);
339 node->setLightedModulateColor(wallLightedModulateColors[0]);
340 node->setMaterial(wallMaterial);
341 node->setTexture(wallTexture);
342 node->setUseColorTexture(useColorTexture);
343
344 db->addStaticNode(node, false);
345 part = (part + 1) % 5;
346 }
347 delete nodeGen;
348 }
349
350
addMesh(SceneDatabase * db,MeshObstacle * mesh)351 void SceneDatabaseBuilder::addMesh(SceneDatabase* db, MeshObstacle* mesh)
352 {
353 WallSceneNode* node;
354 MeshSceneNodeGenerator* nodeGen = new MeshSceneNodeGenerator (mesh);
355
356 while ((node = nodeGen->getNextNode(wallLOD)))
357 {
358 // make the inside node
359 const bool ownTheNode = db->addStaticNode(node, true);
360 // The BSP can split a MeshPolySceneNode and then delete it, which is
361 // not good for the EighthDimShellNode's referencing scheme. If the
362 // BSP would have split and then deleted this node, ownTheNode will
363 // return true, and the EighthDimShellNode will then own the node.
364 EighthDimShellNode* inode = new EighthDimShellNode(node, ownTheNode);
365 mesh->addInsideSceneNode(inode);
366 }
367 delete nodeGen;
368 }
369
370
addBox(SceneDatabase * db,BoxBuilding & o)371 void SceneDatabaseBuilder::addBox(SceneDatabase* db, BoxBuilding& o)
372 {
373 // this assumes boxes have six parts: four sides, a roof, and a bottom.
374 int part = 0;
375 WallSceneNode* node;
376 ObstacleSceneNodeGenerator* nodeGen = new BoxSceneNodeGenerator(&o);
377 TextureManager &tm = TextureManager::instance();
378 int boxTexture = -1;
379 bool useColorTexture[2] = {false,false};
380
381 // try object, standard, then default
382 if (o.userTextures[0].size())
383 boxTexture = tm.getTextureID(o.userTextures[0].c_str(),false);
384 if (boxTexture < 0)
385 boxTexture = tm.getTextureID(BZDB.get("boxWallTexture").c_str(),true);
386
387 useColorTexture[0] = boxTexture >= 0;
388
389 int boxTopTexture = -1;
390
391 if (o.userTextures[1].size())
392 boxTopTexture = tm.getTextureID(o.userTextures[1].c_str(),false);
393 if (boxTopTexture < 0)
394 boxTopTexture = tm.getTextureID(BZDB.get("boxTopTexture").c_str(),true);
395
396 useColorTexture[1] = boxTopTexture >= 0;
397
398 float texutureFactor = BZDB.eval("boxWallTexRepeat");
399 if (renderer->useQuality() >= 2)
400 texutureFactor = BZDB.eval("boxWallHighResTexRepeat");
401
402 while ((node = ((part < 4) ? nodeGen->getNextNode(
403 -texutureFactor*boxTexWidth,
404 -texutureFactor*boxTexWidth, boxLOD) :
405 // I'm using boxTexHeight for roof since textures are same
406 // size and this number is available
407 nodeGen->getNextNode(
408 -boxTexHeight,
409 -boxTexHeight, boxLOD))))
410 {
411 node->setColor(boxColors[part]);
412 node->setModulateColor(boxModulateColors[part]);
413 node->setLightedColor(boxLightedColors[part]);
414 node->setLightedModulateColor(boxLightedModulateColors[part]);
415 node->setMaterial(boxMaterial);
416 if (part < 4)
417 {
418 node->setTexture(boxTexture);
419 node->setUseColorTexture(useColorTexture[0]);
420 }
421 else
422 {
423 node->setTexture(boxTopTexture);
424 node->setUseColorTexture(useColorTexture[1]);
425 }
426
427 #ifdef SHELL_INSIDE_NODES
428 const bool ownTheNode = db->addStaticNode(node, true);
429 EighthDimShellNode* inode = new EighthDimShellNode(node, ownTheNode);
430 o.addInsideSceneNode(inode);
431 #else
432 db->addStaticNode(node, false);
433 #endif // SHELL_INSIDE_NODES
434
435 part = (part + 1) % 6;
436 }
437
438 #ifndef SHELL_INSIDE_NODES
439 // add the inside node
440 GLfloat obstacleSize[3];
441 obstacleSize[0] = o.getWidth();
442 obstacleSize[1] = o.getBreadth();
443 obstacleSize[2] = o.getHeight();
444 SceneNode* inode =
445 new EighthDBoxSceneNode(o.getPosition(), obstacleSize, o.getRotation());
446 o.addInsideSceneNode(inode);
447 #endif // SHELL_INSIDE_NODES
448
449 delete nodeGen;
450 }
451
452
addPyramid(SceneDatabase * db,PyramidBuilding & o)453 void SceneDatabaseBuilder::addPyramid(SceneDatabase* db, PyramidBuilding& o)
454 {
455 // this assumes pyramids have four parts: four sides
456 int part = 0;
457 WallSceneNode* node;
458 ObstacleSceneNodeGenerator* nodeGen = new PyramidSceneNodeGenerator(&o);
459
460 TextureManager &tm = TextureManager::instance();
461 int pyramidTexture = -1;
462
463 bool useColorTexture = false;
464 // try object, standard, then default
465 if (o.userTextures[0].size())
466 pyramidTexture = tm.getTextureID(o.userTextures[0].c_str(),false);
467 if (pyramidTexture < 0)
468 pyramidTexture = tm.getTextureID(BZDB.get("pyrWallTexture").c_str(),false);
469
470 useColorTexture = pyramidTexture >= 0;
471
472 // Using boxTexHeight since it's (currently) the same and it's already available
473 float textureFactor = BZDB.eval("pyrWallTexRepeat");
474 if (renderer->useQuality() >= 2)
475 textureFactor = BZDB.eval("pyrWallHighResTexRepeat");
476
477 while ((node = nodeGen->getNextNode(-textureFactor * boxTexHeight,
478 -textureFactor * boxTexHeight,
479 pyramidLOD)))
480 {
481 node->setColor(pyramidColors[part]);
482 node->setModulateColor(pyramidModulateColors[part]);
483 node->setLightedColor(pyramidLightedColors[part]);
484 node->setLightedModulateColor(pyramidLightedModulateColors[part]);
485 node->setMaterial(pyramidMaterial);
486 node->setTexture(pyramidTexture);
487 node->setUseColorTexture(useColorTexture);
488
489 #ifdef SHELL_INSIDE_NODES
490 const bool ownTheNode = db->addStaticNode(node, true);
491 EighthDimShellNode* inode = new EighthDimShellNode(node, ownTheNode);
492 o.addInsideSceneNode(inode);
493 #else
494 db->addStaticNode(node, false);
495 #endif // SHELL_INSIDE_NODES
496
497 part = (part + 1) % 5;
498 }
499
500 #ifndef SHELL_INSIDE_NODES
501 // add the inside node
502 GLfloat obstacleSize[3];
503 obstacleSize[0] = o.getWidth();
504 obstacleSize[1] = o.getBreadth();
505 obstacleSize[2] = o.getHeight();
506 SceneNode* inode =
507 new EighthDPyrSceneNode(o.getPosition(), obstacleSize, o.getRotation());
508 o.addInsideSceneNode(inode);
509 #endif // SHELL_INSIDE_NODES
510
511 delete nodeGen;
512 }
513
514
addBase(SceneDatabase * db,BaseBuilding & o)515 void SceneDatabaseBuilder::addBase(SceneDatabase *db, BaseBuilding &o)
516 {
517 WallSceneNode* node;
518 ObstacleSceneNodeGenerator* nodeGen = new BaseSceneNodeGenerator(&o);
519
520 TextureManager &tm = TextureManager::instance();
521 int boxTexture = -1;
522
523 bool useColorTexture[2] = {false,false};
524
525 // try object, standard, then default
526 if (o.userTextures[0].size())
527 boxTexture = tm.getTextureID(o.userTextures[0].c_str(),false);
528 if (boxTexture < 0)
529 {
530 std::string teamBase = Team::getImagePrefix((TeamColor)o.getTeam());
531 teamBase += BZDB.get("baseWallTexture");
532 boxTexture = tm.getTextureID(teamBase.c_str(),false);
533 }
534 if (boxTexture < 0)
535 boxTexture = tm.getTextureID( BZDB.get("boxWallTexture").c_str() );
536
537 useColorTexture[0] = boxTexture >= 0;
538
539 int baseTopTexture = -1;
540
541 if (o.userTextures[1].size())
542 baseTopTexture = tm.getTextureID(o.userTextures[1].c_str(),false);
543 if (baseTopTexture < 0)
544 {
545 std::string teamBase = Team::getImagePrefix((TeamColor)o.getTeam());
546 teamBase += BZDB.get("baseTopTexture").c_str();
547 baseTopTexture = tm.getTextureID(teamBase.c_str(),false);
548 }
549 if (baseTopTexture < 0)
550 baseTopTexture = -1;
551 else
552 useColorTexture[1] = baseTopTexture >= 0;
553
554 // this assumes bases have 6 parts - if they don't, it still works
555 unsigned int part = 0;
556 // repeat the textue once for the top and bottom, else use the old messed up way
557 // There are 3 cases for the texture ordering:
558 // 1. getNextNode() only returns the top texture
559 // 2. getNextNode() returns the top texture(0), and the 4 sides(1-4)
560 // 3. getNextNode() returns the top texture(0), and the 4 sides(1-4), and the bottom(5)
561 while ((node = ( ((part % 5) == 0) ? nodeGen->getNextNode(1,1, boxLOD) :
562 nodeGen->getNextNode(o.getBreadth(),
563 o.getHeight(),
564 boxLOD))))
565 {
566 if ((part % 5) != 0)
567 {
568 const unsigned int colorIndex = (part % 5) - 1;
569 node->setColor(boxColors[colorIndex]);
570 node->setModulateColor(boxModulateColors[colorIndex]);
571 node->setLightedColor(boxLightedColors[colorIndex]);
572 node->setLightedModulateColor(boxLightedModulateColors[colorIndex]);
573 node->setMaterial(boxMaterial);
574 node->setTexture(boxTexture);
575 node->setUseColorTexture(useColorTexture[0]);
576 }
577 else
578 {
579 if (useColorTexture[1]) // only set the texture if we have one and are using it
580 {
581 node->setTexture(baseTopTexture);
582 node->setUseColorTexture(useColorTexture[1]);
583 }
584 }
585 part++;
586
587 #ifdef SHELL_INSIDE_NODES
588 const bool ownTheNode = db->addStaticNode(node, true);
589 EighthDimShellNode* inode = new EighthDimShellNode(node, ownTheNode);
590 o.addInsideSceneNode(inode);
591 #else
592 db->addStaticNode(node, false);
593 #endif // SHELL_INSIDE_NODES
594 }
595
596 #ifndef SHELL_INSIDE_NODES
597 // add the inside node
598 GLfloat obstacleSize[3];
599 obstacleSize[0] = o.getWidth();
600 obstacleSize[1] = o.getBreadth();
601 obstacleSize[2] = o.getHeight();
602 SceneNode* inode = new
603 EighthDBaseSceneNode(o.getPosition(), obstacleSize, o.getRotation());
604 o.addInsideSceneNode(inode);
605 #endif // SHELL_INSIDE_NODES
606
607 delete nodeGen;
608 }
609
addTeleporter(SceneDatabase * db,const Teleporter & o,const World * world)610 void SceneDatabaseBuilder::addTeleporter(SceneDatabase* db,
611 const Teleporter& o,
612 const World* world)
613 {
614 // this assumes teleporters have fourteen parts: 12 border sides, 2 faces
615 int part = 0;
616 WallSceneNode* node;
617 ObstacleSceneNodeGenerator* nodeGen = new TeleporterSceneNodeGenerator(&o);
618
619 TextureManager &tm = TextureManager::instance();
620 int teleporterTexture = -1;
621
622 bool useColorTexture = false;
623
624 // try object, standard, then default
625 if (o.userTextures[0].size())
626 teleporterTexture = tm.getTextureID(o.userTextures[0].c_str(),false);
627 if (teleporterTexture < 0)
628 teleporterTexture = tm.getTextureID(BZDB.get("cautionTexture").c_str(),true);
629
630 useColorTexture = teleporterTexture >= 0;
631
632 int numParts = o.isHorizontal() ? 18 : 14;
633
634 while ((node = nodeGen->getNextNode(1.0, o.getHeight() / o.getBreadth(),
635 teleporterLOD)))
636 {
637 if (o.isHorizontal ())
638 {
639 if (part >= 0 && part <= 15)
640 {
641 node->setColor (teleporterColors[0]);
642 node->setModulateColor (teleporterModulateColors[0]);
643 node->setLightedColor (teleporterLightedColors[0]);
644 node->setLightedModulateColor (teleporterLightedModulateColors[0]);
645 node->setMaterial (teleporterMaterial);
646 node->setTexture (teleporterTexture);
647 node->setUseColorTexture (useColorTexture);
648 }
649 }
650 else
651 {
652 if (part >= 0 && part <= 1)
653 {
654 node->setColor (teleporterColors[0]);
655 node->setModulateColor (teleporterModulateColors[0]);
656 node->setLightedColor (teleporterLightedColors[0]);
657 node->setLightedModulateColor (teleporterLightedModulateColors[0]);
658 node->setMaterial (teleporterMaterial);
659 node->setTexture (teleporterTexture);
660 node->setUseColorTexture (useColorTexture);
661 }
662 else if (part >= 2 && part <= 11)
663 {
664 node->setColor (teleporterColors[1]);
665 node->setModulateColor (teleporterModulateColors[1]);
666 node->setLightedColor (teleporterLightedColors[1]);
667 node->setLightedModulateColor (teleporterLightedModulateColors[1]);
668 node->setMaterial (teleporterMaterial);
669 node->setTexture (teleporterTexture);
670 node->setUseColorTexture (useColorTexture);
671 }
672 }
673
674 db->addStaticNode(node, false);
675 part = (part + 1) % numParts;
676 }
677
678 MeshPolySceneNode* linkNode;
679 const BzMaterial* mat = world->getLinkMaterial();
680
681 linkNode = MeshSceneNodeGenerator::getMeshPolySceneNode(o.getBackLink());
682 MeshSceneNodeGenerator::setupNodeMaterial(linkNode, mat);
683 db->addStaticNode(linkNode, false);
684
685 linkNode = MeshSceneNodeGenerator::getMeshPolySceneNode(o.getFrontLink());
686 MeshSceneNodeGenerator::setupNodeMaterial(linkNode, mat);
687 db->addStaticNode(linkNode, false);
688
689 delete nodeGen;
690 }
691
692 // Local Variables: ***
693 // mode: C++ ***
694 // tab-width: 4 ***
695 // c-basic-offset: 4 ***
696 // indent-tabs-mode: nil ***
697 // End: ***
698 // ex: shiftwidth=4 tabstop=4
699