LCOV - code coverage report
Current view: top level - src - content_mapblock.cpp (source / functions) Hit Total Coverage
Test: report Lines: 586 900 65.1 %
Date: 2015-07-11 18:23:49 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /*
       2             : Minetest
       3             : Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
       4             : 
       5             : This program is free software; you can redistribute it and/or modify
       6             : it under the terms of the GNU Lesser General Public License as published by
       7             : the Free Software Foundation; either version 2.1 of the License, or
       8             : (at your option) any later version.
       9             : 
      10             : This program is distributed in the hope that it will be useful,
      11             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             : GNU Lesser General Public License for more details.
      14             : 
      15             : You should have received a copy of the GNU Lesser General Public License along
      16             : with this program; if not, write to the Free Software Foundation, Inc.,
      17             : 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      18             : */
      19             : 
      20             : #include "content_mapblock.h"
      21             : #include "util/numeric.h"
      22             : #include "util/directiontables.h"
      23             : #include "mapblock_mesh.h" // For MapBlock_LightColor() and MeshCollector
      24             : #include "settings.h"
      25             : #include "nodedef.h"
      26             : #include "client/tile.h"
      27             : #include "mesh.h"
      28             : #include <IMeshManipulator.h>
      29             : #include "gamedef.h"
      30             : #include "log.h"
      31             : 
      32             : 
      33             : // Create a cuboid.
      34             : //  collector - the MeshCollector for the resulting polygons
      35             : //  box       - the position and size of the box
      36             : //  tiles     - the tiles (materials) to use (for all 6 faces)
      37             : //  tilecount - number of entries in tiles, 1<=tilecount<=6
      38             : //  c         - vertex colour - used for all
      39             : //  txc       - texture coordinates - this is a list of texture coordinates
      40             : //              for the opposite corners of each face - therefore, there
      41             : //              should be (2+2)*6=24 values in the list. Alternatively, pass
      42             : //              NULL to use the entire texture for each face. The order of
      43             : //              the faces in the list is up-down-right-left-back-front
      44             : //              (compatible with ContentFeatures). If you specified 0,0,1,1
      45             : //              for each face, that would be the same as passing NULL.
      46       94317 : void makeCuboid(MeshCollector *collector, const aabb3f &box,
      47             :         TileSpec *tiles, int tilecount, video::SColor &c, const f32* txc)
      48             : {
      49             :         assert(tilecount >= 1 && tilecount <= 6); // pre-condition
      50             : 
      51       94317 :         v3f min = box.MinEdge;
      52       94317 :         v3f max = box.MaxEdge;
      53             :  
      54             :  
      55             :  
      56       94317 :         if(txc == NULL) {
      57             :                 static const f32 txc_default[24] = {
      58             :                         0,0,1,1,
      59             :                         0,0,1,1,
      60             :                         0,0,1,1,
      61             :                         0,0,1,1,
      62             :                         0,0,1,1,
      63             :                         0,0,1,1
      64             :                 };
      65       72623 :                 txc = txc_default;
      66             :         }
      67             : 
      68             :         video::S3DVertex vertices[24] =
      69             :         {
      70             :                 // up
      71       94317 :                 video::S3DVertex(min.X,max.Y,max.Z, 0,1,0, c, txc[0],txc[1]),
      72      188634 :                 video::S3DVertex(max.X,max.Y,max.Z, 0,1,0, c, txc[2],txc[1]),
      73      188634 :                 video::S3DVertex(max.X,max.Y,min.Z, 0,1,0, c, txc[2],txc[3]),
      74       94317 :                 video::S3DVertex(min.X,max.Y,min.Z, 0,1,0, c, txc[0],txc[3]),
      75             :                 // down
      76      188634 :                 video::S3DVertex(min.X,min.Y,min.Z, 0,-1,0, c, txc[4],txc[5]),
      77      188634 :                 video::S3DVertex(max.X,min.Y,min.Z, 0,-1,0, c, txc[6],txc[5]),
      78      188634 :                 video::S3DVertex(max.X,min.Y,max.Z, 0,-1,0, c, txc[6],txc[7]),
      79      188634 :                 video::S3DVertex(min.X,min.Y,max.Z, 0,-1,0, c, txc[4],txc[7]),
      80             :                 // right
      81      188634 :                 video::S3DVertex(max.X,max.Y,min.Z, 1,0,0, c, txc[ 8],txc[9]),
      82      188634 :                 video::S3DVertex(max.X,max.Y,max.Z, 1,0,0, c, txc[10],txc[9]),
      83      188634 :                 video::S3DVertex(max.X,min.Y,max.Z, 1,0,0, c, txc[10],txc[11]),
      84      188634 :                 video::S3DVertex(max.X,min.Y,min.Z, 1,0,0, c, txc[ 8],txc[11]),
      85             :                 // left
      86      188634 :                 video::S3DVertex(min.X,max.Y,max.Z, -1,0,0, c, txc[12],txc[13]),
      87      188634 :                 video::S3DVertex(min.X,max.Y,min.Z, -1,0,0, c, txc[14],txc[13]),
      88      188634 :                 video::S3DVertex(min.X,min.Y,min.Z, -1,0,0, c, txc[14],txc[15]),
      89      188634 :                 video::S3DVertex(min.X,min.Y,max.Z, -1,0,0, c, txc[12],txc[15]),
      90             :                 // back
      91      188634 :                 video::S3DVertex(max.X,max.Y,max.Z, 0,0,1, c, txc[16],txc[17]),
      92      188634 :                 video::S3DVertex(min.X,max.Y,max.Z, 0,0,1, c, txc[18],txc[17]),
      93      188634 :                 video::S3DVertex(min.X,min.Y,max.Z, 0,0,1, c, txc[18],txc[19]),
      94      188634 :                 video::S3DVertex(max.X,min.Y,max.Z, 0,0,1, c, txc[16],txc[19]),
      95             :                 // front
      96      188634 :                 video::S3DVertex(min.X,max.Y,min.Z, 0,0,-1, c, txc[20],txc[21]),
      97      188634 :                 video::S3DVertex(max.X,max.Y,min.Z, 0,0,-1, c, txc[22],txc[21]),
      98      188634 :                 video::S3DVertex(max.X,min.Y,min.Z, 0,0,-1, c, txc[22],txc[23]),
      99      188634 :                 video::S3DVertex(min.X,min.Y,min.Z, 0,0,-1, c, txc[20],txc[23]),
     100     4432899 :         };
     101             : 
     102      660219 :         for(int i = 0; i < 6; i++)
     103             :                                 {
     104      565902 :                                 switch (tiles[MYMIN(i, tilecount-1)].rotation)
     105             :                                 {
     106             :                                 case 0:
     107      555450 :                                         break;
     108             :                                 case 1: //R90
     109       52260 :                                         for (int x = 0; x < 4; x++)
     110       41808 :                                                 vertices[i*4+x].TCoords.rotateBy(90,irr::core::vector2df(0, 0));
     111       10452 :                                         break;
     112             :                                 case 2: //R180
     113           0 :                                         for (int x = 0; x < 4; x++)
     114           0 :                                                 vertices[i*4+x].TCoords.rotateBy(180,irr::core::vector2df(0, 0));
     115           0 :                                         break;
     116             :                                 case 3: //R270
     117           0 :                                         for (int x = 0; x < 4; x++)
     118           0 :                                                 vertices[i*4+x].TCoords.rotateBy(270,irr::core::vector2df(0, 0));
     119           0 :                                         break;
     120             :                                 case 4: //FXR90
     121           0 :                                         for (int x = 0; x < 4; x++){
     122           0 :                                                 vertices[i*4+x].TCoords.X = 1.0 - vertices[i*4+x].TCoords.X;
     123           0 :                                                 vertices[i*4+x].TCoords.rotateBy(90,irr::core::vector2df(0, 0));
     124             :                                         }
     125           0 :                                         break;
     126             :                                 case 5: //FXR270
     127           0 :                                         for (int x = 0; x < 4; x++){
     128           0 :                                                 vertices[i*4+x].TCoords.X = 1.0 - vertices[i*4+x].TCoords.X;
     129           0 :                                                 vertices[i*4+x].TCoords.rotateBy(270,irr::core::vector2df(0, 0));
     130             :                                         }
     131           0 :                                         break;
     132             :                                 case 6: //FYR90
     133           0 :                                         for (int x = 0; x < 4; x++){
     134           0 :                                                 vertices[i*4+x].TCoords.Y = 1.0 - vertices[i*4+x].TCoords.Y;
     135           0 :                                                 vertices[i*4+x].TCoords.rotateBy(90,irr::core::vector2df(0, 0));
     136             :                                         }
     137           0 :                                         break;
     138             :                                 case 7: //FYR270
     139           0 :                                         for (int x = 0; x < 4; x++){
     140           0 :                                                 vertices[i*4+x].TCoords.Y = 1.0 - vertices[i*4+x].TCoords.Y;
     141           0 :                                                 vertices[i*4+x].TCoords.rotateBy(270,irr::core::vector2df(0, 0));
     142             :                                         }
     143           0 :                                         break;
     144             :                                 case 8: //FX
     145           0 :                                         for (int x = 0; x < 4; x++){
     146           0 :                                                 vertices[i*4+x].TCoords.X = 1.0 - vertices[i*4+x].TCoords.X;
     147             :                                         }
     148           0 :                                         break;
     149             :                                 case 9: //FY
     150           0 :                                         for (int x = 0; x < 4; x++){
     151           0 :                                                 vertices[i*4+x].TCoords.Y = 1.0 - vertices[i*4+x].TCoords.Y;
     152             :                                         }
     153           0 :                                         break;
     154             :                                 default:
     155           0 :                                         break;
     156             :                                 }
     157             :                         }
     158       94317 :         u16 indices[] = {0,1,2,2,3,0};
     159             :         // Add to mesh collector
     160      660219 :         for (s32 j = 0; j < 24; j += 4) {
     161      565902 :                 int tileindex = MYMIN(j / 4, tilecount - 1);
     162      565902 :                 collector->append(tiles[tileindex], vertices + j, 4, indices, 6);
     163             :         }
     164       94317 : }
     165             : 
     166             : /*
     167             :         TODO: Fix alpha blending for special nodes
     168             :         Currently only the last element rendered is blended correct
     169             : */
     170        2140 : void mapblock_mesh_generate_special(MeshMakeData *data,
     171             :                 MeshCollector &collector)
     172             : {
     173        2140 :         INodeDefManager *nodedef = data->m_gamedef->ndef();
     174        2140 :         ITextureSource *tsrc = data->m_gamedef->tsrc();
     175        2140 :         scene::ISceneManager* smgr = data->m_gamedef->getSceneManager();
     176        2140 :         scene::IMeshManipulator* meshmanip = smgr->getMeshManipulator();
     177             : 
     178             :         // 0ms
     179             :         //TimeTaker timer("mapblock_mesh_generate_special()");
     180             : 
     181             :         /*
     182             :                 Some settings
     183             :         */
     184        2140 :         bool enable_mesh_cache  = g_settings->getBool("enable_mesh_cache");
     185        2140 :         bool new_style_water = g_settings->getBool("new_style_water");
     186             : 
     187        2140 :         float node_liquid_level = 1.0;
     188        2140 :         if (new_style_water)
     189           0 :                 node_liquid_level = 0.85;
     190             : 
     191        2140 :         v3s16 blockpos_nodes = data->m_blockpos*MAP_BLOCKSIZE;
     192             : 
     193       36380 :         for(s16 z = 0; z < MAP_BLOCKSIZE; z++)
     194      582080 :         for(s16 y = 0; y < MAP_BLOCKSIZE; y++)
     195     9313280 :         for(s16 x = 0; x < MAP_BLOCKSIZE; x++)
     196             :         {
     197     8765440 :                 v3s16 p(x,y,z);
     198             : 
     199     8765440 :                 MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes + p);
     200     8765440 :                 const ContentFeatures &f = nodedef->get(n);
     201             : 
     202             :                 // Only solidness=0 stuff is drawn here
     203     8765440 :                 if(f.solidness != 0)
     204     9846780 :                         continue;
     205             : 
     206     3842050 :                 switch(f.drawtype){
     207             :                 default:
     208           0 :                         infostream << "Got " << f.drawtype << std::endl;
     209           0 :                         FATAL_ERROR("Unknown drawtype");
     210             :                         break;
     211             :                 case NDT_AIRLIKE:
     212     3677159 :                         break;
     213             :                 case NDT_LIQUID:
     214             :                 {
     215             :                         /*
     216             :                                 Add water sources to mesh if using new style
     217             :                         */
     218           0 :                         TileSpec tile_liquid = f.special_tiles[0];
     219           0 :                         TileSpec tile_liquid_bfculled = getNodeTile(n, p, v3s16(0,0,0), data);
     220             : 
     221           0 :                         bool top_is_same_liquid = false;
     222           0 :                         MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
     223           0 :                         content_t c_flowing = nodedef->getId(f.liquid_alternative_flowing);
     224           0 :                         content_t c_source = nodedef->getId(f.liquid_alternative_source);
     225           0 :                         if(ntop.getContent() == c_flowing || ntop.getContent() == c_source)
     226           0 :                                 top_is_same_liquid = true;
     227             : 
     228           0 :                         u16 l = getInteriorLight(n, 0, nodedef);
     229           0 :                         video::SColor c = MapBlock_LightColor(f.alpha, l, f.light_source);
     230             : 
     231             :                         /*
     232             :                                 Generate sides
     233             :                          */
     234             :                         v3s16 side_dirs[4] = {
     235             :                                 v3s16(1,0,0),
     236             :                                 v3s16(-1,0,0),
     237             :                                 v3s16(0,0,1),
     238             :                                 v3s16(0,0,-1),
     239           0 :                         };
     240           0 :                         for(u32 i=0; i<4; i++)
     241             :                         {
     242           0 :                                 v3s16 dir = side_dirs[i];
     243             : 
     244           0 :                                 MapNode neighbor = data->m_vmanip.getNodeNoEx(blockpos_nodes + p + dir);
     245           0 :                                 content_t neighbor_content = neighbor.getContent();
     246           0 :                                 const ContentFeatures &n_feat = nodedef->get(neighbor_content);
     247           0 :                                 MapNode n_top = data->m_vmanip.getNodeNoEx(blockpos_nodes + p + dir+ v3s16(0,1,0));
     248           0 :                                 content_t n_top_c = n_top.getContent();
     249             : 
     250           0 :                                 if(neighbor_content == CONTENT_IGNORE)
     251           0 :                                         continue;
     252             : 
     253             :                                 /*
     254             :                                         If our topside is liquid and neighbor's topside
     255             :                                         is liquid, don't draw side face
     256             :                                 */
     257           0 :                                 if(top_is_same_liquid && (n_top_c == c_flowing ||
     258           0 :                                                 n_top_c == c_source || n_top_c == CONTENT_IGNORE))
     259           0 :                                         continue;
     260             : 
     261             :                                 // Don't draw face if neighbor is blocking the view
     262           0 :                                 if(n_feat.solidness == 2)
     263           0 :                                         continue;
     264             : 
     265             :                                 bool neighbor_is_same_liquid = (neighbor_content == c_source
     266           0 :                                                 || neighbor_content == c_flowing);
     267             : 
     268             :                                 // Don't draw any faces if neighbor same is liquid and top is
     269             :                                 // same liquid
     270           0 :                                 if(neighbor_is_same_liquid && !top_is_same_liquid)
     271           0 :                                         continue;
     272             : 
     273             :                                 // Use backface culled material if neighbor doesn't have a
     274             :                                 // solidness of 0
     275           0 :                                 const TileSpec *current_tile = &tile_liquid;
     276           0 :                                 if(n_feat.solidness != 0 || n_feat.visual_solidness != 0)
     277           0 :                                         current_tile = &tile_liquid_bfculled;
     278             : 
     279             :                                 video::S3DVertex vertices[4] =
     280             :                                 {
     281             :                                         video::S3DVertex(-BS/2,0,BS/2,0,0,0, c, 0,1),
     282             :                                         video::S3DVertex(BS/2,0,BS/2,0,0,0, c, 1,1),
     283             :                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
     284             :                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),
     285           0 :                                 };
     286             : 
     287             :                                 /*
     288             :                                         If our topside is liquid, set upper border of face
     289             :                                         at upper border of node
     290             :                                 */
     291           0 :                                 if(top_is_same_liquid)
     292             :                                 {
     293           0 :                                         vertices[2].Pos.Y = 0.5*BS;
     294           0 :                                         vertices[3].Pos.Y = 0.5*BS;
     295             :                                 }
     296             :                                 /*
     297             :                                         Otherwise upper position of face is liquid level
     298             :                                 */
     299             :                                 else
     300             :                                 {
     301           0 :                                         vertices[2].Pos.Y = (node_liquid_level-0.5)*BS;
     302           0 :                                         vertices[3].Pos.Y = (node_liquid_level-0.5)*BS;
     303             :                                 }
     304             :                                 /*
     305             :                                         If neighbor is liquid, lower border of face is liquid level
     306             :                                 */
     307           0 :                                 if(neighbor_is_same_liquid)
     308             :                                 {
     309           0 :                                         vertices[0].Pos.Y = (node_liquid_level-0.5)*BS;
     310           0 :                                         vertices[1].Pos.Y = (node_liquid_level-0.5)*BS;
     311             :                                 }
     312             :                                 /*
     313             :                                         If neighbor is not liquid, lower border of face is
     314             :                                         lower border of node
     315             :                                 */
     316             :                                 else
     317             :                                 {
     318           0 :                                         vertices[0].Pos.Y = -0.5*BS;
     319           0 :                                         vertices[1].Pos.Y = -0.5*BS;
     320             :                                 }
     321             : 
     322           0 :                                 for(s32 j=0; j<4; j++)
     323             :                                 {
     324           0 :                                         if(dir == v3s16(0,0,1))
     325           0 :                                                 vertices[j].Pos.rotateXZBy(0);
     326           0 :                                         if(dir == v3s16(0,0,-1))
     327           0 :                                                 vertices[j].Pos.rotateXZBy(180);
     328           0 :                                         if(dir == v3s16(-1,0,0))
     329           0 :                                                 vertices[j].Pos.rotateXZBy(90);
     330           0 :                                         if(dir == v3s16(1,0,-0))
     331           0 :                                                 vertices[j].Pos.rotateXZBy(-90);
     332             : 
     333             :                                         // Do this to not cause glitches when two liquids are
     334             :                                         // side-by-side
     335             :                                         /*if(neighbor_is_same_liquid == false){
     336             :                                                 vertices[j].Pos.X *= 0.98;
     337             :                                                 vertices[j].Pos.Z *= 0.98;
     338             :                                         }*/
     339             : 
     340           0 :                                         vertices[j].Pos += intToFloat(p, BS);
     341             :                                 }
     342             : 
     343           0 :                                 u16 indices[] = {0,1,2,2,3,0};
     344             :                                 // Add to mesh collector
     345           0 :                                 collector.append(*current_tile, vertices, 4, indices, 6);
     346             :                         }
     347             : 
     348             :                         /*
     349             :                                 Generate top
     350             :                          */
     351           0 :                         if(top_is_same_liquid)
     352           0 :                                 continue;
     353             :                         
     354             :                         video::S3DVertex vertices[4] =
     355             :                         {
     356             :                                 video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,1),
     357             :                                 video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,1),
     358             :                                 video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,0),
     359             :                                 video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,0),
     360           0 :                         };
     361             : 
     362           0 :                         v3f offset(p.X*BS, p.Y*BS + (-0.5+node_liquid_level)*BS, p.Z*BS);
     363           0 :                         for(s32 i=0; i<4; i++)
     364             :                         {
     365           0 :                                 vertices[i].Pos += offset;
     366             :                         }
     367             : 
     368           0 :                         u16 indices[] = {0,1,2,2,3,0};
     369             :                         // Add to mesh collector
     370           0 :                         collector.append(tile_liquid, vertices, 4, indices, 6);
     371           0 :                 break;}
     372             :                 case NDT_FLOWINGLIQUID:
     373             :                 {
     374             :                         /*
     375             :                                 Add flowing liquid to mesh
     376             :                         */
     377       30032 :                         TileSpec tile_liquid = f.special_tiles[0];
     378       30032 :                         TileSpec tile_liquid_bfculled = f.special_tiles[1];
     379             : 
     380       15016 :                         bool top_is_same_liquid = false;
     381       15016 :                         MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
     382       15016 :                         content_t c_flowing = nodedef->getId(f.liquid_alternative_flowing);
     383       15016 :                         content_t c_source = nodedef->getId(f.liquid_alternative_source);
     384       15016 :                         if(ntop.getContent() == c_flowing || ntop.getContent() == c_source)
     385        5425 :                                 top_is_same_liquid = true;
     386             :                         
     387       15016 :                         u16 l = 0;
     388             :                         // If this liquid emits light and doesn't contain light, draw
     389             :                         // it at what it emits, for an increased effect
     390       15016 :                         u8 light_source = nodedef->get(n).light_source;
     391       15016 :                         if(light_source != 0){
     392        1682 :                                 l = decode_light(light_source);
     393        1682 :                                 l = l | (l<<8);
     394             :                         }
     395             :                         // Use the light of the node on top if possible
     396       13334 :                         else if(nodedef->get(ntop).param_type == CPT_LIGHT)
     397       12057 :                                 l = getInteriorLight(ntop, 0, nodedef);
     398             :                         // Otherwise use the light of this node (the liquid)
     399             :                         else
     400        1277 :                                 l = getInteriorLight(n, 0, nodedef);
     401       15016 :                         video::SColor c = MapBlock_LightColor(f.alpha, l, f.light_source);
     402             :                         
     403       15016 :                         u8 range = rangelim(nodedef->get(c_flowing).liquid_range, 1, 8);
     404             : 
     405             :                         // Neighbor liquid levels (key = relative position)
     406             :                         // Includes current node
     407       30032 :                         std::map<v3s16, f32> neighbor_levels;
     408       30032 :                         std::map<v3s16, content_t> neighbor_contents;
     409       30032 :                         std::map<v3s16, u8> neighbor_flags;
     410       15016 :                         const u8 neighborflag_top_is_same_liquid = 0x01;
     411             :                         v3s16 neighbor_dirs[9] = {
     412             :                                 v3s16(0,0,0),
     413             :                                 v3s16(0,0,1),
     414             :                                 v3s16(0,0,-1),
     415             :                                 v3s16(1,0,0),
     416             :                                 v3s16(-1,0,0),
     417             :                                 v3s16(1,0,1),
     418             :                                 v3s16(-1,0,-1),
     419             :                                 v3s16(1,0,-1),
     420             :                                 v3s16(-1,0,1),
     421       15016 :                         };
     422      150160 :                         for(u32 i=0; i<9; i++)
     423             :                         {
     424      135144 :                                 content_t content = CONTENT_AIR;
     425      135144 :                                 float level = -0.5 * BS;
     426      135144 :                                 u8 flags = 0;
     427             :                                 // Check neighbor
     428      135144 :                                 v3s16 p2 = p + neighbor_dirs[i];
     429      135144 :                                 MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
     430      135144 :                                 if(n2.getContent() != CONTENT_IGNORE)
     431             :                                 {
     432      131723 :                                         content = n2.getContent();
     433             : 
     434      131723 :                                         if(n2.getContent() == c_source)
     435        7537 :                                                 level = (-0.5+node_liquid_level) * BS;
     436      124186 :                                         else if(n2.getContent() == c_flowing){
     437       79450 :                                                 u8 liquid_level = (n2.param2&LIQUID_LEVEL_MASK);
     438       79450 :                                                 if (liquid_level <= LIQUID_LEVEL_MAX+1-range)
     439        2225 :                                                         liquid_level = 0;
     440             :                                                 else
     441       77225 :                                                         liquid_level -= (LIQUID_LEVEL_MAX+1-range);
     442       79450 :                                                 level = (-0.5 + ((float)liquid_level+ 0.5) / (float)range * node_liquid_level) * BS;
     443             :                                         }
     444             : 
     445             :                                         // Check node above neighbor.
     446             :                                         // NOTE: This doesn't get executed if neighbor
     447             :                                         //       doesn't exist
     448      131723 :                                         p2.Y += 1;
     449      131723 :                                         n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
     450      259625 :                                         if(n2.getContent() == c_source ||
     451      127902 :                                                         n2.getContent() == c_flowing)
     452       34461 :                                                 flags |= neighborflag_top_is_same_liquid;
     453             :                                 }
     454             :                                 
     455      135144 :                                 neighbor_levels[neighbor_dirs[i]] = level;
     456      135144 :                                 neighbor_contents[neighbor_dirs[i]] = content;
     457      135144 :                                 neighbor_flags[neighbor_dirs[i]] = flags;
     458             :                         }
     459             : 
     460             :                         // Corner heights (average between four liquids)
     461             :                         f32 corner_levels[4];
     462             :                         
     463             :                         v3s16 halfdirs[4] = {
     464             :                                 v3s16(0,0,0),
     465             :                                 v3s16(1,0,0),
     466             :                                 v3s16(1,0,1),
     467             :                                 v3s16(0,0,1),
     468       15016 :                         };
     469       75080 :                         for(u32 i=0; i<4; i++)
     470             :                         {
     471       60064 :                                 v3s16 cornerdir = halfdirs[i];
     472       60064 :                                 float cornerlevel = 0;
     473       60064 :                                 u32 valid_count = 0;
     474       60064 :                                 u32 air_count = 0;
     475      200052 :                                 for(u32 j=0; j<4; j++)
     476             :                                 {
     477      170995 :                                         v3s16 neighbordir = cornerdir - halfdirs[j];
     478      170995 :                                         content_t content = neighbor_contents[neighbordir];
     479             :                                         // If top is liquid, draw starting from top of node
     480      170995 :                                         if(neighbor_flags[neighbordir] &
     481             :                                                         neighborflag_top_is_same_liquid)
     482             :                                         {
     483       29803 :                                                 cornerlevel = 0.5*BS;
     484       29803 :                                                 valid_count = 1;
     485       60810 :                                                 break;
     486             :                                         }
     487             :                                         // Source is always the same height
     488      141192 :                                         else if(content == c_source)
     489             :                                         {
     490        1204 :                                                 cornerlevel = (-0.5+node_liquid_level)*BS;
     491        1204 :                                                 valid_count = 1;
     492        1204 :                                                 break;
     493             :                                         }
     494             :                                         // Flowing liquid has level information
     495      139988 :                                         else if(content == c_flowing)
     496             :                                         {
     497       95281 :                                                 cornerlevel += neighbor_levels[neighbordir];
     498       95281 :                                                 valid_count++;
     499             :                                         }
     500       44707 :                                         else if(content == CONTENT_AIR)
     501             :                                         {
     502       18829 :                                                 air_count++;
     503             :                                         }
     504             :                                 }
     505       60064 :                                 if(air_count >= 2)
     506        5244 :                                         cornerlevel = -0.5*BS+0.2;
     507       54820 :                                 else if(valid_count > 0)
     508       54820 :                                         cornerlevel /= valid_count;
     509       60064 :                                 corner_levels[i] = cornerlevel;
     510             :                         }
     511             : 
     512             :                         /*
     513             :                                 Generate sides
     514             :                         */
     515             : 
     516             :                         v3s16 side_dirs[4] = {
     517             :                                 v3s16(1,0,0),
     518             :                                 v3s16(-1,0,0),
     519             :                                 v3s16(0,0,1),
     520             :                                 v3s16(0,0,-1),
     521       15016 :                         };
     522             :                         s16 side_corners[4][2] = {
     523             :                                 {1, 2},
     524             :                                 {3, 0},
     525             :                                 {2, 3},
     526             :                                 {0, 1},
     527       15016 :                         };
     528       75080 :                         for(u32 i=0; i<4; i++)
     529             :                         {
     530       60064 :                                 v3s16 dir = side_dirs[i];
     531             : 
     532             :                                 /*
     533             :                                         If our topside is liquid and neighbor's topside
     534             :                                         is liquid, don't draw side face
     535             :                                 */
     536       81764 :                                 if(top_is_same_liquid &&
     537       21700 :                                                 neighbor_flags[dir] & neighborflag_top_is_same_liquid)
     538       58318 :                                         continue;
     539             : 
     540       48919 :                                 content_t neighbor_content = neighbor_contents[dir];
     541       48919 :                                 const ContentFeatures &n_feat = nodedef->get(neighbor_content);
     542             :                                 
     543             :                                 // Don't draw face if neighbor is blocking the view
     544       48919 :                                 if(n_feat.solidness == 2)
     545        9056 :                                         continue;
     546             :                                 
     547             :                                 bool neighbor_is_same_liquid = (neighbor_content == c_source
     548       39863 :                                                 || neighbor_content == c_flowing);
     549             :                                 
     550             :                                 // Don't draw any faces if neighbor same is liquid and top is
     551             :                                 // same liquid
     552       39863 :                                 if(neighbor_is_same_liquid == true
     553       30687 :                                                 && top_is_same_liquid == false)
     554       26972 :                                         continue;
     555             : 
     556             :                                 // Use backface culled material if neighbor doesn't have a
     557             :                                 // solidness of 0
     558       12891 :                                 const TileSpec *current_tile = &tile_liquid;
     559       12891 :                                 if(n_feat.solidness != 0 || n_feat.visual_solidness != 0)
     560         293 :                                         current_tile = &tile_liquid_bfculled;
     561             :                                 
     562             :                                 video::S3DVertex vertices[4] =
     563             :                                 {
     564             :                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,1),
     565             :                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,1),
     566             :                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
     567             :                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),
     568       12891 :                                 };
     569             :                                 
     570             :                                 /*
     571             :                                         If our topside is liquid, set upper border of face
     572             :                                         at upper border of node
     573             :                                 */
     574       12891 :                                 if(top_is_same_liquid)
     575             :                                 {
     576        7652 :                                         vertices[2].Pos.Y = 0.5*BS;
     577        7652 :                                         vertices[3].Pos.Y = 0.5*BS;
     578             :                                 }
     579             :                                 /*
     580             :                                         Otherwise upper position of face is corner levels
     581             :                                 */
     582             :                                 else
     583             :                                 {
     584        5239 :                                         vertices[2].Pos.Y = corner_levels[side_corners[i][0]];
     585        5239 :                                         vertices[3].Pos.Y = corner_levels[side_corners[i][1]];
     586             :                                 }
     587             :                                 
     588             :                                 /*
     589             :                                         If neighbor is liquid, lower border of face is corner
     590             :                                         liquid levels
     591             :                                 */
     592       12891 :                                 if(neighbor_is_same_liquid)
     593             :                                 {
     594        3715 :                                         vertices[0].Pos.Y = corner_levels[side_corners[i][1]];
     595        3715 :                                         vertices[1].Pos.Y = corner_levels[side_corners[i][0]];
     596             :                                 }
     597             :                                 /*
     598             :                                         If neighbor is not liquid, lower border of face is
     599             :                                         lower border of node
     600             :                                 */
     601             :                                 else
     602             :                                 {
     603        9176 :                                         vertices[0].Pos.Y = -0.5*BS;
     604        9176 :                                         vertices[1].Pos.Y = -0.5*BS;
     605             :                                 }
     606             :                                 
     607       64455 :                                 for(s32 j=0; j<4; j++)
     608             :                                 {
     609       51564 :                                         if(dir == v3s16(0,0,1))
     610       13012 :                                                 vertices[j].Pos.rotateXZBy(0);
     611       51564 :                                         if(dir == v3s16(0,0,-1))
     612       12552 :                                                 vertices[j].Pos.rotateXZBy(180);
     613       51564 :                                         if(dir == v3s16(-1,0,0))
     614       13060 :                                                 vertices[j].Pos.rotateXZBy(90);
     615       51564 :                                         if(dir == v3s16(1,0,-0))
     616       12940 :                                                 vertices[j].Pos.rotateXZBy(-90);
     617             :                                                 
     618             :                                         // Do this to not cause glitches when two liquids are
     619             :                                         // side-by-side
     620             :                                         /*if(neighbor_is_same_liquid == false){
     621             :                                                 vertices[j].Pos.X *= 0.98;
     622             :                                                 vertices[j].Pos.Z *= 0.98;
     623             :                                         }*/
     624             : 
     625       51564 :                                         vertices[j].Pos += intToFloat(p, BS);
     626             :                                 }
     627             : 
     628       12891 :                                 u16 indices[] = {0,1,2,2,3,0};
     629             :                                 // Add to mesh collector
     630       12891 :                                 collector.append(*current_tile, vertices, 4, indices, 6);
     631             :                         }
     632             :                         
     633             :                         /*
     634             :                                 Generate top side, if appropriate
     635             :                         */
     636             :                         
     637       15016 :                         if(top_is_same_liquid == false)
     638             :                         {
     639             :                                 video::S3DVertex vertices[4] =
     640             :                                 {
     641             :                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,1),
     642             :                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,1),
     643             :                                         video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,0),
     644             :                                         video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,0),
     645        9591 :                                 };
     646             :                                 
     647             :                                 // To get backface culling right, the vertices need to go
     648             :                                 // clockwise around the front of the face. And we happened to
     649             :                                 // calculate corner levels in exact reverse order.
     650        9591 :                                 s32 corner_resolve[4] = {3,2,1,0};
     651             : 
     652       47955 :                                 for(s32 i=0; i<4; i++)
     653             :                                 {
     654             :                                         //vertices[i].Pos.Y += liquid_level;
     655             :                                         //vertices[i].Pos.Y += neighbor_levels[v3s16(0,0,0)];
     656       38364 :                                         s32 j = corner_resolve[i];
     657       38364 :                                         vertices[i].Pos.Y += corner_levels[j];
     658       38364 :                                         vertices[i].Pos += intToFloat(p, BS);
     659             :                                 }
     660             :                                 
     661             :                                 // Default downwards-flowing texture animation goes from 
     662             :                                 // -Z towards +Z, thus the direction is +Z.
     663             :                                 // Rotate texture to make animation go in flow direction
     664             :                                 // Positive if liquid moves towards +Z
     665       19182 :                                 f32 dz = (corner_levels[side_corners[3][0]] +
     666        9591 :                                                 corner_levels[side_corners[3][1]]) -
     667       19182 :                                                 (corner_levels[side_corners[2][0]] +
     668       19182 :                                                 corner_levels[side_corners[2][1]]);
     669             :                                 // Positive if liquid moves towards +X
     670       19182 :                                 f32 dx = (corner_levels[side_corners[1][0]] +
     671        9591 :                                                 corner_levels[side_corners[1][1]]) -
     672       19182 :                                                 (corner_levels[side_corners[0][0]] +
     673       19182 :                                                 corner_levels[side_corners[0][1]]);
     674        9591 :                                 f32 tcoord_angle = atan2(dz, dx) * core::RADTODEG ;
     675        9591 :                                 v2f tcoord_center(0.5, 0.5);
     676             :                                 v2f tcoord_translate(
     677        9591 :                                                 blockpos_nodes.Z + z,
     678       19182 :                                                 blockpos_nodes.X + x);
     679        9591 :                                 tcoord_translate.rotateBy(tcoord_angle);
     680        9591 :                                 tcoord_translate.X -= floor(tcoord_translate.X);
     681        9591 :                                 tcoord_translate.Y -= floor(tcoord_translate.Y);
     682             : 
     683       47955 :                                 for(s32 i=0; i<4; i++)
     684             :                                 {
     685             :                                         vertices[i].TCoords.rotateBy(
     686             :                                                         tcoord_angle,
     687       38364 :                                                         tcoord_center);
     688       38364 :                                         vertices[i].TCoords += tcoord_translate;
     689             :                                 }
     690             : 
     691        9591 :                                 v2f t = vertices[0].TCoords;
     692        9591 :                                 vertices[0].TCoords = vertices[2].TCoords;
     693        9591 :                                 vertices[2].TCoords = t;
     694             : 
     695        9591 :                                 u16 indices[] = {0,1,2,2,3,0};
     696             :                                 // Add to mesh collector
     697        9591 :                                 collector.append(tile_liquid, vertices, 4, indices, 6);
     698             :                         }
     699       15016 :                 break;}
     700             :                 case NDT_GLASSLIKE:
     701             :                 {
     702           0 :                         TileSpec tile = getNodeTile(n, p, v3s16(0,0,0), data);
     703             : 
     704           0 :                         u16 l = getInteriorLight(n, 1, nodedef);
     705           0 :                         video::SColor c = MapBlock_LightColor(255, l, f.light_source);
     706             : 
     707           0 :                         for(u32 j=0; j<6; j++)
     708             :                         {
     709             :                                 // Check this neighbor
     710           0 :                                 v3s16 dir = g_6dirs[j];
     711           0 :                                 v3s16 n2p = blockpos_nodes + p + dir;
     712           0 :                                 MapNode n2 = data->m_vmanip.getNodeNoEx(n2p);
     713             :                                 // Don't make face if neighbor is of same type
     714           0 :                                 if(n2.getContent() == n.getContent())
     715           0 :                                         continue;
     716             : 
     717             :                                 // The face at Z+
     718             :                                 video::S3DVertex vertices[4] = {
     719           0 :                                         video::S3DVertex(-BS/2,-BS/2,BS/2, dir.X,dir.Y,dir.Z, c, 1,1),
     720           0 :                                         video::S3DVertex(BS/2,-BS/2,BS/2, dir.X,dir.Y,dir.Z, c, 0,1),
     721           0 :                                         video::S3DVertex(BS/2,BS/2,BS/2, dir.X,dir.Y,dir.Z, c, 0,0),
     722           0 :                                         video::S3DVertex(-BS/2,BS/2,BS/2, dir.X,dir.Y,dir.Z, c, 1,0),
     723           0 :                                 };
     724             :                                 
     725             :                                 // Rotations in the g_6dirs format
     726           0 :                                 if(j == 0) // Z+
     727           0 :                                         for(u16 i=0; i<4; i++)
     728           0 :                                                 vertices[i].Pos.rotateXZBy(0);
     729           0 :                                 else if(j == 1) // Y+
     730           0 :                                         for(u16 i=0; i<4; i++)
     731           0 :                                                 vertices[i].Pos.rotateYZBy(-90);
     732           0 :                                 else if(j == 2) // X+
     733           0 :                                         for(u16 i=0; i<4; i++)
     734           0 :                                                 vertices[i].Pos.rotateXZBy(-90);
     735           0 :                                 else if(j == 3) // Z-
     736           0 :                                         for(u16 i=0; i<4; i++)
     737           0 :                                                 vertices[i].Pos.rotateXZBy(180);
     738           0 :                                 else if(j == 4) // Y-
     739           0 :                                         for(u16 i=0; i<4; i++)
     740           0 :                                                 vertices[i].Pos.rotateYZBy(90);
     741           0 :                                 else if(j == 5) // X-
     742           0 :                                         for(u16 i=0; i<4; i++)
     743           0 :                                                 vertices[i].Pos.rotateXZBy(90);
     744             : 
     745           0 :                                 for(u16 i=0; i<4; i++){
     746           0 :                                         vertices[i].Pos += intToFloat(p, BS);
     747             :                                 }
     748             : 
     749           0 :                                 u16 indices[] = {0,1,2,2,3,0};
     750             :                                 // Add to mesh collector
     751           0 :                                 collector.append(tile, vertices, 4, indices, 6);
     752             :                         }
     753           0 :                 break;}
     754             :                 case NDT_GLASSLIKE_FRAMED_OPTIONAL:
     755             :                         // This is always pre-converted to something else
     756           0 :                         FATAL_ERROR("NDT_GLASSLIKE_FRAMED_OPTIONAL not pre-converted as expected");
     757             :                         break;
     758             :                 case NDT_GLASSLIKE_FRAMED:
     759             :                 {
     760             :                         static const v3s16 dirs[6] = {
     761             :                                 v3s16( 0, 1, 0),
     762             :                                 v3s16( 0,-1, 0),
     763             :                                 v3s16( 1, 0, 0),
     764             :                                 v3s16(-1, 0, 0),
     765             :                                 v3s16( 0, 0, 1),
     766             :                                 v3s16( 0, 0,-1)
     767        2332 :                         };
     768             : 
     769             :                         u8 i;
     770        4664 :                         TileSpec tiles[6];
     771       16324 :                         for (i = 0; i < 6; i++)
     772       13992 :                                 tiles[i] = getNodeTile(n, p, dirs[i], data);
     773             :                         
     774        4664 :                         TileSpec glass_tiles[6];
     775        2332 :                         if (tiles[1].texture && tiles[2].texture && tiles[3].texture) {
     776        2332 :                                 glass_tiles[0] = tiles[2];
     777        2332 :                                 glass_tiles[1] = tiles[3];
     778        2332 :                                 glass_tiles[2] = tiles[1];
     779        2332 :                                 glass_tiles[3] = tiles[1];
     780        2332 :                                 glass_tiles[4] = tiles[1];
     781        2332 :                                 glass_tiles[5] = tiles[1];
     782             :                         } else {
     783           0 :                                 for (i = 0; i < 6; i++)
     784           0 :                                         glass_tiles[i] = tiles[1];      
     785             :                         }
     786             :                         
     787        2332 :                         u8 param2 = n.getParam2();
     788        2332 :                         bool H_merge = ! bool(param2 & 128);
     789        2332 :                         bool V_merge = ! bool(param2 & 64);
     790        2332 :                         param2  = param2 & 63;
     791             :                         
     792        2332 :                         u16 l = getInteriorLight(n, 1, nodedef);
     793        2332 :                         video::SColor c = MapBlock_LightColor(255, l, f.light_source);
     794        2332 :                         v3f pos = intToFloat(p, BS);
     795             :                         static const float a = BS / 2;
     796             :                         static const float g = a - 0.003;
     797             :                         static const float b = .876 * ( BS / 2 );
     798             :                         
     799             :                         static const aabb3f frame_edges[12] = {
     800             :                                 aabb3f( b, b,-a, a, a, a), // y+
     801             :                                 aabb3f(-a, b,-a,-b, a, a), // y+
     802             :                                 aabb3f( b,-a,-a, a,-b, a), // y-
     803             :                                 aabb3f(-a,-a,-a,-b,-b, a), // y-
     804             :                                 aabb3f( b,-a, b, a, a, a), // x+
     805             :                                 aabb3f( b,-a,-a, a, a,-b), // x+
     806             :                                 aabb3f(-a,-a, b,-b, a, a), // x-
     807             :                                 aabb3f(-a,-a,-a,-b, a,-b), // x-
     808             :                                 aabb3f(-a, b, b, a, a, a), // z+
     809             :                                 aabb3f(-a,-a, b, a,-b, a), // z+
     810             :                                 aabb3f(-a,-a,-a, a,-b,-b), // z-
     811             :                                 aabb3f(-a, b,-a, a, a,-b)  // z-
     812        2332 :                         };
     813             :                         static const aabb3f glass_faces[6] = {
     814             :                                 aabb3f(-g, g,-g, g, g, g), // y+
     815             :                                 aabb3f(-g,-g,-g, g,-g, g), // y-
     816             :                                 aabb3f( g,-g,-g, g, g, g), // x+
     817             :                                 aabb3f(-g,-g,-g,-g, g, g), // x-
     818             :                                 aabb3f(-g,-g, g, g, g, g), // z+
     819             :                                 aabb3f(-g,-g,-g, g, g,-g)  // z-
     820        2332 :                         };
     821             :                         
     822             :                         // table of node visible faces, 0 = invisible
     823        2332 :                         int visible_faces[6] = {0,0,0,0,0,0};
     824             :                         
     825             :                         // table of neighbours, 1 = same type, checked with g_26dirs
     826        2332 :                         int nb[18] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
     827             :                         
     828             :                         // g_26dirs to check when only horizontal merge is allowed
     829        2332 :                         int nb_H_dirs[8] = {0,2,3,5,10,11,12,13};
     830             :                         
     831        2332 :                         content_t current = n.getContent();
     832             :                         content_t n2c;
     833        2332 :                         MapNode n2;
     834        2332 :                         v3s16 n2p;
     835             : 
     836             :                         // neighbours checks for frames visibility
     837             : 
     838        2332 :                         if (!H_merge && V_merge) {
     839           0 :                                 n2p = blockpos_nodes + p + g_26dirs[1];
     840           0 :                                 n2 = data->m_vmanip.getNodeNoEx(n2p);
     841           0 :                                 n2c = n2.getContent();
     842           0 :                                 if (n2c == current || n2c == CONTENT_IGNORE)
     843           0 :                                         nb[1] = 1;
     844           0 :                                 n2p = blockpos_nodes + p + g_26dirs[4];
     845           0 :                                 n2 = data->m_vmanip.getNodeNoEx(n2p);
     846           0 :                                 n2c = n2.getContent();
     847           0 :                                 if (n2c == current || n2c == CONTENT_IGNORE)
     848           0 :                                         nb[4] = 1;      
     849        2332 :                         } else if (H_merge && !V_merge) {
     850           0 :                                 for(i = 0; i < 8; i++) {
     851           0 :                                         n2p = blockpos_nodes + p + g_26dirs[nb_H_dirs[i]];
     852           0 :                                         n2 = data->m_vmanip.getNodeNoEx(n2p);
     853           0 :                                         n2c = n2.getContent();
     854           0 :                                         if (n2c == current || n2c == CONTENT_IGNORE)
     855           0 :                                                 nb[nb_H_dirs[i]] = 1;           
     856             :                                 }
     857        2332 :                         } else if (H_merge && V_merge) {
     858       44308 :                                 for(i = 0; i < 18; i++)      {
     859       41976 :                                         n2p = blockpos_nodes + p + g_26dirs[i];
     860       41976 :                                         n2 = data->m_vmanip.getNodeNoEx(n2p);
     861       41976 :                                         n2c = n2.getContent();
     862       41976 :                                         if (n2c == current || n2c == CONTENT_IGNORE)
     863       11189 :                                                 nb[i] = 1;
     864             :                                 }
     865             :                         }
     866             : 
     867             :                         // faces visibility checks
     868             : 
     869        2332 :                         if (!V_merge) {
     870           0 :                                 visible_faces[0] = 1;
     871           0 :                                 visible_faces[1] = 1;
     872             :                         } else {
     873        6996 :                                 for(i = 0; i < 2; i++) {
     874        4664 :                                         n2p = blockpos_nodes + p + dirs[i];
     875        4664 :                                         n2 = data->m_vmanip.getNodeNoEx(n2p);
     876        4664 :                                         n2c = n2.getContent();
     877        4664 :                                         if (n2c != current)
     878        2444 :                                                 visible_faces[i] = 1;
     879             :                                 }
     880             :                         }
     881             :                                 
     882        2332 :                         if (!H_merge) {
     883           0 :                                 visible_faces[2] = 1;
     884           0 :                                 visible_faces[3] = 1;
     885           0 :                                 visible_faces[4] = 1;
     886           0 :                                 visible_faces[5] = 1;
     887             :                         } else {
     888       11660 :                                 for(i = 2; i < 6; i++) {
     889        9328 :                                         n2p = blockpos_nodes + p + dirs[i];
     890        9328 :                                         n2 = data->m_vmanip.getNodeNoEx(n2p);
     891        9328 :                                         n2c = n2.getContent();
     892        9328 :                                         if (n2c != current)
     893        5486 :                                                 visible_faces[i] = 1;
     894             :                                 }
     895             :                         }
     896             :         
     897             :                         static const u8 nb_triplet[12*3] = {
     898             :                                 1,2, 7,  1,5, 6,  4,2,15,  4,5,14,
     899             :                                 2,0,11,  2,3,13,  5,0,10,  5,3,12,
     900             :                                 0,1, 8,  0,4,16,  3,4,17,  3,1, 9
     901             :                         };
     902             : 
     903             :                         f32 tx1, ty1, tz1, tx2, ty2, tz2;
     904        2332 :                         aabb3f box;
     905             : 
     906       30316 :                         for(i = 0; i < 12; i++)
     907             :                         {
     908             :                                 int edge_invisible;
     909       27984 :                                 if (nb[nb_triplet[i*3+2]])
     910        5105 :                                         edge_invisible = nb[nb_triplet[i*3]] & nb[nb_triplet[i*3+1]];
     911             :                                 else
     912       22879 :                                         edge_invisible = nb[nb_triplet[i*3]] ^ nb[nb_triplet[i*3+1]];
     913       27984 :                                 if (edge_invisible)
     914       18986 :                                         continue;
     915        8998 :                                 box = frame_edges[i];
     916        8998 :                                 box.MinEdge += pos;
     917        8998 :                                 box.MaxEdge += pos;
     918        8998 :                                 tx1 = (box.MinEdge.X / BS) + 0.5;
     919        8998 :                                 ty1 = (box.MinEdge.Y / BS) + 0.5;
     920        8998 :                                 tz1 = (box.MinEdge.Z / BS) + 0.5;
     921        8998 :                                 tx2 = (box.MaxEdge.X / BS) + 0.5;
     922        8998 :                                 ty2 = (box.MaxEdge.Y / BS) + 0.5;
     923        8998 :                                 tz2 = (box.MaxEdge.Z / BS) + 0.5;
     924             :                                 f32 txc1[24] = {
     925       17996 :                                         tx1,   1-tz2,   tx2, 1-tz1,
     926             :                                         tx1,     tz1,   tx2,   tz2,
     927       17996 :                                         tz1,   1-ty2,   tz2, 1-ty1,
     928       35992 :                                         1-tz2, 1-ty2, 1-tz1, 1-ty1,
     929       35992 :                                         1-tx2, 1-ty2, 1-tx1, 1-ty1,
     930       17996 :                                         tx1,   1-ty2,   tx2, 1-ty1,
     931      134970 :                                 };
     932        8998 :                                 makeCuboid(&collector, box, &tiles[0], 1, c, txc1);
     933             :                         }
     934             : 
     935       16324 :                         for(i = 0; i < 6; i++)
     936             :                         {
     937       13992 :                                 if (!visible_faces[i])
     938        6062 :                                         continue;
     939        7930 :                                 box = glass_faces[i];
     940        7930 :                                 box.MinEdge += pos;
     941        7930 :                                 box.MaxEdge += pos;
     942        7930 :                                 tx1 = (box.MinEdge.X / BS) + 0.5;
     943        7930 :                                 ty1 = (box.MinEdge.Y / BS) + 0.5;
     944        7930 :                                 tz1 = (box.MinEdge.Z / BS) + 0.5;
     945        7930 :                                 tx2 = (box.MaxEdge.X / BS) + 0.5;
     946        7930 :                                 ty2 = (box.MaxEdge.Y / BS) + 0.5;
     947        7930 :                                 tz2 = (box.MaxEdge.Z / BS) + 0.5;
     948             :                                 f32 txc2[24] = {
     949       15860 :                                         tx1,   1-tz2,   tx2, 1-tz1,
     950             :                                         tx1,     tz1,   tx2,   tz2,
     951       15860 :                                         tz1,   1-ty2,   tz2, 1-ty1,
     952       31720 :                                         1-tz2, 1-ty2, 1-tz1, 1-ty1,
     953       31720 :                                         1-tx2, 1-ty2, 1-tx1, 1-ty1,
     954       15860 :                                         tx1,   1-ty2,   tx2, 1-ty1,
     955      118950 :                                 };
     956        7930 :                                 makeCuboid(&collector, box, &glass_tiles[i], 1, c, txc2);
     957             :                         }
     958             : 
     959        2332 :                         if (param2 > 0 && f.special_tiles[0].texture) {
     960             :                                 // Interior volume level is in range 0 .. 63,
     961             :                                 // convert it to -0.5 .. 0.5
     962           0 :                                 float vlev = (((float)param2 / 63.0 ) * 2.0 - 1.0);
     963           0 :                                 TileSpec interior_tiles[6];
     964           0 :                                 for (i = 0; i < 6; i++)
     965           0 :                                         interior_tiles[i] = f.special_tiles[0];
     966           0 :                                 float offset = 0.003;
     967           0 :                                 box = aabb3f(visible_faces[3] ? -b : -a + offset,
     968           0 :                                                          visible_faces[1] ? -b : -a + offset,
     969           0 :                                                          visible_faces[5] ? -b : -a + offset,
     970           0 :                                                          visible_faces[2] ? b : a - offset,
     971           0 :                                                          visible_faces[0] ? b * vlev : a * vlev - offset,
     972           0 :                                                          visible_faces[4] ? b : a - offset);
     973           0 :                                 box.MinEdge += pos;
     974           0 :                                 box.MaxEdge += pos;
     975           0 :                                 tx1 = (box.MinEdge.X / BS) + 0.5;
     976           0 :                                 ty1 = (box.MinEdge.Y / BS) + 0.5;
     977           0 :                                 tz1 = (box.MinEdge.Z / BS) + 0.5;
     978           0 :                                 tx2 = (box.MaxEdge.X / BS) + 0.5;
     979           0 :                                 ty2 = (box.MaxEdge.Y / BS) + 0.5;
     980           0 :                                 tz2 = (box.MaxEdge.Z / BS) + 0.5;
     981             :                                 f32 txc3[24] = {
     982           0 :                                         tx1,   1-tz2,   tx2, 1-tz1,
     983             :                                         tx1,     tz1,   tx2,   tz2,
     984           0 :                                         tz1,   1-ty2,   tz2, 1-ty1,
     985           0 :                                         1-tz2, 1-ty2, 1-tz1, 1-ty1,
     986           0 :                                         1-tx2, 1-ty2, 1-tx1, 1-ty1,
     987           0 :                                         tx1,   1-ty2,   tx2, 1-ty1,
     988           0 :                                 };
     989           0 :                                 makeCuboid(&collector, box, interior_tiles, 6, c,  txc3);
     990             :                         }
     991        2332 :                 break;}
     992             :                 case NDT_ALLFACES:
     993             :                 {
     994             :                         TileSpec tile_leaves = getNodeTile(n, p,
     995      145156 :                                         v3s16(0,0,0), data);
     996             : 
     997       72578 :                         u16 l = getInteriorLight(n, 1, nodedef);
     998       72578 :                         video::SColor c = MapBlock_LightColor(255, l, f.light_source);
     999             : 
    1000       72578 :                         v3f pos = intToFloat(p, BS);
    1001       72578 :                         aabb3f box(-BS/2,-BS/2,-BS/2,BS/2,BS/2,BS/2);
    1002       72578 :                         box.MinEdge += pos;
    1003       72578 :                         box.MaxEdge += pos;
    1004       72578 :                         makeCuboid(&collector, box, &tile_leaves, 1, c, NULL);
    1005       72578 :                 break;}
    1006             :                 case NDT_ALLFACES_OPTIONAL:
    1007             :                         // This is always pre-converted to something else
    1008           0 :                         FATAL_ERROR("NDT_ALLFACES_OPTIONAL not pre-converted");
    1009             :                         break;
    1010             :                 case NDT_TORCHLIKE:
    1011             :                 {
    1012        1361 :                         v3s16 dir = n.getWallMountedDir(nodedef);
    1013             :                         
    1014        1361 :                         u8 tileindex = 0;
    1015        1361 :                         if(dir == v3s16(0,-1,0)){
    1016          56 :                                 tileindex = 0; // floor
    1017        1305 :                         } else if(dir == v3s16(0,1,0)){
    1018           0 :                                 tileindex = 1; // ceiling
    1019             :                         // For backwards compatibility
    1020        1305 :                         } else if(dir == v3s16(0,0,0)){
    1021           0 :                                 tileindex = 0; // floor
    1022             :                         } else {
    1023        1305 :                                 tileindex = 2; // side
    1024             :                         }
    1025             : 
    1026        2722 :                         TileSpec tile = getNodeTileN(n, p, tileindex, data);
    1027        1361 :                         tile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
    1028        1361 :                         tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
    1029             : 
    1030        1361 :                         u16 l = getInteriorLight(n, 1, nodedef);
    1031        1361 :                         video::SColor c = MapBlock_LightColor(255, l, f.light_source);
    1032             : 
    1033        1361 :                         float s = BS/2*f.visual_scale;
    1034             :                         // Wall at X+ of node
    1035             :                         video::S3DVertex vertices[4] =
    1036             :                         {
    1037             :                                 video::S3DVertex(-s,-s,0, 0,0,0, c, 0,1),
    1038             :                                 video::S3DVertex( s,-s,0, 0,0,0, c, 1,1),
    1039             :                                 video::S3DVertex( s, s,0, 0,0,0, c, 1,0),
    1040             :                                 video::S3DVertex(-s, s,0, 0,0,0, c, 0,0),
    1041        1361 :                         };
    1042             : 
    1043        6805 :                         for(s32 i=0; i<4; i++)
    1044             :                         {
    1045        5444 :                                 if(dir == v3s16(1,0,0))
    1046        1296 :                                         vertices[i].Pos.rotateXZBy(0);
    1047        5444 :                                 if(dir == v3s16(-1,0,0))
    1048        1292 :                                         vertices[i].Pos.rotateXZBy(180);
    1049        5444 :                                 if(dir == v3s16(0,0,1))
    1050        1192 :                                         vertices[i].Pos.rotateXZBy(90);
    1051        5444 :                                 if(dir == v3s16(0,0,-1))
    1052        1440 :                                         vertices[i].Pos.rotateXZBy(-90);
    1053        5444 :                                 if(dir == v3s16(0,-1,0))
    1054         224 :                                         vertices[i].Pos.rotateXZBy(45);
    1055        5444 :                                 if(dir == v3s16(0,1,0))
    1056           0 :                                         vertices[i].Pos.rotateXZBy(-45);
    1057             : 
    1058        5444 :                                 vertices[i].Pos += intToFloat(p, BS);
    1059             :                         }
    1060             : 
    1061        1361 :                         u16 indices[] = {0,1,2,2,3,0};
    1062             :                         // Add to mesh collector
    1063        1361 :                         collector.append(tile, vertices, 4, indices, 6);
    1064        1361 :                 break;}
    1065             :                 case NDT_SIGNLIKE:
    1066             :                 {
    1067       31964 :                         TileSpec tile = getNodeTileN(n, p, 0, data);
    1068       15982 :                         tile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
    1069       15982 :                         tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
    1070             : 
    1071       15982 :                         u16 l = getInteriorLight(n, 0, nodedef);
    1072       15982 :                         video::SColor c = MapBlock_LightColor(255, l, f.light_source);
    1073             :                                 
    1074       15982 :                         float d = (float)BS/16;
    1075       15982 :                         float s = BS/2*f.visual_scale;
    1076             :                         // Wall at X+ of node
    1077             :                         video::S3DVertex vertices[4] =
    1078             :                         {
    1079             :                                 video::S3DVertex(BS/2-d,  s,  s, 0,0,0, c, 0,0),
    1080             :                                 video::S3DVertex(BS/2-d,  s, -s, 0,0,0, c, 1,0),
    1081             :                                 video::S3DVertex(BS/2-d, -s, -s, 0,0,0, c, 1,1),
    1082             :                                 video::S3DVertex(BS/2-d, -s,  s, 0,0,0, c, 0,1),
    1083       15982 :                         };
    1084             : 
    1085       15982 :                         v3s16 dir = n.getWallMountedDir(nodedef);
    1086             : 
    1087       79910 :                         for(s32 i=0; i<4; i++)
    1088             :                         {
    1089       63928 :                                 if(dir == v3s16(1,0,0))
    1090       28164 :                                         vertices[i].Pos.rotateXZBy(0);
    1091       63928 :                                 if(dir == v3s16(-1,0,0))
    1092       19532 :                                         vertices[i].Pos.rotateXZBy(180);
    1093       63928 :                                 if(dir == v3s16(0,0,1))
    1094        7652 :                                         vertices[i].Pos.rotateXZBy(90);
    1095       63928 :                                 if(dir == v3s16(0,0,-1))
    1096        8580 :                                         vertices[i].Pos.rotateXZBy(-90);
    1097       63928 :                                 if(dir == v3s16(0,-1,0))
    1098           0 :                                         vertices[i].Pos.rotateXYBy(-90);
    1099       63928 :                                 if(dir == v3s16(0,1,0))
    1100           0 :                                         vertices[i].Pos.rotateXYBy(90);
    1101             : 
    1102       63928 :                                 vertices[i].Pos += intToFloat(p, BS);
    1103             :                         }
    1104             : 
    1105       15982 :                         u16 indices[] = {0,1,2,2,3,0};
    1106             :                         // Add to mesh collector
    1107       15982 :                         collector.append(tile, vertices, 4, indices, 6);
    1108       15982 :                 break;}
    1109             :                 case NDT_PLANTLIKE:
    1110             :                 {
    1111       57548 :                         TileSpec tile = getNodeTileN(n, p, 0, data);
    1112       28774 :                         tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
    1113             : 
    1114       28774 :                         u16 l = getInteriorLight(n, 1, nodedef);
    1115       28774 :                         video::SColor c = MapBlock_LightColor(255, l, f.light_source);
    1116             :                         
    1117       28774 :                         float s = BS / 2 * f.visual_scale;
    1118             : 
    1119       86322 :                         for (int j = 0; j < 2; j++)
    1120             :                         {
    1121             :                                 video::S3DVertex vertices[4] =
    1122             :                                 {
    1123             :                                         video::S3DVertex(-s,-BS/2, 0, 0,0,0, c, 0,1),
    1124             :                                         video::S3DVertex( s,-BS/2, 0, 0,0,0, c, 1,1),
    1125       57548 :                                         video::S3DVertex( s,-BS/2 + s*2,0, 0,0,0, c, 1,0),
    1126       57548 :                                         video::S3DVertex(-s,-BS/2 + s*2,0, 0,0,0, c, 0,0),
    1127      172644 :                                 };
    1128             : 
    1129       57548 :                                 if(j == 0)
    1130             :                                 {
    1131      143870 :                                         for(u16 i = 0; i < 4; i++)
    1132      115096 :                                                 vertices[i].Pos.rotateXZBy(46 + n.param2 * 2);
    1133             :                                 }
    1134       28774 :                                 else if(j == 1)
    1135             :                                 {
    1136      143870 :                                         for(u16 i = 0; i < 4; i++)
    1137      115096 :                                                 vertices[i].Pos.rotateXZBy(-44 + n.param2 * 2);
    1138             :                                 }
    1139             : 
    1140      287740 :                                 for (int i = 0; i < 4; i++)
    1141             :                                 {
    1142      230192 :                                         vertices[i].Pos *= f.visual_scale;
    1143      230192 :                                         vertices[i].Pos.Y += BS/2 * (f.visual_scale - 1);
    1144      230192 :                                         vertices[i].Pos += intToFloat(p, BS);
    1145             :                                 }
    1146             : 
    1147       57548 :                                 u16 indices[] = {0, 1, 2, 2, 3, 0};
    1148             :                                 // Add to mesh collector
    1149       57548 :                                 collector.append(tile, vertices, 4, indices, 6);
    1150             :                         }
    1151       28774 :                 break;}
    1152             :                 case NDT_FIRELIKE:
    1153             :                 {
    1154           0 :                         TileSpec tile = getNodeTileN(n, p, 0, data);
    1155           0 :                         tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
    1156             : 
    1157           0 :                         u16 l = getInteriorLight(n, 1, nodedef);
    1158           0 :                         video::SColor c = MapBlock_LightColor(255, l, f.light_source);
    1159             : 
    1160           0 :                         float s = BS/2*f.visual_scale;
    1161             : 
    1162           0 :                         content_t current = n.getContent();
    1163             :                         content_t n2c;
    1164           0 :                         MapNode n2;
    1165           0 :                         v3s16 n2p;
    1166             : 
    1167             :                         static const v3s16 dirs[6] = {
    1168             :                                 v3s16( 0, 1, 0),
    1169             :                                 v3s16( 0,-1, 0),
    1170             :                                 v3s16( 1, 0, 0),
    1171             :                                 v3s16(-1, 0, 0),
    1172             :                                 v3s16( 0, 0, 1),
    1173             :                                 v3s16( 0, 0,-1)
    1174           0 :                         };
    1175             : 
    1176           0 :                         int doDraw[6] = {0,0,0,0,0,0};
    1177             : 
    1178           0 :                         bool drawAllFaces = true;
    1179             : 
    1180           0 :                         bool drawBottomFacesOnly = false; // Currently unused
    1181             : 
    1182             :                         // Check for adjacent nodes
    1183           0 :                         for(int i = 0; i < 6; i++)
    1184             :                         {
    1185           0 :                                 n2p = blockpos_nodes + p + dirs[i];
    1186           0 :                                 n2 = data->m_vmanip.getNodeNoEx(n2p);
    1187           0 :                                 n2c = n2.getContent();
    1188           0 :                                 if (n2c != CONTENT_IGNORE && n2c != CONTENT_AIR && n2c != current) {
    1189           0 :                                         doDraw[i] = 1;
    1190           0 :                                         if(drawAllFaces)
    1191           0 :                                                 drawAllFaces = false;
    1192             : 
    1193             :                                 }
    1194             :                         }
    1195             : 
    1196           0 :                         for(int j = 0; j < 6; j++)
    1197             :                         {
    1198           0 :                                 int vOffset = 0; // Vertical offset of faces after rotation
    1199           0 :                                 int hOffset = 4; // Horizontal offset of faces to reach the edge
    1200             : 
    1201             :                                 video::S3DVertex vertices[4] =
    1202             :                                 {
    1203             :                                         video::S3DVertex(-s,-BS/2,      0, 0,0,0, c, 0,1),
    1204             :                                         video::S3DVertex( s,-BS/2,      0, 0,0,0, c, 1,1),
    1205           0 :                                         video::S3DVertex( s,-BS/2 + s*2,0, 0,0,0, c, 1,0),
    1206           0 :                                         video::S3DVertex(-s,-BS/2 + s*2,0, 0,0,0, c, 0,0),
    1207           0 :                                 };
    1208             : 
    1209             :                                 // Calculate which faces should be drawn, (top or sides)
    1210           0 :                                 if(j == 0 && (drawAllFaces || (doDraw[3] == 1 || doDraw[1] == 1)))
    1211             :                                 {
    1212           0 :                                         for(int i = 0; i < 4; i++) {
    1213           0 :                                                 vertices[i].Pos.rotateXZBy(90 + n.param2 * 2);
    1214           0 :                                                 vertices[i].Pos.rotateXYBy(-10);
    1215           0 :                                                 vertices[i].Pos.Y -= vOffset;
    1216           0 :                                                 vertices[i].Pos.X -= hOffset;
    1217           0 :                                         }
    1218             :                                 }
    1219           0 :                                 else if(j == 1 && (drawAllFaces || (doDraw[5] == 1 || doDraw[1] == 1)))
    1220             :                                 {
    1221           0 :                                         for(int i = 0; i < 4; i++) {
    1222           0 :                                                 vertices[i].Pos.rotateXZBy(180 + n.param2 * 2);
    1223           0 :                                                 vertices[i].Pos.rotateYZBy(10);
    1224           0 :                                                 vertices[i].Pos.Y -= vOffset;
    1225           0 :                                                 vertices[i].Pos.Z -= hOffset;
    1226           0 :                                         }
    1227             :                                 }
    1228           0 :                                 else if(j == 2 && (drawAllFaces || (doDraw[2] == 1 || doDraw[1] == 1)))
    1229             :                                 {
    1230           0 :                                         for(int i = 0; i < 4; i++) {
    1231           0 :                                                 vertices[i].Pos.rotateXZBy(270 + n.param2 * 2);
    1232           0 :                                                 vertices[i].Pos.rotateXYBy(10);
    1233           0 :                                                 vertices[i].Pos.Y -= vOffset;
    1234           0 :                                                 vertices[i].Pos.X += hOffset;
    1235           0 :                                         }
    1236             :                                 }
    1237           0 :                                 else if(j == 3 && (drawAllFaces || (doDraw[4] == 1 || doDraw[1] == 1)))
    1238             :                                 {
    1239           0 :                                         for(int i = 0; i < 4; i++) {
    1240           0 :                                                 vertices[i].Pos.rotateYZBy(-10);
    1241           0 :                                                 vertices[i].Pos.Y -= vOffset;
    1242           0 :                                                 vertices[i].Pos.Z += hOffset;
    1243           0 :                                         }
    1244             :                                 }
    1245             : 
    1246             :                                 // Center cross-flames
    1247           0 :                                 else if(j == 4 && (drawAllFaces || doDraw[1] == 1))
    1248             :                                 {
    1249           0 :                                         for(int i=0; i<4; i++) {
    1250           0 :                                                 vertices[i].Pos.rotateXZBy(45 + n.param2 * 2);
    1251           0 :                                                 vertices[i].Pos.Y -= vOffset;
    1252           0 :                                         }
    1253             :                                 }
    1254           0 :                                 else if(j == 5 && (drawAllFaces || doDraw[1] == 1))
    1255             :                                 {
    1256           0 :                                         for(int i=0; i<4; i++) {
    1257           0 :                                                 vertices[i].Pos.rotateXZBy(-45 + n.param2 * 2);
    1258           0 :                                                 vertices[i].Pos.Y -= vOffset;
    1259           0 :                                         }
    1260             :                                 }
    1261             : 
    1262             :                                 // Render flames on bottom
    1263           0 :                                 else if(j == 0 && (drawBottomFacesOnly || (doDraw[0] == 1 && doDraw[1] == 0)))
    1264             :                                 {
    1265           0 :                                         for(int i = 0; i < 4; i++) {
    1266           0 :                                                 vertices[i].Pos.rotateYZBy(70);
    1267           0 :                                                 vertices[i].Pos.rotateXZBy(90 + n.param2 * 2);
    1268           0 :                                                 vertices[i].Pos.Y += 4.84;
    1269           0 :                                                 vertices[i].Pos.X -= hOffset+0.7;
    1270           0 :                                         }
    1271             :                                 }
    1272           0 :                                 else if(j == 1 && (drawBottomFacesOnly || (doDraw[0] == 1 && doDraw[1] == 0)))
    1273             :                                 {
    1274           0 :                                         for(int i = 0; i < 4; i++) {
    1275           0 :                                                 vertices[i].Pos.rotateYZBy(70);
    1276           0 :                                                 vertices[i].Pos.rotateXZBy(180 + n.param2 * 2);
    1277           0 :                                                 vertices[i].Pos.Y += 4.84;
    1278           0 :                                                 vertices[i].Pos.Z -= hOffset+0.7;
    1279           0 :                                         }
    1280             :                                 }
    1281           0 :                                 else if(j == 2 && (drawBottomFacesOnly || (doDraw[0] == 1 && doDraw[1] == 0)))
    1282             :                                 {
    1283           0 :                                         for(int i = 0; i < 4; i++) {
    1284           0 :                                                 vertices[i].Pos.rotateYZBy(70);
    1285           0 :                                                 vertices[i].Pos.rotateXZBy(270 + n.param2 * 2);
    1286           0 :                                                 vertices[i].Pos.Y += 4.84;
    1287           0 :                                                 vertices[i].Pos.X += hOffset+0.7;
    1288           0 :                                         }
    1289             :                                 }
    1290           0 :                                 else if(j == 3 && (drawBottomFacesOnly || (doDraw[0] == 1 && doDraw[1] == 0)))
    1291             :                                 {
    1292           0 :                                         for(int i = 0; i < 4; i++) {
    1293           0 :                                                 vertices[i].Pos.rotateYZBy(70);
    1294           0 :                                                 vertices[i].Pos.Y += 4.84;
    1295           0 :                                                 vertices[i].Pos.Z += hOffset+0.7;
    1296           0 :                                         }
    1297             :                                 }
    1298             :                                 else {
    1299             :                                         // Skip faces that aren't adjacent to a node
    1300           0 :                                         continue;
    1301             :                                 }
    1302             : 
    1303           0 :                                 for(int i=0; i<4; i++)
    1304             :                                 {
    1305           0 :                                         vertices[i].Pos *= f.visual_scale;
    1306           0 :                                         vertices[i].Pos += intToFloat(p, BS);
    1307             :                                 }
    1308             : 
    1309           0 :                                 u16 indices[] = {0,1,2,2,3,0};
    1310             :                                 // Add to mesh collector
    1311           0 :                                 collector.append(tile, vertices, 4, indices, 6);
    1312             :                         }
    1313           0 :                 break;}
    1314             :                 case NDT_FENCELIKE:
    1315             :                 {
    1316        3484 :                         TileSpec tile = getNodeTile(n, p, v3s16(0,0,0), data);
    1317        3484 :                         TileSpec tile_nocrack = tile;
    1318        1742 :                         tile_nocrack.material_flags &= ~MATERIAL_FLAG_CRACK;
    1319             : 
    1320             :                         // Put wood the right way around in the posts
    1321        3484 :                         TileSpec tile_rot = tile;
    1322        1742 :                         tile_rot.rotation = 1;
    1323             : 
    1324        1742 :                         u16 l = getInteriorLight(n, 1, nodedef);
    1325        1742 :                         video::SColor c = MapBlock_LightColor(255, l, f.light_source);
    1326             : 
    1327        1742 :                         const f32 post_rad=(f32)BS/8;
    1328        1742 :                         const f32 bar_rad=(f32)BS/16;
    1329        1742 :                         const f32 bar_len=(f32)(BS/2)-post_rad;
    1330             : 
    1331        1742 :                         v3f pos = intToFloat(p, BS);
    1332             : 
    1333             :                         // The post - always present
    1334        1742 :                         aabb3f post(-post_rad,-BS/2,-post_rad,post_rad,BS/2,post_rad);
    1335        1742 :                         post.MinEdge += pos;
    1336        1742 :                         post.MaxEdge += pos;
    1337             :                         f32 postuv[24]={
    1338             :                                         6/16.,6/16.,10/16.,10/16.,
    1339             :                                         6/16.,6/16.,10/16.,10/16.,
    1340             :                                         0/16.,0,4/16.,1,
    1341             :                                         4/16.,0,8/16.,1,
    1342             :                                         8/16.,0,12/16.,1,
    1343        1742 :                                         12/16.,0,16/16.,1};
    1344        1742 :                         makeCuboid(&collector, post, &tile_rot, 1, c, postuv);
    1345             : 
    1346             :                         // Now a section of fence, +X, if there's a post there
    1347        1742 :                         v3s16 p2 = p;
    1348        1742 :                         p2.X++;
    1349        1742 :                         MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
    1350        1742 :                         const ContentFeatures *f2 = &nodedef->get(n2);
    1351        1742 :                         if(f2->drawtype == NDT_FENCELIKE)
    1352             :                         {
    1353             :                                 aabb3f bar(-bar_len+BS/2,-bar_rad+BS/4,-bar_rad,
    1354         549 :                                                 bar_len+BS/2,bar_rad+BS/4,bar_rad);
    1355         549 :                                 bar.MinEdge += pos;
    1356         549 :                                 bar.MaxEdge += pos;
    1357             :                                 f32 xrailuv[24]={
    1358             :                                         0/16.,2/16.,16/16.,4/16.,
    1359             :                                         0/16.,4/16.,16/16.,6/16.,
    1360             :                                         6/16.,6/16.,8/16.,8/16.,
    1361             :                                         10/16.,10/16.,12/16.,12/16.,
    1362             :                                         0/16.,8/16.,16/16.,10/16.,
    1363         549 :                                         0/16.,14/16.,16/16.,16/16.};
    1364             :                                 makeCuboid(&collector, bar, &tile_nocrack, 1,
    1365         549 :                                                 c, xrailuv);
    1366         549 :                                 bar.MinEdge.Y -= BS/2;
    1367         549 :                                 bar.MaxEdge.Y -= BS/2;
    1368             :                                 makeCuboid(&collector, bar, &tile_nocrack, 1,
    1369         549 :                                                 c, xrailuv);
    1370             :                         }
    1371             : 
    1372             :                         // Now a section of fence, +Z, if there's a post there
    1373        1742 :                         p2 = p;
    1374        1742 :                         p2.Z++;
    1375        1742 :                         n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
    1376        1742 :                         f2 = &nodedef->get(n2);
    1377        1742 :                         if(f2->drawtype == NDT_FENCELIKE)
    1378             :                         {
    1379             :                                 aabb3f bar(-bar_rad,-bar_rad+BS/4,-bar_len+BS/2,
    1380         880 :                                                 bar_rad,bar_rad+BS/4,bar_len+BS/2);
    1381         880 :                                 bar.MinEdge += pos;
    1382         880 :                                 bar.MaxEdge += pos;
    1383             :                                 f32 zrailuv[24]={
    1384             :                                         3/16.,1/16.,5/16.,5/16., // cannot rotate; stretch
    1385             :                                         4/16.,1/16.,6/16.,5/16., // for wood texture instead
    1386             :                                         0/16.,9/16.,16/16.,11/16.,
    1387             :                                         0/16.,6/16.,16/16.,8/16.,
    1388             :                                         6/16.,6/16.,8/16.,8/16.,
    1389         880 :                                         10/16.,10/16.,12/16.,12/16.};
    1390             :                                 makeCuboid(&collector, bar, &tile_nocrack, 1,
    1391         880 :                                                 c, zrailuv);
    1392         880 :                                 bar.MinEdge.Y -= BS/2;
    1393         880 :                                 bar.MaxEdge.Y -= BS/2;
    1394             :                                 makeCuboid(&collector, bar, &tile_nocrack, 1,
    1395         880 :                                                 c, zrailuv);
    1396             :                         }
    1397        1742 :                 break;}
    1398             :                 case NDT_RAILLIKE:
    1399             :                 {
    1400             :                         bool is_rail_x[6]; /* (-1,-1,0) X (1,-1,0) (-1,0,0) X (1,0,0) (-1,1,0) X (1,1,0) */
    1401             :                         bool is_rail_z[6];
    1402             : 
    1403        3204 :                         content_t thiscontent = n.getContent();
    1404        6408 :                         std::string groupname = "connect_to_raillike"; // name of the group that enables connecting to raillike nodes of different kind
    1405        3204 :                         int self_group = ((ItemGroupList) nodedef->get(n).groups)[groupname];
    1406             : 
    1407        3204 :                         u8 index = 0;
    1408       12816 :                         for (s8 y0 = -1; y0 <= 1; y0++) {
    1409             :                                 // Prevent from indexing never used coordinates
    1410       38448 :                                 for (s8 xz = -1; xz <= 1; xz++) {
    1411       28836 :                                         if (xz == 0)
    1412        9612 :                                                 continue;
    1413       19224 :                                         MapNode n_xy = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x + xz, y + y0, z));
    1414       19224 :                                         MapNode n_zy = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x, y + y0, z + xz));
    1415       38448 :                                         ContentFeatures def_xy = nodedef->get(n_xy);
    1416       38448 :                                         ContentFeatures def_zy = nodedef->get(n_zy);
    1417             : 
    1418             :                                         // Check if current node would connect with the rail
    1419       38448 :                                         is_rail_x[index] = ((def_xy.drawtype == NDT_RAILLIKE
    1420       23752 :                                                         && ((ItemGroupList) def_xy.groups)[groupname] == self_group)
    1421       72368 :                                                         || n_xy.getContent() == thiscontent);
    1422             : 
    1423       38448 :                                         is_rail_z[index] = ((def_zy.drawtype == NDT_RAILLIKE
    1424       27292 :                                                         && ((ItemGroupList) def_zy.groups)[groupname] == self_group)
    1425       68828 :                                                         || n_zy.getContent() == thiscontent);
    1426       19224 :                                         index++;
    1427             :                                 }
    1428             :                         }
    1429             : 
    1430             :                         bool is_rail_x_all[2]; // [0] = negative x, [1] = positive x coordinate from the current node position
    1431             :                         bool is_rail_z_all[2];
    1432        3204 :                         is_rail_x_all[0] = is_rail_x[0] || is_rail_x[2] || is_rail_x[4];
    1433        3204 :                         is_rail_x_all[1] = is_rail_x[1] || is_rail_x[3] || is_rail_x[5];
    1434        3204 :                         is_rail_z_all[0] = is_rail_z[0] || is_rail_z[2] || is_rail_z[4];
    1435        3204 :                         is_rail_z_all[1] = is_rail_z[1] || is_rail_z[3] || is_rail_z[5];
    1436             : 
    1437             :                         // reasonable default, flat straight unrotated rail
    1438        3204 :                         bool is_straight = true;
    1439        3204 :                         int adjacencies = 0;
    1440        3204 :                         int angle = 0;
    1441        3204 :                         u8 tileindex = 0;
    1442             : 
    1443             :                         // check for sloped rail
    1444        3204 :                         if (is_rail_x[4] || is_rail_x[5] || is_rail_z[4] || is_rail_z[5]) {
    1445         423 :                                 adjacencies = 5; // 5 means sloped
    1446         423 :                                 is_straight = true; // sloped is always straight
    1447             :                         } else {
    1448             :                                 // is really straight, rails on both sides
    1449        2781 :                                 is_straight = (is_rail_x_all[0] && is_rail_x_all[1]) || (is_rail_z_all[0] && is_rail_z_all[1]);
    1450        2781 :                                 adjacencies = is_rail_x_all[0] + is_rail_x_all[1] + is_rail_z_all[0] + is_rail_z_all[1];
    1451             :                         }
    1452             : 
    1453        3204 :                         switch (adjacencies) {
    1454             :                         case 1:
    1455         110 :                                 if (is_rail_x_all[0] || is_rail_x_all[1])
    1456          57 :                                         angle = 90;
    1457         110 :                                 break;
    1458             :                         case 2:
    1459        2662 :                                 if (!is_straight)
    1460         437 :                                         tileindex = 1; // curved
    1461        2662 :                                 if (is_rail_x_all[0] && is_rail_x_all[1])
    1462         751 :                                         angle = 90;
    1463        2662 :                                 if (is_rail_z_all[0] && is_rail_z_all[1]) {
    1464        2948 :                                         if (is_rail_z[4])
    1465           0 :                                                 angle = 180;
    1466             :                                 }
    1467        1188 :                                 else if (is_rail_x_all[0] && is_rail_z_all[0])
    1468          65 :                                         angle = 270;
    1469        1123 :                                 else if (is_rail_x_all[0] && is_rail_z_all[1])
    1470         144 :                                         angle = 180;
    1471         979 :                                 else if (is_rail_x_all[1] && is_rail_z_all[1])
    1472          95 :                                         angle = 90;
    1473        2662 :                                 break;
    1474             :                         case 3:
    1475             :                                 // here is where the potential to 'switch' a junction is, but not implemented at present
    1476           9 :                                 tileindex = 2; // t-junction
    1477           9 :                                 if(!is_rail_x_all[1])
    1478           0 :                                         angle = 180;
    1479           9 :                                 if(!is_rail_z_all[0])
    1480           4 :                                         angle = 90;
    1481           9 :                                 if(!is_rail_z_all[1])
    1482           5 :                                         angle = 270;
    1483           9 :                                 break;
    1484             :                         case 4:
    1485           0 :                                 tileindex = 3; // crossing
    1486           0 :                                 break;
    1487             :                         case 5: //sloped
    1488         423 :                                 if (is_rail_z[4])
    1489         200 :                                         angle = 180;
    1490         423 :                                 if (is_rail_x[4])
    1491          65 :                                         angle = 90;
    1492         423 :                                 if (is_rail_x[5])
    1493          62 :                                         angle = -90;
    1494         423 :                                 break;
    1495             :                         default:
    1496           0 :                                 break;
    1497             :                         }
    1498             : 
    1499        6408 :                         TileSpec tile = getNodeTileN(n, p, tileindex, data);
    1500        3204 :                         tile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
    1501        3204 :                         tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
    1502             : 
    1503        3204 :                         u16 l = getInteriorLight(n, 0, nodedef);
    1504        3204 :                         video::SColor c = MapBlock_LightColor(255, l, f.light_source);
    1505             : 
    1506        3204 :                         float d = (float)BS/64;
    1507        3204 :                         float s = BS/2;
    1508             : 
    1509        3204 :                         short g = -1;
    1510        3204 :                         if (is_rail_x[4] || is_rail_x[5] || is_rail_z[4] || is_rail_z[5])
    1511         423 :                                 g = 1; //Object is at a slope
    1512             : 
    1513             :                         video::S3DVertex vertices[4] =
    1514             :                         {
    1515             :                                         video::S3DVertex(-s,  -s+d,-s,  0,0,0,  c,0,1),
    1516             :                                         video::S3DVertex( s,  -s+d,-s,  0,0,0,  c,1,1),
    1517        3204 :                                         video::S3DVertex( s, g*s+d, s,  0,0,0,  c,1,0),
    1518        3204 :                                         video::S3DVertex(-s, g*s+d, s,  0,0,0,  c,0,0),
    1519        9612 :                         };
    1520             : 
    1521       16020 :                         for(s32 i=0; i<4; i++)
    1522             :                         {
    1523       12816 :                                 if(angle != 0)
    1524        5792 :                                         vertices[i].Pos.rotateXZBy(angle);
    1525       12816 :                                 vertices[i].Pos += intToFloat(p, BS);
    1526             :                         }
    1527             : 
    1528        3204 :                         u16 indices[] = {0,1,2,2,3,0};
    1529        3204 :                         collector.append(tile, vertices, 4, indices, 6);
    1530        3204 :                 break;}
    1531             :                 case NDT_NODEBOX:
    1532             :                 {
    1533             :                         static const v3s16 tile_dirs[6] = {
    1534             :                                 v3s16(0, 1, 0),
    1535             :                                 v3s16(0, -1, 0),
    1536             :                                 v3s16(1, 0, 0),
    1537             :                                 v3s16(-1, 0, 0),
    1538             :                                 v3s16(0, 0, 1),
    1539             :                                 v3s16(0, 0, -1)
    1540         166 :                         };
    1541         332 :                         TileSpec tiles[6];
    1542             :                         
    1543         166 :                         u16 l = getInteriorLight(n, 1, nodedef);
    1544         166 :                         video::SColor c = MapBlock_LightColor(255, l, f.light_source);
    1545             : 
    1546         166 :                         v3f pos = intToFloat(p, BS);
    1547             : 
    1548         332 :                         std::vector<aabb3f> boxes = n.getNodeBoxes(nodedef);
    1549         830 :                         for(std::vector<aabb3f>::iterator
    1550         166 :                                         i = boxes.begin();
    1551         664 :                                         i != boxes.end(); i++)
    1552             :                         {
    1553        1162 :                         for(int j = 0; j < 6; j++)
    1554             :                                 {
    1555             :                                 // Handles facedir rotation for textures
    1556         996 :                                 tiles[j] = getNodeTile(n, p, tile_dirs[j], data);
    1557             :                                 }
    1558         166 :                                 aabb3f box = *i;
    1559         166 :                                 box.MinEdge += pos;
    1560         166 :                                 box.MaxEdge += pos;
    1561             :                                 
    1562             :                                 f32 temp;
    1563         166 :                                 if (box.MinEdge.X > box.MaxEdge.X)
    1564             :                                 {
    1565           0 :                                         temp=box.MinEdge.X;
    1566           0 :                                         box.MinEdge.X=box.MaxEdge.X;
    1567           0 :                                         box.MaxEdge.X=temp;
    1568             :                                 }
    1569         166 :                                 if (box.MinEdge.Y > box.MaxEdge.Y)
    1570             :                                 {
    1571           0 :                                         temp=box.MinEdge.Y;
    1572           0 :                                         box.MinEdge.Y=box.MaxEdge.Y;
    1573           0 :                                         box.MaxEdge.Y=temp;
    1574             :                                 }
    1575         166 :                                 if (box.MinEdge.Z > box.MaxEdge.Z)
    1576             :                                 {
    1577           0 :                                         temp=box.MinEdge.Z;
    1578           0 :                                         box.MinEdge.Z=box.MaxEdge.Z;
    1579           0 :                                         box.MaxEdge.Z=temp;
    1580             :                                 }
    1581             : 
    1582             :                                 //
    1583             :                                 // Compute texture coords
    1584         166 :                                 f32 tx1 = (box.MinEdge.X/BS)+0.5;
    1585         166 :                                 f32 ty1 = (box.MinEdge.Y/BS)+0.5;
    1586         166 :                                 f32 tz1 = (box.MinEdge.Z/BS)+0.5;
    1587         166 :                                 f32 tx2 = (box.MaxEdge.X/BS)+0.5;
    1588         166 :                                 f32 ty2 = (box.MaxEdge.Y/BS)+0.5;
    1589         166 :                                 f32 tz2 = (box.MaxEdge.Z/BS)+0.5;
    1590             :                                 f32 txc[24] = {
    1591             :                                         // up
    1592         332 :                                         tx1, 1-tz2, tx2, 1-tz1,
    1593             :                                         // down
    1594             :                                         tx1, tz1, tx2, tz2,
    1595             :                                         // right
    1596         332 :                                         tz1, 1-ty2, tz2, 1-ty1,
    1597             :                                         // left
    1598         664 :                                         1-tz2, 1-ty2, 1-tz1, 1-ty1,
    1599             :                                         // back
    1600         664 :                                         1-tx2, 1-ty2, 1-tx1, 1-ty1,
    1601             :                                         // front
    1602         332 :                                         tx1, 1-ty2, tx2, 1-ty1,
    1603        2490 :                                 };
    1604         166 :                                 makeCuboid(&collector, box, tiles, 6, c, txc);
    1605             :                         }
    1606         166 :                 break;}
    1607             :                 case NDT_MESH:
    1608             :                 {
    1609       23736 :                         v3f pos = intToFloat(p, BS);
    1610       23736 :                         video::SColor c = MapBlock_LightColor(255, getInteriorLight(n, 1, nodedef), f.light_source);
    1611             : 
    1612       23736 :                         u8 facedir = 0;
    1613       23736 :                         if (f.param_type_2 == CPT2_FACEDIR) {
    1614       18792 :                                 facedir = n.getFaceDir(nodedef);
    1615        4944 :                         } else if (f.param_type_2 == CPT2_WALLMOUNTED) {
    1616             :                                 //convert wallmounted to 6dfacedir.
    1617             :                                 //when cache enabled, it is already converted
    1618           0 :                                 facedir = n.getWallMounted(nodedef);
    1619           0 :                                 if (!enable_mesh_cache) {
    1620             :                                         static const u8 wm_to_6d[6] = {20, 0, 16+1, 12+3, 8, 4+2};
    1621           0 :                                         facedir = wm_to_6d[facedir];
    1622             :                                 }
    1623             :                         }
    1624             : 
    1625       23736 :                         if (f.mesh_ptr[facedir]) {
    1626             :                                 // use cached meshes
    1627      137403 :                                 for(u16 j = 0; j < f.mesh_ptr[0]->getMeshBufferCount(); j++) {
    1628      113667 :                                         scene::IMeshBuffer *buf = f.mesh_ptr[facedir]->getMeshBuffer(j);
    1629      568335 :                                         collector.append(getNodeTileN(n, p, j, data),
    1630      227334 :                                                 (video::S3DVertex *)buf->getVertices(), buf->getVertexCount(),
    1631      341001 :                                                 buf->getIndices(), buf->getIndexCount(), pos, c);
    1632             :                                 }
    1633           0 :                         } else if (f.mesh_ptr[0]) {
    1634             :                                 // no cache, clone and rotate mesh
    1635           0 :                                 scene::IMesh* mesh = cloneMesh(f.mesh_ptr[0]);
    1636           0 :                                 rotateMeshBy6dFacedir(mesh, facedir);
    1637           0 :                                 recalculateBoundingBox(mesh);
    1638           0 :                                 meshmanip->recalculateNormals(mesh, true, false);
    1639           0 :                                 for(u16 j = 0; j < mesh->getMeshBufferCount(); j++) {
    1640           0 :                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
    1641           0 :                                         collector.append(getNodeTileN(n, p, j, data),
    1642           0 :                                                 (video::S3DVertex *)buf->getVertices(), buf->getVertexCount(),
    1643           0 :                                                 buf->getIndices(), buf->getIndexCount(), pos, c);
    1644             :                                 }
    1645           0 :                                 mesh->drop();
    1646             :                         }
    1647       23736 :                 break;}
    1648             :                 }
    1649             :         }
    1650             :         
    1651             :         /*
    1652             :                 Caused by incorrect alpha blending, selection mesh needs to be created as
    1653             :                 last element to ensure it gets blended correct over nodes with alpha channel
    1654             :         */
    1655             :         // Create selection mesh
    1656        2140 :         v3s16 p = data->m_highlighted_pos_relative;
    1657        2687 :         if (data->m_show_hud &&
    1658        1209 :                         (p.X >= 0) && (p.X < MAP_BLOCKSIZE) &&
    1659         366 :                         (p.Y >= 0) && (p.Y < MAP_BLOCKSIZE) &&
    1660         127 :                         (p.Z >= 0) && (p.Z < MAP_BLOCKSIZE)) {
    1661             : 
    1662          45 :                 MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes + p);
    1663          45 :                 if(n.getContent() != CONTENT_AIR) {
    1664             :                         // Get selection mesh light level
    1665             :                         static const v3s16 dirs[7] = {
    1666             :                                         v3s16( 0, 0, 0),
    1667             :                                         v3s16( 0, 1, 0),
    1668             :                                         v3s16( 0,-1, 0),
    1669             :                                         v3s16( 1, 0, 0),
    1670             :                                         v3s16(-1, 0, 0),
    1671             :                                         v3s16( 0, 0, 1),
    1672             :                                         v3s16( 0, 0,-1)
    1673          45 :                         };
    1674             : 
    1675          45 :                         u16 l = 0;
    1676          45 :                         u16 l1 = 0;
    1677         360 :                         for (u8 i = 0; i < 7; i++) {
    1678         315 :                                 MapNode n1 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p + dirs[i]);       
    1679         315 :                                 l1 = getInteriorLight(n1, -4, nodedef);
    1680         315 :                                 if (l1 > l) 
    1681          95 :                                         l = l1;
    1682             :                         }
    1683          45 :                         video::SColor c = MapBlock_LightColor(255, l, 0);
    1684          45 :                         data->m_highlight_mesh_color = c;
    1685          90 :                         std::vector<aabb3f> boxes = n.getSelectionBoxes(nodedef);
    1686          90 :                         TileSpec h_tile;                        
    1687          45 :                         h_tile.material_flags |= MATERIAL_FLAG_HIGHLIGHTED;
    1688          45 :                         h_tile.texture = tsrc->getTextureForMesh("halo.png",&h_tile.texture_id);
    1689          45 :                         v3f pos = intToFloat(p, BS);
    1690          45 :                         f32 d = 0.05 * BS;
    1691         270 :                         for (std::vector<aabb3f>::iterator i = boxes.begin();
    1692         180 :                                         i != boxes.end(); i++) {
    1693          45 :                                 aabb3f box = *i;
    1694          45 :                                 box.MinEdge += v3f(-d, -d, -d) + pos;
    1695          45 :                                 box.MaxEdge += v3f(d, d, d) + pos;
    1696          45 :                                 makeCuboid(&collector, box, &h_tile, 1, c, NULL);
    1697             :                         }
    1698             :                 }
    1699             :         }
    1700        2143 : }
    1701             : 

Generated by: LCOV version 1.11