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