{"action":"created","comment":{"url":"https://api.github.com/repos/minetest/minetest/pulls/comments/106778660","pull_request_review_id":27722123,"id":106778660,"diff_hunk":"@@ -525,1633 +371,955 @@ static TileSpec getSpecialTile(const ContentFeatures &f,\n \treturn copy;\n }\n \n-/*\n-\tTODO: Fix alpha blending for special nodes\n-\tCurrently only the last element rendered is blended correct\n-*/\n-void mapblock_mesh_generate_special(MeshMakeData *data,\n-\t\tMeshCollector &collector)\n+void MapblockMeshGenerator::prepareLiquidNodeDrawing(bool flowing)\n {\n-\tINodeDefManager *nodedef = data->m_client->ndef();\n-\tscene::ISceneManager* smgr = data->m_client->getSceneManager();\n-\tscene::IMeshManipulator* meshmanip = smgr->getMeshManipulator();\n-\n-\t// 0ms\n-\t//TimeTaker timer(\"mapblock_mesh_generate_special()\");\n+\ttile_liquid_top = getSpecialTile(*f, n, 0);\n+\ttile_liquid = getSpecialTile(*f, n, flowing ? 1 : 0);\n+\n+\tMapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(p.X,p.Y+1,p.Z));\n+\tc_flowing = nodedef->getId(f->liquid_alternative_flowing);\n+\tc_source = nodedef->getId(f->liquid_alternative_source);\n+\ttop_is_same_liquid = (ntop.getContent() == c_flowing) || (ntop.getContent() == c_source);\n+\n+\tif (data->m_smooth_lighting)\n+\t\treturn; // don't need to pre-compute anything in this case\n+\n+\tif (f->light_source != 0) {\n+\t\t// If this liquid emits light and doesn't contain light, draw\n+\t\t// it at what it emits, for an increased effect\n+\t\tlight = decode_light(f->light_source);\n+\t\tlight = light | (light << 8);\n+\t} else if (nodedef->get(ntop).param_type == CPT_LIGHT) {\n+\t\t// Otherwise, use the light of the node on top if possible\n+\t\tlight = getInteriorLight(ntop, 0, nodedef);\n+\t}\n \n-\t/*\n-\t\tSome settings\n-\t*/\n-\tbool enable_mesh_cache\t= g_settings->getBool(\"enable_mesh_cache\") &&\n-\t\t!data->m_smooth_lighting; // Mesh cache is not supported with smooth lighting\n+\tcolor_liquid_top = encode_light_and_color(light, tile_liquid_top.color, f->light_source);\n+\tcolor = encode_light_and_color(light, tile_liquid.color, f->light_source);\n+}\n \n-\tv3s16 blockpos_nodes = data->m_blockpos*MAP_BLOCKSIZE;\n+void MapblockMeshGenerator::getLiquidNeighborhood(bool flowing)\n+{\n+\tu8 range = rangelim(nodedef->get(c_flowing).liquid_range, 1, 8);\n \n-\tfor(s16 z = 0; z < MAP_BLOCKSIZE; z++)\n-\tfor(s16 y = 0; y < MAP_BLOCKSIZE; y++)\n-\tfor(s16 x = 0; x < MAP_BLOCKSIZE; x++)\n+\tfor (int w = -1; w <= 1; w++)\n+\tfor (int u = -1; u <= 1; u++)\n \t{\n-\t\tv3s16 p(x,y,z);\n-\n-\t\tMapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes + p);\n-\t\tconst ContentFeatures &f = nodedef->get(n);\n-\n-\t\t// Only solidness=0 stuff is drawn here\n-\t\tif(f.solidness != 0)\n-\t\t\tcontinue;\n-\n-\t\tif (f.drawtype == NDT_AIRLIKE)\n+\t\t// Skip getting unneeded data\n+\t\tif (!flowing && u && w)\n \t\t\tcontinue;\n \n-\t\tLightFrame frame;\n-\t\tif (data->m_smooth_lighting)\n-\t\t\tgetSmoothLightFrame(&frame, blockpos_nodes + p, data, f.light_source);\n-\t\telse\n-\t\t\tframe.light_source = f.light_source;\n+\t\tNeighborData &neighbor = liquid_neighbors[w + 1][u + 1];\n+\t\tv3s16 p2 = p + v3s16(u, 0, w);\n+\t\tMapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);\n+\t\tneighbor.content = n2.getContent();\n+\t\tneighbor.level = -0.5 * BS;\n+\t\tneighbor.is_same_liquid = false;\n+\t\tneighbor.top_is_same_liquid = false;\n \n-\t\tswitch(f.drawtype) {\n-\t\tdefault:\n-\t\t\tinfostream << \"Got \" << f.drawtype << std::endl;\n-\t\t\tFATAL_ERROR(\"Unknown drawtype\");\n-\t\t\tbreak;\n-\t\tcase NDT_LIQUID:\n-\t\t{\n-\t\t\t/*\n-\t\t\t\tAdd water sources to mesh if using new style\n-\t\t\t*/\n-\t\t\tTileSpec tile_liquid = getSpecialTile(f, n, 0);\n-\t\t\tTileSpec tile_liquid_bfculled = getNodeTile(n, p, v3s16(0,0,0), data);\n-\t\t\tu16 l = getInteriorLight(n, 0, nodedef);\n-\t\t\tvideo::SColor c1 = encode_light_and_color(l,\n-\t\t\t\ttile_liquid.color, f.light_source);\n-\t\t\tvideo::SColor c2 = encode_light_and_color(l,\n-\t\t\t\ttile_liquid_bfculled.color, f.light_source);\n-\n-\t\t\tbool top_is_same_liquid = false;\n-\t\t\tMapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));\n-\t\t\tcontent_t c_flowing = nodedef->getId(f.liquid_alternative_flowing);\n-\t\t\tcontent_t c_source = nodedef->getId(f.liquid_alternative_source);\n-\t\t\tif(ntop.getContent() == c_flowing || ntop.getContent() == c_source)\n-\t\t\t\ttop_is_same_liquid = true;\n-\n-\t\t\t/*\n-\t\t\t\tGenerate sides\n-\t\t\t */\n-\t\t\tv3s16 side_dirs[4] = {\n-\t\t\t\tv3s16(1,0,0),\n-\t\t\t\tv3s16(-1,0,0),\n-\t\t\t\tv3s16(0,0,1),\n-\t\t\t\tv3s16(0,0,-1),\n-\t\t\t};\n-\t\t\tfor(u32 i=0; i<4; i++)\n-\t\t\t{\n-\t\t\t\tv3s16 dir = side_dirs[i];\n-\n-\t\t\t\tMapNode neighbor = data->m_vmanip.getNodeNoEx(blockpos_nodes + p + dir);\n-\t\t\t\tcontent_t neighbor_content = neighbor.getContent();\n-\t\t\t\tconst ContentFeatures &n_feat = nodedef->get(neighbor_content);\n-\t\t\t\tMapNode n_top = data->m_vmanip.getNodeNoEx(blockpos_nodes + p + dir+ v3s16(0,1,0));\n-\t\t\t\tcontent_t n_top_c = n_top.getContent();\n-\n-\t\t\t\tif(neighbor_content == CONTENT_IGNORE)\n-\t\t\t\t\tcontinue;\n-\n-\t\t\t\t/*\n-\t\t\t\t\tIf our topside is liquid and neighbor's topside\n-\t\t\t\t\tis liquid, don't draw side face\n-\t\t\t\t*/\n-\t\t\t\tif(top_is_same_liquid && (n_top_c == c_flowing ||\n-\t\t\t\t\t\tn_top_c == c_source || n_top_c == CONTENT_IGNORE))\n-\t\t\t\t\tcontinue;\n-\n-\t\t\t\t// Don't draw face if neighbor is blocking the view\n-\t\t\t\tif(n_feat.solidness == 2)\n-\t\t\t\t\tcontinue;\n-\n-\t\t\t\tbool neighbor_is_same_liquid = (neighbor_content == c_source\n-\t\t\t\t\t\t|| neighbor_content == c_flowing);\n-\n-\t\t\t\t// Don't draw any faces if neighbor same is liquid and top is\n-\t\t\t\t// same liquid\n-\t\t\t\tif(neighbor_is_same_liquid && !top_is_same_liquid)\n-\t\t\t\t\tcontinue;\n-\n-\t\t\t\t// Use backface culled material if neighbor doesn't have a\n-\t\t\t\t// solidness of 0\n-\t\t\t\tconst TileSpec *current_tile = &tile_liquid;\n-\t\t\t\tvideo::SColor *c = &c1;\n-\t\t\t\tif(n_feat.solidness != 0 || n_feat.visual_solidness != 0) {\n-\t\t\t\t\tcurrent_tile = &tile_liquid_bfculled;\n-\t\t\t\t\tc = &c2;\n-\t\t\t\t}\n-\n-\t\t\t\tvideo::S3DVertex vertices[4] =\n-\t\t\t\t{\n-\t\t\t\t\tvideo::S3DVertex(-BS/2,0,BS/2,0,0,0, *c, 0,1),\n-\t\t\t\t\tvideo::S3DVertex(BS/2,0,BS/2,0,0,0, *c, 1,1),\n-\t\t\t\t\tvideo::S3DVertex(BS/2,0,BS/2, 0,0,0, *c, 1,0),\n-\t\t\t\t\tvideo::S3DVertex(-BS/2,0,BS/2, 0,0,0, *c, 0,0),\n-\t\t\t\t};\n-\n-\t\t\t\t/*\n-\t\t\t\t\tIf our topside is liquid, set upper border of face\n-\t\t\t\t\tat upper border of node\n-\t\t\t\t*/\n-\t\t\t\tif (top_is_same_liquid) {\n-\t\t\t\t\tvertices[2].Pos.Y = 0.5 * BS;\n-\t\t\t\t\tvertices[3].Pos.Y = 0.5 * BS;\n-\t\t\t\t} else {\n-\t\t\t\t/*\n-\t\t\t\t\tOtherwise upper position of face is liquid level\n-\t\t\t\t*/\n-\t\t\t\t\tvertices[2].Pos.Y = 0.5 * BS;\n-\t\t\t\t\tvertices[3].Pos.Y = 0.5 * BS;\n-\t\t\t\t}\n-\t\t\t\t/*\n-\t\t\t\t\tIf neighbor is liquid, lower border of face is liquid level\n-\t\t\t\t*/\n-\t\t\t\tif (neighbor_is_same_liquid) {\n-\t\t\t\t\tvertices[0].Pos.Y = 0.5 * BS;\n-\t\t\t\t\tvertices[1].Pos.Y = 0.5 * BS;\n-\t\t\t\t} else {\n-\t\t\t\t/*\n-\t\t\t\t\tIf neighbor is not liquid, lower border of face is\n-\t\t\t\t\tlower border of node\n-\t\t\t\t*/\n-\t\t\t\t\tvertices[0].Pos.Y = -0.5 * BS;\n-\t\t\t\t\tvertices[1].Pos.Y = -0.5 * BS;\n-\t\t\t\t}\n-\n-\t\t\t\tfor (s32 j = 0; j < 4; j++) {\n-\t\t\t\t\tif(dir == v3s16(0,0,1))\n-\t\t\t\t\t\tvertices[j].Pos.rotateXZBy(0);\n-\t\t\t\t\tif(dir == v3s16(0,0,-1))\n-\t\t\t\t\t\tvertices[j].Pos.rotateXZBy(180);\n-\t\t\t\t\tif(dir == v3s16(-1,0,0))\n-\t\t\t\t\t\tvertices[j].Pos.rotateXZBy(90);\n-\t\t\t\t\tif(dir == v3s16(1,0,-0))\n-\t\t\t\t\t\tvertices[j].Pos.rotateXZBy(-90);\n-\n-\t\t\t\t\t// Do this to not cause glitches when two liquids are\n-\t\t\t\t\t// side-by-side\n-\t\t\t\t\t/*if(neighbor_is_same_liquid == false){\n-\t\t\t\t\t\tvertices[j].Pos.X *= 0.98;\n-\t\t\t\t\t\tvertices[j].Pos.Z *= 0.98;\n-\t\t\t\t\t}*/\n-\n-\t\t\t\t\tif (data->m_smooth_lighting)\n-\t\t\t\t\t\tvertices[j].Color = blendLight(frame, vertices[j].Pos, current_tile->color);\n-\t\t\t\t\tvertices[j].Pos += intToFloat(p, BS);\n-\t\t\t\t}\n-\n-\t\t\t\tu16 indices[] = {0,1,2,2,3,0};\n-\t\t\t\t// Add to mesh collector\n-\t\t\t\tcollector.append(*current_tile, vertices, 4, indices, 6);\n-\t\t\t}\n-\n-\t\t\t/*\n-\t\t\t\tGenerate top\n-\t\t\t */\n-\t\t\tif(top_is_same_liquid)\n-\t\t\t\tcontinue;\n+\t\tif (neighbor.content == CONTENT_IGNORE)\n+\t\t\tcontinue;\n \n-\t\t\tvideo::S3DVertex vertices[4] =\n-\t\t\t{\n-\t\t\t\tvideo::S3DVertex(-BS/2,0,BS/2, 0,0,0, c1, 0,1),\n-\t\t\t\tvideo::S3DVertex(BS/2,0,BS/2, 0,0,0, c1, 1,1),\n-\t\t\t\tvideo::S3DVertex(BS/2,0,-BS/2, 0,0,0, c1, 1,0),\n-\t\t\t\tvideo::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c1, 0,0),\n-\t\t\t};\n+\t\tif (neighbor.content == c_source) {\n+\t\t\tneighbor.is_same_liquid = true;\n+\t\t\tneighbor.level = 0.5 * BS;\n+\t\t} else if (neighbor.content == c_flowing) {\n+\t\t\tneighbor.is_same_liquid = true;\n+\t\t\tu8 liquid_level = (n2.param2 & LIQUID_LEVEL_MASK);\n+\t\t\tif (liquid_level <= LIQUID_LEVEL_MAX + 1 - range)\n+\t\t\t\tliquid_level = 0;\n+\t\t\telse\n+\t\t\t\tliquid_level -= (LIQUID_LEVEL_MAX + 1 - range);\n+\t\t\tneighbor.level = (-0.5 + (liquid_level + 0.5) / range) * BS;\n+\t\t}\n \n-\t\t\tfor (s32 i = 0; i < 4; i++) {\n-\t\t\t\tvertices[i].Pos.Y += 0.5 * BS;\n-\t\t\t\tif (data->m_smooth_lighting)\n-\t\t\t\t\tvertices[i].Color = blendLight(frame, vertices[i].Pos, tile_liquid.color);\n-\t\t\t\tvertices[i].Pos += intToFloat(p, BS);\n-\t\t\t}\n+\t\t// Check node above neighbor.\n+\t\t// NOTE: This doesn't get executed if neighbor\n+\t\t//       doesn't exist\n+\t\tp2.Y += 1;\n+\t\tn2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);\n+\t\tif (n2.getContent() == c_source || n2.getContent() == c_flowing)\n+\t\t\tneighbor.top_is_same_liquid = true;\n+\t}\n+}\n \n-\t\t\tu16 indices[] = {0,1,2,2,3,0};\n-\t\t\t// Add to mesh collector\n-\t\t\tcollector.append(tile_liquid, vertices, 4, indices, 6);\n-\t\tbreak;}\n-\t\tcase NDT_FLOWINGLIQUID:\n-\t\t{\n-\t\t\t/*\n-\t\t\t\tAdd flowing liquid to mesh\n-\t\t\t*/\n-\t\t\tTileSpec tile_liquid = getSpecialTile(f, n, 0);\n-\t\t\tTileSpec tile_liquid_bfculled = getSpecialTile(f, n, 1);\n-\n-\t\t\tbool top_is_same_liquid = false;\n-\t\t\tMapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));\n-\t\t\tcontent_t c_flowing = nodedef->getId(f.liquid_alternative_flowing);\n-\t\t\tcontent_t c_source = nodedef->getId(f.liquid_alternative_source);\n-\t\t\tif(ntop.getContent() == c_flowing || ntop.getContent() == c_source)\n-\t\t\t\ttop_is_same_liquid = true;\n-\n-\t\t\tu16 l = 0;\n-\t\t\t// If this liquid emits light and doesn't contain light, draw\n-\t\t\t// it at what it emits, for an increased effect\n-\t\t\tu8 light_source = nodedef->get(n).light_source;\n-\t\t\tif(light_source != 0){\n-\t\t\t\tl = decode_light(light_source);\n-\t\t\t\tl = l | (l<<8);\n-\t\t\t}\n-\t\t\t// Use the light of the node on top if possible\n-\t\t\telse if(nodedef->get(ntop).param_type == CPT_LIGHT)\n-\t\t\t\tl = getInteriorLight(ntop, 0, nodedef);\n-\t\t\t// Otherwise use the light of this node (the liquid)\n-\t\t\telse\n-\t\t\t\tl = getInteriorLight(n, 0, nodedef);\n-\t\t\tvideo::SColor c1 = encode_light_and_color(l,\n-\t\t\t\ttile_liquid.color, f.light_source);\n-\t\t\tvideo::SColor c2 = encode_light_and_color(l,\n-\t\t\t\ttile_liquid_bfculled.color, f.light_source);\n+void MapblockMeshGenerator::resetCornerLevels()\n+{\n+\tfor (int k = 0; k < 2; k++)\n+\tfor (int i = 0; i < 2; i++)\n+\t\tcorner_levels[k][i] = 0.5 * BS;\n+}\n \n-\t\t\tu8 range = rangelim(nodedef->get(c_flowing).liquid_range, 1, 8);\n+void MapblockMeshGenerator::calculateCornerLevels()\n+{\n+\tfor (int k = 0; k < 2; k++)\n+\tfor (int i = 0; i < 2; i++)\n+\t\tcorner_levels[k][i] = getCornerLevel(i, k);\n+}\n \n-\t\t\t// Neighbor liquid levels (key = relative position)\n-\t\t\t// Includes current node\n+f32 MapblockMeshGenerator::getCornerLevel(int i, int k)\n+{\n+\tfloat sum = 0;\n+\tint count = 0;\n+\tint air_count = 0;\n+\tfor (int dk = 0; dk < 2; dk++)\n+\tfor (int di = 0; di < 2; di++)\n+\t{\n+\t\tNeighborData &neighbor_data = liquid_neighbors[k + dk][i + di];\n+\t\tcontent_t content = neighbor_data.content;\n+\n+\t\t// If top is liquid, draw starting from top of node\n+\t\tif (neighbor_data.top_is_same_liquid)\n+\t\t\treturn 0.5 * BS;\n+\n+\t\t// Source always has the full height\n+\t\tif (content == c_source)\n+\t\t\treturn sum = 0.5 * BS;\n+\n+\t\t// Flowing liquid has level information\n+\t\tif (content == c_flowing) {\n+\t\t\tsum += neighbor_data.level;\n+\t\t\tcount++;\n+\t\t} else if (content == CONTENT_AIR) {\n+\t\t\tair_count++;\n+\t\t\tif (air_count >= 2)\n+\t\t\t\treturn -0.5 * BS + 0.2;\n+\t\t}\n+\t}\n+\tif (count > 0)\n+\t\treturn sum / count;\n+\treturn 0;\n+}\n \n-\t\t\tstruct NeighborData {\n-\t\t\t\tf32 level;\n-\t\t\t\tcontent_t content;\n-\t\t\t\tu8 flags;\n-\t\t\t};\n-\t\t\tNeighborData neighbor_data_matrix[27];\n-\n-\t\t\tconst u8 neighborflag_top_is_same_liquid = 0x01;\n-\t\t\tv3s16 neighbor_dirs[9] = {\n-\t\t\t\tv3s16(0,0,0),\n-\t\t\t\tv3s16(0,0,1),\n-\t\t\t\tv3s16(0,0,-1),\n-\t\t\t\tv3s16(1,0,0),\n-\t\t\t\tv3s16(-1,0,0),\n-\t\t\t\tv3s16(1,0,1),\n-\t\t\t\tv3s16(-1,0,-1),\n-\t\t\t\tv3s16(1,0,-1),\n-\t\t\t\tv3s16(-1,0,1),\n-\t\t\t};\n-\t\t\tfor(u32 i=0; i<9; i++)\n-\t\t\t{\n-\t\t\t\tcontent_t content = CONTENT_AIR;\n-\t\t\t\tfloat level = -0.5 * BS;\n-\t\t\t\tu8 flags = 0;\n-\t\t\t\t// Check neighbor\n-\t\t\t\tv3s16 p2 = p + neighbor_dirs[i];\n-\t\t\t\tMapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);\n-\t\t\t\tif(n2.getContent() != CONTENT_IGNORE)\n-\t\t\t\t{\n-\t\t\t\t\tcontent = n2.getContent();\n-\n-\t\t\t\t\tif(n2.getContent() == c_source)\n-\t\t\t\t\t\tlevel = 0.5 * BS;\n-\t\t\t\t\telse if(n2.getContent() == c_flowing){\n-\t\t\t\t\t\tu8 liquid_level = (n2.param2&LIQUID_LEVEL_MASK);\n-\t\t\t\t\t\tif (liquid_level <= LIQUID_LEVEL_MAX+1-range)\n-\t\t\t\t\t\t\tliquid_level = 0;\n-\t\t\t\t\t\telse\n-\t\t\t\t\t\t\tliquid_level -= (LIQUID_LEVEL_MAX+1-range);\n-\t\t\t\t\t\tlevel = (-0.5 + ((float)liquid_level + 0.5) / (float)range) * BS;\n-\t\t\t\t\t}\n-\n-\t\t\t\t\t// Check node above neighbor.\n-\t\t\t\t\t// NOTE: This doesn't get executed if neighbor\n-\t\t\t\t\t//       doesn't exist\n-\t\t\t\t\tp2.Y += 1;\n-\t\t\t\t\tn2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);\n-\t\t\t\t\tif(n2.getContent() == c_source ||\n-\t\t\t\t\t\t\tn2.getContent() == c_flowing)\n-\t\t\t\t\t\tflags |= neighborflag_top_is_same_liquid;\n-\t\t\t\t}\n-\n-\t\t\t\tNeighborData &neighbor_data =\n-\t\t\t\t\tneighbor_data_matrix[NeighborToIndex(neighbor_dirs[i])];\n-\n-\t\t\t\tneighbor_data.level = level;\n-\t\t\t\tneighbor_data.content = content;\n-\t\t\t\tneighbor_data.flags = flags;\n-\t\t\t}\n+void MapblockMeshGenerator::drawLiquidSides(bool flowing)\n+{\n+\tstruct LiquidFaceDesc {\n+\t\tv3s16 dir; // XZ\n+\t\tv3s16 p[2]; // XZ only; 1 means +, 0 means -\n+\t};\n+\tstruct UV {\n+\t\tint u, v;\n+\t};\n+\tstatic const LiquidFaceDesc base_faces[4] = {\n+\t\t{ v3s16( 1, 0,  0), { v3s16(1, 0, 1), v3s16(1, 0, 0) }},\n+\t\t{ v3s16(-1, 0,  0), { v3s16(0, 0, 0), v3s16(0, 0, 1) }},\n+\t\t{ v3s16( 0, 0,  1), { v3s16(0, 0, 1), v3s16(1, 0, 1) }},\n+\t\t{ v3s16( 0, 0, -1), { v3s16(1, 0, 0), v3s16(0, 0, 0) }},\n+\t};\n+\tstatic const UV base_vertices[4] = {\n+\t\t{ 0, 1 },\n+\t\t{ 1, 1 },\n+\t\t{ 1, 0 },\n+\t\t{ 0, 0 }\n+\t};\n+\tfor (int i = 0; i < 4; i++) {\n+\t\tconst LiquidFaceDesc &face = base_faces[i];\n+\t\tconst NeighborData &neighbor = liquid_neighbors[face.dir.Z + 1][face.dir.X + 1];\n+\n+\t\t// No face between nodes of the same liquid, unless there is node\n+\t\t// at the top to which it should be connected. Again, unless the face\n+\t\t// there would be inside the liquid\n+\t\tif (neighbor.is_same_liquid) {\n+\t\t\tif (!flowing)\n+\t\t\t\tcontinue;\n+\t\t\tif (!top_is_same_liquid)\n+\t\t\t\tcontinue;\n+\t\t\tif (neighbor.top_is_same_liquid)\n+\t\t\t\tcontinue;\n+\t\t}\n \n-\t\t\t// Corner heights (average between four liquids)\n-\t\t\tf32 corner_levels[4];\n+\t\tif (!flowing && (neighbor.content == CONTENT_IGNORE))\n+\t\t\tcontinue;\n \n-\t\t\tv3s16 halfdirs[4] = {\n-\t\t\t\tv3s16(0,0,0),\n-\t\t\t\tv3s16(1,0,0),\n-\t\t\t\tv3s16(1,0,1),\n-\t\t\t\tv3s16(0,0,1),\n-\t\t\t};\n-\t\t\tfor(u32 i=0; i<4; i++)\n-\t\t\t{\n-\t\t\t\tv3s16 cornerdir = halfdirs[i];\n-\t\t\t\tfloat cornerlevel = 0;\n-\t\t\t\tu32 valid_count = 0;\n-\t\t\t\tu32 air_count = 0;\n-\t\t\t\tfor(u32 j=0; j<4; j++)\n-\t\t\t\t{\n-\t\t\t\t\tv3s16 neighbordir = cornerdir - halfdirs[j];\n-\n-\t\t\t\t\tNeighborData &neighbor_data =\n-\t\t\t\t\t\tneighbor_data_matrix[NeighborToIndex(neighbordir)];\n-\t\t\t\t\tcontent_t content = neighbor_data.content;\n-\t\t\t\t\t// If top is liquid, draw starting from top of node\n-\t\t\t\t\tif (neighbor_data.flags & neighborflag_top_is_same_liquid)\n-\t\t\t\t\t{\n-\t\t\t\t\t\tcornerlevel = 0.5*BS;\n-\t\t\t\t\t\tvalid_count = 1;\n-\t\t\t\t\t\tbreak;\n-\t\t\t\t\t}\n-\t\t\t\t\t// Source is always the same height\n-\t\t\t\t\telse if(content == c_source)\n-\t\t\t\t\t{\n-\t\t\t\t\t\tcornerlevel = 0.5 * BS;\n-\t\t\t\t\t\tvalid_count = 1;\n-\t\t\t\t\t\tbreak;\n-\t\t\t\t\t}\n-\t\t\t\t\t// Flowing liquid has level information\n-\t\t\t\t\telse if(content == c_flowing)\n-\t\t\t\t\t{\n-\t\t\t\t\t\tcornerlevel += neighbor_data.level;\n-\t\t\t\t\t\tvalid_count++;\n-\t\t\t\t\t}\n-\t\t\t\t\telse if(content == CONTENT_AIR)\n-\t\t\t\t\t{\n-\t\t\t\t\t\tair_count++;\n-\t\t\t\t\t}\n-\t\t\t\t}\n-\t\t\t\tif(air_count >= 2)\n-\t\t\t\t\tcornerlevel = -0.5*BS+0.2;\n-\t\t\t\telse if(valid_count > 0)\n-\t\t\t\t\tcornerlevel /= valid_count;\n-\t\t\t\tcorner_levels[i] = cornerlevel;\n-\t\t\t}\n+\t\tconst ContentFeatures &neighbor_features = nodedef->get(neighbor.content);\n+\t\t// Don't draw face if neighbor is blocking the view\n+\t\tif (neighbor_features.solidness == 2)\n+\t\t\tcontinue;\n \n-\t\t\t/*\n-\t\t\t\tGenerate sides\n-\t\t\t*/\n+\t\tvideo::S3DVertex vertices[4];\n+\t\tfor (int j = 0; j < 4; j++) {\n+\t\t\tconst UV &vertex = base_vertices[j];\n+\t\t\tconst v3s16 &base = face.p[vertex.u];\n+\t\t\tv3f pos;\n+\t\t\tpos.X = (base.X - 0.5) * BS;\n+\t\t\tpos.Z = (base.Z - 0.5) * BS;\n+\t\t\tif (vertex.v)\n+\t\t\t\tpos.Y = neighbor.is_same_liquid ? corner_levels[base.Z][base.X] : -0.5 * BS;\n+\t\t\telse\n+\t\t\t\tpos.Y =     !top_is_same_liquid ? corner_levels[base.Z][base.X] :  0.5 * BS;\n+\t\t\tif (data->m_smooth_lighting)\n+\t\t\t\tcolor = blendLight(pos, tile_liquid.color);\n+\t\t\tpos += origin;\n+\t\t\tvertices[j] = video::S3DVertex(pos.X, pos.Y, pos.Z, 0, 0, 0, color, vertex.u, vertex.v);\n+\t\t};\n+\t\tstatic const u16 indices[] = { 0, 1, 2, 2, 3, 0 };\n+\t\tcollector->append(tile_liquid, vertices, 4, indices, 6);\n+\t}\n+}\n \n-\t\t\tv3s16 side_dirs[4] = {\n-\t\t\t\tv3s16(1,0,0),\n-\t\t\t\tv3s16(-1,0,0),\n-\t\t\t\tv3s16(0,0,1),\n-\t\t\t\tv3s16(0,0,-1),\n-\t\t\t};\n-\t\t\ts16 side_corners[4][2] = {\n-\t\t\t\t{1, 2},\n-\t\t\t\t{3, 0},\n-\t\t\t\t{2, 3},\n-\t\t\t\t{0, 1},\n-\t\t\t};\n-\t\t\tfor(u32 i=0; i<4; i++)\n-\t\t\t{\n-\t\t\t\tv3s16 dir = side_dirs[i];\n-\n-\t\t\t\tNeighborData& neighbor_data =\n-\t\t\t\t\tneighbor_data_matrix[NeighborToIndex(dir)];\n-\t\t\t\t/*\n-\t\t\t\t\tIf our topside is liquid and neighbor's topside\n-\t\t\t\t\tis liquid, don't draw side face\n-\t\t\t\t*/\n-\t\t\t\tif (top_is_same_liquid &&\n-\t\t\t\t\t\t(neighbor_data.flags & neighborflag_top_is_same_liquid))\n-\t\t\t\t\tcontinue;\n-\n-\t\t\t\tcontent_t neighbor_content = neighbor_data.content;\n-\t\t\t\tconst ContentFeatures &n_feat = nodedef->get(neighbor_content);\n-\n-\t\t\t\t// Don't draw face if neighbor is blocking the view\n-\t\t\t\tif(n_feat.solidness == 2)\n-\t\t\t\t\tcontinue;\n-\n-\t\t\t\tbool neighbor_is_same_liquid = (neighbor_content == c_source\n-\t\t\t\t\t\t|| neighbor_content == c_flowing);\n-\n-\t\t\t\t// Don't draw any faces if neighbor same is liquid and top is\n-\t\t\t\t// same liquid\n-\t\t\t\tif(neighbor_is_same_liquid == true\n-\t\t\t\t\t\t&& top_is_same_liquid == false)\n-\t\t\t\t\tcontinue;\n-\n-\t\t\t\t// Use backface culled material if neighbor doesn't have a\n-\t\t\t\t// solidness of 0\n-\t\t\t\tconst TileSpec *current_tile = &tile_liquid;\n-\t\t\t\tvideo::SColor *c = &c1;\n-\t\t\t\tif(n_feat.solidness != 0 || n_feat.visual_solidness != 0) {\n-\t\t\t\t\tcurrent_tile = &tile_liquid_bfculled;\n-\t\t\t\t\tc = &c2;\n-\t\t\t\t}\n-\n-\t\t\t\tvideo::S3DVertex vertices[4] =\n-\t\t\t\t{\n-\t\t\t\t\tvideo::S3DVertex(-BS/2,0,BS/2, 0,0,0, *c, 0,1),\n-\t\t\t\t\tvideo::S3DVertex(BS/2,0,BS/2, 0,0,0, *c, 1,1),\n-\t\t\t\t\tvideo::S3DVertex(BS/2,0,BS/2, 0,0,0, *c, 1,0),\n-\t\t\t\t\tvideo::S3DVertex(-BS/2,0,BS/2, 0,0,0, *c, 0,0),\n-\t\t\t\t};\n-\n-\t\t\t\t/*\n-\t\t\t\t\tIf our topside is liquid, set upper border of face\n-\t\t\t\t\tat upper border of node\n-\t\t\t\t*/\n-\t\t\t\tif(top_is_same_liquid)\n-\t\t\t\t{\n-\t\t\t\t\tvertices[2].Pos.Y = 0.5*BS;\n-\t\t\t\t\tvertices[3].Pos.Y = 0.5*BS;\n-\t\t\t\t}\n-\t\t\t\t/*\n-\t\t\t\t\tOtherwise upper position of face is corner levels\n-\t\t\t\t*/\n-\t\t\t\telse\n-\t\t\t\t{\n-\t\t\t\t\tvertices[2].Pos.Y = corner_levels[side_corners[i][0]];\n-\t\t\t\t\tvertices[3].Pos.Y = corner_levels[side_corners[i][1]];\n-\t\t\t\t}\n-\n-\t\t\t\t/*\n-\t\t\t\t\tIf neighbor is liquid, lower border of face is corner\n-\t\t\t\t\tliquid levels\n-\t\t\t\t*/\n-\t\t\t\tif(neighbor_is_same_liquid)\n-\t\t\t\t{\n-\t\t\t\t\tvertices[0].Pos.Y = corner_levels[side_corners[i][1]];\n-\t\t\t\t\tvertices[1].Pos.Y = corner_levels[side_corners[i][0]];\n-\t\t\t\t}\n-\t\t\t\t/*\n-\t\t\t\t\tIf neighbor is not liquid, lower border of face is\n-\t\t\t\t\tlower border of node\n-\t\t\t\t*/\n-\t\t\t\telse\n-\t\t\t\t{\n-\t\t\t\t\tvertices[0].Pos.Y = -0.5*BS;\n-\t\t\t\t\tvertices[1].Pos.Y = -0.5*BS;\n-\t\t\t\t}\n-\n-\t\t\t\tfor(s32 j=0; j<4; j++)\n-\t\t\t\t{\n-\t\t\t\t\tif(dir == v3s16(0,0,1))\n-\t\t\t\t\t\tvertices[j].Pos.rotateXZBy(0);\n-\t\t\t\t\tif(dir == v3s16(0,0,-1))\n-\t\t\t\t\t\tvertices[j].Pos.rotateXZBy(180);\n-\t\t\t\t\tif(dir == v3s16(-1,0,0))\n-\t\t\t\t\t\tvertices[j].Pos.rotateXZBy(90);\n-\t\t\t\t\tif(dir == v3s16(1,0,-0))\n-\t\t\t\t\t\tvertices[j].Pos.rotateXZBy(-90);\n-\n-\t\t\t\t\t// Do this to not cause glitches when two liquids are\n-\t\t\t\t\t// side-by-side\n-\t\t\t\t\t/*if(neighbor_is_same_liquid == false){\n-\t\t\t\t\t\tvertices[j].Pos.X *= 0.98;\n-\t\t\t\t\t\tvertices[j].Pos.Z *= 0.98;\n-\t\t\t\t\t}*/\n-\n-\t\t\t\t\tif (data->m_smooth_lighting)\n-\t\t\t\t\t\tvertices[j].Color = blendLight(frame, vertices[j].Pos, current_tile->color);\n-\t\t\t\t\tvertices[j].Pos += intToFloat(p, BS);\n-\t\t\t\t}\n-\n-\t\t\t\tu16 indices[] = {0,1,2,2,3,0};\n-\t\t\t\t// Add to mesh collector\n-\t\t\t\tcollector.append(*current_tile, vertices, 4, indices, 6);\n-\t\t\t}\n+void MapblockMeshGenerator::drawLiquidTop(bool flowing)\n+{\n+\t// To get backface culling right, the vertices need to go\n+\t// clockwise around the front of the face. And we happened to\n+\t// calculate corner levels in exact reverse order.\n+\tstatic const int corner_resolve[4][2] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};\n+\n+\tvideo::S3DVertex vertices[4] = {\n+\t\tvideo::S3DVertex(-BS/2, 0,  BS/2, 0,0,0, color_liquid_top, 0,1),\n+\t\tvideo::S3DVertex( BS/2, 0,  BS/2, 0,0,0, color_liquid_top, 1,1),\n+\t\tvideo::S3DVertex( BS/2, 0, -BS/2, 0,0,0, color_liquid_top, 1,0),\n+\t\tvideo::S3DVertex(-BS/2, 0, -BS/2, 0,0,0, color_liquid_top, 0,0),\n+\t};\n \n-\t\t\t/*\n-\t\t\t\tGenerate top side, if appropriate\n-\t\t\t*/\n-\n-\t\t\tif(top_is_same_liquid == false)\n-\t\t\t{\n-\t\t\t\tvideo::S3DVertex vertices[4] =\n-\t\t\t\t{\n-\t\t\t\t\tvideo::S3DVertex(-BS/2,0,BS/2, 0,0,0, c1, 0,1),\n-\t\t\t\t\tvideo::S3DVertex(BS/2,0,BS/2, 0,0,0, c1, 1,1),\n-\t\t\t\t\tvideo::S3DVertex(BS/2,0,-BS/2, 0,0,0, c1, 1,0),\n-\t\t\t\t\tvideo::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c1, 0,0),\n-\t\t\t\t};\n-\n-\t\t\t\t// To get backface culling right, the vertices need to go\n-\t\t\t\t// clockwise around the front of the face. And we happened to\n-\t\t\t\t// calculate corner levels in exact reverse order.\n-\t\t\t\ts32 corner_resolve[4] = {3,2,1,0};\n-\n-\t\t\t\tfor(s32 i=0; i<4; i++)\n-\t\t\t\t{\n-\t\t\t\t\t//vertices[i].Pos.Y += liquid_level;\n-\t\t\t\t\t//vertices[i].Pos.Y += neighbor_levels[v3s16(0,0,0)];\n-\t\t\t\t\ts32 j = corner_resolve[i];\n-\t\t\t\t\tvertices[i].Pos.Y += corner_levels[j];\n-\t\t\t\t\tif (data->m_smooth_lighting)\n-\t\t\t\t\t\tvertices[i].Color = blendLight(frame, vertices[i].Pos, tile_liquid.color);\n-\t\t\t\t\tvertices[i].Pos += intToFloat(p, BS);\n-\t\t\t\t}\n-\n-\t\t\t\t// Default downwards-flowing texture animation goes from\n-\t\t\t\t// -Z towards +Z, thus the direction is +Z.\n-\t\t\t\t// Rotate texture to make animation go in flow direction\n-\t\t\t\t// Positive if liquid moves towards +Z\n-\t\t\t\tf32 dz = (corner_levels[side_corners[3][0]] +\n-\t\t\t\t\t\tcorner_levels[side_corners[3][1]]) -\n-\t\t\t\t\t\t(corner_levels[side_corners[2][0]] +\n-\t\t\t\t\t\tcorner_levels[side_corners[2][1]]);\n-\t\t\t\t// Positive if liquid moves towards +X\n-\t\t\t\tf32 dx = (corner_levels[side_corners[1][0]] +\n-\t\t\t\t\t\tcorner_levels[side_corners[1][1]]) -\n-\t\t\t\t\t\t(corner_levels[side_corners[0][0]] +\n-\t\t\t\t\t\tcorner_levels[side_corners[0][1]]);\n-\t\t\t\tf32 tcoord_angle = atan2(dz, dx) * core::RADTODEG ;\n-\t\t\t\tv2f tcoord_center(0.5, 0.5);\n-\t\t\t\tv2f tcoord_translate(\n-\t\t\t\t\t\tblockpos_nodes.Z + z,\n-\t\t\t\t\t\tblockpos_nodes.X + x);\n-\t\t\t\ttcoord_translate.rotateBy(tcoord_angle);\n-\t\t\t\ttcoord_translate.X -= floor(tcoord_translate.X);\n-\t\t\t\ttcoord_translate.Y -= floor(tcoord_translate.Y);\n-\n-\t\t\t\tfor(s32 i=0; i<4; i++)\n-\t\t\t\t{\n-\t\t\t\t\tvertices[i].TCoords.rotateBy(\n-\t\t\t\t\t\t\ttcoord_angle,\n-\t\t\t\t\t\t\ttcoord_center);\n-\t\t\t\t\tvertices[i].TCoords += tcoord_translate;\n-\t\t\t\t}\n-\n-\t\t\t\tv2f t = vertices[0].TCoords;\n-\t\t\t\tvertices[0].TCoords = vertices[2].TCoords;\n-\t\t\t\tvertices[2].TCoords = t;\n-\n-\t\t\t\tu16 indices[] = {0,1,2,2,3,0};\n-\t\t\t\t// Add to mesh collector\n-\t\t\t\tcollector.append(tile_liquid, vertices, 4, indices, 6);\n-\t\t\t}\n-\t\tbreak;}\n-\t\tcase NDT_GLASSLIKE:\n-\t\t{\n-\t\t\tTileSpec tile = getNodeTile(n, p, v3s16(0,0,0), data);\n-\n-\t\t\tu16 l = getInteriorLight(n, 1, nodedef);\n-\t\t\tvideo::SColor c = encode_light_and_color(l, tile.color,\n-\t\t\t\tf.light_source);\n-\t\t\tfor(u32 j=0; j<6; j++)\n-\t\t\t{\n-\t\t\t\t// Check this neighbor\n-\t\t\t\tv3s16 dir = g_6dirs[j];\n-\t\t\t\tv3s16 n2p = blockpos_nodes + p + dir;\n-\t\t\t\tMapNode n2 = data->m_vmanip.getNodeNoEx(n2p);\n-\t\t\t\t// Don't make face if neighbor is of same type\n-\t\t\t\tif(n2.getContent() == n.getContent())\n-\t\t\t\t\tcontinue;\n-\t\t\t\tvideo::SColor c2=c;\n-\t\t\t\tif(!f.light_source)\n-\t\t\t\t\tapplyFacesShading(c2, v3f(dir.X, dir.Y, dir.Z));\n-\n-\n-\t\t\t\t// The face at Z+\n-\t\t\t\tvideo::S3DVertex vertices[4] = {\n-\t\t\t\t\tvideo::S3DVertex(-BS/2,-BS/2,BS/2, dir.X,dir.Y,dir.Z, c2, 1,1),\n-\t\t\t\t\tvideo::S3DVertex(BS/2,-BS/2,BS/2, dir.X,dir.Y,dir.Z, c2, 0,1),\n-\t\t\t\t\tvideo::S3DVertex(BS/2,BS/2,BS/2, dir.X,dir.Y,dir.Z, c2, 0,0),\n-\t\t\t\t\tvideo::S3DVertex(-BS/2,BS/2,BS/2, dir.X,dir.Y,dir.Z, c2, 1,0),\n-\t\t\t\t};\n-\n-\t\t\t\t// Rotations in the g_6dirs format\n-\t\t\t\tif(j == 0) // Z+\n-\t\t\t\t\tfor(u16 i=0; i<4; i++)\n-\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(0);\n-\t\t\t\telse if(j == 1) // Y+\n-\t\t\t\t\tfor(u16 i=0; i<4; i++)\n-\t\t\t\t\t\tvertices[i].Pos.rotateYZBy(-90);\n-\t\t\t\telse if(j == 2) // X+\n-\t\t\t\t\tfor(u16 i=0; i<4; i++)\n-\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(-90);\n-\t\t\t\telse if(j == 3) // Z-\n-\t\t\t\t\tfor(u16 i=0; i<4; i++)\n-\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(180);\n-\t\t\t\telse if(j == 4) // Y-\n-\t\t\t\t\tfor(u16 i=0; i<4; i++)\n-\t\t\t\t\t\tvertices[i].Pos.rotateYZBy(90);\n-\t\t\t\telse if(j == 5) // X-\n-\t\t\t\t\tfor(u16 i=0; i<4; i++)\n-\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(90);\n-\n-\t\t\t\tfor (u16 i = 0; i < 4; i++) {\n-\t\t\t\t\tif (data->m_smooth_lighting)\n-\t\t\t\t\t\tvertices[i].Color = blendLight(frame, vertices[i].Pos, vertices[i].Normal, tile.color);\n-\t\t\t\t\tvertices[i].Pos += intToFloat(p, BS);\n-\t\t\t\t}\n-\n-\t\t\t\tu16 indices[] = {0,1,2,2,3,0};\n-\t\t\t\t// Add to mesh collector\n-\t\t\t\tcollector.append(tile, vertices, 4, indices, 6);\n-\t\t\t}\n-\t\tbreak;}\n-\t\tcase NDT_GLASSLIKE_FRAMED_OPTIONAL:\n-\t\t\t// This is always pre-converted to something else\n-\t\t\tFATAL_ERROR(\"NDT_GLASSLIKE_FRAMED_OPTIONAL not pre-converted as expected\");\n-\t\t\tbreak;\n-\t\tcase NDT_GLASSLIKE_FRAMED:\n-\t\t{\n-\t\t\tstatic const v3s16 dirs[6] = {\n-\t\t\t\tv3s16( 0, 1, 0),\n-\t\t\t\tv3s16( 0,-1, 0),\n-\t\t\t\tv3s16( 1, 0, 0),\n-\t\t\t\tv3s16(-1, 0, 0),\n-\t\t\t\tv3s16( 0, 0, 1),\n-\t\t\t\tv3s16( 0, 0,-1)\n-\t\t\t};\n+\tfor (int i = 0; i < 4; i++) {\n+\t\tint u = corner_resolve[i][0];\n+\t\tint w = corner_resolve[i][1];\n+\t\tvertices[i].Pos.Y += corner_levels[w][u];\n+\t\tif (data->m_smooth_lighting)\n+\t\t\tvertices[i].Color = blendLight(vertices[i].Pos, tile_liquid_top.color);\n+\t\tvertices[i].Pos += origin;\n+\t}\n \n-\t\t\tu16 l = getInteriorLight(n, 1, nodedef);\n-\t\t\tu8 i;\n-\t\t\tTileSpec tiles[6];\n-\t\t\tfor (i = 0; i < 6; i++)\n-\t\t\t\ttiles[i] = getNodeTile(n, p, dirs[i], data);\n-\n-\t\t\tvideo::SColor tile0color = encode_light_and_color(l,\n-\t\t\t\ttiles[0].color, f.light_source);\n-\n-\t\t\tTileSpec glass_tiles[6];\n-\t\t\tvideo::SColor glasscolor[6];\n-\t\t\tif (tiles[1].texture && tiles[2].texture && tiles[3].texture) {\n-\t\t\t\tglass_tiles[0] = tiles[2];\n-\t\t\t\tglass_tiles[1] = tiles[3];\n-\t\t\t\tglass_tiles[2] = tiles[1];\n-\t\t\t\tglass_tiles[3] = tiles[1];\n-\t\t\t\tglass_tiles[4] = tiles[1];\n-\t\t\t\tglass_tiles[5] = tiles[1];\n-\t\t\t} else {\n-\t\t\t\tfor (i = 0; i < 6; i++)\n-\t\t\t\t\tglass_tiles[i] = tiles[1];\n-\t\t\t}\n-\t\t\tfor (i = 0; i < 6; i++)\n-\t\t\t\tglasscolor[i] = encode_light_and_color(l, glass_tiles[i].color,\n-\t\t\t\t\tf.light_source);\n-\n-\t\t\tu8 param2 = n.getParam2();\n-\t\t\tbool H_merge = ! bool(param2 & 128);\n-\t\t\tbool V_merge = ! bool(param2 & 64);\n-\t\t\tparam2  = param2 & 63;\n-\n-\t\t\tv3f pos = intToFloat(p, BS);\n-\t\t\tstatic const float a = BS / 2;\n-\t\t\tstatic const float g = a - 0.003;\n-\t\t\tstatic const float b = .876 * ( BS / 2 );\n-\n-\t\t\tstatic const aabb3f frame_edges[12] = {\n-\t\t\t\taabb3f( b, b,-a, a, a, a), // y+\n-\t\t\t\taabb3f(-a, b,-a,-b, a, a), // y+\n-\t\t\t\taabb3f( b,-a,-a, a,-b, a), // y-\n-\t\t\t\taabb3f(-a,-a,-a,-b,-b, a), // y-\n-\t\t\t\taabb3f( b,-a, b, a, a, a), // x+\n-\t\t\t\taabb3f( b,-a,-a, a, a,-b), // x+\n-\t\t\t\taabb3f(-a,-a, b,-b, a, a), // x-\n-\t\t\t\taabb3f(-a,-a,-a,-b, a,-b), // x-\n-\t\t\t\taabb3f(-a, b, b, a, a, a), // z+\n-\t\t\t\taabb3f(-a,-a, b, a,-b, a), // z+\n-\t\t\t\taabb3f(-a,-a,-a, a,-b,-b), // z-\n-\t\t\t\taabb3f(-a, b,-a, a, a,-b)  // z-\n-\t\t\t};\n-\t\t\tstatic const aabb3f glass_faces[6] = {\n-\t\t\t\taabb3f(-g, g,-g, g, g, g), // y+\n-\t\t\t\taabb3f(-g,-g,-g, g,-g, g), // y-\n-\t\t\t\taabb3f( g,-g,-g, g, g, g), // x+\n-\t\t\t\taabb3f(-g,-g,-g,-g, g, g), // x-\n-\t\t\t\taabb3f(-g,-g, g, g, g, g), // z+\n-\t\t\t\taabb3f(-g,-g,-g, g, g,-g)  // z-\n-\t\t\t};\n+\tif (flowing) {\n+\t\t// Default downwards-flowing texture animation goes from\n+\t\t// -Z towards +Z, thus the direction is +Z.\n+\t\t// Rotate texture to make animation go in flow direction\n+\t\t// Positive if liquid moves towards +Z\n+\t\tf32 dz = (corner_levels[0][0] + corner_levels[0][1]) -\n+\t\t         (corner_levels[1][0] + corner_levels[1][1]);\n+\t\t// Positive if liquid moves towards +X\n+\t\tf32 dx = (corner_levels[0][0] + corner_levels[1][0]) -\n+\t\t         (corner_levels[0][1] + corner_levels[1][1]);\n+\t\tf32 tcoord_angle = atan2(dz, dx) * core::RADTODEG;\n+\t\tv2f tcoord_center(0.5, 0.5);\n+\t\tv2f tcoord_translate(blockpos_nodes.Z + p.Z, blockpos_nodes.X + p.X);\n+\t\ttcoord_translate.rotateBy(tcoord_angle);\n+\t\ttcoord_translate.X -= floor(tcoord_translate.X);\n+\t\ttcoord_translate.Y -= floor(tcoord_translate.Y);\n+\n+\t\tfor (int i = 0; i < 4; i++) {\n+\t\t\tvertices[i].TCoords.rotateBy(tcoord_angle, tcoord_center);\n+\t\t\tvertices[i].TCoords += tcoord_translate;\n+\t\t}\n \n-\t\t\t// table of node visible faces, 0 = invisible\n-\t\t\tint visible_faces[6] = {0,0,0,0,0,0};\n-\n-\t\t\t// table of neighbours, 1 = same type, checked with g_26dirs\n-\t\t\tint nb[18] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};\n-\n-\t\t\t// g_26dirs to check when only horizontal merge is allowed\n-\t\t\tint nb_H_dirs[8] = {0,2,3,5,10,11,12,13};\n-\n-\t\t\tcontent_t current = n.getContent();\n-\t\t\tcontent_t n2c;\n-\t\t\tMapNode n2;\n-\t\t\tv3s16 n2p;\n-\n-\t\t\t// neighbours checks for frames visibility\n-\n-\t\t\tif (!H_merge && V_merge) {\n-\t\t\t\tn2p = blockpos_nodes + p + g_26dirs[1];\n-\t\t\t\tn2 = data->m_vmanip.getNodeNoEx(n2p);\n-\t\t\t\tn2c = n2.getContent();\n-\t\t\t\tif (n2c == current || n2c == CONTENT_IGNORE)\n-\t\t\t\t\tnb[1] = 1;\n-\t\t\t\tn2p = blockpos_nodes + p + g_26dirs[4];\n-\t\t\t\tn2 = data->m_vmanip.getNodeNoEx(n2p);\n-\t\t\t\tn2c = n2.getContent();\n-\t\t\t\tif (n2c == current || n2c == CONTENT_IGNORE)\n-\t\t\t\t\tnb[4] = 1;\n-\t\t\t} else if (H_merge && !V_merge) {\n-\t\t\t\tfor(i = 0; i < 8; i++) {\n-\t\t\t\t\tn2p = blockpos_nodes + p + g_26dirs[nb_H_dirs[i]];\n-\t\t\t\t\tn2 = data->m_vmanip.getNodeNoEx(n2p);\n-\t\t\t\t\tn2c = n2.getContent();\n-\t\t\t\t\tif (n2c == current || n2c == CONTENT_IGNORE)\n-\t\t\t\t\t\tnb[nb_H_dirs[i]] = 1;\n-\t\t\t\t}\n-\t\t\t} else if (H_merge && V_merge) {\n-\t\t\t\tfor(i = 0; i < 18; i++)\t{\n-\t\t\t\t\tn2p = blockpos_nodes + p + g_26dirs[i];\n-\t\t\t\t\tn2 = data->m_vmanip.getNodeNoEx(n2p);\n-\t\t\t\t\tn2c = n2.getContent();\n-\t\t\t\t\tif (n2c == current || n2c == CONTENT_IGNORE)\n-\t\t\t\t\t\tnb[i] = 1;\n-\t\t\t\t}\n-\t\t\t}\n+\t\tstd::swap(vertices[0].TCoords, vertices[2].TCoords);\n+\t}\n \n-\t\t\t// faces visibility checks\n-\n-\t\t\tif (!V_merge) {\n-\t\t\t\tvisible_faces[0] = 1;\n-\t\t\t\tvisible_faces[1] = 1;\n-\t\t\t} else {\n-\t\t\t\tfor(i = 0; i < 2; i++) {\n-\t\t\t\t\tn2p = blockpos_nodes + p + dirs[i];\n-\t\t\t\t\tn2 = data->m_vmanip.getNodeNoEx(n2p);\n-\t\t\t\t\tn2c = n2.getContent();\n-\t\t\t\t\tif (n2c != current)\n-\t\t\t\t\t\tvisible_faces[i] = 1;\n-\t\t\t\t}\n-\t\t\t}\n+\tstatic const u16 indices[] = { 0, 1, 2, 2, 3, 0 };\n+\tcollector->append(tile_liquid_top, vertices, 4, indices, 6);\n+}\n \n-\t\t\tif (!H_merge) {\n-\t\t\t\tvisible_faces[2] = 1;\n-\t\t\t\tvisible_faces[3] = 1;\n-\t\t\t\tvisible_faces[4] = 1;\n-\t\t\t\tvisible_faces[5] = 1;\n-\t\t\t} else {\n-\t\t\t\tfor(i = 2; i < 6; i++) {\n-\t\t\t\t\tn2p = blockpos_nodes + p + dirs[i];\n-\t\t\t\t\tn2 = data->m_vmanip.getNodeNoEx(n2p);\n-\t\t\t\t\tn2c = n2.getContent();\n-\t\t\t\t\tif (n2c != current)\n-\t\t\t\t\t\tvisible_faces[i] = 1;\n-\t\t\t\t}\n-\t\t\t}\n+void MapblockMeshGenerator::drawLiquidNode(bool flowing)\n+{\n+\tprepareLiquidNodeDrawing(flowing);\n+\tgetLiquidNeighborhood(flowing);\n+\tif (flowing)\n+\t\tcalculateCornerLevels();\n+\telse\n+\t\tresetCornerLevels();\n+\tdrawLiquidSides(flowing);\n+\tif (!top_is_same_liquid)\n+\t\tdrawLiquidTop(flowing);\n+}\n \n-\t\t\tstatic const u8 nb_triplet[12*3] = {\n-\t\t\t\t1,2, 7,  1,5, 6,  4,2,15,  4,5,14,\n-\t\t\t\t2,0,11,  2,3,13,  5,0,10,  5,3,12,\n-\t\t\t\t0,1, 8,  0,4,16,  3,4,17,  3,1, 9\n+void MapblockMeshGenerator::drawGlasslikeNode()\n+{\n+\tuseDefaultTile();\n+\n+\tfor (int face = 0; face < 6; face++) {\n+\t\t// Check this neighbor\n+\t\tv3s16 dir = g_6dirs[face];\n+\t\tv3s16 neighbor_pos = blockpos_nodes + p + dir;\n+\t\tMapNode neighbor = data->m_vmanip.getNodeNoExNoEmerge(neighbor_pos);\n+\t\t// Don't make face if neighbor is of same type\n+\t\tif (neighbor.getContent() == n.getContent())\n+\t\t\tcontinue;\n+\t\tv3f vertices[4] = {\n+\t\t\tv3f(-BS/2, -BS/2, BS/2),\n+\t\t\tv3f( BS/2, -BS/2, BS/2),\n+\t\t\tv3f( BS/2,  BS/2, BS/2),\n+\t\t\tv3f(-BS/2,  BS/2, BS/2),\n+\t\t};\n+\t\tfor (int i = 0; i < 4; i++) {\n+\t\t\t// Rotations in the g_6dirs format\n+\t\t\tswitch (face) {\n+\t\t\t\tcase 0: vertices[i].rotateXZBy(  0); break; // Z+\n+\t\t\t\tcase 1: vertices[i].rotateYZBy(-90); break; // Y+\n+\t\t\t\tcase 2: vertices[i].rotateXZBy(-90); break; // X+\n+\t\t\t\tcase 3: vertices[i].rotateXZBy(180); break; // Z-\n+\t\t\t\tcase 4: vertices[i].rotateYZBy( 90); break; // Y-\n+\t\t\t\tcase 5: vertices[i].rotateXZBy( 90); break; // X-\n \t\t\t};\n+\t\t}\n+\t\tdrawQuad(vertices, dir);\n+\t}\n+}\n \n-\t\t\taabb3f box;\n-\n-\t\t\tfor(i = 0; i < 12; i++)\n-\t\t\t{\n-\t\t\t\tint edge_invisible;\n-\t\t\t\tif (nb[nb_triplet[i*3+2]])\n-\t\t\t\t\tedge_invisible = nb[nb_triplet[i*3]] & nb[nb_triplet[i*3+1]];\n-\t\t\t\telse\n-\t\t\t\t\tedge_invisible = nb[nb_triplet[i*3]] ^ nb[nb_triplet[i*3+1]];\n-\t\t\t\tif (edge_invisible)\n-\t\t\t\t\tcontinue;\n-\t\t\t\tbox = frame_edges[i];\n-\t\t\t\tmakeAutoLightedCuboid(&collector, data, pos, box, tiles[0], tile0color, frame);\n-\t\t\t}\n-\n-\t\t\tfor(i = 0; i < 6; i++)\n-\t\t\t{\n-\t\t\t\tif (!visible_faces[i])\n-\t\t\t\t\tcontinue;\n-\t\t\t\tbox = glass_faces[i];\n-\t\t\t\tmakeAutoLightedCuboid(&collector, data, pos, box, glass_tiles[i], glasscolor[i], frame);\n-\t\t\t}\n+void MapblockMeshGenerator::drawGlasslikeFramedNode()\n+{\n+\tTileSpec tiles[6];\n+\tfor (int face = 0; face < 6; face++)\n+\t\ttiles[face] = getTile(g_6dirs[face]);\n+\n+\tTileSpec glass_tiles[6];\n+\tif (tiles[0].texture && tiles[3].texture && tiles[4].texture) {\n+\t\tglass_tiles[0] = tiles[4];\n+\t\tglass_tiles[1] = tiles[0];\n+\t\tglass_tiles[2] = tiles[4];\n+\t\tglass_tiles[3] = tiles[4];\n+\t\tglass_tiles[4] = tiles[3];\n+\t\tglass_tiles[5] = tiles[4];\n+\t} else {\n+\t\tfor (int face = 0; face < 6; face++)\n+\t\t\tglass_tiles[face] = tiles[4];\n+\t}\n \n-\t\t\tif (param2 > 0 && f.special_tiles[0].texture) {\n-\t\t\t\t// Interior volume level is in range 0 .. 63,\n-\t\t\t\t// convert it to -0.5 .. 0.5\n-\t\t\t\tfloat vlev = (((float)param2 / 63.0 ) * 2.0 - 1.0);\n-\t\t\t\tTileSpec tile = getSpecialTile(f, n, 0);\n-\t\t\t\tvideo::SColor special_color = encode_light_and_color(l,\n-\t\t\t\t\ttile.color, f.light_source);\n-\t\t\t\tfloat offset = 0.003;\n-\t\t\t\tbox = aabb3f(visible_faces[3] ? -b : -a + offset,\n-\t\t\t\t\t\t\t visible_faces[1] ? -b : -a + offset,\n-\t\t\t\t\t\t\t visible_faces[5] ? -b : -a + offset,\n-\t\t\t\t\t\t\t visible_faces[2] ? b : a - offset,\n-\t\t\t\t\t\t\t visible_faces[0] ? b * vlev : a * vlev - offset,\n-\t\t\t\t\t\t\t visible_faces[4] ? b : a - offset);\n-\t\t\t\tmakeAutoLightedCuboid(&collector, data, pos, box, tile, special_color, frame);\n-\t\t\t}\n-\t\tbreak;}\n-\t\tcase NDT_ALLFACES:\n-\t\t{\n-\t\t\tTileSpec tile_leaves = getNodeTile(n, p,\n-\t\t\t\t\tv3s16(0,0,0), data);\n-\t\t\tu16 l = getInteriorLight(n, 1, nodedef);\n-\t\t\tvideo::SColor c = encode_light_and_color(l,\n-\t\t\t\ttile_leaves.color, f.light_source);\n-\n-\t\t\tv3f pos = intToFloat(p, BS);\n-\t\t\taabb3f box(-BS/2,-BS/2,-BS/2,BS/2,BS/2,BS/2);\n-\t\t\tmakeAutoLightedCuboid(&collector, data, pos, box, tile_leaves, c, frame);\n-\t\tbreak;}\n-\t\tcase NDT_ALLFACES_OPTIONAL:\n-\t\t\t// This is always pre-converted to something else\n-\t\t\tFATAL_ERROR(\"NDT_ALLFACES_OPTIONAL not pre-converted\");\n-\t\t\tbreak;\n-\t\tcase NDT_TORCHLIKE:\n-\t\t{\n-\t\t\tv3s16 dir = n.getWallMountedDir(nodedef);\n-\n-\t\t\tu8 tileindex = 0;\n-\t\t\tif(dir == v3s16(0,-1,0)){\n-\t\t\t\ttileindex = 0; // floor\n-\t\t\t} else if(dir == v3s16(0,1,0)){\n-\t\t\t\ttileindex = 1; // ceiling\n-\t\t\t// For backwards compatibility\n-\t\t\t} else if(dir == v3s16(0,0,0)){\n-\t\t\t\ttileindex = 0; // floor\n-\t\t\t} else {\n-\t\t\t\ttileindex = 2; // side\n-\t\t\t}\n+\tu8 param2 = n.getParam2();\n+\tbool H_merge = !(param2 & 128);\n+\tbool V_merge = !(param2 & 64);\n+\tparam2 &= 63;\n+\n+\tstatic const float a = BS / 2;\n+\tstatic const float g = a - 0.003;\n+\tstatic const float b = .876 * ( BS / 2 );\n+\n+\tstatic const aabb3f frame_edges[12] = {\n+\t\taabb3f( b, b,-a, a, a, a), // y+\n+\t\taabb3f(-a, b,-a,-b, a, a), // y+\n+\t\taabb3f( b,-a,-a, a,-b, a), // y-\n+\t\taabb3f(-a,-a,-a,-b,-b, a), // y-\n+\t\taabb3f( b,-a, b, a, a, a), // x+\n+\t\taabb3f( b,-a,-a, a, a,-b), // x+\n+\t\taabb3f(-a,-a, b,-b, a, a), // x-\n+\t\taabb3f(-a,-a,-a,-b, a,-b), // x-\n+\t\taabb3f(-a, b, b, a, a, a), // z+\n+\t\taabb3f(-a,-a, b, a,-b, a), // z+\n+\t\taabb3f(-a,-a,-a, a,-b,-b), // z-\n+\t\taabb3f(-a, b,-a, a, a,-b), // z-\n+\t};\n+\tstatic const aabb3f glass_faces[6] = {\n+\t\taabb3f(-g,-g, g, g, g, g), // z+\n+\t\taabb3f(-g, g,-g, g, g, g), // y+\n+\t\taabb3f( g,-g,-g, g, g, g), // x+\n+\t\taabb3f(-g,-g,-g, g, g,-g), // z-\n+\t\taabb3f(-g,-g,-g, g,-g, g), // y-\n+\t\taabb3f(-g,-g,-g,-g, g, g), // x-\n+\t};\n \n-\t\t\tTileSpec tile = getNodeTileN(n, p, tileindex, data);\n-\t\t\ttile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;\n-\t\t\ttile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;\n-\n-\t\t\tu16 l = getInteriorLight(n, 1, nodedef);\n-\t\t\tvideo::SColor c = encode_light_and_color(l, tile.color,\n-\t\t\t\tf.light_source);\n-\n-\t\t\tfloat s = BS/2*f.visual_scale;\n-\t\t\t// Wall at X+ of node\n-\t\t\tvideo::S3DVertex vertices[4] =\n-\t\t\t{\n-\t\t\t\tvideo::S3DVertex(-s,-s,0, 0,0,0, c, 0,1),\n-\t\t\t\tvideo::S3DVertex( s,-s,0, 0,0,0, c, 1,1),\n-\t\t\t\tvideo::S3DVertex( s, s,0, 0,0,0, c, 1,0),\n-\t\t\t\tvideo::S3DVertex(-s, s,0, 0,0,0, c, 0,0),\n-\t\t\t};\n+\t// tables of neighbour (connect if same type and merge allowed),\n+\t// checked with g_26dirs\n+\n+\t// 1 = connect, 0 = face visible\n+\tbool nb[18] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };\n+\n+\t// 1 = check\n+\tstatic const bool check_nb_vertical   [18] = { 0,1,0,0,1,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };\n+\tstatic const bool check_nb_horizontal [18] = { 1,0,1,1,0,1, 0,0,0,0, 1,1,1,1, 0,0,0,0 };\n+\tstatic const bool check_nb_all        [18] = { 1,1,1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1 };\n+\tconst bool *check_nb = check_nb_all;\n+\n+\t// neighbours checks for frames visibility\n+\tif (H_merge || V_merge) {\n+\t\tif (!H_merge)\n+\t\t\tcheck_nb = check_nb_vertical; // vertical-only merge\n+\t\tif (!V_merge)\n+\t\t\tcheck_nb = check_nb_horizontal; // horizontal-only merge\n+\t\tcontent_t current = n.getContent();\n+\t\tfor (int i = 0; i < 18; i++) {\n+\t\t\tif (!check_nb[i])\n+\t\t\t\tcontinue;\n+\t\t\tv3s16 n2p = blockpos_nodes + p + g_26dirs[i];\n+\t\t\tMapNode n2 = data->m_vmanip.getNodeNoEx(n2p);\n+\t\t\tcontent_t n2c = n2.getContent();\n+\t\t\tif (n2c == current || n2c == CONTENT_IGNORE)\n+\t\t\t\tnb[i] = 1;\n+\t\t}\n+\t}\n \n-\t\t\tfor (s32 i = 0; i < 4; i++)\n-\t\t\t{\n-\t\t\t\tif(dir == v3s16(1,0,0))\n-\t\t\t\t\tvertices[i].Pos.rotateXZBy(0);\n-\t\t\t\tif(dir == v3s16(-1,0,0))\n-\t\t\t\t\tvertices[i].Pos.rotateXZBy(180);\n-\t\t\t\tif(dir == v3s16(0,0,1))\n-\t\t\t\t\tvertices[i].Pos.rotateXZBy(90);\n-\t\t\t\tif(dir == v3s16(0,0,-1))\n-\t\t\t\t\tvertices[i].Pos.rotateXZBy(-90);\n-\t\t\t\tif(dir == v3s16(0,-1,0))\n-\t\t\t\t\tvertices[i].Pos.rotateXZBy(45);\n-\t\t\t\tif(dir == v3s16(0,1,0))\n-\t\t\t\t\tvertices[i].Pos.rotateXZBy(-45);\n-\n-\t\t\t\tif (data->m_smooth_lighting)\n-\t\t\t\t\tvertices[i].Color = blendLight(frame, vertices[i].Pos, tile.color);\n-\t\t\t\tvertices[i].Pos += intToFloat(p, BS);\n-\t\t\t}\n+\t// edge visibility\n \n-\t\t\tu16 indices[] = {0,1,2,2,3,0};\n-\t\t\t// Add to mesh collector\n-\t\t\tcollector.append(tile, vertices, 4, indices, 6);\n-\t\tbreak;}\n-\t\tcase NDT_SIGNLIKE:\n-\t\t{\n-\t\t\tTileSpec tile = getNodeTileN(n, p, 0, data);\n-\t\t\ttile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;\n-\t\t\ttile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;\n-\n-\t\t\tu16 l = getInteriorLight(n, 0, nodedef);\n-\t\t\tvideo::SColor c = encode_light_and_color(l, tile.color,\n-\t\t\t\tf.light_source);\n-\n-\t\t\tfloat d = (float)BS/16;\n-\t\t\tfloat s = BS/2*f.visual_scale;\n-\t\t\t// Wall at X+ of node\n-\t\t\tvideo::S3DVertex vertices[4] =\n-\t\t\t{\n-\t\t\t\tvideo::S3DVertex(BS/2-d,  s,  s, 0,0,0, c, 0,0),\n-\t\t\t\tvideo::S3DVertex(BS/2-d,  s, -s, 0,0,0, c, 1,0),\n-\t\t\t\tvideo::S3DVertex(BS/2-d, -s, -s, 0,0,0, c, 1,1),\n-\t\t\t\tvideo::S3DVertex(BS/2-d, -s,  s, 0,0,0, c, 0,1),\n-\t\t\t};\n+\tstatic const u8 nb_triplet[12*3] = {\n+\t\t1,2, 7,  1,5, 6,  4,2,15,  4,5,14,\n+\t\t2,0,11,  2,3,13,  5,0,10,  5,3,12,\n+\t\t0,1, 8,  0,4,16,  3,4,17,  3,1, 9\n+\t};\n \n-\t\t\tv3s16 dir = n.getWallMountedDir(nodedef);\n-\n-\t\t\tfor (s32 i = 0; i < 4; i++)\n-\t\t\t{\n-\t\t\t\tif(dir == v3s16(1,0,0))\n-\t\t\t\t\tvertices[i].Pos.rotateXZBy(0);\n-\t\t\t\tif(dir == v3s16(-1,0,0))\n-\t\t\t\t\tvertices[i].Pos.rotateXZBy(180);\n-\t\t\t\tif(dir == v3s16(0,0,1))\n-\t\t\t\t\tvertices[i].Pos.rotateXZBy(90);\n-\t\t\t\tif(dir == v3s16(0,0,-1))\n-\t\t\t\t\tvertices[i].Pos.rotateXZBy(-90);\n-\t\t\t\tif(dir == v3s16(0,-1,0))\n-\t\t\t\t\tvertices[i].Pos.rotateXYBy(-90);\n-\t\t\t\tif(dir == v3s16(0,1,0))\n-\t\t\t\t\tvertices[i].Pos.rotateXYBy(90);\n-\n-\t\t\t\tif (data->m_smooth_lighting)\n-\t\t\t\t\tvertices[i].Color = blendLight(frame, vertices[i].Pos, tile.color);\n-\t\t\t\tvertices[i].Pos += intToFloat(p, BS);\n-\t\t\t}\n+\ttile = tiles[1];\n+\tfor (int edge = 0; edge < 12; edge++) {\n+\t\tbool edge_invisible;\n+\t\tif (nb[nb_triplet[edge * 3 + 2]])\n+\t\t\tedge_invisible = nb[nb_triplet[edge * 3]] & nb[nb_triplet[edge * 3 + 1]];\n+\t\telse\n+\t\t\tedge_invisible = nb[nb_triplet[edge * 3]] ^ nb[nb_triplet[edge * 3 + 1]];\n+\t\tif (edge_invisible)\n+\t\t\tcontinue;\n+\t\tdrawAutoLightedCuboid(frame_edges[edge]);\n+\t}\n \n-\t\t\tu16 indices[] = {0,1,2,2,3,0};\n-\t\t\t// Add to mesh collector\n-\t\t\tcollector.append(tile, vertices, 4, indices, 6);\n-\t\tbreak;}\n-\t\tcase NDT_PLANTLIKE:\n-\t\t{\n-\t\t\tPseudoRandom rng(x<<8 | z | y<<16);\n-\n-\t\t\tTileSpec tile = getNodeTileN(n, p, 0, data);\n-\t\t\ttile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;\n-\n-\t\t\tu16 l = getInteriorLight(n, 1, nodedef);\n-\t\t\tvideo::SColor c = encode_light_and_color(l, tile.color,\n-\t\t\t\tf.light_source);\n-\n-\t\t\tfloat s = BS / 2 * f.visual_scale;\n-\t\t\t// add sqrt(2) visual scale\n-\t\t\tif ((f.param_type_2 == CPT2_MESHOPTIONS) && ((n.param2 & 0x10) != 0))\n-\t\t\t\ts *= 1.41421;\n-\n-\t\t\tfloat random_offset_X = .0;\n-\t\t\tfloat random_offset_Z = .0;\n-\t\t\tif ((f.param_type_2 == CPT2_MESHOPTIONS) && ((n.param2 & 0x8) != 0)) {\n-\t\t\t\trandom_offset_X = BS * ((rng.next() % 16 / 16.0) * 0.29 - 0.145);\n-\t\t\t\trandom_offset_Z = BS * ((rng.next() % 16 / 16.0) * 0.29 - 0.145);\n-\t\t\t}\n+\tfor (int face = 0; face < 6; face++) {\n+\t\tif (nb[face])\n+\t\t\tcontinue;\n+\t\ttile = glass_tiles[face];\n+\t\tdrawAutoLightedCuboid(glass_faces[face]);\n+\t}\n \n-\t\t\tfor (int j = 0; j < 4; j++) {\n-\t\t\t\tvideo::S3DVertex vertices[4] =\n-\t\t\t\t{\n-\t\t\t\t\tvideo::S3DVertex(-s,-BS/2, 0, 0,0,0, c, 0,1),\n-\t\t\t\t\tvideo::S3DVertex( s,-BS/2, 0, 0,0,0, c, 1,1),\n-\t\t\t\t\tvideo::S3DVertex( s,-BS/2 + s*2,0, 0,0,0, c, 1,0),\n-\t\t\t\t\tvideo::S3DVertex(-s,-BS/2 + s*2,0, 0,0,0, c, 0,0),\n-\t\t\t\t};\n-\n-\t\t\t\tfloat rotate_degree = 0;\n-\t\t\t\tu8 p2mesh = 0;\n-\t\t\t\tif (f.param_type_2 == CPT2_DEGROTATE)\n-\t\t\t\t\trotate_degree = n.param2 * 2;\n-\t\t\t\tif (f.param_type_2 != CPT2_MESHOPTIONS) {\n-\t\t\t\t\tif (j == 0) {\n-\t\t\t\t\t\tfor (u16 i = 0; i < 4; i++)\n-\t\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(46 + rotate_degree);\n-\t\t\t\t\t} else if (j == 1) {\n-\t\t\t\t\t\tfor (u16 i = 0; i < 4; i++)\n-\t\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(-44 + rotate_degree);\n-\t\t\t\t\t}\n-\t\t\t\t} else {\n-\t\t\t\t\tp2mesh = n.param2 & 0x7;\n-\t\t\t\t\tswitch (p2mesh) {\n-\t\t\t\t\tcase 0:\n-\t\t\t\t\t\t// x\n-\t\t\t\t\t\tif (j == 0) {\n-\t\t\t\t\t\t\tfor (u16 i = 0; i < 4; i++)\n-\t\t\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(46);\n-\t\t\t\t\t\t} else if (j == 1) {\n-\t\t\t\t\t\t\tfor (u16 i = 0; i < 4; i++)\n-\t\t\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(-44);\n-\t\t\t\t\t\t}\n-\t\t\t\t\t\tbreak;\n-\t\t\t\t\tcase 1:\n-\t\t\t\t\t\t// +\n-\t\t\t\t\t\tif (j == 0) {\n-\t\t\t\t\t\t\tfor (u16 i = 0; i < 4; i++)\n-\t\t\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(91);\n-\t\t\t\t\t\t} else if (j == 1) {\n-\t\t\t\t\t\t\tfor (u16 i = 0; i < 4; i++)\n-\t\t\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(1);\n-\t\t\t\t\t\t}\n-\t\t\t\t\t\tbreak;\n-\t\t\t\t\tcase 2:\n-\t\t\t\t\t\t// *\n-\t\t\t\t\t\tif (j == 0) {\n-\t\t\t\t\t\t\tfor (u16 i = 0; i < 4; i++)\n-\t\t\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(121);\n-\t\t\t\t\t\t} else if (j == 1) {\n-\t\t\t\t\t\t\tfor (u16 i = 0; i < 4; i++)\n-\t\t\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(241);\n-\t\t\t\t\t\t} else { // (j == 2)\n-\t\t\t\t\t\t\tfor (u16 i = 0; i < 4; i++)\n-\t\t\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(1);\n-\t\t\t\t\t\t}\n-\t\t\t\t\t\tbreak;\n-\t\t\t\t\tcase 3:\n-\t\t\t\t\t\t// #\n-\t\t\t\t\t\tswitch (j) {\n-\t\t\t\t\t\tcase 0:\n-\t\t\t\t\t\t\tfor (u16 i = 0; i < 4; i++) {\n-\t\t\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(1);\n-\t\t\t\t\t\t\t\tvertices[i].Pos.Z += BS / 4;\n-\t\t\t\t\t\t\t}\n-\t\t\t\t\t\t\tbreak;\n-\t\t\t\t\t\tcase 1:\n-\t\t\t\t\t\t\tfor (u16 i = 0; i < 4; i++) {\n-\t\t\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(91);\n-\t\t\t\t\t\t\t\tvertices[i].Pos.X += BS / 4;\n-\t\t\t\t\t\t\t}\n-\t\t\t\t\t\t\tbreak;\n-\t\t\t\t\t\tcase 2:\n-\t\t\t\t\t\t\tfor (u16 i = 0; i < 4; i++) {\n-\t\t\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(181);\n-\t\t\t\t\t\t\t\tvertices[i].Pos.Z -= BS / 4;\n-\t\t\t\t\t\t\t}\n-\t\t\t\t\t\t\tbreak;\n-\t\t\t\t\t\tcase 3:\n-\t\t\t\t\t\t\tfor (u16 i = 0; i < 4; i++) {\n-\t\t\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(271);\n-\t\t\t\t\t\t\t\tvertices[i].Pos.X -= BS / 4;\n-\t\t\t\t\t\t\t}\n-\t\t\t\t\t\t\tbreak;\n-\t\t\t\t\t\t}\n-\t\t\t\t\t\tbreak;\n-\t\t\t\t\tcase 4:\n-\t\t\t\t\t\t// outward leaning #-like\n-\t\t\t\t\t\tswitch (j) {\n-\t\t\t\t\t\tcase 0:\n-\t\t\t\t\t\t\tfor (u16 i = 2; i < 4; i++)\n-\t\t\t\t\t\t\t\tvertices[i].Pos.Z -= BS / 2;\n-\t\t\t\t\t\t\tfor (u16 i = 0; i < 4; i++)\n-\t\t\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(1);\n-\t\t\t\t\t\t\tbreak;\n-\t\t\t\t\t\tcase 1:\n-\t\t\t\t\t\t\tfor (u16 i = 2; i < 4; i++)\n-\t\t\t\t\t\t\t\tvertices[i].Pos.Z -= BS / 2;\n-\t\t\t\t\t\t\tfor (u16 i = 0; i < 4; i++)\n-\t\t\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(91);\n-\t\t\t\t\t\t\tbreak;\n-\t\t\t\t\t\tcase 2:\n-\t\t\t\t\t\t\tfor (u16 i = 2; i < 4; i++)\n-\t\t\t\t\t\t\t\tvertices[i].Pos.Z -= BS / 2;\n-\t\t\t\t\t\t\tfor (u16 i = 0; i < 4; i++)\n-\t\t\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(181);\n-\t\t\t\t\t\t\tbreak;\n-\t\t\t\t\t\tcase 3:\n-\t\t\t\t\t\t\tfor (u16 i = 2; i < 4; i++)\n-\t\t\t\t\t\t\t\tvertices[i].Pos.Z -= BS / 2;\n-\t\t\t\t\t\t\tfor (u16 i = 0; i < 4; i++)\n-\t\t\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(271);\n-\t\t\t\t\t\t\tbreak;\n-\t\t\t\t\t\t}\n-\t\t\t\t\t\tbreak;\n-\t\t\t\t\t}\n-\t\t\t\t}\n-\n-\t\t\t\tfor (int i = 0; i < 4; i++) {\n-\t\t\t\t\tif (data->m_smooth_lighting)\n-\t\t\t\t\t\tvertices[i].Color = blendLight(frame, vertices[i].Pos, tile.color);\n-\t\t\t\t\tvertices[i].Pos += intToFloat(p, BS);\n-\t\t\t\t\t// move to a random spot to avoid moire\n-\t\t\t\t\tif ((f.param_type_2 == CPT2_MESHOPTIONS) && ((n.param2 & 0x8) != 0)) {\n-\t\t\t\t\t\tvertices[i].Pos.X += random_offset_X;\n-\t\t\t\t\t\tvertices[i].Pos.Z += random_offset_Z;\n-\t\t\t\t\t}\n-\t\t\t\t\t// randomly move each face up/down\n-\t\t\t\t\tif ((f.param_type_2 == CPT2_MESHOPTIONS) && ((n.param2 & 0x20) != 0)) {\n-\t\t\t\t\t\tPseudoRandom yrng(j | x<<16 | z<<8 | y<<24 );\n-\t\t\t\t\t\tvertices[i].Pos.Y -= BS * ((yrng.next() % 16 / 16.0) * 0.125);\n-\t\t\t\t\t}\n-\t\t\t\t}\n-\n-\t\t\t\tu16 indices[] = {0, 1, 2, 2, 3, 0};\n-\t\t\t\t// Add to mesh collector\n-\t\t\t\tcollector.append(tile, vertices, 4, indices, 6);\n-\n-\t\t\t\t// stop adding faces for meshes with less than 4 faces\n-\t\t\t\tif (f.param_type_2 == CPT2_MESHOPTIONS) {\n-\t\t\t\t\tif (((p2mesh == 0) || (p2mesh == 1)) && (j == 1))\n-\t\t\t\t\t\tbreak;\n-\t\t\t\t\telse if ((p2mesh == 2) && (j == 2))\n-\t\t\t\t\t\tbreak;\n-\t\t\t\t} else if (j == 1) {\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n+\tif (param2 > 0 && f->special_tiles[0].texture) {\n+\t\t// Interior volume level is in range 0 .. 63,\n+\t\t// convert it to -0.5 .. 0.5\n+\t\tfloat vlev = (param2 / 63.0) * 2.0 - 1.0;\n+\t\ttile = getSpecialTile(*f, n, 0);\n+\t\taabb3f box(-(nb[5] ? g : b),\n+\t\t           -(nb[4] ? g : b),\n+\t\t           -(nb[3] ? g : b),\n+\t\t            (nb[2] ? g : b),\n+\t\t            (nb[1] ? g : b) * vlev,\n+\t\t            (nb[0] ? g : b));\n+\t\tdrawAutoLightedCuboid(box);\n+\t}\n+}\n \n-\t\t\t}\n-\t\tbreak;}\n-\t\tcase NDT_FIRELIKE:\n-\t\t{\n-\t\t\tTileSpec tile = getNodeTileN(n, p, 0, data);\n-\t\t\ttile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;\n-\n-\t\t\tu16 l = getInteriorLight(n, 1, nodedef);\n-\t\t\tvideo::SColor c = encode_light_and_color(l, tile.color,\n-\t\t\t\tf.light_source);\n-\n-\t\t\tfloat s = BS / 2 * f.visual_scale;\n-\n-\t\t\tcontent_t current = n.getContent();\n-\t\t\tcontent_t n2c;\n-\t\t\tMapNode n2;\n-\t\t\tv3s16 n2p;\n-\n-\t\t\tstatic const v3s16 dirs[6] = {\n-\t\t\t\tv3s16( 0,  1,  0),\n-\t\t\t\tv3s16( 0, -1,  0),\n-\t\t\t\tv3s16( 1,  0,  0),\n-\t\t\t\tv3s16(-1,  0,  0),\n-\t\t\t\tv3s16( 0,  0,  1),\n-\t\t\t\tv3s16( 0,  0, -1)\n-\t\t\t};\n+void MapblockMeshGenerator::drawAllfacesNode()\n+{\n+\tstatic const aabb3f box(-BS/2, -BS/2, -BS/2, BS/2, BS/2, BS/2);\n+\tuseDefaultTile(false);\n+\tdrawAutoLightedCuboid(box);\n+}\n \n-\t\t\tint doDraw[6] = {0, 0, 0, 0, 0, 0};\n+void MapblockMeshGenerator::drawTorchlikeNode()\n+{\n+\tu8 wall = n.getWallMounted(nodedef);\n+\tu8 tileindex = 0;\n+\tswitch (wall) {\n+\t\tcase DWM_YP: tileindex = 1; break; // ceiling\n+\t\tcase DWM_YN: tileindex = 0; break; // floor\n+\t\tdefault:     tileindex = 2; // side (or invalid—should we care?)\n+\t}\n+\tuseTile(tileindex, true);\n+\n+\tfloat size = BS / 2 * f->visual_scale;\n+\tv3f vertices[4] = {\n+\t\tv3f(-size, -size, 0),\n+\t\tv3f( size, -size, 0),\n+\t\tv3f( size,  size, 0),\n+\t\tv3f(-size,  size, 0),\n+\t};\n+\tfor (int i = 0; i < 4; i++) {\n+\t\tswitch (wall) {\n+\t\t\tcase DWM_YP: vertices[i].rotateXZBy(-45); break;\n+\t\t\tcase DWM_YN: vertices[i].rotateXZBy( 45); break;\n+\t\t\tcase DWM_XP: vertices[i].rotateXZBy(  0); break;\n+\t\t\tcase DWM_XN: vertices[i].rotateXZBy(180); break;\n+\t\t\tcase DWM_ZP: vertices[i].rotateXZBy( 90); break;\n+\t\t\tcase DWM_ZN: vertices[i].rotateXZBy(-90); break;\n+\t\t}\n+\t}\n+\tdrawQuad(vertices);\n+}\n \n-\t\t\tbool drawAllFaces = true;\n+void MapblockMeshGenerator::drawSignlikeNode()\n+{\n+\tu8 wall = n.getWallMounted(nodedef);\n+\tuseTile(0, true);\n+\tfloat offset = BS/16;\n+\tfloat size = BS/2 * f->visual_scale;\n+\t// Wall at X+ of node\n+\tv3f vertices[4] = {\n+\t\tv3f(BS/2 - offset,  size,  size),\n+\t\tv3f(BS/2 - offset,  size, -size),\n+\t\tv3f(BS/2 - offset, -size, -size),\n+\t\tv3f(BS/2 - offset, -size,  size),\n+\t};\n+\tfor (int i = 0; i < 4; i++) {\n+\t\tswitch (wall) {\n+\t\t\tcase DWM_YP: vertices[i].rotateXYBy( 90); break;\n+\t\t\tcase DWM_YN: vertices[i].rotateXYBy(-90); break;\n+\t\t\tcase DWM_XP: vertices[i].rotateXZBy(  0); break;\n+\t\t\tcase DWM_XN: vertices[i].rotateXZBy(180); break;\n+\t\t\tcase DWM_ZP: vertices[i].rotateXZBy( 90); break;\n+\t\t\tcase DWM_ZN: vertices[i].rotateXZBy(-90); break;\n+\t\t}\n+\t}\n+\tdrawQuad(vertices);\n+}\n \n-\t\t\t// Check for adjacent nodes\n-\t\t\tfor (int i = 0; i < 6; i++) {\n-\t\t\t\tn2p = blockpos_nodes + p + dirs[i];\n-\t\t\t\tn2 = data->m_vmanip.getNodeNoEx(n2p);\n-\t\t\t\tn2c = n2.getContent();\n-\t\t\t\tif (n2c != CONTENT_IGNORE && n2c != CONTENT_AIR && n2c != current) {\n-\t\t\t\t\tdoDraw[i] = 1;\n-\t\t\t\t\tif (drawAllFaces)\n-\t\t\t\t\t\tdrawAllFaces = false;\n+void MapblockMeshGenerator::drawPlantlikeQuad(float rotation, float quad_offset,\n+\tbool offset_top_only)\n+{\n+\tv3f vertices[4] = {\n+\t\tv3f(-scale, -BS/2, 0),\n+\t\tv3f( scale, -BS/2, 0),\n+\t\tv3f( scale, -BS/2 + scale * 2, 0),\n+\t\tv3f(-scale, -BS/2 + scale * 2, 0),\n+\t};\n+\tif (random_offset_Y) {\n+\t\tPseudoRandom yrng(face_num++ | p.X << 16 | p.Z << 8 | p.Y << 24);\n+\t\toffset.Y = BS * ((yrng.next() % 16 / 16.0) * 0.125);\n+\t}\n+\tint offset_first_index = offset_top_only ? 2 : 0;\n+\tfor (int i = 0; i < 4; i++) {\n+\t\tif (i >= offset_first_index)\n+\t\t\tvertices[i].Z += quad_offset;\n+\t\tvertices[i].rotateXZBy(rotation + rotate_degree);\n+\t\tvertices[i] += offset;\n+\t}\n+\tdrawQuad(vertices);\n+}\n \n-\t\t\t\t}\n-\t\t\t}\n+void MapblockMeshGenerator::drawPlantlikeNode()\n+{\n+\tuseTile(0, false);\n+\tdraw_style = PLANT_STYLE_CROSS;\n+\tscale = BS / 2 * f->visual_scale;\n+\toffset = v3f(0, 0, 0);\n+\trotate_degree = 0;\n+\trandom_offset_Y = false;\n+\tface_num = 0;\n+\n+\tswitch (f->param_type_2) {\n+\tcase CPT2_MESHOPTIONS:\n+\t\tdraw_style = PlantlikeStyle(n.param2 & MO_MASK_STYLE);\n+\t\tif (n.param2 & MO_BIT_SCALE_SQRT2)\n+\t\t\tscale *= 1.41421;\n+\t\tif (n.param2 & MO_BIT_RANDOM_OFFSET) {\n+\t\t\tPseudoRandom rng(p.X << 8 | p.Z | p.Y << 16);\n+\t\t\toffset.X = BS * ((rng.next() % 16 / 16.0) * 0.29 - 0.145);\n+\t\t\toffset.Z = BS * ((rng.next() % 16 / 16.0) * 0.29 - 0.145);\n+\t\t}\n+\t\tif (n.param2 & MO_BIT_RANDOM_OFFSET_Y)\n+\t\t\trandom_offset_Y = true;\n+\t\tbreak;\n \n-\t\t\tfor (int j = 0; j < 6; j++) {\n-\n-\t\t\t\tvideo::S3DVertex vertices[4] = {\n-\t\t\t\t\tvideo::S3DVertex(-s, -BS / 2,         0, 0, 0, 0, c, 0, 1),\n-\t\t\t\t\tvideo::S3DVertex( s, -BS / 2,         0, 0, 0, 0, c, 1, 1),\n-\t\t\t\t\tvideo::S3DVertex( s, -BS / 2 + s * 2, 0, 0, 0, 0, c, 1, 0),\n-\t\t\t\t\tvideo::S3DVertex(-s, -BS / 2 + s * 2, 0, 0, 0, 0, c, 0, 0),\n-\t\t\t\t};\n-\n-\t\t\t\t// Calculate which faces should be drawn, (top or sides)\n-\t\t\t\tif (j == 0 && (drawAllFaces ||\n-\t\t\t\t\t\t(doDraw[3] == 1 || doDraw[1] == 1))) {\n-\t\t\t\t\tfor (int i = 0; i < 4; i++) {\n-\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(90);\n-\t\t\t\t\t\tvertices[i].Pos.rotateXYBy(-10);\n-\t\t\t\t\t\tvertices[i].Pos.X -= 4.0;\n-\t\t\t\t\t}\n-\t\t\t\t} else if (j == 1 && (drawAllFaces ||\n-\t\t\t\t\t\t(doDraw[5] == 1 || doDraw[1] == 1))) {\n-\t\t\t\t\tfor (int i = 0; i < 4; i++) {\n-\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(180);\n-\t\t\t\t\t\tvertices[i].Pos.rotateYZBy(10);\n-\t\t\t\t\t\tvertices[i].Pos.Z -= 4.0;\n-\t\t\t\t\t}\n-\t\t\t\t} else if (j == 2 && (drawAllFaces ||\n-\t\t\t\t\t\t(doDraw[2] == 1 || doDraw[1] == 1))) {\n-\t\t\t\t\tfor (int i = 0; i < 4; i++) {\n-\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(270);\n-\t\t\t\t\t\tvertices[i].Pos.rotateXYBy(10);\n-\t\t\t\t\t\tvertices[i].Pos.X += 4.0;\n-\t\t\t\t\t}\n-\t\t\t\t} else if (j == 3 && (drawAllFaces ||\n-\t\t\t\t\t\t(doDraw[4] == 1 || doDraw[1] == 1))) {\n-\t\t\t\t\tfor (int i = 0; i < 4; i++) {\n-\t\t\t\t\t\tvertices[i].Pos.rotateYZBy(-10);\n-\t\t\t\t\t\tvertices[i].Pos.Z += 4.0;\n-\t\t\t\t\t}\n-\t\t\t\t// Center cross-flames\n-\t\t\t\t} else if (j == 4 && (drawAllFaces || doDraw[1] == 1)) {\n-\t\t\t\t\tfor (int i = 0; i < 4; i++) {\n-\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(45);\n-\t\t\t\t\t}\n-\t\t\t\t} else if (j == 5 && (drawAllFaces || doDraw[1] == 1)) {\n-\t\t\t\t\tfor (int i = 0; i < 4; i++) {\n-\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(-45);\n-\t\t\t\t\t}\n-\t\t\t\t// Render flames on bottom of node above\n-\t\t\t\t} else if (j == 0 && doDraw[0] == 1 && doDraw[1] == 0) {\n-\t\t\t\t\tfor (int i = 0; i < 4; i++) {\n-\t\t\t\t\t\tvertices[i].Pos.rotateYZBy(70);\n-\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(90);\n-\t\t\t\t\t\tvertices[i].Pos.Y += 4.84;\n-\t\t\t\t\t\tvertices[i].Pos.X -= 4.7;\n-\t\t\t\t\t}\n-\t\t\t\t} else if (j == 1 && doDraw[0] == 1 && doDraw[1] == 0) {\n-\t\t\t\t\tfor (int i = 0; i < 4; i++) {\n-\t\t\t\t\t\tvertices[i].Pos.rotateYZBy(70);\n-\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(180);\n-\t\t\t\t\t\tvertices[i].Pos.Y += 4.84;\n-\t\t\t\t\t\tvertices[i].Pos.Z -= 4.7;\n-\t\t\t\t\t}\n-\t\t\t\t} else if (j == 2 && doDraw[0] == 1 && doDraw[1] == 0) {\n-\t\t\t\t\tfor (int i = 0; i < 4; i++) {\n-\t\t\t\t\t\tvertices[i].Pos.rotateYZBy(70);\n-\t\t\t\t\t\tvertices[i].Pos.rotateXZBy(270);\n-\t\t\t\t\t\tvertices[i].Pos.Y += 4.84;\n-\t\t\t\t\t\tvertices[i].Pos.X += 4.7;\n-\t\t\t\t\t}\n-\t\t\t\t} else if (j == 3 && doDraw[0] == 1 && doDraw[1] == 0) {\n-\t\t\t\t\tfor (int i = 0; i < 4; i++) {\n-\t\t\t\t\t\tvertices[i].Pos.rotateYZBy(70);\n-\t\t\t\t\t\tvertices[i].Pos.Y += 4.84;\n-\t\t\t\t\t\tvertices[i].Pos.Z += 4.7;\n-\t\t\t\t\t}\n-\t\t\t\t} else {\n-\t\t\t\t\t// Skip faces that aren't adjacent to a node\n-\t\t\t\t\tcontinue;\n-\t\t\t\t}\n-\n-\t\t\t\tfor (int i = 0; i < 4; i++) {\n-\t\t\t\t\tvertices[i].Pos *= f.visual_scale;\n-\t\t\t\t\tif (data->m_smooth_lighting)\n-\t\t\t\t\t\tvertices[i].Color = blendLight(frame, vertices[i].Pos, tile.color);\n-\t\t\t\t\tvertices[i].Pos += intToFloat(p, BS);\n-\t\t\t\t}\n-\n-\t\t\t\tu16 indices[] = {0, 1, 2, 2, 3, 0};\n-\t\t\t\t// Add to mesh collector\n-\t\t\t\tcollector.append(tile, vertices, 4, indices, 6);\n-\t\t\t}\n-\t\tbreak;}\n-\t\tcase NDT_FENCELIKE:\n-\t\t{\n-\t\t\tTileSpec tile = getNodeTile(n, p, v3s16(0,0,0), data);\n-\t\t\tTileSpec tile_nocrack = tile;\n-\t\t\ttile_nocrack.material_flags &= ~MATERIAL_FLAG_CRACK;\n-\n-\t\t\t// Put wood the right way around in the posts\n-\t\t\tTileSpec tile_rot = tile;\n-\t\t\ttile_rot.rotation = 1;\n-\n-\t\t\tu16 l = getInteriorLight(n, 1, nodedef);\n-\t\t\tvideo::SColor c = encode_light_and_color(l, tile.color,\n-\t\t\t\tf.light_source);\n-\n-\t\t\tconst f32 post_rad=(f32)BS/8;\n-\t\t\tconst f32 bar_rad=(f32)BS/16;\n-\t\t\tconst f32 bar_len=(f32)(BS/2)-post_rad;\n-\n-\t\t\tv3f pos = intToFloat(p, BS);\n-\n-\t\t\t// The post - always present\n-\t\t\taabb3f post(-post_rad,-BS/2,-post_rad,post_rad,BS/2,post_rad);\n-\t\t\tf32 postuv[24]={\n-\t\t\t\t\t6/16.,6/16.,10/16.,10/16.,\n-\t\t\t\t\t6/16.,6/16.,10/16.,10/16.,\n-\t\t\t\t\t0/16.,0,4/16.,1,\n-\t\t\t\t\t4/16.,0,8/16.,1,\n-\t\t\t\t\t8/16.,0,12/16.,1,\n-\t\t\t\t\t12/16.,0,16/16.,1};\n-\t\t\tmakeAutoLightedCuboidEx(&collector, data, pos, post, tile_rot, postuv, c, frame);\n-\n-\t\t\t// Now a section of fence, +X, if there's a post there\n-\t\t\tv3s16 p2 = p;\n-\t\t\tp2.X++;\n-\t\t\tMapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);\n-\t\t\tconst ContentFeatures *f2 = &nodedef->get(n2);\n-\t\t\tif(f2->drawtype == NDT_FENCELIKE)\n-\t\t\t{\n-\t\t\t\taabb3f bar(-bar_len+BS/2,-bar_rad+BS/4,-bar_rad,\n-\t\t\t\t\t\tbar_len+BS/2,bar_rad+BS/4,bar_rad);\n-\t\t\t\tf32 xrailuv[24]={\n-\t\t\t\t\t0/16.,2/16.,16/16.,4/16.,\n-\t\t\t\t\t0/16.,4/16.,16/16.,6/16.,\n-\t\t\t\t\t6/16.,6/16.,8/16.,8/16.,\n-\t\t\t\t\t10/16.,10/16.,12/16.,12/16.,\n-\t\t\t\t\t0/16.,8/16.,16/16.,10/16.,\n-\t\t\t\t\t0/16.,14/16.,16/16.,16/16.};\n-\t\t\t\tmakeAutoLightedCuboidEx(&collector, data, pos, bar, tile_nocrack, xrailuv, c, frame);\n-\t\t\t\tbar.MinEdge.Y -= BS/2;\n-\t\t\t\tbar.MaxEdge.Y -= BS/2;\n-\t\t\t\tmakeAutoLightedCuboidEx(&collector, data, pos, bar, tile_nocrack, xrailuv, c, frame);\n-\t\t\t}\n+\tcase CPT2_DEGROTATE:\n+\t\trotate_degree = n.param2 * 2;\n+\t\tbreak;\n \n-\t\t\t// Now a section of fence, +Z, if there's a post there\n-\t\t\tp2 = p;\n-\t\t\tp2.Z++;\n-\t\t\tn2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);\n-\t\t\tf2 = &nodedef->get(n2);\n-\t\t\tif(f2->drawtype == NDT_FENCELIKE)\n-\t\t\t{\n-\t\t\t\taabb3f bar(-bar_rad,-bar_rad+BS/4,-bar_len+BS/2,\n-\t\t\t\t\t\tbar_rad,bar_rad+BS/4,bar_len+BS/2);\n-\t\t\t\tf32 zrailuv[24]={\n-\t\t\t\t\t3/16.,1/16.,5/16.,5/16., // cannot rotate; stretch\n-\t\t\t\t\t4/16.,1/16.,6/16.,5/16., // for wood texture instead\n-\t\t\t\t\t0/16.,9/16.,16/16.,11/16.,\n-\t\t\t\t\t0/16.,6/16.,16/16.,8/16.,\n-\t\t\t\t\t6/16.,6/16.,8/16.,8/16.,\n-\t\t\t\t\t10/16.,10/16.,12/16.,12/16.};\n-\t\t\t\tmakeAutoLightedCuboidEx(&collector, data, pos, bar, tile_nocrack, zrailuv, c, frame);\n-\t\t\t\tbar.MinEdge.Y -= BS/2;\n-\t\t\t\tbar.MaxEdge.Y -= BS/2;\n-\t\t\t\tmakeAutoLightedCuboidEx(&collector, data, pos, bar, tile_nocrack, zrailuv, c, frame);\n-\t\t\t}\n-\t\tbreak;}\n-\t\tcase NDT_RAILLIKE:\n-\t\t{\n-\t\t\tbool 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) */\n-\t\t\tbool is_rail_z[6];\n-\n-\t\t\tcontent_t thiscontent = n.getContent();\n-\t\t\tstd::string groupname = \"connect_to_raillike\"; // name of the group that enables connecting to raillike nodes of different kind\n-\t\t\tint self_group = ((ItemGroupList) nodedef->get(n).groups)[groupname];\n-\n-\t\t\tu8 index = 0;\n-\t\t\tfor (s8 y0 = -1; y0 <= 1; y0++) {\n-\t\t\t\t// Prevent from indexing never used coordinates\n-\t\t\t\tfor (s8 xz = -1; xz <= 1; xz++) {\n-\t\t\t\t\tif (xz == 0)\n-\t\t\t\t\t\tcontinue;\n-\t\t\t\t\tMapNode n_xy = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x + xz, y + y0, z));\n-\t\t\t\t\tMapNode n_zy = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x, y + y0, z + xz));\n-\t\t\t\t\tconst ContentFeatures &def_xy = nodedef->get(n_xy);\n-\t\t\t\t\tconst ContentFeatures &def_zy = nodedef->get(n_zy);\n-\n-\t\t\t\t\t// Check if current node would connect with the rail\n-\t\t\t\t\tis_rail_x[index] = ((def_xy.drawtype == NDT_RAILLIKE\n-\t\t\t\t\t\t\t&& ((ItemGroupList) def_xy.groups)[groupname] == self_group)\n-\t\t\t\t\t\t\t|| n_xy.getContent() == thiscontent);\n-\n-\t\t\t\t\tis_rail_z[index] = ((def_zy.drawtype == NDT_RAILLIKE\n-\t\t\t\t\t\t\t&& ((ItemGroupList) def_zy.groups)[groupname] == self_group)\n-\t\t\t\t\t\t\t|| n_zy.getContent() == thiscontent);\n-\t\t\t\t\tindex++;\n-\t\t\t\t}\n-\t\t\t}\n+\tdefault:\n+\t\tbreak;\n+\t}\n \n-\t\t\tbool is_rail_x_all[2]; // [0] = negative x, [1] = positive x coordinate from the current node position\n-\t\t\tbool is_rail_z_all[2];\n-\t\t\tis_rail_x_all[0] = is_rail_x[0] || is_rail_x[2] || is_rail_x[4];\n-\t\t\tis_rail_x_all[1] = is_rail_x[1] || is_rail_x[3] || is_rail_x[5];\n-\t\t\tis_rail_z_all[0] = is_rail_z[0] || is_rail_z[2] || is_rail_z[4];\n-\t\t\tis_rail_z_all[1] = is_rail_z[1] || is_rail_z[3] || is_rail_z[5];\n-\n-\t\t\t// reasonable default, flat straight unrotated rail\n-\t\t\tbool is_straight = true;\n-\t\t\tint adjacencies = 0;\n-\t\t\tint angle = 0;\n-\t\t\tu8 tileindex = 0;\n-\n-\t\t\t// check for sloped rail\n-\t\t\tif (is_rail_x[4] || is_rail_x[5] || is_rail_z[4] || is_rail_z[5]) {\n-\t\t\t\tadjacencies = 5; // 5 means sloped\n-\t\t\t\tis_straight = true; // sloped is always straight\n-\t\t\t} else {\n-\t\t\t\t// is really straight, rails on both sides\n-\t\t\t\tis_straight = (is_rail_x_all[0] && is_rail_x_all[1]) || (is_rail_z_all[0] && is_rail_z_all[1]);\n-\t\t\t\tadjacencies = is_rail_x_all[0] + is_rail_x_all[1] + is_rail_z_all[0] + is_rail_z_all[1];\n-\t\t\t}\n+\tswitch (draw_style) {\n+\tcase PLANT_STYLE_CROSS:\n+\t\tdrawPlantlikeQuad(46);\n+\t\tdrawPlantlikeQuad(-44);\n+\t\tbreak;\n+\n+\tcase PLANT_STYLE_CROSS2:\n+\t\tdrawPlantlikeQuad(91);\n+\t\tdrawPlantlikeQuad(1);\n+\t\tbreak;\n+\n+\tcase PLANT_STYLE_STAR:\n+\t\tdrawPlantlikeQuad(121);\n+\t\tdrawPlantlikeQuad(241);\n+\t\tdrawPlantlikeQuad(1);\n+\t\tbreak;\n+\n+\tcase PLANT_STYLE_HASH:\n+\t\tdrawPlantlikeQuad(  1, BS/4);\n+\t\tdrawPlantlikeQuad( 91, BS/4);\n+\t\tdrawPlantlikeQuad(181, BS/4);\n+\t\tdrawPlantlikeQuad(271, BS/4);\n+\t\tbreak;\n+\n+\tcase PLANT_STYLE_HASH2:\n+\t\tdrawPlantlikeQuad(  1, -BS/2, true);\n+\t\tdrawPlantlikeQuad( 91, -BS/2, true);\n+\t\tdrawPlantlikeQuad(181, -BS/2, true);\n+\t\tdrawPlantlikeQuad(271, -BS/2, true);\n+\t\tbreak;\n+\t}\n+}\n \n-\t\t\tswitch (adjacencies) {\n-\t\t\tcase 1:\n-\t\t\t\tif (is_rail_x_all[0] || is_rail_x_all[1])\n-\t\t\t\t\tangle = 90;\n-\t\t\t\tbreak;\n-\t\t\tcase 2:\n-\t\t\t\tif (!is_straight)\n-\t\t\t\t\ttileindex = 1; // curved\n-\t\t\t\tif (is_rail_x_all[0] && is_rail_x_all[1])\n-\t\t\t\t\tangle = 90;\n-\t\t\t\tif (is_rail_z_all[0] && is_rail_z_all[1]) {\n-\t\t\t\t\tif (is_rail_z[4])\n-\t\t\t\t\t\tangle = 180;\n-\t\t\t\t}\n-\t\t\t\telse if (is_rail_x_all[0] && is_rail_z_all[0])\n-\t\t\t\t\tangle = 270;\n-\t\t\t\telse if (is_rail_x_all[0] && is_rail_z_all[1])\n-\t\t\t\t\tangle = 180;\n-\t\t\t\telse if (is_rail_x_all[1] && is_rail_z_all[1])\n-\t\t\t\t\tangle = 90;\n-\t\t\t\tbreak;\n-\t\t\tcase 3:\n-\t\t\t\t// here is where the potential to 'switch' a junction is, but not implemented at present\n-\t\t\t\ttileindex = 2; // t-junction\n-\t\t\t\tif(!is_rail_x_all[1])\n-\t\t\t\t\tangle = 180;\n-\t\t\t\tif(!is_rail_z_all[0])\n-\t\t\t\t\tangle = 90;\n-\t\t\t\tif(!is_rail_z_all[1])\n-\t\t\t\t\tangle = 270;\n-\t\t\t\tbreak;\n-\t\t\tcase 4:\n-\t\t\t\ttileindex = 3; // crossing\n-\t\t\t\tbreak;\n-\t\t\tcase 5: //sloped\n-\t\t\t\tif (is_rail_z[4])\n-\t\t\t\t\tangle = 180;\n-\t\t\t\tif (is_rail_x[4])\n-\t\t\t\t\tangle = 90;\n-\t\t\t\tif (is_rail_x[5])\n-\t\t\t\t\tangle = -90;\n-\t\t\t\tbreak;\n-\t\t\tdefault:\n-\t\t\t\tbreak;\n-\t\t\t}\n+void MapblockMeshGenerator::drawFirelikeQuad(float rotation, float opening_angle,\n+\tfloat offset_h, float offset_v)\n+{\n+\tv3f vertices[4] = {\n+\t\tv3f(-scale, -BS/2, 0),\n+\t\tv3f( scale, -BS/2, 0),\n+\t\tv3f( scale, -BS/2 + scale * 2, 0),\n+\t\tv3f(-scale, -BS/2 + scale * 2, 0),\n+\t};\n+\tfor (int i = 0; i < 4; i++) {\n+\t\tvertices[i].rotateYZBy(opening_angle);\n+\t\tvertices[i].Z += offset_h;\n+\t\tvertices[i].rotateXZBy(rotation);\n+\t\tvertices[i].Y += offset_v;\n+\t}\n+\tdrawQuad(vertices);\n+}\n \n-\t\t\tTileSpec tile = getNodeTileN(n, p, tileindex, data);\n-\t\t\ttile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;\n-\t\t\ttile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;\n+void MapblockMeshGenerator::drawFirelikeNode()\n+{\n+\tuseTile(0, false);\n+\tscale = BS / 2 * f->visual_scale;\n+\n+\t// Check for adjacent nodes\n+\tbool neighbors = false;\n+\tbool neighbor[6] = { 0, 0, 0, 0, 0, 0 };\n+\tcontent_t current = n.getContent();\n+\tfor (int i = 0; i < 6; i++) {\n+\t\tv3s16 n2p = blockpos_nodes + p + g_6dirs[i];\n+\t\tMapNode n2 = data->m_vmanip.getNodeNoEx(n2p);\n+\t\tcontent_t n2c = n2.getContent();\n+\t\tif (n2c != CONTENT_IGNORE && n2c != CONTENT_AIR && n2c != current) {\n+\t\t\tneighbor[i] = true;\n+\t\t\tneighbors = true;\n+\t\t}\n+\t}\n+\tbool drawBasicFire = neighbor[D6D_YN] || !neighbors;\n+\tbool drawBottomFire = neighbor[D6D_YP];\n+\n+\tif (drawBasicFire || neighbor[D6D_ZP])\n+\t\tdrawFirelikeQuad(  0, -10, 0.4 * BS);\n+\telse if (drawBottomFire)\n+\t\tdrawFirelikeQuad(  0, 70, 0.47 * BS, 0.484 * BS);\n+\n+\tif (drawBasicFire || neighbor[D6D_XN])\n+\t\tdrawFirelikeQuad( 90, -10, 0.4 * BS);\n+\telse if (drawBottomFire)\n+\t\tdrawFirelikeQuad( 90, 70, 0.47 * BS, 0.484 * BS);\n+\n+\tif (drawBasicFire || neighbor[D6D_ZN])\n+\t\tdrawFirelikeQuad(180, -10, 0.4 * BS);\n+\telse if (drawBottomFire)\n+\t\tdrawFirelikeQuad(180, 70, 0.47 * BS, 0.484 * BS);\n+\n+\tif (drawBasicFire || neighbor[D6D_XP])\n+\t\tdrawFirelikeQuad(270, -10, 0.4 * BS);\n+\telse if (drawBottomFire)\n+\t\tdrawFirelikeQuad(270, 70, 0.47 * BS, 0.484 * BS);\n+\n+\tif (drawBasicFire) {\n+\t\tdrawFirelikeQuad(45, 0, 0.0);\n+\t\tdrawFirelikeQuad(-45, 0, 0.0);\n+\t}\n+}\n \n-\t\t\tu16 l = getInteriorLight(n, 0, nodedef);\n-\t\t\tvideo::SColor c = encode_light_and_color(l, tile.color,\n-\t\t\t\tf.light_source);\n+void MapblockMeshGenerator::drawFencelikeNode()\n+{\n+\tuseDefaultTile(false);\n+\tTileSpec tile_nocrack = tile;\n+\ttile_nocrack.material_flags &= ~MATERIAL_FLAG_CRACK;\n+\n+\t// Put wood the right way around in the posts\n+\tTileSpec tile_rot = tile;\n+\ttile_rot.rotation = 1;\n+\n+\tstatic const f32 post_rad = BS/8;\n+\tstatic const f32 bar_rad  = BS/16;\n+\tstatic const f32 bar_len  = BS/2 - post_rad;\n+\n+\t// The post - always present\n+\tstatic const aabb3f post(-post_rad, -BS/2, -post_rad,\n+\t                          post_rad,  BS/2,  post_rad);\n+\tstatic const f32 postuv[24] = {\n+\t\t0.375, 0.375, 0.625, 0.625,\n+\t\t0.375, 0.375, 0.625, 0.625,\n+\t\t0.000, 0.000, 0.250, 1.000,\n+\t\t0.250, 0.000, 0.500, 1.000,\n+\t\t0.500, 0.000, 0.750, 1.000,\n+\t\t0.750, 0.000, 1.000, 1.000,\n+\t};\n+\ttile = tile_rot;\n+\tdrawAutoLightedCuboid(post, postuv);\n+\n+\ttile = tile_nocrack;\n+\n+\t// Now a section of fence, +X, if there's a post there\n+\tv3s16 p2 = p;\n+\tp2.X++;\n+\tMapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);\n+\tconst ContentFeatures *f2 = &nodedef->get(n2);\n+\tif (f2->drawtype == NDT_FENCELIKE) {\n+\t\tstatic const aabb3f bar_x1(BS/2 - bar_len,  BS/4 - bar_rad, -bar_rad,\n+\t\t                           BS/2 + bar_len,  BS/4 + bar_rad,  bar_rad);\n+\t\tstatic const aabb3f bar_x2(BS/2 - bar_len, -BS/4 - bar_rad, -bar_rad,\n+\t\t                           BS/2 + bar_len, -BS/4 + bar_rad,  bar_rad);\n+\t\tstatic const f32 xrailuv[24] = {\n+\t\t\t0.000, 0.125, 1.000, 0.250,\n+\t\t\t0.000, 0.250, 1.000, 0.375,\n+\t\t\t0.375, 0.375, 0.500, 0.500,\n+\t\t\t0.625, 0.625, 0.750, 0.750,\n+\t\t\t0.000, 0.500, 1.000, 0.625,\n+\t\t\t0.000, 0.875, 1.000, 1.000,\n+\t\t};\n+\t\tdrawAutoLightedCuboid(bar_x1, xrailuv);\n+\t\tdrawAutoLightedCuboid(bar_x2, xrailuv);\n+\t}\n \n-\t\t\tfloat d = (float)BS/64;\n-\t\t\tfloat s = BS/2;\n+\t// Now a section of fence, +Z, if there's a post there\n+\tp2 = p;\n+\tp2.Z++;\n+\tn2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);\n+\tf2 = &nodedef->get(n2);\n+\tif (f2->drawtype == NDT_FENCELIKE) {\n+\t\tstatic const aabb3f bar_z1(-bar_rad,  BS/4 - bar_rad, BS/2 - bar_len,\n+\t\t                            bar_rad,  BS/4 + bar_rad, BS/2 + bar_len);\n+\t\tstatic const aabb3f bar_z2(-bar_rad, -BS/4 - bar_rad, BS/2 - bar_len,\n+\t\t                            bar_rad, -BS/4 + bar_rad, BS/2 + bar_len);\n+\t\tstatic const f32 zrailuv[24] = {\n+\t\t\t0.1875, 0.0625, 0.3125, 0.3125, // cannot rotate; stretch\n+\t\t\t0.2500, 0.0625, 0.3750, 0.3125, // for wood texture instead\n+\t\t\t0.0000, 0.5625, 1.0000, 0.6875,\n+\t\t\t0.0000, 0.3750, 1.0000, 0.5000,\n+\t\t\t0.3750, 0.3750, 0.5000, 0.5000,\n+\t\t\t0.6250, 0.6250, 0.7500, 0.7500,\n+\t\t};\n+\t\tdrawAutoLightedCuboid(bar_z1, zrailuv);\n+\t\tdrawAutoLightedCuboid(bar_z2, zrailuv);\n+\t}\n+}\n \n-\t\t\tshort g = -1;\n-\t\t\tif (is_rail_x[4] || is_rail_x[5] || is_rail_z[4] || is_rail_z[5])\n-\t\t\t\tg = 1; //Object is at a slope\n+bool MapblockMeshGenerator::isSameRail(v3s16 dir)\n+{\n+\tMapNode node2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p + dir);\n+\tif (node2.getContent() == n.getContent())\n+\t\treturn true;\n+\tconst ContentFeatures &def2 = nodedef->get(node2);\n+\treturn (def2.drawtype == NDT_RAILLIKE) &&\n+\t\t(def2.getGroup(raillike_groupname) ","path":"src/content_mapblock.cpp","position":null,"original_position":2790,"commit_id":"2c4899a16dff3a52b77d60b48571d4ee320c2431","original_commit_id":"2c4899a16dff3a52b77d60b48571d4ee320c2431","user":{"login":"numberZero","id":7352626,"avatar_url":"https://avatars3.githubusercontent.com/u/7352626?v=3","gravatar_id":"","url":"https://api.github.com/users/numberZero","html_url":"https://github.com/numberZero","followers_url":"https://api.github.com/users/numberZero/followers","following_url":"https://api.github.com/users/numberZero/following{/other_user}","gists_url":"https://api.github.com/users/numberZero/gists{/gist_id}","starred_url":"https://api.github.com/users/numberZero/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/numberZero/subscriptions","organizations_url":"https://api.github.com/users/numberZero/orgs","repos_url":"https://api.github.com/users/numberZero/repos","events_url":"https://api.github.com/users/numberZero/events{/privacy}","received_events_url":"https://api.github.com/users/numberZero/received_events","type":"User","site_admin":false},"body":"where? do you mean you see this (due to 4-space tabs):\r\n```\r\n    return (def2.drawtype == NDT_RAILLIKE) &&\r\n        (def2.getGroup(raillike_groupname) == raillike_group);\r\n```\r\nand want to see this:\r\n```\r\n    return (def2.drawtype == NDT_RAILLIKE) &&\r\n           (def2.getGroup(raillike_groupname) == raillike_group);\r\n```\r\nor this\r\n```\r\n    return ((def2.drawtype == NDT_RAILLIKE) &&\r\n            (def2.getGroup(raillike_groupname) == raillike_group));\r\n```\r\n?\r\n(I usually use variable-width font myself so everything looks a bit different for me)","created_at":"2017-03-18T11:04:40Z","updated_at":"2017-03-18T11:04:40Z","html_url":"https://github.com/minetest/minetest/pull/5227#discussion_r106778660","pull_request_url":"https://api.github.com/repos/minetest/minetest/pulls/5227","_links":{"self":{"href":"https://api.github.com/repos/minetest/minetest/pulls/comments/106778660"},"html":{"href":"https://github.com/minetest/minetest/pull/5227#discussion_r106778660"},"pull_request":{"href":"https://api.github.com/repos/minetest/minetest/pulls/5227"}}},"pull_request":{"url":"https://api.github.com/repos/minetest/minetest/pulls/5227","id":105928810,"html_url":"https://github.com/minetest/minetest/pull/5227","diff_url":"https://github.com/minetest/minetest/pull/5227.diff","patch_url":"https://github.com/minetest/minetest/pull/5227.patch","issue_url":"https://api.github.com/repos/minetest/minetest/issues/5227","number":5227,"state":"open","locked":false,"title":"[squashed] Refactor content_mapblock","user":{"login":"numberZero","id":7352626,"avatar_url":"https://avatars3.githubusercontent.com/u/7352626?v=3","gravatar_id":"","url":"https://api.github.com/users/numberZero","html_url":"https://github.com/numberZero","followers_url":"https://api.github.com/users/numberZero/followers","following_url":"https://api.github.com/users/numberZero/following{/other_user}","gists_url":"https://api.github.com/users/numberZero/gists{/gist_id}","starred_url":"https://api.github.com/users/numberZero/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/numberZero/subscriptions","organizations_url":"https://api.github.com/users/numberZero/orgs","repos_url":"https://api.github.com/users/numberZero/repos","events_url":"https://api.github.com/users/numberZero/events{/privacy}","received_events_url":"https://api.github.com/users/numberZero/received_events","type":"User","site_admin":false},"body":"Squashed #5159 ","created_at":"2017-02-13T16:29:56Z","updated_at":"2017-03-18T11:04:40Z","closed_at":null,"merged_at":null,"merge_commit_sha":"77f428b4a4204cfb512dc13f648da630147fa515","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/minetest/minetest/pulls/5227/commits","review_comments_url":"https://api.github.com/repos/minetest/minetest/pulls/5227/comments","review_comment_url":"https://api.github.com/repos/minetest/minetest/pulls/comments{/number}","comments_url":"https://api.github.com/repos/minetest/minetest/issues/5227/comments","statuses_url":"https://api.github.com/repos/minetest/minetest/statuses/2c4899a16dff3a52b77d60b48571d4ee320c2431","head":{"label":"numberZero:dev-refactor-content-mapblock-squashed","ref":"dev-refactor-content-mapblock-squashed","sha":"2c4899a16dff3a52b77d60b48571d4ee320c2431","user":{"login":"numberZero","id":7352626,"avatar_url":"https://avatars3.githubusercontent.com/u/7352626?v=3","gravatar_id":"","url":"https://api.github.com/users/numberZero","html_url":"https://github.com/numberZero","followers_url":"https://api.github.com/users/numberZero/followers","following_url":"https://api.github.com/users/numberZero/following{/other_user}","gists_url":"https://api.github.com/users/numberZero/gists{/gist_id}","starred_url":"https://api.github.com/users/numberZero/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/numberZero/subscriptions","organizations_url":"https://api.github.com/users/numberZero/orgs","repos_url":"https://api.github.com/users/numberZero/repos","events_url":"https://api.github.com/users/numberZero/events{/privacy}","received_events_url":"https://api.github.com/users/numberZero/received_events","type":"User","site_admin":false},"repo":{"id":68446342,"name":"minetest","full_name":"numberZero/minetest","owner":{"login":"numberZero","id":7352626,"avatar_url":"https://avatars3.githubusercontent.com/u/7352626?v=3","gravatar_id":"","url":"https://api.github.com/users/numberZero","html_url":"https://github.com/numberZero","followers_url":"https://api.github.com/users/numberZero/followers","following_url":"https://api.github.com/users/numberZero/following{/other_user}","gists_url":"https://api.github.com/users/numberZero/gists{/gist_id}","starred_url":"https://api.github.com/users/numberZero/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/numberZero/subscriptions","organizations_url":"https://api.github.com/users/numberZero/orgs","repos_url":"https://api.github.com/users/numberZero/repos","events_url":"https://api.github.com/users/numberZero/events{/privacy}","received_events_url":"https://api.github.com/users/numberZero/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/numberZero/minetest","description":"Minetest, an open source infinite-world block sandbox game with survival and crafting. [also https://github.com/minetest/minetest_game]","fork":true,"url":"https://api.github.com/repos/numberZero/minetest","forks_url":"https://api.github.com/repos/numberZero/minetest/forks","keys_url":"https://api.github.com/repos/numberZero/minetest/keys{/key_id}","collaborators_url":"https://api.github.com/repos/numberZero/minetest/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/numberZero/minetest/teams","hooks_url":"https://api.github.com/repos/numberZero/minetest/hooks","issue_events_url":"https://api.github.com/repos/numberZero/minetest/issues/events{/number}","events_url":"https://api.github.com/repos/numberZero/minetest/events","assignees_url":"https://api.github.com/repos/numberZero/minetest/assignees{/user}","branches_url":"https://api.github.com/repos/numberZero/minetest/branches{/branch}","tags_url":"https://api.github.com/repos/numberZero/minetest/tags","blobs_url":"https://api.github.com/repos/numberZero/minetest/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/numberZero/minetest/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/numberZero/minetest/git/refs{/sha}","trees_url":"https://api.github.com/repos/numberZero/minetest/git/trees{/sha}","statuses_url":"https://api.github.com/repos/numberZero/minetest/statuses/{sha}","languages_url":"https://api.github.com/repos/numberZero/minetest/languages","stargazers_url":"https://api.github.com/repos/numberZero/minetest/stargazers","contributors_url":"https://api.github.com/repos/numberZero/minetest/contributors","subscribers_url":"https://api.github.com/repos/numberZero/minetest/subscribers","subscription_url":"https://api.github.com/repos/numberZero/minetest/subscription","commits_url":"https://api.github.com/repos/numberZero/minetest/commits{/sha}","git_commits_url":"https://api.github.com/repos/numberZero/minetest/git/commits{/sha}","comments_url":"https://api.github.com/repos/numberZero/minetest/comments{/number}","issue_comment_url":"https://api.github.com/repos/numberZero/minetest/issues/comments{/number}","contents_url":"https://api.github.com/repos/numberZero/minetest/contents/{+path}","compare_url":"https://api.github.com/repos/numberZero/minetest/compare/{base}...{head}","merges_url":"https://api.github.com/repos/numberZero/minetest/merges","archive_url":"https://api.github.com/repos/numberZero/minetest/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/numberZero/minetest/downloads","issues_url":"https://api.github.com/repos/numberZero/minetest/issues{/number}","pulls_url":"https://api.github.com/repos/numberZero/minetest/pulls{/number}","milestones_url":"https://api.github.com/repos/numberZero/minetest/milestones{/number}","notifications_url":"https://api.github.com/repos/numberZero/minetest/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/numberZero/minetest/labels{/name}","releases_url":"https://api.github.com/repos/numberZero/minetest/releases{/id}","deployments_url":"https://api.github.com/repos/numberZero/minetest/deployments","created_at":"2016-09-17T10:42:06Z","updated_at":"2016-09-17T10:42:10Z","pushed_at":"2017-03-11T14:31:08Z","git_url":"git://github.com/numberZero/minetest.git","ssh_url":"git@github.com:numberZero/minetest.git","clone_url":"https://github.com/numberZero/minetest.git","svn_url":"https://github.com/numberZero/minetest","homepage":"http://minetest.net/","size":46295,"stargazers_count":0,"watchers_count":0,"language":"C++","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"experimental"}},"base":{"label":"minetest:master","ref":"master","sha":"2dcbc019044b1af22e056c5bdb586f94c83092ad","user":{"login":"minetest","id":2624745,"avatar_url":"https://avatars2.githubusercontent.com/u/2624745?v=3","gravatar_id":"","url":"https://api.github.com/users/minetest","html_url":"https://github.com/minetest","followers_url":"https://api.github.com/users/minetest/followers","following_url":"https://api.github.com/users/minetest/following{/other_user}","gists_url":"https://api.github.com/users/minetest/gists{/gist_id}","starred_url":"https://api.github.com/users/minetest/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/minetest/subscriptions","organizations_url":"https://api.github.com/users/minetest/orgs","repos_url":"https://api.github.com/users/minetest/repos","events_url":"https://api.github.com/users/minetest/events{/privacy}","received_events_url":"https://api.github.com/users/minetest/received_events","type":"Organization","site_admin":false},"repo":{"id":2168780,"name":"minetest","full_name":"minetest/minetest","owner":{"login":"minetest","id":2624745,"avatar_url":"https://avatars2.githubusercontent.com/u/2624745?v=3","gravatar_id":"","url":"https://api.github.com/users/minetest","html_url":"https://github.com/minetest","followers_url":"https://api.github.com/users/minetest/followers","following_url":"https://api.github.com/users/minetest/following{/other_user}","gists_url":"https://api.github.com/users/minetest/gists{/gist_id}","starred_url":"https://api.github.com/users/minetest/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/minetest/subscriptions","organizations_url":"https://api.github.com/users/minetest/orgs","repos_url":"https://api.github.com/users/minetest/repos","events_url":"https://api.github.com/users/minetest/events{/privacy}","received_events_url":"https://api.github.com/users/minetest/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/minetest/minetest","description":"Minetest, an open source infinite-world block sandbox game with survival and crafting. [also https://github.com/minetest/minetest_game]","fork":false,"url":"https://api.github.com/repos/minetest/minetest","forks_url":"https://api.github.com/repos/minetest/minetest/forks","keys_url":"https://api.github.com/repos/minetest/minetest/keys{/key_id}","collaborators_url":"https://api.github.com/repos/minetest/minetest/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/minetest/minetest/teams","hooks_url":"https://api.github.com/repos/minetest/minetest/hooks","issue_events_url":"https://api.github.com/repos/minetest/minetest/issues/events{/number}","events_url":"https://api.github.com/repos/minetest/minetest/events","assignees_url":"https://api.github.com/repos/minetest/minetest/assignees{/user}","branches_url":"https://api.github.com/repos/minetest/minetest/branches{/branch}","tags_url":"https://api.github.com/repos/minetest/minetest/tags","blobs_url":"https://api.github.com/repos/minetest/minetest/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/minetest/minetest/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/minetest/minetest/git/refs{/sha}","trees_url":"https://api.github.com/repos/minetest/minetest/git/trees{/sha}","statuses_url":"https://api.github.com/repos/minetest/minetest/statuses/{sha}","languages_url":"https://api.github.com/repos/minetest/minetest/languages","stargazers_url":"https://api.github.com/repos/minetest/minetest/stargazers","contributors_url":"https://api.github.com/repos/minetest/minetest/contributors","subscribers_url":"https://api.github.com/repos/minetest/minetest/subscribers","subscription_url":"https://api.github.com/repos/minetest/minetest/subscription","commits_url":"https://api.github.com/repos/minetest/minetest/commits{/sha}","git_commits_url":"https://api.github.com/repos/minetest/minetest/git/commits{/sha}","comments_url":"https://api.github.com/repos/minetest/minetest/comments{/number}","issue_comment_url":"https://api.github.com/repos/minetest/minetest/issues/comments{/number}","contents_url":"https://api.github.com/repos/minetest/minetest/contents/{+path}","compare_url":"https://api.github.com/repos/minetest/minetest/compare/{base}...{head}","merges_url":"https://api.github.com/repos/minetest/minetest/merges","archive_url":"https://api.github.com/repos/minetest/minetest/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/minetest/minetest/downloads","issues_url":"https://api.github.com/repos/minetest/minetest/issues{/number}","pulls_url":"https://api.github.com/repos/minetest/minetest/pulls{/number}","milestones_url":"https://api.github.com/repos/minetest/minetest/milestones{/number}","notifications_url":"https://api.github.com/repos/minetest/minetest/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/minetest/minetest/labels{/name}","releases_url":"https://api.github.com/repos/minetest/minetest/releases{/id}","deployments_url":"https://api.github.com/repos/minetest/minetest/deployments","created_at":"2011-08-07T13:48:36Z","updated_at":"2017-03-17T13:31:14Z","pushed_at":"2017-03-18T10:10:15Z","git_url":"git://github.com/minetest/minetest.git","ssh_url":"git@github.com:minetest/minetest.git","clone_url":"https://github.com/minetest/minetest.git","svn_url":"https://github.com/minetest/minetest","homepage":"http://minetest.net/","size":46321,"stargazers_count":2453,"watchers_count":2453,"language":"C++","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":743,"mirror_url":null,"open_issues_count":1051,"forks":743,"open_issues":1051,"watchers":2453,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/minetest/minetest/pulls/5227"},"html":{"href":"https://github.com/minetest/minetest/pull/5227"},"issue":{"href":"https://api.github.com/repos/minetest/minetest/issues/5227"},"comments":{"href":"https://api.github.com/repos/minetest/minetest/issues/5227/comments"},"review_comments":{"href":"https://api.github.com/repos/minetest/minetest/pulls/5227/comments"},"review_comment":{"href":"https://api.github.com/repos/minetest/minetest/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/minetest/minetest/pulls/5227/commits"},"statuses":{"href":"https://api.github.com/repos/minetest/minetest/statuses/2c4899a16dff3a52b77d60b48571d4ee320c2431"}}}}
{"actor":{"display_login":"numberZero"}}